diff options
Diffstat (limited to 'contrib/llvm-project/clang/include/clang/AST/Expr.h')
-rw-r--r-- | contrib/llvm-project/clang/include/clang/AST/Expr.h | 908 |
1 files changed, 555 insertions, 353 deletions
diff --git a/contrib/llvm-project/clang/include/clang/AST/Expr.h b/contrib/llvm-project/clang/include/clang/AST/Expr.h index 8efa8fdbe2bb..9820bd11da86 100644 --- a/contrib/llvm-project/clang/include/clang/AST/Expr.h +++ b/contrib/llvm-project/clang/include/clang/AST/Expr.h @@ -13,6 +13,7 @@ #ifndef LLVM_CLANG_AST_EXPR_H #define LLVM_CLANG_AST_EXPR_H +#include "clang/AST/APNumericStorage.h" #include "clang/AST/APValue.h" #include "clang/AST/ASTVector.h" #include "clang/AST/ComputeDependence.h" @@ -36,6 +37,7 @@ #include "llvm/Support/AtomicOrdering.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/TrailingObjects.h" +#include <optional> namespace clang { class APValue; @@ -134,8 +136,8 @@ protected: void setDependence(ExprDependence Deps) { ExprBits.Dependent = static_cast<unsigned>(Deps); } - friend class ASTImporter; // Sets dependence dircetly. - friend class ASTStmtReader; // Sets dependence dircetly. + friend class ASTImporter; // Sets dependence directly. + friend class ASTStmtReader; // Sets dependence directly. public: QualType getType() const { return TR; } @@ -170,7 +172,7 @@ public: } /// Determines whether the type of this expression depends on - /// - a template paramter (C++ [temp.dep.expr], which means that its type + /// - a template parameter (C++ [temp.dep.expr], which means that its type /// could change from one template instantiation to the next) /// - or an error /// @@ -523,15 +525,25 @@ public: /// semantically correspond to a bool. bool isKnownToHaveBooleanValue(bool Semantic = true) const; + /// Check whether this array fits the idiom of a flexible array member, + /// depending on the value of -fstrict-flex-array. + /// When IgnoreTemplateOrMacroSubstitution is set, it doesn't consider sizes + /// resulting from the substitution of a macro or a template as special sizes. + bool isFlexibleArrayMemberLike( + ASTContext &Context, + LangOptions::StrictFlexArraysLevelKind StrictFlexArraysLevel, + bool IgnoreTemplateOrMacroSubstitution = false) const; + /// isIntegerConstantExpr - Return the value if this expression is a valid - /// integer constant expression. If not a valid i-c-e, return None and fill - /// in Loc (if specified) with the location of the invalid expression. + /// integer constant expression. If not a valid i-c-e, return std::nullopt + /// and fill in Loc (if specified) with the location of the invalid + /// expression. /// /// Note: This does not perform the implicit conversions required by C++11 /// [expr.const]p5. - Optional<llvm::APSInt> getIntegerConstantExpr(const ASTContext &Ctx, - SourceLocation *Loc = nullptr, - bool isEvaluated = true) const; + std::optional<llvm::APSInt> + getIntegerConstantExpr(const ASTContext &Ctx, + SourceLocation *Loc = nullptr) const; bool isIntegerConstantExpr(const ASTContext &Ctx, SourceLocation *Loc = nullptr) const; @@ -555,7 +567,7 @@ public: SmallVectorImpl< PartialDiagnosticAt> &Diags); - /// isPotentialConstantExprUnevaluted - Return true if this expression might + /// isPotentialConstantExprUnevaluated - Return true if this expression might /// be usable in a constant expression in C++11 in an unevaluated context, if /// it were in function FD marked constexpr. Return false if the function can /// never produce a constant expression, along with diagnostics describing @@ -572,16 +584,22 @@ public: bool isConstantInitializer(ASTContext &Ctx, bool ForRef, const Expr **Culprit = nullptr) const; + /// If this expression is an unambiguous reference to a single declaration, + /// in the style of __builtin_function_start, return that declaration. Note + /// that this may return a non-static member function or field in C++ if this + /// expression is a member pointer constant. + const ValueDecl *getAsBuiltinConstantDeclRef(const ASTContext &Context) const; + /// EvalStatus is a struct with detailed info about an evaluation in progress. struct EvalStatus { /// Whether the evaluated expression has side effects. /// For example, (f() && 0) can be folded, but it still has side effects. - bool HasSideEffects; + bool HasSideEffects = false; /// Whether the evaluation hit undefined behavior. /// For example, 1.0 / 0.0 can be folded to Inf, but has undefined behavior. /// Likewise, INT_MAX + 1 can be folded to INT_MIN, but has UB. - bool HasUndefinedBehavior; + bool HasUndefinedBehavior = false; /// Diag - If this is non-null, it will be filled in with a stack of notes /// indicating why evaluation failed (or why it failed to produce a constant @@ -590,10 +608,16 @@ public: /// foldable. If the expression is foldable, but not a constant expression, /// the notes will describes why it isn't a constant expression. If the /// expression *is* a constant expression, no notes will be produced. - SmallVectorImpl<PartialDiagnosticAt> *Diag; + /// + /// FIXME: this causes significant performance concerns and should be + /// refactored at some point. Not all evaluations of the constant + /// expression interpreter will display the given diagnostics, this means + /// those kinds of uses are paying the expense of generating a diagnostic + /// (which may include expensive operations like converting APValue objects + /// to a string representation). + SmallVectorImpl<PartialDiagnosticAt> *Diag = nullptr; - EvalStatus() - : HasSideEffects(false), HasUndefinedBehavior(false), Diag(nullptr) {} + EvalStatus() = default; // hasSideEffects - Return true if the evaluated expression has // side effects. @@ -648,8 +672,8 @@ public: SideEffectsKind AllowSideEffects = SE_NoSideEffects, bool InConstantContext = false) const; - /// EvaluateAsFloat - Return true if this is a constant which we can fold and - /// convert to a fixed point value. + /// EvaluateAsFixedPoint - Return true if this is a constant which we can fold + /// and convert to a fixed point value. bool EvaluateAsFixedPoint(EvalResult &Result, const ASTContext &Ctx, SideEffectsKind AllowSideEffects = SE_NoSideEffects, bool InConstantContext = false) const; @@ -697,7 +721,8 @@ public: /// notes will be produced if the expression is not a constant expression. bool EvaluateAsInitializer(APValue &Result, const ASTContext &Ctx, const VarDecl *VD, - SmallVectorImpl<PartialDiagnosticAt> &Notes) const; + SmallVectorImpl<PartialDiagnosticAt> &Notes, + bool IsConstantInitializer) const; /// EvaluateWithSubstitution - Evaluate an expression as if from the context /// of a call to the given function with the given arguments, inside an @@ -739,6 +764,17 @@ public: bool tryEvaluateObjectSize(uint64_t &Result, ASTContext &Ctx, unsigned Type) const; + /// If the current Expr is a pointer, this will try to statically + /// determine the strlen of the string pointed to. + /// Returns true if all of the above holds and we were able to figure out the + /// strlen, false otherwise. + bool tryEvaluateStrLen(uint64_t &Result, ASTContext &Ctx) const; + + bool EvaluateCharRangeAsString(std::string &Result, + const Expr *SizeExpression, + const Expr *PtrExpression, ASTContext &Ctx, + EvalResult &Status) const; + /// Enumeration used to describe the kind of Null pointer constant /// returned from \c isNullPointerConstant(). enum NullPointerConstantKind { @@ -796,7 +832,7 @@ public: /// member expression. static QualType findBoundMemberType(const Expr *expr); - /// Skip past any invisble AST nodes which might surround this + /// Skip past any invisible AST nodes which might surround this /// statement, such as ExprWithCleanups or ImplicitCastExpr nodes, /// but also injected CXXMemberExpr and CXXConstructExpr which represent /// implicit conversions. @@ -900,7 +936,7 @@ public: return const_cast<Expr *>(this)->IgnoreParenLValueCasts(); } - /// Skip past any parenthese and casts which do not change the value + /// Skip past any parentheses and casts which do not change the value /// (including ptr->int casts of the same size) until reaching a fixed point. /// Skips: /// * What IgnoreParens() skips @@ -1014,6 +1050,9 @@ public: } }; +/// Describes the kind of result that can be tail-allocated. +enum class ConstantResultStorageKind { None, Int64, APValue }; + /// ConstantExpr - An expression that occurs in a constant context and /// optionally the result of evaluating the expression. class ConstantExpr final @@ -1026,20 +1065,15 @@ class ConstantExpr final friend class ASTStmtReader; friend class ASTStmtWriter; -public: - /// Describes the kind of result that can be tail-allocated. - enum ResultStorageKind { RSK_None, RSK_Int64, RSK_APValue }; - -private: size_t numTrailingObjects(OverloadToken<APValue>) const { - return ConstantExprBits.ResultKind == ConstantExpr::RSK_APValue; + return getResultStorageKind() == ConstantResultStorageKind::APValue; } size_t numTrailingObjects(OverloadToken<uint64_t>) const { - return ConstantExprBits.ResultKind == ConstantExpr::RSK_Int64; + return getResultStorageKind() == ConstantResultStorageKind::Int64; } uint64_t &Int64Result() { - assert(ConstantExprBits.ResultKind == ConstantExpr::RSK_Int64 && + assert(getResultStorageKind() == ConstantResultStorageKind::Int64 && "invalid accessor"); return *getTrailingObjects<uint64_t>(); } @@ -1047,7 +1081,7 @@ private: return const_cast<ConstantExpr *>(this)->Int64Result(); } APValue &APValueResult() { - assert(ConstantExprBits.ResultKind == ConstantExpr::RSK_APValue && + assert(getResultStorageKind() == ConstantResultStorageKind::APValue && "invalid accessor"); return *getTrailingObjects<APValue>(); } @@ -1055,22 +1089,23 @@ private: return const_cast<ConstantExpr *>(this)->APValueResult(); } - ConstantExpr(Expr *SubExpr, ResultStorageKind StorageKind, + ConstantExpr(Expr *SubExpr, ConstantResultStorageKind StorageKind, bool IsImmediateInvocation); - ConstantExpr(EmptyShell Empty, ResultStorageKind StorageKind); + ConstantExpr(EmptyShell Empty, ConstantResultStorageKind StorageKind); public: static ConstantExpr *Create(const ASTContext &Context, Expr *E, const APValue &Result); - static ConstantExpr *Create(const ASTContext &Context, Expr *E, - ResultStorageKind Storage = RSK_None, - bool IsImmediateInvocation = false); + static ConstantExpr * + Create(const ASTContext &Context, Expr *E, + ConstantResultStorageKind Storage = ConstantResultStorageKind::None, + bool IsImmediateInvocation = false); static ConstantExpr *CreateEmpty(const ASTContext &Context, - ResultStorageKind StorageKind); + ConstantResultStorageKind StorageKind); - static ResultStorageKind getStorageKind(const APValue &Value); - static ResultStorageKind getStorageKind(const Type *T, - const ASTContext &Context); + static ConstantResultStorageKind getStorageKind(const APValue &Value); + static ConstantResultStorageKind getStorageKind(const Type *T, + const ASTContext &Context); SourceLocation getBeginLoc() const LLVM_READONLY { return SubExpr->getBeginLoc(); @@ -1091,8 +1126,8 @@ public: APValue::ValueKind getResultAPValueKind() const { return static_cast<APValue::ValueKind>(ConstantExprBits.APValueKind); } - ResultStorageKind getResultStorageKind() const { - return static_cast<ResultStorageKind>(ConstantExprBits.ResultKind); + ConstantResultStorageKind getResultStorageKind() const { + return static_cast<ConstantResultStorageKind>(ConstantExprBits.ResultKind); } bool isImmediateInvocation() const { return ConstantExprBits.IsImmediateInvocation; @@ -1101,7 +1136,6 @@ public: return ConstantExprBits.APValueKind != APValue::None; } APValue getAPValueResult() const; - APValue &getResultAsAPValue() const { return APValueResult(); } llvm::APSInt getResultAsAPSInt() const; // Iterators child_range children() { return child_range(&SubExpr, &SubExpr+1); } @@ -1413,68 +1447,35 @@ public: return DeclRefExprBits.RefersToEnclosingVariableOrCapture; } - static bool classof(const Stmt *T) { - return T->getStmtClass() == DeclRefExprClass; + bool isImmediateEscalating() const { + return DeclRefExprBits.IsImmediateEscalating; } - // Iterators - child_range children() { - return child_range(child_iterator(), child_iterator()); + void setIsImmediateEscalating(bool Set) { + DeclRefExprBits.IsImmediateEscalating = Set; } - const_child_range children() const { - return const_child_range(const_child_iterator(), const_child_iterator()); + bool isCapturedByCopyInLambdaWithExplicitObjectParameter() const { + return DeclRefExprBits.CapturedByCopyInLambdaWithExplicitObjectParameter; } -}; -/// Used by IntegerLiteral/FloatingLiteral to store the numeric without -/// leaking memory. -/// -/// For large floats/integers, APFloat/APInt will allocate memory from the heap -/// to represent these numbers. Unfortunately, when we use a BumpPtrAllocator -/// to allocate IntegerLiteral/FloatingLiteral nodes the memory associated with -/// the APFloat/APInt values will never get freed. APNumericStorage uses -/// ASTContext's allocator for memory allocation. -class APNumericStorage { - union { - uint64_t VAL; ///< Used to store the <= 64 bits integer value. - uint64_t *pVal; ///< Used to store the >64 bits integer value. - }; - unsigned BitWidth; - - bool hasAllocation() const { return llvm::APInt::getNumWords(BitWidth) > 1; } - - APNumericStorage(const APNumericStorage &) = delete; - void operator=(const APNumericStorage &) = delete; - -protected: - APNumericStorage() : VAL(0), BitWidth(0) { } - - llvm::APInt getIntValue() const { - unsigned NumWords = llvm::APInt::getNumWords(BitWidth); - if (NumWords > 1) - return llvm::APInt(BitWidth, NumWords, pVal); - else - return llvm::APInt(BitWidth, VAL); + void setCapturedByCopyInLambdaWithExplicitObjectParameter( + bool Set, const ASTContext &Context) { + DeclRefExprBits.CapturedByCopyInLambdaWithExplicitObjectParameter = Set; + setDependence(computeDependence(this, Context)); } - void setIntValue(const ASTContext &C, const llvm::APInt &Val); -}; -class APIntStorage : private APNumericStorage { -public: - llvm::APInt getValue() const { return getIntValue(); } - void setValue(const ASTContext &C, const llvm::APInt &Val) { - setIntValue(C, Val); + static bool classof(const Stmt *T) { + return T->getStmtClass() == DeclRefExprClass; } -}; -class APFloatStorage : private APNumericStorage { -public: - llvm::APFloat getValue(const llvm::fltSemantics &Semantics) const { - return llvm::APFloat(Semantics, getIntValue()); + // Iterators + child_range children() { + return child_range(child_iterator(), child_iterator()); } - void setValue(const ASTContext &C, const llvm::APFloat &Val) { - setIntValue(C, Val.bitcastToAPInt()); + + const_child_range children() const { + return const_child_range(const_child_iterator(), const_child_iterator()); } }; @@ -1568,26 +1569,18 @@ class FixedPointLiteral : public Expr, public APIntStorage { } }; -class CharacterLiteral : public Expr { -public: - enum CharacterKind { - Ascii, - Wide, - UTF8, - UTF16, - UTF32 - }; +enum class CharacterLiteralKind { Ascii, Wide, UTF8, UTF16, UTF32 }; -private: +class CharacterLiteral : public Expr { unsigned Value; SourceLocation Loc; public: // type should be IntTy - CharacterLiteral(unsigned value, CharacterKind kind, QualType type, + CharacterLiteral(unsigned value, CharacterLiteralKind kind, QualType type, SourceLocation l) : Expr(CharacterLiteralClass, type, VK_PRValue, OK_Ordinary), Value(value), Loc(l) { - CharacterLiteralBits.Kind = kind; + CharacterLiteralBits.Kind = llvm::to_underlying(kind); setDependence(ExprDependence::None); } @@ -1595,8 +1588,8 @@ public: CharacterLiteral(EmptyShell Empty) : Expr(CharacterLiteralClass, Empty) { } SourceLocation getLocation() const { return Loc; } - CharacterKind getKind() const { - return static_cast<CharacterKind>(CharacterLiteralBits.Kind); + CharacterLiteralKind getKind() const { + return static_cast<CharacterLiteralKind>(CharacterLiteralBits.Kind); } SourceLocation getBeginLoc() const LLVM_READONLY { return Loc; } @@ -1605,14 +1598,16 @@ public: unsigned getValue() const { return Value; } void setLocation(SourceLocation Location) { Loc = Location; } - void setKind(CharacterKind kind) { CharacterLiteralBits.Kind = kind; } + void setKind(CharacterLiteralKind kind) { + CharacterLiteralBits.Kind = llvm::to_underlying(kind); + } void setValue(unsigned Val) { Value = Val; } static bool classof(const Stmt *T) { return T->getStmtClass() == CharacterLiteralClass; } - static void print(unsigned val, CharacterKind Kind, raw_ostream &OS); + static void print(unsigned val, CharacterLiteralKind Kind, raw_ostream &OS); // Iterators child_range children() { @@ -1734,6 +1729,15 @@ public: } }; +enum class StringLiteralKind { + Ordinary, + Wide, + UTF8, + UTF16, + UTF32, + Unevaluated +}; + /// StringLiteral - This represents a string literal expression, e.g. "foo" /// or L"bar" (wide strings). The actual string data can be obtained with /// getBytes() and is NOT null-terminated. The length of the string data is @@ -1772,10 +1776,6 @@ class StringLiteral final /// /// * An array of getByteLength() char used to store the string data. -public: - enum StringKind { Ascii, Wide, UTF8, UTF16, UTF32 }; - -private: unsigned numTrailingObjects(OverloadToken<unsigned>) const { return 1; } unsigned numTrailingObjects(OverloadToken<SourceLocation>) const { return getNumConcatenated(); @@ -1797,7 +1797,7 @@ private: } /// Build a string literal. - StringLiteral(const ASTContext &Ctx, StringRef Str, StringKind Kind, + StringLiteral(const ASTContext &Ctx, StringRef Str, StringLiteralKind Kind, bool Pascal, QualType Ty, const SourceLocation *Loc, unsigned NumConcatenated); @@ -1806,7 +1806,8 @@ private: unsigned CharByteWidth); /// Map a target and string kind to the appropriate character width. - static unsigned mapCharByteWidth(TargetInfo const &Target, StringKind SK); + static unsigned mapCharByteWidth(TargetInfo const &Target, + StringLiteralKind SK); /// Set one of the string literal token. void setStrTokenLoc(unsigned TokNum, SourceLocation L) { @@ -1818,13 +1819,13 @@ public: /// This is the "fully general" constructor that allows representation of /// strings formed from multiple concatenated tokens. static StringLiteral *Create(const ASTContext &Ctx, StringRef Str, - StringKind Kind, bool Pascal, QualType Ty, + StringLiteralKind Kind, bool Pascal, QualType Ty, const SourceLocation *Loc, unsigned NumConcatenated); /// Simple constructor for string literals made from one token. static StringLiteral *Create(const ASTContext &Ctx, StringRef Str, - StringKind Kind, bool Pascal, QualType Ty, + StringLiteralKind Kind, bool Pascal, QualType Ty, SourceLocation Loc) { return Create(Ctx, Str, Kind, Pascal, Ty, &Loc, 1); } @@ -1835,7 +1836,7 @@ public: unsigned CharByteWidth); StringRef getString() const { - assert(getCharByteWidth() == 1 && + assert((isUnevaluated() || getCharByteWidth() == 1) && "This function is used in places that assume strings use char"); return StringRef(getStrDataAsChar(), getByteLength()); } @@ -1866,15 +1867,16 @@ public: unsigned getLength() const { return *getTrailingObjects<unsigned>(); } unsigned getCharByteWidth() const { return StringLiteralBits.CharByteWidth; } - StringKind getKind() const { - return static_cast<StringKind>(StringLiteralBits.Kind); + StringLiteralKind getKind() const { + return static_cast<StringLiteralKind>(StringLiteralBits.Kind); } - bool isAscii() const { return getKind() == Ascii; } - bool isWide() const { return getKind() == Wide; } - bool isUTF8() const { return getKind() == UTF8; } - bool isUTF16() const { return getKind() == UTF16; } - bool isUTF32() const { return getKind() == UTF32; } + bool isOrdinary() const { return getKind() == StringLiteralKind::Ordinary; } + bool isWide() const { return getKind() == StringLiteralKind::Wide; } + bool isUTF8() const { return getKind() == StringLiteralKind::UTF8; } + bool isUTF16() const { return getKind() == StringLiteralKind::UTF16; } + bool isUTF32() const { return getKind() == StringLiteralKind::UTF32; } + bool isUnevaluated() const { return getKind() == StringLiteralKind::Unevaluated; } bool isPascal() const { return StringLiteralBits.IsPascal; } bool containsNonAscii() const { @@ -1942,6 +1944,19 @@ public: } }; +enum class PredefinedIdentKind { + Func, + Function, + LFunction, // Same as Function, but as wide string. + FuncDName, + FuncSig, + LFuncSig, // Same as FuncSig, but as wide string + PrettyFunction, + /// The same as PrettyFunction, except that the + /// 'virtual' keyword is omitted for virtual member functions. + PrettyFunctionNoVirtual +}; + /// [C99 6.4.2.2] - A predefined identifier such as __func__. class PredefinedExpr final : public Expr, @@ -1953,23 +1968,8 @@ class PredefinedExpr final // "Stmt *" for the predefined identifier. It is present if and only if // hasFunctionName() is true and is always a "StringLiteral *". -public: - enum IdentKind { - Func, - Function, - LFunction, // Same as Function, but as wide string. - FuncDName, - FuncSig, - LFuncSig, // Same as FuncSig, but as as wide string - PrettyFunction, - /// The same as PrettyFunction, except that the - /// 'virtual' keyword is omitted for virtual member functions. - PrettyFunctionNoVirtual - }; - -private: - PredefinedExpr(SourceLocation L, QualType FNTy, IdentKind IK, - StringLiteral *SL); + PredefinedExpr(SourceLocation L, QualType FNTy, PredefinedIdentKind IK, + bool IsTransparent, StringLiteral *SL); explicit PredefinedExpr(EmptyShell Empty, bool HasFunctionName); @@ -1984,17 +1984,23 @@ private: public: /// Create a PredefinedExpr. + /// + /// If IsTransparent, the PredefinedExpr is transparently handled as a + /// StringLiteral. static PredefinedExpr *Create(const ASTContext &Ctx, SourceLocation L, - QualType FNTy, IdentKind IK, StringLiteral *SL); + QualType FNTy, PredefinedIdentKind IK, + bool IsTransparent, StringLiteral *SL); /// Create an empty PredefinedExpr. static PredefinedExpr *CreateEmpty(const ASTContext &Ctx, bool HasFunctionName); - IdentKind getIdentKind() const { - return static_cast<IdentKind>(PredefinedExprBits.Kind); + PredefinedIdentKind getIdentKind() const { + return static_cast<PredefinedIdentKind>(PredefinedExprBits.Kind); } + bool isTransparent() const { return PredefinedExprBits.IsTransparent; } + SourceLocation getLocation() const { return PredefinedExprBits.Loc; } void setLocation(SourceLocation L) { PredefinedExprBits.Loc = L; } @@ -2010,12 +2016,13 @@ public: : nullptr; } - static StringRef getIdentKindName(IdentKind IK); + static StringRef getIdentKindName(PredefinedIdentKind IK); StringRef getIdentKindName() const { return getIdentKindName(getIdentKind()); } - static std::string ComputeName(IdentKind IK, const Decl *CurrentDecl); + static std::string ComputeName(PredefinedIdentKind IK, + const Decl *CurrentDecl); SourceLocation getBeginLoc() const { return getLocation(); } SourceLocation getEndLoc() const { return getLocation(); } @@ -2210,14 +2217,14 @@ public: bool canOverflow() const { return UnaryOperatorBits.CanOverflow; } void setCanOverflow(bool C) { UnaryOperatorBits.CanOverflow = C; } - // Get the FP contractability status of this operator. Only meaningful for - // operations on floating point types. + /// Get the FP contractability status of this operator. Only meaningful for + /// operations on floating point types. bool isFPContractableWithinStatement(const LangOptions &LO) const { return getFPFeaturesInEffect(LO).allowFPContractWithinStatement(); } - // Get the FENV_ACCESS status of this operator. Only meaningful for - // operations on floating point types. + /// Get the FENV_ACCESS status of this operator. Only meaningful for + /// operations on floating point types. bool isFEnvAccessOn(const LangOptions &LO) const { return getFPFeaturesInEffect(LO).getAllowFEnvAccess(); } @@ -2298,12 +2305,12 @@ public: } protected: - /// Set FPFeatures in trailing storage, used only by Serialization + /// Set FPFeatures in trailing storage, used by Serialization & ASTImporter. void setStoredFPFeatures(FPOptionsOverride F) { getTrailingFPFeatures() = F; } public: - // Get the FP features status of this operator. Only meaningful for - // operations on floating point types. + /// Get the FP features status of this operator. Only meaningful for + /// operations on floating point types. FPOptions getFPFeaturesInEffect(const LangOptions &LO) const { if (UnaryOperatorBits.HasFPFeatures) return getStoredFPFeatures().applyOverrides(LO); @@ -2316,6 +2323,7 @@ public: } friend TrailingObjects; + friend class ASTNodeImporter; friend class ASTReader; friend class ASTStmtReader; friend class ASTStmtWriter; @@ -2375,7 +2383,7 @@ public: /// Create an offsetof node that refers into a C++ base class. explicit OffsetOfNode(const CXXBaseSpecifier *Base) - : Range(), Data(reinterpret_cast<uintptr_t>(Base) | OffsetOfNode::Base) {} + : Data(reinterpret_cast<uintptr_t>(Base) | OffsetOfNode::Base) {} /// Determine what kind of offsetof node this is. Kind getKind() const { return static_cast<Kind>(Data & Mask); } @@ -2791,7 +2799,7 @@ class CallExpr : public Expr { /// The number of arguments in the call expression. unsigned NumArgs; - /// The location of the right parenthese. This has a different meaning for + /// The location of the right parentheses. This has a different meaning for /// the derived classes of CallExpr. SourceLocation RParenLoc; @@ -2997,7 +3005,7 @@ public: /// Compute and set dependence bits. void computeDependence() { setDependence(clang::computeDependence( - this, llvm::makeArrayRef( + this, llvm::ArrayRef( reinterpret_cast<Expr **>(getTrailingStmts() + PREARGS_START), getNumPreArgs()))); } @@ -3044,14 +3052,10 @@ public: /// interface. This provides efficient reverse iteration of the /// subexpressions. This is currently used for CFG construction. ArrayRef<Stmt *> getRawSubExprs() { - return llvm::makeArrayRef(getTrailingStmts(), - PREARGS_START + getNumPreArgs() + getNumArgs()); + return llvm::ArrayRef(getTrailingStmts(), + PREARGS_START + getNumPreArgs() + getNumArgs()); } - /// getNumCommas - Return the number of commas that must have been present in - /// this function call. - unsigned getNumCommas() const { return getNumArgs() ? getNumArgs() - 1 : 0; } - /// Get FPOptionsOverride from trailing storage. FPOptionsOverride getStoredFPFeatures() const { assert(hasStoredFPFeatures()); @@ -3063,8 +3067,8 @@ public: *getTrailingFPFeatures() = F; } - // Get the FP features status of this operator. Only meaningful for - // operations on floating point types. + /// Get the FP features status of this operator. Only meaningful for + /// operations on floating point types. FPOptions getFPFeaturesInEffect(const LangOptions &LO) const { if (hasStoredFPFeatures()) return getStoredFPFeatures().applyOverrides(LO); @@ -3115,11 +3119,7 @@ public: setDependence(getDependence() | ExprDependence::TypeValueInstantiation); } - bool isCallToStdMove() const { - const FunctionDecl *FD = getDirectCallee(); - return getNumArgs() == 1 && FD && FD->isInStdNamespace() && - FD->getIdentifier() && FD->getIdentifier()->isStr("move"); - } + bool isCallToStdMove() const; static bool classof(const Stmt *T) { return T->getStmtClass() >= firstCallExprConstant && @@ -3484,7 +3484,6 @@ protected: CastExprBits.BasePathSize = BasePathSize; assert((CastExprBits.BasePathSize == BasePathSize) && "BasePathSize overflow!"); - setDependence(computeDependence(this)); assert(CastConsistency()); CastExprBits.HasFPFeatures = HasFPFeatures; } @@ -3559,8 +3558,8 @@ public: return *getTrailingFPFeatures(); } - // Get the FP features status of this operation. Only meaningful for - // operations on floating point types. + /// Get the FP features status of this operation. Only meaningful for + /// operations on floating point types. FPOptions getFPFeaturesInEffect(const LangOptions &LO) const { if (hasStoredFPFeatures()) return getStoredFPFeatures().applyOverrides(LO); @@ -3573,6 +3572,19 @@ public: return FPOptionsOverride(); } + /// Return + // True : if this conversion changes the volatile-ness of a gl-value. + // Qualification conversions on gl-values currently use CK_NoOp, but + // it's important to recognize volatile-changing conversions in + // clients code generation that normally eagerly peephole loads. Note + // that the query is answering for this specific node; Sema may + // produce multiple cast nodes for any particular conversion sequence. + // False : Otherwise. + bool changesVolatileQualification() const { + return (isGLValue() && (getType().isVolatileQualified() != + getSubExpr()->getType().isVolatileQualified())); + } + static const FieldDecl *getTargetFieldForToUnionCast(QualType unionType, QualType opType); static const FieldDecl *getTargetFieldForToUnionCast(const RecordDecl *RD, @@ -3618,6 +3630,7 @@ class ImplicitCastExpr final ExprValueKind VK) : CastExpr(ImplicitCastExprClass, ty, VK, kind, op, BasePathLength, FPO.requiresTrailingStorage()) { + setDependence(computeDependence(this)); if (hasStoredFPFeatures()) *getTrailingFPFeatures() = FPO; } @@ -3695,7 +3708,9 @@ protected: CastKind kind, Expr *op, unsigned PathSize, bool HasFPFeatures, TypeSourceInfo *writtenTy) : CastExpr(SC, exprTy, VK, kind, op, PathSize, HasFPFeatures), - TInfo(writtenTy) {} + TInfo(writtenTy) { + setDependence(computeDependence(this)); + } /// Construct an empty explicit cast. ExplicitCastExpr(StmtClass SC, EmptyShell Shell, unsigned PathSize, @@ -3954,11 +3969,12 @@ public: return isShiftAssignOp(getOpcode()); } - // Return true if a binary operator using the specified opcode and operands - // would match the 'p = (i8*)nullptr + n' idiom for casting a pointer-sized - // integer to a pointer. + /// Return true if a binary operator using the specified opcode and operands + /// would match the 'p = (i8*)nullptr + n' idiom for casting a pointer-sized + /// integer to a pointer. static bool isNullPointerArithmeticExtension(ASTContext &Ctx, Opcode Opc, - Expr *LHS, Expr *RHS); + const Expr *LHS, + const Expr *RHS); static bool classof(const Stmt *S) { return S->getStmtClass() >= firstBinaryOperatorConstant && @@ -3989,8 +4005,8 @@ public: *getTrailingFPFeatures() = F; } - // Get the FP features status of this operator. Only meaningful for - // operations on floating point types. + /// Get the FP features status of this operator. Only meaningful for + /// operations on floating point types. FPOptions getFPFeaturesInEffect(const LangOptions &LO) const { if (BinaryOperatorBits.HasFPFeatures) return getStoredFPFeatures().applyOverrides(LO); @@ -3998,20 +4014,20 @@ public: } // This is used in ASTImporter - FPOptionsOverride getFPFeatures(const LangOptions &LO) const { + FPOptionsOverride getFPFeatures() const { if (BinaryOperatorBits.HasFPFeatures) return getStoredFPFeatures(); return FPOptionsOverride(); } - // Get the FP contractability status of this operator. Only meaningful for - // operations on floating point types. + /// Get the FP contractability status of this operator. Only meaningful for + /// operations on floating point types. bool isFPContractableWithinStatement(const LangOptions &LO) const { return getFPFeaturesInEffect(LO).allowFPContractWithinStatement(); } - // Get the FENV_ACCESS status of this operator. Only meaningful for - // operations on floating point types. + /// Get the FENV_ACCESS status of this operator. Only meaningful for + /// operations on floating point types. bool isFEnvAccessOn(const LangOptions &LO) const { return getFPFeaturesInEffect(LO).getAllowFEnvAccess(); } @@ -4107,17 +4123,17 @@ protected: : Expr(SC, Empty) { } public: - // getCond - Return the expression representing the condition for - // the ?: operator. + /// getCond - Return the expression representing the condition for + /// the ?: operator. Expr *getCond() const; - // getTrueExpr - Return the subexpression representing the value of - // the expression if the condition evaluates to true. + /// getTrueExpr - Return the subexpression representing the value of + /// the expression if the condition evaluates to true. Expr *getTrueExpr() const; - // getFalseExpr - Return the subexpression representing the value of - // the expression if the condition evaluates to false. This is - // the same as getRHS. + /// getFalseExpr - Return the subexpression representing the value of + /// the expression if the condition evaluates to false. This is + /// the same as getRHS. Expr *getFalseExpr() const; SourceLocation getQuestionLoc() const { return QuestionLoc; } @@ -4152,17 +4168,17 @@ public: explicit ConditionalOperator(EmptyShell Empty) : AbstractConditionalOperator(ConditionalOperatorClass, Empty) { } - // getCond - Return the expression representing the condition for - // the ?: operator. + /// getCond - Return the expression representing the condition for + /// the ?: operator. Expr *getCond() const { return cast<Expr>(SubExprs[COND]); } - // getTrueExpr - Return the subexpression representing the value of - // the expression if the condition evaluates to true. + /// getTrueExpr - Return the subexpression representing the value of + /// the expression if the condition evaluates to true. Expr *getTrueExpr() const { return cast<Expr>(SubExprs[LHS]); } - // getFalseExpr - Return the subexpression representing the value of - // the expression if the condition evaluates to false. This is - // the same as getRHS. + /// getFalseExpr - Return the subexpression representing the value of + /// the expression if the condition evaluates to false. This is + /// the same as getRHS. Expr *getFalseExpr() const { return cast<Expr>(SubExprs[RHS]); } Expr *getLHS() const { return cast<Expr>(SubExprs[LHS]); } @@ -4666,16 +4682,26 @@ public: } }; +enum class SourceLocIdentKind { + Function, + FuncSig, + File, + FileName, + Line, + Column, + SourceLocStruct +}; + /// Represents a function call to one of __builtin_LINE(), __builtin_COLUMN(), -/// __builtin_FUNCTION(), or __builtin_FILE(). +/// __builtin_FUNCTION(), __builtin_FUNCSIG(), __builtin_FILE(), +/// __builtin_FILE_NAME() or __builtin_source_location(). class SourceLocExpr final : public Expr { SourceLocation BuiltinLoc, RParenLoc; DeclContext *ParentContext; public: - enum IdentKind { Function, File, Line, Column }; - - SourceLocExpr(const ASTContext &Ctx, IdentKind Type, SourceLocation BLoc, + SourceLocExpr(const ASTContext &Ctx, SourceLocIdentKind Type, + QualType ResultTy, SourceLocation BLoc, SourceLocation RParenLoc, DeclContext *Context); /// Build an empty call expression. @@ -4689,22 +4715,24 @@ public: /// Return a string representing the name of the specific builtin function. StringRef getBuiltinStr() const; - IdentKind getIdentKind() const { - return static_cast<IdentKind>(SourceLocExprBits.Kind); + SourceLocIdentKind getIdentKind() const { + return static_cast<SourceLocIdentKind>(SourceLocExprBits.Kind); } - bool isStringType() const { + bool isIntType() const { switch (getIdentKind()) { - case File: - case Function: - return true; - case Line: - case Column: + case SourceLocIdentKind::File: + case SourceLocIdentKind::FileName: + case SourceLocIdentKind::Function: + case SourceLocIdentKind::FuncSig: + case SourceLocIdentKind::SourceLocStruct: return false; + case SourceLocIdentKind::Line: + case SourceLocIdentKind::Column: + return true; } llvm_unreachable("unknown source location expression kind"); } - bool isIntType() const LLVM_READONLY { return !isStringType(); } /// If the SourceLocExpr has been resolved return the subexpression /// representing the resolved value. Otherwise return null. @@ -4727,6 +4755,17 @@ public: return T->getStmtClass() == SourceLocExprClass; } + static bool MayBeDependent(SourceLocIdentKind Kind) { + switch (Kind) { + case SourceLocIdentKind::Function: + case SourceLocIdentKind::FuncSig: + case SourceLocIdentKind::SourceLocStruct: + return true; + default: + return false; + } + } + private: friend class ASTStmtReader; }; @@ -4816,12 +4855,10 @@ public: return reinterpret_cast<Expr * const *>(InitExprs.data()); } - ArrayRef<Expr *> inits() { - return llvm::makeArrayRef(getInits(), getNumInits()); - } + ArrayRef<Expr *> inits() { return llvm::ArrayRef(getInits(), getNumInits()); } ArrayRef<Expr *> inits() const { - return llvm::makeArrayRef(getInits(), getNumInits()); + return llvm::ArrayRef(getInits(), getNumInits()); } const Expr *getInit(unsigned Init) const { @@ -4884,6 +4921,13 @@ public: /// has been set. bool hasArrayFiller() const { return getArrayFiller(); } + /// Determine whether this initializer list contains a designated initializer. + bool hasDesignatedInit() const { + return std::any_of(begin(), end(), [](const Stmt *S) { + return isa<DesignatedInitExpr>(S); + }); + } + /// If this initializes a union, specifies which field in the /// union to initialize. /// @@ -4912,8 +4956,8 @@ public: return LBraceLoc.isValid() && RBraceLoc.isValid(); } - // Is this an initializer for an array of characters, initialized by a string - // literal or an @encode? + /// Is this an initializer for an array of characters, initialized by a string + /// literal or an @encode? bool isStringLiteralInit() const; /// Is this a transparent initializer list (that is, an InitListExpr that is @@ -5028,6 +5072,7 @@ private: /// Whether this designated initializer used the GNU deprecated /// syntax rather than the C99 '=' syntax. + LLVM_PREFERRED_TYPE(bool) unsigned GNUSyntax : 1; /// The number of designators in this initializer expression. @@ -5052,37 +5097,6 @@ private: NumDesignators(0), NumSubExprs(NumSubExprs), Designators(nullptr) { } public: - /// A field designator, e.g., ".x". - struct FieldDesignator { - /// Refers to the field that is being initialized. The low bit - /// of this field determines whether this is actually a pointer - /// to an IdentifierInfo (if 1) or a FieldDecl (if 0). When - /// initially constructed, a field designator will store an - /// IdentifierInfo*. After semantic analysis has resolved that - /// name, the field designator will instead store a FieldDecl*. - uintptr_t NameOrField; - - /// The location of the '.' in the designated initializer. - SourceLocation DotLoc; - - /// The location of the field name in the designated initializer. - SourceLocation FieldLoc; - }; - - /// An array or GNU array-range designator, e.g., "[9]" or "[10..15]". - struct ArrayOrRangeDesignator { - /// Location of the first index expression within the designated - /// initializer expression's list of subexpressions. - unsigned Index; - /// The location of the '[' starting the array range designator. - SourceLocation LBracketLoc; - /// The location of the ellipsis separating the start and end - /// indices. Only valid for GNU array-range designators. - SourceLocation EllipsisLoc; - /// The location of the ']' terminating the array range designator. - SourceLocation RBracketLoc; - }; - /// Represents a single C99 designator. /// /// @todo This class is infuriatingly similar to clang::Designator, @@ -5090,118 +5104,177 @@ public: /// keep us from reusing it. Try harder, later, to rectify these /// differences. class Designator { + /// A field designator, e.g., ".x". + struct FieldDesignatorInfo { + /// Refers to the field that is being initialized. The low bit + /// of this field determines whether this is actually a pointer + /// to an IdentifierInfo (if 1) or a FieldDecl (if 0). When + /// initially constructed, a field designator will store an + /// IdentifierInfo*. After semantic analysis has resolved that + /// name, the field designator will instead store a FieldDecl*. + uintptr_t NameOrField; + + /// The location of the '.' in the designated initializer. + SourceLocation DotLoc; + + /// The location of the field name in the designated initializer. + SourceLocation FieldLoc; + + FieldDesignatorInfo(const IdentifierInfo *II, SourceLocation DotLoc, + SourceLocation FieldLoc) + : NameOrField(reinterpret_cast<uintptr_t>(II) | 0x1), DotLoc(DotLoc), + FieldLoc(FieldLoc) {} + }; + + /// An array or GNU array-range designator, e.g., "[9]" or "[10...15]". + struct ArrayOrRangeDesignatorInfo { + /// Location of the first index expression within the designated + /// initializer expression's list of subexpressions. + unsigned Index; + + /// The location of the '[' starting the array range designator. + SourceLocation LBracketLoc; + + /// The location of the ellipsis separating the start and end + /// indices. Only valid for GNU array-range designators. + SourceLocation EllipsisLoc; + + /// The location of the ']' terminating the array range designator. + SourceLocation RBracketLoc; + + ArrayOrRangeDesignatorInfo(unsigned Index, SourceLocation LBracketLoc, + SourceLocation RBracketLoc) + : Index(Index), LBracketLoc(LBracketLoc), RBracketLoc(RBracketLoc) {} + + ArrayOrRangeDesignatorInfo(unsigned Index, + SourceLocation LBracketLoc, + SourceLocation EllipsisLoc, + SourceLocation RBracketLoc) + : Index(Index), LBracketLoc(LBracketLoc), EllipsisLoc(EllipsisLoc), + RBracketLoc(RBracketLoc) {} + }; + /// The kind of designator this describes. - enum { + enum DesignatorKind { FieldDesignator, ArrayDesignator, ArrayRangeDesignator - } Kind; + }; + + DesignatorKind Kind; union { /// A field designator, e.g., ".x". - struct FieldDesignator Field; + struct FieldDesignatorInfo FieldInfo; + /// An array or GNU array-range designator, e.g., "[9]" or "[10..15]". - struct ArrayOrRangeDesignator ArrayOrRange; + struct ArrayOrRangeDesignatorInfo ArrayOrRangeInfo; }; - friend class DesignatedInitExpr; + + Designator(DesignatorKind Kind) : Kind(Kind) {} public: Designator() {} - /// Initializes a field designator. - Designator(const IdentifierInfo *FieldName, SourceLocation DotLoc, - SourceLocation FieldLoc) - : Kind(FieldDesignator) { - new (&Field) DesignatedInitExpr::FieldDesignator; - Field.NameOrField = reinterpret_cast<uintptr_t>(FieldName) | 0x01; - Field.DotLoc = DotLoc; - Field.FieldLoc = FieldLoc; - } - - /// Initializes an array designator. - Designator(unsigned Index, SourceLocation LBracketLoc, - SourceLocation RBracketLoc) - : Kind(ArrayDesignator) { - new (&ArrayOrRange) DesignatedInitExpr::ArrayOrRangeDesignator; - ArrayOrRange.Index = Index; - ArrayOrRange.LBracketLoc = LBracketLoc; - ArrayOrRange.EllipsisLoc = SourceLocation(); - ArrayOrRange.RBracketLoc = RBracketLoc; - } - - /// Initializes a GNU array-range designator. - Designator(unsigned Index, SourceLocation LBracketLoc, - SourceLocation EllipsisLoc, SourceLocation RBracketLoc) - : Kind(ArrayRangeDesignator) { - new (&ArrayOrRange) DesignatedInitExpr::ArrayOrRangeDesignator; - ArrayOrRange.Index = Index; - ArrayOrRange.LBracketLoc = LBracketLoc; - ArrayOrRange.EllipsisLoc = EllipsisLoc; - ArrayOrRange.RBracketLoc = RBracketLoc; - } - bool isFieldDesignator() const { return Kind == FieldDesignator; } bool isArrayDesignator() const { return Kind == ArrayDesignator; } bool isArrayRangeDesignator() const { return Kind == ArrayRangeDesignator; } - IdentifierInfo *getFieldName() const; + //===------------------------------------------------------------------===// + // FieldDesignatorInfo + + /// Creates a field designator. + static Designator CreateFieldDesignator(const IdentifierInfo *FieldName, + SourceLocation DotLoc, + SourceLocation FieldLoc) { + Designator D(FieldDesignator); + new (&D.FieldInfo) FieldDesignatorInfo(FieldName, DotLoc, FieldLoc); + return D; + } - FieldDecl *getField() const { - assert(Kind == FieldDesignator && "Only valid on a field designator"); - if (Field.NameOrField & 0x01) + const IdentifierInfo *getFieldName() const; + + FieldDecl *getFieldDecl() const { + assert(isFieldDesignator() && "Only valid on a field designator"); + if (FieldInfo.NameOrField & 0x01) return nullptr; - else - return reinterpret_cast<FieldDecl *>(Field.NameOrField); + return reinterpret_cast<FieldDecl *>(FieldInfo.NameOrField); } - void setField(FieldDecl *FD) { - assert(Kind == FieldDesignator && "Only valid on a field designator"); - Field.NameOrField = reinterpret_cast<uintptr_t>(FD); + void setFieldDecl(FieldDecl *FD) { + assert(isFieldDesignator() && "Only valid on a field designator"); + FieldInfo.NameOrField = reinterpret_cast<uintptr_t>(FD); } SourceLocation getDotLoc() const { - assert(Kind == FieldDesignator && "Only valid on a field designator"); - return Field.DotLoc; + assert(isFieldDesignator() && "Only valid on a field designator"); + return FieldInfo.DotLoc; } SourceLocation getFieldLoc() const { - assert(Kind == FieldDesignator && "Only valid on a field designator"); - return Field.FieldLoc; + assert(isFieldDesignator() && "Only valid on a field designator"); + return FieldInfo.FieldLoc; } - SourceLocation getLBracketLoc() const { - assert((Kind == ArrayDesignator || Kind == ArrayRangeDesignator) && + //===------------------------------------------------------------------===// + // ArrayOrRangeDesignator + + /// Creates an array designator. + static Designator CreateArrayDesignator(unsigned Index, + SourceLocation LBracketLoc, + SourceLocation RBracketLoc) { + Designator D(ArrayDesignator); + new (&D.ArrayOrRangeInfo) ArrayOrRangeDesignatorInfo(Index, LBracketLoc, + RBracketLoc); + return D; + } + + /// Creates a GNU array-range designator. + static Designator CreateArrayRangeDesignator(unsigned Index, + SourceLocation LBracketLoc, + SourceLocation EllipsisLoc, + SourceLocation RBracketLoc) { + Designator D(ArrayRangeDesignator); + new (&D.ArrayOrRangeInfo) ArrayOrRangeDesignatorInfo(Index, LBracketLoc, + EllipsisLoc, + RBracketLoc); + return D; + } + + unsigned getArrayIndex() const { + assert((isArrayDesignator() || isArrayRangeDesignator()) && "Only valid on an array or array-range designator"); - return ArrayOrRange.LBracketLoc; + return ArrayOrRangeInfo.Index; } - SourceLocation getRBracketLoc() const { - assert((Kind == ArrayDesignator || Kind == ArrayRangeDesignator) && + SourceLocation getLBracketLoc() const { + assert((isArrayDesignator() || isArrayRangeDesignator()) && "Only valid on an array or array-range designator"); - return ArrayOrRange.RBracketLoc; + return ArrayOrRangeInfo.LBracketLoc; } SourceLocation getEllipsisLoc() const { - assert(Kind == ArrayRangeDesignator && + assert(isArrayRangeDesignator() && "Only valid on an array-range designator"); - return ArrayOrRange.EllipsisLoc; + return ArrayOrRangeInfo.EllipsisLoc; } - unsigned getFirstExprIndex() const { - assert((Kind == ArrayDesignator || Kind == ArrayRangeDesignator) && + SourceLocation getRBracketLoc() const { + assert((isArrayDesignator() || isArrayRangeDesignator()) && "Only valid on an array or array-range designator"); - return ArrayOrRange.Index; + return ArrayOrRangeInfo.RBracketLoc; } SourceLocation getBeginLoc() const LLVM_READONLY { - if (Kind == FieldDesignator) - return getDotLoc().isInvalid()? getFieldLoc() : getDotLoc(); - else - return getLBracketLoc(); + if (isFieldDesignator()) + return getDotLoc().isInvalid() ? getFieldLoc() : getDotLoc(); + return getLBracketLoc(); } + SourceLocation getEndLoc() const LLVM_READONLY { - return Kind == FieldDesignator ? getFieldLoc() : getRBracketLoc(); + return isFieldDesignator() ? getFieldLoc() : getRBracketLoc(); } + SourceRange getSourceRange() const LLVM_READONLY { return SourceRange(getBeginLoc(), getEndLoc()); } @@ -5563,9 +5636,7 @@ public: return reinterpret_cast<Expr **>(getTrailingObjects<Stmt *>()); } - ArrayRef<Expr *> exprs() { - return llvm::makeArrayRef(getExprs(), getNumExprs()); - } + ArrayRef<Expr *> exprs() { return llvm::ArrayRef(getExprs(), getNumExprs()); } SourceLocation getLParenLoc() const { return LParenLoc; } SourceLocation getRParenLoc() const { return RParenLoc; } @@ -5613,6 +5684,12 @@ public: /// which names a dependent type in its association list is result-dependent, /// which means that the choice of result expression is dependent. /// Result-dependent generic associations are both type- and value-dependent. +/// +/// We also allow an extended form in both C and C++ where the controlling +/// predicate for the selection expression is a type rather than an expression. +/// This type argument form does not perform any conversions for the +/// controlling type, which makes it suitable for use with qualified type +/// associations, which is not possible with the expression form. class GenericSelectionExpr final : public Expr, private llvm::TrailingObjects<GenericSelectionExpr, Stmt *, @@ -5625,31 +5702,68 @@ class GenericSelectionExpr final /// expression in the case where the generic selection expression is not /// result-dependent. The result index is equal to ResultDependentIndex /// if and only if the generic selection expression is result-dependent. - unsigned NumAssocs, ResultIndex; + unsigned NumAssocs : 15; + unsigned ResultIndex : 15; // NB: ResultDependentIndex is tied to this width. + LLVM_PREFERRED_TYPE(bool) + unsigned IsExprPredicate : 1; enum : unsigned { - ResultDependentIndex = std::numeric_limits<unsigned>::max(), - ControllingIndex = 0, - AssocExprStartIndex = 1 + ResultDependentIndex = 0x7FFF }; + unsigned getIndexOfControllingExpression() const { + // If controlled by an expression, the first offset into the Stmt * + // trailing array is the controlling expression, the associated expressions + // follow this. + assert(isExprPredicate() && "Asking for the controlling expression of a " + "selection expr predicated by a type"); + return 0; + } + + unsigned getIndexOfControllingType() const { + // If controlled by a type, the first offset into the TypeSourceInfo * + // trailing array is the controlling type, the associated types follow this. + assert(isTypePredicate() && "Asking for the controlling type of a " + "selection expr predicated by an expression"); + return 0; + } + + unsigned getIndexOfStartOfAssociatedExprs() const { + // If the predicate is a type, then the associated expressions are the only + // Stmt * in the trailing array, otherwise we need to offset past the + // predicate expression. + return (int)isExprPredicate(); + } + + unsigned getIndexOfStartOfAssociatedTypes() const { + // If the predicate is a type, then the associated types follow it in the + // trailing array. Otherwise, the associated types are the only + // TypeSourceInfo * in the trailing array. + return (int)isTypePredicate(); + } + + /// The location of the "default" and of the right parenthesis. SourceLocation DefaultLoc, RParenLoc; // GenericSelectionExpr is followed by several trailing objects. // They are (in order): // - // * A single Stmt * for the controlling expression. + // * A single Stmt * for the controlling expression or a TypeSourceInfo * for + // the controlling type, depending on the result of isTypePredicate() or + // isExprPredicate(). // * An array of getNumAssocs() Stmt * for the association expressions. // * An array of getNumAssocs() TypeSourceInfo *, one for each of the // association expressions. unsigned numTrailingObjects(OverloadToken<Stmt *>) const { // Add one to account for the controlling expression; the remainder // are the associated expressions. - return 1 + getNumAssocs(); + return getNumAssocs() + (int)isExprPredicate(); } unsigned numTrailingObjects(OverloadToken<TypeSourceInfo *>) const { - return getNumAssocs(); + // Add one to account for the controlling type predicate, the remainder + // are the associated types. + return getNumAssocs() + (int)isTypePredicate(); } template <bool Const> class AssociationIteratorTy; @@ -5730,7 +5844,8 @@ class GenericSelectionExpr final bool operator==(AssociationIteratorTy Other) const { return E == Other.E; } }; // class AssociationIterator - /// Build a non-result-dependent generic selection expression. + /// Build a non-result-dependent generic selection expression accepting an + /// expression predicate. GenericSelectionExpr(const ASTContext &Context, SourceLocation GenericLoc, Expr *ControllingExpr, ArrayRef<TypeSourceInfo *> AssocTypes, @@ -5739,7 +5854,8 @@ class GenericSelectionExpr final bool ContainsUnexpandedParameterPack, unsigned ResultIndex); - /// Build a result-dependent generic selection expression. + /// Build a result-dependent generic selection expression accepting an + /// expression predicate. GenericSelectionExpr(const ASTContext &Context, SourceLocation GenericLoc, Expr *ControllingExpr, ArrayRef<TypeSourceInfo *> AssocTypes, @@ -5747,11 +5863,31 @@ class GenericSelectionExpr final SourceLocation RParenLoc, bool ContainsUnexpandedParameterPack); + /// Build a non-result-dependent generic selection expression accepting a + /// type predicate. + GenericSelectionExpr(const ASTContext &Context, SourceLocation GenericLoc, + TypeSourceInfo *ControllingType, + ArrayRef<TypeSourceInfo *> AssocTypes, + ArrayRef<Expr *> AssocExprs, SourceLocation DefaultLoc, + SourceLocation RParenLoc, + bool ContainsUnexpandedParameterPack, + unsigned ResultIndex); + + /// Build a result-dependent generic selection expression accepting a type + /// predicate. + GenericSelectionExpr(const ASTContext &Context, SourceLocation GenericLoc, + TypeSourceInfo *ControllingType, + ArrayRef<TypeSourceInfo *> AssocTypes, + ArrayRef<Expr *> AssocExprs, SourceLocation DefaultLoc, + SourceLocation RParenLoc, + bool ContainsUnexpandedParameterPack); + /// Build an empty generic selection expression for deserialization. explicit GenericSelectionExpr(EmptyShell Empty, unsigned NumAssocs); public: - /// Create a non-result-dependent generic selection expression. + /// Create a non-result-dependent generic selection expression accepting an + /// expression predicate. static GenericSelectionExpr * Create(const ASTContext &Context, SourceLocation GenericLoc, Expr *ControllingExpr, ArrayRef<TypeSourceInfo *> AssocTypes, @@ -5759,13 +5895,31 @@ public: SourceLocation RParenLoc, bool ContainsUnexpandedParameterPack, unsigned ResultIndex); - /// Create a result-dependent generic selection expression. + /// Create a result-dependent generic selection expression accepting an + /// expression predicate. static GenericSelectionExpr * Create(const ASTContext &Context, SourceLocation GenericLoc, Expr *ControllingExpr, ArrayRef<TypeSourceInfo *> AssocTypes, ArrayRef<Expr *> AssocExprs, SourceLocation DefaultLoc, SourceLocation RParenLoc, bool ContainsUnexpandedParameterPack); + /// Create a non-result-dependent generic selection expression accepting a + /// type predicate. + static GenericSelectionExpr * + Create(const ASTContext &Context, SourceLocation GenericLoc, + TypeSourceInfo *ControllingType, ArrayRef<TypeSourceInfo *> AssocTypes, + ArrayRef<Expr *> AssocExprs, SourceLocation DefaultLoc, + SourceLocation RParenLoc, bool ContainsUnexpandedParameterPack, + unsigned ResultIndex); + + /// Create a result-dependent generic selection expression accepting a type + /// predicate + static GenericSelectionExpr * + Create(const ASTContext &Context, SourceLocation GenericLoc, + TypeSourceInfo *ControllingType, ArrayRef<TypeSourceInfo *> AssocTypes, + ArrayRef<Expr *> AssocExprs, SourceLocation DefaultLoc, + SourceLocation RParenLoc, bool ContainsUnexpandedParameterPack); + /// Create an empty generic selection expression for deserialization. static GenericSelectionExpr *CreateEmpty(const ASTContext &Context, unsigned NumAssocs); @@ -5793,32 +5947,56 @@ public: /// Whether this generic selection is result-dependent. bool isResultDependent() const { return ResultIndex == ResultDependentIndex; } + /// Whether this generic selection uses an expression as its controlling + /// argument. + bool isExprPredicate() const { return IsExprPredicate; } + /// Whether this generic selection uses a type as its controlling argument. + bool isTypePredicate() const { return !IsExprPredicate; } + /// Return the controlling expression of this generic selection expression. + /// Only valid to call if the selection expression used an expression as its + /// controlling argument. Expr *getControllingExpr() { - return cast<Expr>(getTrailingObjects<Stmt *>()[ControllingIndex]); + return cast<Expr>( + getTrailingObjects<Stmt *>()[getIndexOfControllingExpression()]); } const Expr *getControllingExpr() const { - return cast<Expr>(getTrailingObjects<Stmt *>()[ControllingIndex]); + return cast<Expr>( + getTrailingObjects<Stmt *>()[getIndexOfControllingExpression()]); + } + + /// Return the controlling type of this generic selection expression. Only + /// valid to call if the selection expression used a type as its controlling + /// argument. + TypeSourceInfo *getControllingType() { + return getTrailingObjects<TypeSourceInfo *>()[getIndexOfControllingType()]; + } + const TypeSourceInfo* getControllingType() const { + return getTrailingObjects<TypeSourceInfo *>()[getIndexOfControllingType()]; } /// Return the result expression of this controlling expression. Defined if /// and only if the generic selection expression is not result-dependent. Expr *getResultExpr() { return cast<Expr>( - getTrailingObjects<Stmt *>()[AssocExprStartIndex + getResultIndex()]); + getTrailingObjects<Stmt *>()[getIndexOfStartOfAssociatedExprs() + + getResultIndex()]); } const Expr *getResultExpr() const { return cast<Expr>( - getTrailingObjects<Stmt *>()[AssocExprStartIndex + getResultIndex()]); + getTrailingObjects<Stmt *>()[getIndexOfStartOfAssociatedExprs() + + getResultIndex()]); } ArrayRef<Expr *> getAssocExprs() const { return {reinterpret_cast<Expr *const *>(getTrailingObjects<Stmt *>() + - AssocExprStartIndex), + getIndexOfStartOfAssociatedExprs()), NumAssocs}; } ArrayRef<TypeSourceInfo *> getAssocTypeSourceInfos() const { - return {getTrailingObjects<TypeSourceInfo *>(), NumAssocs}; + return {getTrailingObjects<TypeSourceInfo *>() + + getIndexOfStartOfAssociatedTypes(), + NumAssocs}; } /// Return the Ith association expression with its TypeSourceInfo, @@ -5827,23 +6005,30 @@ public: assert(I < getNumAssocs() && "Out-of-range index in GenericSelectionExpr::getAssociation!"); return Association( - cast<Expr>(getTrailingObjects<Stmt *>()[AssocExprStartIndex + I]), - getTrailingObjects<TypeSourceInfo *>()[I], + cast<Expr>( + getTrailingObjects<Stmt *>()[getIndexOfStartOfAssociatedExprs() + + I]), + getTrailingObjects< + TypeSourceInfo *>()[getIndexOfStartOfAssociatedTypes() + I], !isResultDependent() && (getResultIndex() == I)); } ConstAssociation getAssociation(unsigned I) const { assert(I < getNumAssocs() && "Out-of-range index in GenericSelectionExpr::getAssociation!"); return ConstAssociation( - cast<Expr>(getTrailingObjects<Stmt *>()[AssocExprStartIndex + I]), - getTrailingObjects<TypeSourceInfo *>()[I], + cast<Expr>( + getTrailingObjects<Stmt *>()[getIndexOfStartOfAssociatedExprs() + + I]), + getTrailingObjects< + TypeSourceInfo *>()[getIndexOfStartOfAssociatedTypes() + I], !isResultDependent() && (getResultIndex() == I)); } association_range associations() { AssociationIterator Begin(getTrailingObjects<Stmt *>() + - AssocExprStartIndex, - getTrailingObjects<TypeSourceInfo *>(), + getIndexOfStartOfAssociatedExprs(), + getTrailingObjects<TypeSourceInfo *>() + + getIndexOfStartOfAssociatedTypes(), /*Offset=*/0, ResultIndex); AssociationIterator End(Begin.E + NumAssocs, Begin.TSI + NumAssocs, /*Offset=*/NumAssocs, ResultIndex); @@ -5852,8 +6037,9 @@ public: const_association_range associations() const { ConstAssociationIterator Begin(getTrailingObjects<Stmt *>() + - AssocExprStartIndex, - getTrailingObjects<TypeSourceInfo *>(), + getIndexOfStartOfAssociatedExprs(), + getTrailingObjects<TypeSourceInfo *>() + + getIndexOfStartOfAssociatedTypes(), /*Offset=*/0, ResultIndex); ConstAssociationIterator End(Begin.E + NumAssocs, Begin.TSI + NumAssocs, /*Offset=*/NumAssocs, ResultIndex); @@ -6166,11 +6352,11 @@ public: return getSubExprsBuffer() + getNumSubExprs(); } - llvm::iterator_range<semantics_iterator> semantics() { - return llvm::make_range(semantics_begin(), semantics_end()); + ArrayRef<Expr*> semantics() { + return ArrayRef(semantics_begin(), semantics_end()); } - llvm::iterator_range<const_semantics_iterator> semantics() const { - return llvm::make_range(semantics_begin(), semantics_end()); + ArrayRef<const Expr*> semantics() const { + return ArrayRef(semantics_begin(), semantics_end()); } Expr *getSemanticExpr(unsigned index) { @@ -6272,7 +6458,7 @@ public: return cast<Expr>(SubExprs[ORDER_FAIL]); } Expr *getVal2() const { - if (Op == AO__atomic_exchange) + if (Op == AO__atomic_exchange || Op == AO__scoped_atomic_exchange) return cast<Expr>(SubExprs[ORDER_FAIL]); assert(NumSubExprs > VAL2); return cast<Expr>(SubExprs[VAL2]); @@ -6284,6 +6470,16 @@ public: QualType getValueType() const; AtomicOp getOp() const { return Op; } + StringRef getOpAsString() const { + switch (Op) { +#define BUILTIN(ID, TYPE, ATTRS) +#define ATOMIC_BUILTIN(ID, TYPE, ATTRS) \ + case AO##ID: \ + return #ID; +#include "clang/Basic/Builtins.def" + } + llvm_unreachable("not an atomic operator?"); + } unsigned getNumSubExprs() const { return NumSubExprs; } Expr **getSubExprs() { return reinterpret_cast<Expr **>(SubExprs); } @@ -6298,10 +6494,14 @@ public: bool isCmpXChg() const { return getOp() == AO__c11_atomic_compare_exchange_strong || getOp() == AO__c11_atomic_compare_exchange_weak || + getOp() == AO__hip_atomic_compare_exchange_strong || getOp() == AO__opencl_atomic_compare_exchange_strong || getOp() == AO__opencl_atomic_compare_exchange_weak || + getOp() == AO__hip_atomic_compare_exchange_weak || getOp() == AO__atomic_compare_exchange || - getOp() == AO__atomic_compare_exchange_n; + getOp() == AO__atomic_compare_exchange_n || + getOp() == AO__scoped_atomic_compare_exchange || + getOp() == AO__scoped_atomic_compare_exchange_n; } bool isOpenCL() const { @@ -6331,11 +6531,13 @@ public: /// \return empty atomic scope model if the atomic op code does not have /// scope operand. static std::unique_ptr<AtomicScopeModel> getScopeModel(AtomicOp Op) { - auto Kind = - (Op >= AO__opencl_atomic_load && Op <= AO__opencl_atomic_fetch_max) - ? AtomicScopeModelKind::OpenCL - : AtomicScopeModelKind::None; - return AtomicScopeModel::create(Kind); + if (Op >= AO__opencl_atomic_load && Op <= AO__opencl_atomic_fetch_max) + return AtomicScopeModel::create(AtomicScopeModelKind::OpenCL); + else if (Op >= AO__hip_atomic_load && Op <= AO__hip_atomic_fetch_max) + return AtomicScopeModel::create(AtomicScopeModelKind::HIP); + else if (Op >= AO__scoped_atomic_load && Op <= AO__scoped_atomic_fetch_max) + return AtomicScopeModel::create(AtomicScopeModelKind::Generic); + return AtomicScopeModel::create(AtomicScopeModelKind::None); } /// Get atomic scope model. @@ -6412,7 +6614,7 @@ public: ArrayRef<Expr *> subExpressions() { auto *B = getTrailingObjects<Expr *>(); - return llvm::makeArrayRef(B, B + NumExprs); + return llvm::ArrayRef(B, B + NumExprs); } ArrayRef<const Expr *> subExpressions() const { |