Index: vendor/llvm-project/release-10.x/clang/include/clang/AST/Expr.h =================================================================== --- vendor/llvm-project/release-10.x/clang/include/clang/AST/Expr.h (revision 359078) +++ vendor/llvm-project/release-10.x/clang/include/clang/AST/Expr.h (revision 359079) @@ -1,6006 +1,6012 @@ //===--- Expr.h - Classes for representing expressions ----------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This file defines the Expr interface and subclasses. // //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_AST_EXPR_H #define LLVM_CLANG_AST_EXPR_H #include "clang/AST/APValue.h" #include "clang/AST/ASTVector.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclAccessPair.h" #include "clang/AST/OperationKinds.h" #include "clang/AST/Stmt.h" #include "clang/AST/TemplateBase.h" #include "clang/AST/Type.h" #include "clang/Basic/CharInfo.h" #include "clang/Basic/FixedPoint.h" #include "clang/Basic/LangOptions.h" #include "clang/Basic/SyncScope.h" #include "clang/Basic/TypeTraits.h" #include "llvm/ADT/APFloat.h" #include "llvm/ADT/APSInt.h" #include "llvm/ADT/iterator.h" #include "llvm/ADT/iterator_range.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/AtomicOrdering.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/TrailingObjects.h" namespace clang { class APValue; class ASTContext; class BlockDecl; class CXXBaseSpecifier; class CXXMemberCallExpr; class CXXOperatorCallExpr; class CastExpr; class Decl; class IdentifierInfo; class MaterializeTemporaryExpr; class NamedDecl; class ObjCPropertyRefExpr; class OpaqueValueExpr; class ParmVarDecl; class StringLiteral; class TargetInfo; class ValueDecl; /// A simple array of base specifiers. typedef SmallVector CXXCastPath; /// An adjustment to be made to the temporary created when emitting a /// reference binding, which accesses a particular subobject of that temporary. struct SubobjectAdjustment { enum { DerivedToBaseAdjustment, FieldAdjustment, MemberPointerAdjustment } Kind; struct DTB { const CastExpr *BasePath; const CXXRecordDecl *DerivedClass; }; struct P { const MemberPointerType *MPT; Expr *RHS; }; union { struct DTB DerivedToBase; FieldDecl *Field; struct P Ptr; }; SubobjectAdjustment(const CastExpr *BasePath, const CXXRecordDecl *DerivedClass) : Kind(DerivedToBaseAdjustment) { DerivedToBase.BasePath = BasePath; DerivedToBase.DerivedClass = DerivedClass; } SubobjectAdjustment(FieldDecl *Field) : Kind(FieldAdjustment) { this->Field = Field; } SubobjectAdjustment(const MemberPointerType *MPT, Expr *RHS) : Kind(MemberPointerAdjustment) { this->Ptr.MPT = MPT; this->Ptr.RHS = RHS; } }; /// This represents one expression. Note that Expr's are subclasses of Stmt. /// This allows an expression to be transparently used any place a Stmt is /// required. class Expr : public ValueStmt { QualType TR; public: Expr() = delete; Expr(const Expr&) = delete; Expr(Expr &&) = delete; Expr &operator=(const Expr&) = delete; Expr &operator=(Expr&&) = delete; protected: Expr(StmtClass SC, QualType T, ExprValueKind VK, ExprObjectKind OK, bool TD, bool VD, bool ID, bool ContainsUnexpandedParameterPack) : ValueStmt(SC) { ExprBits.TypeDependent = TD; ExprBits.ValueDependent = VD; ExprBits.InstantiationDependent = ID; ExprBits.ValueKind = VK; ExprBits.ObjectKind = OK; assert(ExprBits.ObjectKind == OK && "truncated kind"); ExprBits.ContainsUnexpandedParameterPack = ContainsUnexpandedParameterPack; setType(T); } /// Construct an empty expression. explicit Expr(StmtClass SC, EmptyShell) : ValueStmt(SC) { } public: QualType getType() const { return TR; } void setType(QualType t) { // In C++, the type of an expression is always adjusted so that it // will not have reference type (C++ [expr]p6). Use // QualType::getNonReferenceType() to retrieve the non-reference // type. Additionally, inspect Expr::isLvalue to determine whether // an expression that is adjusted in this manner should be // considered an lvalue. assert((t.isNull() || !t->isReferenceType()) && "Expressions can't have reference type"); TR = t; } /// isValueDependent - Determines whether this expression is /// value-dependent (C++ [temp.dep.constexpr]). For example, the /// array bound of "Chars" in the following example is /// value-dependent. /// @code /// template struct meta_string; /// @endcode bool isValueDependent() const { return ExprBits.ValueDependent; } /// Set whether this expression is value-dependent or not. void setValueDependent(bool VD) { ExprBits.ValueDependent = VD; } /// isTypeDependent - Determines whether this expression is /// type-dependent (C++ [temp.dep.expr]), which means that its type /// could change from one template instantiation to the next. For /// example, the expressions "x" and "x + y" are type-dependent in /// the following code, but "y" is not type-dependent: /// @code /// template /// void add(T x, int y) { /// x + y; /// } /// @endcode bool isTypeDependent() const { return ExprBits.TypeDependent; } /// Set whether this expression is type-dependent or not. void setTypeDependent(bool TD) { ExprBits.TypeDependent = TD; } /// Whether this expression is instantiation-dependent, meaning that /// it depends in some way on a template parameter, even if neither its type /// nor (constant) value can change due to the template instantiation. /// /// In the following example, the expression \c sizeof(sizeof(T() + T())) is /// instantiation-dependent (since it involves a template parameter \c T), but /// is neither type- nor value-dependent, since the type of the inner /// \c sizeof is known (\c std::size_t) and therefore the size of the outer /// \c sizeof is known. /// /// \code /// template /// void f(T x, T y) { /// sizeof(sizeof(T() + T()); /// } /// \endcode /// bool isInstantiationDependent() const { return ExprBits.InstantiationDependent; } /// Set whether this expression is instantiation-dependent or not. void setInstantiationDependent(bool ID) { ExprBits.InstantiationDependent = ID; } /// Whether this expression contains an unexpanded parameter /// pack (for C++11 variadic templates). /// /// Given the following function template: /// /// \code /// template /// void forward(const F &f, Types &&...args) { /// f(static_cast(args)...); /// } /// \endcode /// /// The expressions \c args and \c static_cast(args) both /// contain parameter packs. bool containsUnexpandedParameterPack() const { return ExprBits.ContainsUnexpandedParameterPack; } /// Set the bit that describes whether this expression /// contains an unexpanded parameter pack. void setContainsUnexpandedParameterPack(bool PP = true) { ExprBits.ContainsUnexpandedParameterPack = PP; } /// getExprLoc - Return the preferred location for the arrow when diagnosing /// a problem with a generic expression. SourceLocation getExprLoc() const LLVM_READONLY; /// isUnusedResultAWarning - Return true if this immediate expression should /// be warned about if the result is unused. If so, fill in expr, location, /// and ranges with expr to warn on and source locations/ranges appropriate /// for a warning. bool isUnusedResultAWarning(const Expr *&WarnExpr, SourceLocation &Loc, SourceRange &R1, SourceRange &R2, ASTContext &Ctx) const; /// isLValue - True if this expression is an "l-value" according to /// the rules of the current language. C and C++ give somewhat /// different rules for this concept, but in general, the result of /// an l-value expression identifies a specific object whereas the /// result of an r-value expression is a value detached from any /// specific storage. /// /// C++11 divides the concept of "r-value" into pure r-values /// ("pr-values") and so-called expiring values ("x-values"), which /// identify specific objects that can be safely cannibalized for /// their resources. This is an unfortunate abuse of terminology on /// the part of the C++ committee. In Clang, when we say "r-value", /// we generally mean a pr-value. bool isLValue() const { return getValueKind() == VK_LValue; } bool isRValue() const { return getValueKind() == VK_RValue; } bool isXValue() const { return getValueKind() == VK_XValue; } bool isGLValue() const { return getValueKind() != VK_RValue; } enum LValueClassification { LV_Valid, LV_NotObjectType, LV_IncompleteVoidType, LV_DuplicateVectorComponents, LV_InvalidExpression, LV_InvalidMessageExpression, LV_MemberFunction, LV_SubObjCPropertySetting, LV_ClassTemporary, LV_ArrayTemporary }; /// Reasons why an expression might not be an l-value. LValueClassification ClassifyLValue(ASTContext &Ctx) const; enum isModifiableLvalueResult { MLV_Valid, MLV_NotObjectType, MLV_IncompleteVoidType, MLV_DuplicateVectorComponents, MLV_InvalidExpression, MLV_LValueCast, // Specialized form of MLV_InvalidExpression. MLV_IncompleteType, MLV_ConstQualified, MLV_ConstQualifiedField, MLV_ConstAddrSpace, MLV_ArrayType, MLV_NoSetterProperty, MLV_MemberFunction, MLV_SubObjCPropertySetting, MLV_InvalidMessageExpression, MLV_ClassTemporary, MLV_ArrayTemporary }; /// isModifiableLvalue - C99 6.3.2.1: an lvalue that does not have array type, /// does not have an incomplete type, does not have a const-qualified type, /// and if it is a structure or union, does not have any member (including, /// recursively, any member or element of all contained aggregates or unions) /// with a const-qualified type. /// /// \param Loc [in,out] - A source location which *may* be filled /// in with the location of the expression making this a /// non-modifiable lvalue, if specified. isModifiableLvalueResult isModifiableLvalue(ASTContext &Ctx, SourceLocation *Loc = nullptr) const; /// The return type of classify(). Represents the C++11 expression /// taxonomy. class Classification { public: /// The various classification results. Most of these mean prvalue. enum Kinds { CL_LValue, CL_XValue, CL_Function, // Functions cannot be lvalues in C. CL_Void, // Void cannot be an lvalue in C. CL_AddressableVoid, // Void expression whose address can be taken in C. CL_DuplicateVectorComponents, // A vector shuffle with dupes. CL_MemberFunction, // An expression referring to a member function CL_SubObjCPropertySetting, CL_ClassTemporary, // A temporary of class type, or subobject thereof. CL_ArrayTemporary, // A temporary of array type. CL_ObjCMessageRValue, // ObjC message is an rvalue CL_PRValue // A prvalue for any other reason, of any other type }; /// The results of modification testing. enum ModifiableType { CM_Untested, // testModifiable was false. CM_Modifiable, CM_RValue, // Not modifiable because it's an rvalue CM_Function, // Not modifiable because it's a function; C++ only CM_LValueCast, // Same as CM_RValue, but indicates GCC cast-as-lvalue ext CM_NoSetterProperty,// Implicit assignment to ObjC property without setter CM_ConstQualified, CM_ConstQualifiedField, CM_ConstAddrSpace, CM_ArrayType, CM_IncompleteType }; private: friend class Expr; unsigned short Kind; unsigned short Modifiable; explicit Classification(Kinds k, ModifiableType m) : Kind(k), Modifiable(m) {} public: Classification() {} Kinds getKind() const { return static_cast(Kind); } ModifiableType getModifiable() const { assert(Modifiable != CM_Untested && "Did not test for modifiability."); return static_cast(Modifiable); } bool isLValue() const { return Kind == CL_LValue; } bool isXValue() const { return Kind == CL_XValue; } bool isGLValue() const { return Kind <= CL_XValue; } bool isPRValue() const { return Kind >= CL_Function; } bool isRValue() const { return Kind >= CL_XValue; } bool isModifiable() const { return getModifiable() == CM_Modifiable; } /// Create a simple, modifiably lvalue static Classification makeSimpleLValue() { return Classification(CL_LValue, CM_Modifiable); } }; /// Classify - Classify this expression according to the C++11 /// expression taxonomy. /// /// C++11 defines ([basic.lval]) a new taxonomy of expressions to replace the /// old lvalue vs rvalue. This function determines the type of expression this /// is. There are three expression types: /// - lvalues are classical lvalues as in C++03. /// - prvalues are equivalent to rvalues in C++03. /// - xvalues are expressions yielding unnamed rvalue references, e.g. a /// function returning an rvalue reference. /// lvalues and xvalues are collectively referred to as glvalues, while /// prvalues and xvalues together form rvalues. Classification Classify(ASTContext &Ctx) const { return ClassifyImpl(Ctx, nullptr); } /// ClassifyModifiable - Classify this expression according to the /// C++11 expression taxonomy, and see if it is valid on the left side /// of an assignment. /// /// This function extends classify in that it also tests whether the /// expression is modifiable (C99 6.3.2.1p1). /// \param Loc A source location that might be filled with a relevant location /// if the expression is not modifiable. Classification ClassifyModifiable(ASTContext &Ctx, SourceLocation &Loc) const{ return ClassifyImpl(Ctx, &Loc); } /// getValueKindForType - Given a formal return or parameter type, /// give its value kind. static ExprValueKind getValueKindForType(QualType T) { if (const ReferenceType *RT = T->getAs()) return (isa(RT) ? VK_LValue : (RT->getPointeeType()->isFunctionType() ? VK_LValue : VK_XValue)); return VK_RValue; } /// getValueKind - The value kind that this expression produces. ExprValueKind getValueKind() const { return static_cast(ExprBits.ValueKind); } /// getObjectKind - The object kind that this expression produces. /// Object kinds are meaningful only for expressions that yield an /// l-value or x-value. ExprObjectKind getObjectKind() const { return static_cast(ExprBits.ObjectKind); } bool isOrdinaryOrBitFieldObject() const { ExprObjectKind OK = getObjectKind(); return (OK == OK_Ordinary || OK == OK_BitField); } /// setValueKind - Set the value kind produced by this expression. void setValueKind(ExprValueKind Cat) { ExprBits.ValueKind = Cat; } /// setObjectKind - Set the object kind produced by this expression. void setObjectKind(ExprObjectKind Cat) { ExprBits.ObjectKind = Cat; } private: Classification ClassifyImpl(ASTContext &Ctx, SourceLocation *Loc) const; public: /// Returns true if this expression is a gl-value that /// potentially refers to a bit-field. /// /// In C++, whether a gl-value refers to a bitfield is essentially /// an aspect of the value-kind type system. bool refersToBitField() const { return getObjectKind() == OK_BitField; } /// If this expression refers to a bit-field, retrieve the /// declaration of that bit-field. /// /// Note that this returns a non-null pointer in subtly different /// places than refersToBitField returns true. In particular, this can /// return a non-null pointer even for r-values loaded from /// bit-fields, but it will return null for a conditional bit-field. FieldDecl *getSourceBitField(); const FieldDecl *getSourceBitField() const { return const_cast(this)->getSourceBitField(); } Decl *getReferencedDeclOfCallee(); const Decl *getReferencedDeclOfCallee() const { return const_cast(this)->getReferencedDeclOfCallee(); } /// If this expression is an l-value for an Objective C /// property, find the underlying property reference expression. const ObjCPropertyRefExpr *getObjCProperty() const; /// Check if this expression is the ObjC 'self' implicit parameter. bool isObjCSelfExpr() const; /// Returns whether this expression refers to a vector element. bool refersToVectorElement() const; /// Returns whether this expression refers to a global register /// variable. bool refersToGlobalRegisterVar() const; /// Returns whether this expression has a placeholder type. bool hasPlaceholderType() const { return getType()->isPlaceholderType(); } /// Returns whether this expression has a specific placeholder type. bool hasPlaceholderType(BuiltinType::Kind K) const { assert(BuiltinType::isPlaceholderTypeKind(K)); if (const BuiltinType *BT = dyn_cast(getType())) return BT->getKind() == K; return false; } /// isKnownToHaveBooleanValue - Return true if this is an integer expression /// that is known to return 0 or 1. This happens for _Bool/bool expressions /// but also int expressions which are produced by things like comparisons in /// C. /// /// \param Semantic If true, only return true for expressions that are known /// to be semantically boolean, which might not be true even for expressions /// that are known to evaluate to 0/1. For instance, reading an unsigned /// bit-field with width '1' will evaluate to 0/1, but doesn't necessarily /// semantically correspond to a bool. bool isKnownToHaveBooleanValue(bool Semantic = true) const; /// isIntegerConstantExpr - Return true if this expression is a valid integer /// constant expression, and, if so, return its value in Result. If not a /// valid i-c-e, return false 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. bool isIntegerConstantExpr(llvm::APSInt &Result, const ASTContext &Ctx, SourceLocation *Loc = nullptr, bool isEvaluated = true) const; bool isIntegerConstantExpr(const ASTContext &Ctx, SourceLocation *Loc = nullptr) const; /// isCXX98IntegralConstantExpr - Return true if this expression is an /// integral constant expression in C++98. Can only be used in C++. bool isCXX98IntegralConstantExpr(const ASTContext &Ctx) const; /// isCXX11ConstantExpr - Return true if this expression is a constant /// expression in C++11. Can only be used in C++. /// /// Note: This does not perform the implicit conversions required by C++11 /// [expr.const]p5. bool isCXX11ConstantExpr(const ASTContext &Ctx, APValue *Result = nullptr, SourceLocation *Loc = nullptr) const; /// isPotentialConstantExpr - Return true if this function's definition /// might be usable in a constant expression in C++11, if it were marked /// constexpr. Return false if the function can never produce a constant /// expression, along with diagnostics describing why not. static bool isPotentialConstantExpr(const FunctionDecl *FD, SmallVectorImpl< PartialDiagnosticAt> &Diags); /// isPotentialConstantExprUnevaluted - 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 /// why not. static bool isPotentialConstantExprUnevaluated(Expr *E, const FunctionDecl *FD, SmallVectorImpl< PartialDiagnosticAt> &Diags); /// isConstantInitializer - Returns true if this expression can be emitted to /// IR as a constant, and thus can be used as a constant initializer in C. /// If this expression is not constant and Culprit is non-null, /// it is used to store the address of first non constant expr. bool isConstantInitializer(ASTContext &Ctx, bool ForRef, const Expr **Culprit = nullptr) 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; /// 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; /// 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 /// expression). /// If the expression is unfoldable, the notes will indicate why it's not /// 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 *Diag; EvalStatus() : HasSideEffects(false), HasUndefinedBehavior(false), Diag(nullptr) {} // hasSideEffects - Return true if the evaluated expression has // side effects. bool hasSideEffects() const { return HasSideEffects; } }; /// EvalResult is a struct with detailed info about an evaluated expression. struct EvalResult : EvalStatus { /// Val - This is the value the expression can be folded to. APValue Val; // isGlobalLValue - Return true if the evaluated lvalue expression // is global. bool isGlobalLValue() const; }; /// EvaluateAsRValue - Return true if this is a constant which we can fold to /// an rvalue using any crazy technique (that has nothing to do with language /// standards) that we want to, even if the expression has side-effects. If /// this function returns true, it returns the folded constant in Result. If /// the expression is a glvalue, an lvalue-to-rvalue conversion will be /// applied. bool EvaluateAsRValue(EvalResult &Result, const ASTContext &Ctx, bool InConstantContext = false) const; /// EvaluateAsBooleanCondition - Return true if this is a constant /// which we can fold and convert to a boolean condition using /// any crazy technique that we want to, even if the expression has /// side-effects. bool EvaluateAsBooleanCondition(bool &Result, const ASTContext &Ctx, bool InConstantContext = false) const; enum SideEffectsKind { SE_NoSideEffects, ///< Strictly evaluate the expression. SE_AllowUndefinedBehavior, ///< Allow UB that we can give a value, but not ///< arbitrary unmodeled side effects. SE_AllowSideEffects ///< Allow any unmodeled side effect. }; /// EvaluateAsInt - Return true if this is a constant which we can fold and /// convert to an integer, using any crazy technique that we want to. bool EvaluateAsInt(EvalResult &Result, const ASTContext &Ctx, SideEffectsKind AllowSideEffects = SE_NoSideEffects, bool InConstantContext = false) const; /// EvaluateAsFloat - Return true if this is a constant which we can fold and /// convert to a floating point value, using any crazy technique that we /// want to. bool EvaluateAsFloat(llvm::APFloat &Result, const ASTContext &Ctx, 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. bool EvaluateAsFixedPoint(EvalResult &Result, const ASTContext &Ctx, SideEffectsKind AllowSideEffects = SE_NoSideEffects, bool InConstantContext = false) const; /// isEvaluatable - Call EvaluateAsRValue to see if this expression can be /// constant folded without side-effects, but discard the result. bool isEvaluatable(const ASTContext &Ctx, SideEffectsKind AllowSideEffects = SE_NoSideEffects) const; /// HasSideEffects - This routine returns true for all those expressions /// which have any effect other than producing a value. Example is a function /// call, volatile variable read, or throwing an exception. If /// IncludePossibleEffects is false, this call treats certain expressions with /// potential side effects (such as function call-like expressions, /// instantiation-dependent expressions, or invocations from a macro) as not /// having side effects. bool HasSideEffects(const ASTContext &Ctx, bool IncludePossibleEffects = true) const; /// Determine whether this expression involves a call to any function /// that is not trivial. bool hasNonTrivialCall(const ASTContext &Ctx) const; /// EvaluateKnownConstInt - Call EvaluateAsRValue and return the folded /// integer. This must be called on an expression that constant folds to an /// integer. llvm::APSInt EvaluateKnownConstInt( const ASTContext &Ctx, SmallVectorImpl *Diag = nullptr) const; llvm::APSInt EvaluateKnownConstIntCheckOverflow( const ASTContext &Ctx, SmallVectorImpl *Diag = nullptr) const; void EvaluateForOverflow(const ASTContext &Ctx) const; /// EvaluateAsLValue - Evaluate an expression to see if we can fold it to an /// lvalue with link time known address, with no side-effects. bool EvaluateAsLValue(EvalResult &Result, const ASTContext &Ctx, bool InConstantContext = false) const; /// EvaluateAsInitializer - Evaluate an expression as if it were the /// initializer of the given declaration. Returns true if the initializer /// can be folded to a constant, and produces any relevant notes. In C++11, /// notes will be produced if the expression is not a constant expression. bool EvaluateAsInitializer(APValue &Result, const ASTContext &Ctx, const VarDecl *VD, SmallVectorImpl &Notes) const; /// EvaluateWithSubstitution - Evaluate an expression as if from the context /// of a call to the given function with the given arguments, inside an /// unevaluated context. Returns true if the expression could be folded to a /// constant. bool EvaluateWithSubstitution(APValue &Value, ASTContext &Ctx, const FunctionDecl *Callee, ArrayRef Args, const Expr *This = nullptr) const; /// Indicates how the constant expression will be used. enum ConstExprUsage { EvaluateForCodeGen, EvaluateForMangling }; /// Evaluate an expression that is required to be a constant expression. bool EvaluateAsConstantExpr(EvalResult &Result, ConstExprUsage Usage, const ASTContext &Ctx) const; /// If the current Expr is a pointer, this will try to statically /// determine the number of bytes available where the pointer is pointing. /// Returns true if all of the above holds and we were able to figure out the /// size, false otherwise. /// /// \param Type - How to evaluate the size of the Expr, as defined by the /// "type" parameter of __builtin_object_size bool tryEvaluateObjectSize(uint64_t &Result, ASTContext &Ctx, unsigned Type) const; /// Enumeration used to describe the kind of Null pointer constant /// returned from \c isNullPointerConstant(). enum NullPointerConstantKind { /// Expression is not a Null pointer constant. NPCK_NotNull = 0, /// Expression is a Null pointer constant built from a zero integer /// expression that is not a simple, possibly parenthesized, zero literal. /// C++ Core Issue 903 will classify these expressions as "not pointers" /// once it is adopted. /// http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#903 NPCK_ZeroExpression, /// Expression is a Null pointer constant built from a literal zero. NPCK_ZeroLiteral, /// Expression is a C++11 nullptr. NPCK_CXX11_nullptr, /// Expression is a GNU-style __null constant. NPCK_GNUNull }; /// Enumeration used to describe how \c isNullPointerConstant() /// should cope with value-dependent expressions. enum NullPointerConstantValueDependence { /// Specifies that the expression should never be value-dependent. NPC_NeverValueDependent = 0, /// Specifies that a value-dependent expression of integral or /// dependent type should be considered a null pointer constant. NPC_ValueDependentIsNull, /// Specifies that a value-dependent expression should be considered /// to never be a null pointer constant. NPC_ValueDependentIsNotNull }; /// isNullPointerConstant - C99 6.3.2.3p3 - Test if this reduces down to /// a Null pointer constant. The return value can further distinguish the /// kind of NULL pointer constant that was detected. NullPointerConstantKind isNullPointerConstant( ASTContext &Ctx, NullPointerConstantValueDependence NPC) const; /// isOBJCGCCandidate - Return true if this expression may be used in a read/ /// write barrier. bool isOBJCGCCandidate(ASTContext &Ctx) const; /// Returns true if this expression is a bound member function. bool isBoundMemberFunction(ASTContext &Ctx) const; /// Given an expression of bound-member type, find the type /// of the member. Returns null if this is an *overloaded* bound /// member expression. static QualType findBoundMemberType(const Expr *expr); /// Skip past any invisble AST nodes which might surround this /// statement, such as ExprWithCleanups or ImplicitCastExpr nodes, /// but also injected CXXMemberExpr and CXXConstructExpr which represent /// implicit conversions. Expr *IgnoreUnlessSpelledInSource(); const Expr *IgnoreUnlessSpelledInSource() const { return const_cast(this)->IgnoreUnlessSpelledInSource(); } /// Skip past any implicit casts which might surround this expression until /// reaching a fixed point. Skips: /// * ImplicitCastExpr /// * FullExpr Expr *IgnoreImpCasts() LLVM_READONLY; const Expr *IgnoreImpCasts() const { return const_cast(this)->IgnoreImpCasts(); } /// Skip past any casts which might surround this expression until reaching /// a fixed point. Skips: /// * CastExpr /// * FullExpr /// * MaterializeTemporaryExpr /// * SubstNonTypeTemplateParmExpr Expr *IgnoreCasts() LLVM_READONLY; const Expr *IgnoreCasts() const { return const_cast(this)->IgnoreCasts(); } /// Skip past any implicit AST nodes which might surround this expression /// until reaching a fixed point. Skips: /// * What IgnoreImpCasts() skips /// * MaterializeTemporaryExpr /// * CXXBindTemporaryExpr Expr *IgnoreImplicit() LLVM_READONLY; const Expr *IgnoreImplicit() const { return const_cast(this)->IgnoreImplicit(); } /// Skip past any implicit AST nodes which might surround this expression /// until reaching a fixed point. Same as IgnoreImplicit, except that it /// also skips over implicit calls to constructors and conversion functions. /// /// FIXME: Should IgnoreImplicit do this? Expr *IgnoreImplicitAsWritten() LLVM_READONLY; const Expr *IgnoreImplicitAsWritten() const { return const_cast(this)->IgnoreImplicitAsWritten(); } /// Skip past any parentheses which might surround this expression until /// reaching a fixed point. Skips: /// * ParenExpr /// * UnaryOperator if `UO_Extension` /// * GenericSelectionExpr if `!isResultDependent()` /// * ChooseExpr if `!isConditionDependent()` /// * ConstantExpr Expr *IgnoreParens() LLVM_READONLY; const Expr *IgnoreParens() const { return const_cast(this)->IgnoreParens(); } /// Skip past any parentheses and implicit casts which might surround this /// expression until reaching a fixed point. /// FIXME: IgnoreParenImpCasts really ought to be equivalent to /// IgnoreParens() + IgnoreImpCasts() until reaching a fixed point. However /// this is currently not the case. Instead IgnoreParenImpCasts() skips: /// * What IgnoreParens() skips /// * What IgnoreImpCasts() skips /// * MaterializeTemporaryExpr /// * SubstNonTypeTemplateParmExpr Expr *IgnoreParenImpCasts() LLVM_READONLY; const Expr *IgnoreParenImpCasts() const { return const_cast(this)->IgnoreParenImpCasts(); } /// Skip past any parentheses and casts which might surround this expression /// until reaching a fixed point. Skips: /// * What IgnoreParens() skips /// * What IgnoreCasts() skips Expr *IgnoreParenCasts() LLVM_READONLY; const Expr *IgnoreParenCasts() const { return const_cast(this)->IgnoreParenCasts(); } /// Skip conversion operators. If this Expr is a call to a conversion /// operator, return the argument. Expr *IgnoreConversionOperator() LLVM_READONLY; const Expr *IgnoreConversionOperator() const { return const_cast(this)->IgnoreConversionOperator(); } /// Skip past any parentheses and lvalue casts which might surround this /// expression until reaching a fixed point. Skips: /// * What IgnoreParens() skips /// * What IgnoreCasts() skips, except that only lvalue-to-rvalue /// casts are skipped /// FIXME: This is intended purely as a temporary workaround for code /// that hasn't yet been rewritten to do the right thing about those /// casts, and may disappear along with the last internal use. Expr *IgnoreParenLValueCasts() LLVM_READONLY; const Expr *IgnoreParenLValueCasts() const { return const_cast(this)->IgnoreParenLValueCasts(); } /// Skip past any parenthese 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 /// * CastExpr which do not change the value /// * SubstNonTypeTemplateParmExpr Expr *IgnoreParenNoopCasts(const ASTContext &Ctx) LLVM_READONLY; const Expr *IgnoreParenNoopCasts(const ASTContext &Ctx) const { return const_cast(this)->IgnoreParenNoopCasts(Ctx); } /// Skip past any parentheses and derived-to-base casts until reaching a /// fixed point. Skips: /// * What IgnoreParens() skips /// * CastExpr which represent a derived-to-base cast (CK_DerivedToBase, /// CK_UncheckedDerivedToBase and CK_NoOp) Expr *ignoreParenBaseCasts() LLVM_READONLY; const Expr *ignoreParenBaseCasts() const { return const_cast(this)->ignoreParenBaseCasts(); } /// Determine whether this expression is a default function argument. /// /// Default arguments are implicitly generated in the abstract syntax tree /// by semantic analysis for function calls, object constructions, etc. in /// C++. Default arguments are represented by \c CXXDefaultArgExpr nodes; /// this routine also looks through any implicit casts to determine whether /// the expression is a default argument. bool isDefaultArgument() const; /// Determine whether the result of this expression is a /// temporary object of the given class type. bool isTemporaryObject(ASTContext &Ctx, const CXXRecordDecl *TempTy) const; /// Whether this expression is an implicit reference to 'this' in C++. bool isImplicitCXXThis() const; static bool hasAnyTypeDependentArguments(ArrayRef Exprs); /// For an expression of class type or pointer to class type, /// return the most derived class decl the expression is known to refer to. /// /// If this expression is a cast, this method looks through it to find the /// most derived decl that can be inferred from the expression. /// This is valid because derived-to-base conversions have undefined /// behavior if the object isn't dynamically of the derived type. const CXXRecordDecl *getBestDynamicClassType() const; /// Get the inner expression that determines the best dynamic class. /// If this is a prvalue, we guarantee that it is of the most-derived type /// for the object itself. const Expr *getBestDynamicClassTypeExpr() const; /// Walk outwards from an expression we want to bind a reference to and /// find the expression whose lifetime needs to be extended. Record /// the LHSs of comma expressions and adjustments needed along the path. const Expr *skipRValueSubobjectAdjustments( SmallVectorImpl &CommaLHS, SmallVectorImpl &Adjustments) const; const Expr *skipRValueSubobjectAdjustments() const { SmallVector CommaLHSs; SmallVector Adjustments; return skipRValueSubobjectAdjustments(CommaLHSs, Adjustments); } /// Checks that the two Expr's will refer to the same value as a comparison /// operand. The caller must ensure that the values referenced by the Expr's /// are not modified between E1 and E2 or the result my be invalid. static bool isSameComparisonOperand(const Expr* E1, const Expr* E2); static bool classof(const Stmt *T) { return T->getStmtClass() >= firstExprConstant && T->getStmtClass() <= lastExprConstant; } }; //===----------------------------------------------------------------------===// // Wrapper Expressions. //===----------------------------------------------------------------------===// /// FullExpr - Represents a "full-expression" node. class FullExpr : public Expr { protected: Stmt *SubExpr; FullExpr(StmtClass SC, Expr *subexpr) : Expr(SC, subexpr->getType(), subexpr->getValueKind(), subexpr->getObjectKind(), subexpr->isTypeDependent(), subexpr->isValueDependent(), subexpr->isInstantiationDependent(), subexpr->containsUnexpandedParameterPack()), SubExpr(subexpr) {} FullExpr(StmtClass SC, EmptyShell Empty) : Expr(SC, Empty) {} public: const Expr *getSubExpr() const { return cast(SubExpr); } Expr *getSubExpr() { return cast(SubExpr); } /// As with any mutator of the AST, be very careful when modifying an /// existing AST to preserve its invariants. void setSubExpr(Expr *E) { SubExpr = E; } static bool classof(const Stmt *T) { return T->getStmtClass() >= firstFullExprConstant && T->getStmtClass() <= lastFullExprConstant; } }; /// ConstantExpr - An expression that occurs in a constant context and /// optionally the result of evaluating the expression. class ConstantExpr final : public FullExpr, private llvm::TrailingObjects { static_assert(std::is_same::value, "this class assumes llvm::APInt::WordType is uint64_t for " "trail-allocated storage"); public: /// Describes the kind of result that can be trail-allocated. enum ResultStorageKind { RSK_None, RSK_Int64, RSK_APValue }; private: size_t numTrailingObjects(OverloadToken) const { return ConstantExprBits.ResultKind == ConstantExpr::RSK_APValue; } size_t numTrailingObjects(OverloadToken) const { return ConstantExprBits.ResultKind == ConstantExpr::RSK_Int64; } void DefaultInit(ResultStorageKind StorageKind); uint64_t &Int64Result() { assert(ConstantExprBits.ResultKind == ConstantExpr::RSK_Int64 && "invalid accessor"); return *getTrailingObjects(); } const uint64_t &Int64Result() const { return const_cast(this)->Int64Result(); } APValue &APValueResult() { assert(ConstantExprBits.ResultKind == ConstantExpr::RSK_APValue && "invalid accessor"); return *getTrailingObjects(); } const APValue &APValueResult() const { return const_cast(this)->APValueResult(); } ConstantExpr(Expr *subexpr, ResultStorageKind StorageKind); ConstantExpr(ResultStorageKind StorageKind, EmptyShell Empty); public: friend TrailingObjects; friend class ASTStmtReader; friend class ASTStmtWriter; static ConstantExpr *Create(const ASTContext &Context, Expr *E, const APValue &Result); static ConstantExpr *Create(const ASTContext &Context, Expr *E, ResultStorageKind Storage = RSK_None); static ConstantExpr *CreateEmpty(const ASTContext &Context, ResultStorageKind StorageKind, EmptyShell Empty); static ResultStorageKind getStorageKind(const APValue &Value); static ResultStorageKind getStorageKind(const Type *T, const ASTContext &Context); SourceLocation getBeginLoc() const LLVM_READONLY { return SubExpr->getBeginLoc(); } SourceLocation getEndLoc() const LLVM_READONLY { return SubExpr->getEndLoc(); } static bool classof(const Stmt *T) { return T->getStmtClass() == ConstantExprClass; } void SetResult(APValue Value, const ASTContext &Context) { MoveIntoResult(Value, Context); } void MoveIntoResult(APValue &Value, const ASTContext &Context); APValue::ValueKind getResultAPValueKind() const { return static_cast(ConstantExprBits.APValueKind); } ResultStorageKind getResultStorageKind() const { return static_cast(ConstantExprBits.ResultKind); } APValue getAPValueResult() const; const APValue &getResultAsAPValue() const { return APValueResult(); } llvm::APSInt getResultAsAPSInt() const; // Iterators child_range children() { return child_range(&SubExpr, &SubExpr+1); } const_child_range children() const { return const_child_range(&SubExpr, &SubExpr + 1); } }; //===----------------------------------------------------------------------===// // Primary Expressions. //===----------------------------------------------------------------------===// /// OpaqueValueExpr - An expression referring to an opaque object of a /// fixed type and value class. These don't correspond to concrete /// syntax; instead they're used to express operations (usually copy /// operations) on values whose source is generally obvious from /// context. class OpaqueValueExpr : public Expr { friend class ASTStmtReader; Expr *SourceExpr; public: OpaqueValueExpr(SourceLocation Loc, QualType T, ExprValueKind VK, ExprObjectKind OK = OK_Ordinary, Expr *SourceExpr = nullptr) : Expr(OpaqueValueExprClass, T, VK, OK, T->isDependentType() || (SourceExpr && SourceExpr->isTypeDependent()), T->isDependentType() || (SourceExpr && SourceExpr->isValueDependent()), T->isInstantiationDependentType() || (SourceExpr && SourceExpr->isInstantiationDependent()), false), SourceExpr(SourceExpr) { setIsUnique(false); OpaqueValueExprBits.Loc = Loc; } /// Given an expression which invokes a copy constructor --- i.e. a /// CXXConstructExpr, possibly wrapped in an ExprWithCleanups --- /// find the OpaqueValueExpr that's the source of the construction. static const OpaqueValueExpr *findInCopyConstruct(const Expr *expr); explicit OpaqueValueExpr(EmptyShell Empty) : Expr(OpaqueValueExprClass, Empty) {} /// Retrieve the location of this expression. SourceLocation getLocation() const { return OpaqueValueExprBits.Loc; } SourceLocation getBeginLoc() const LLVM_READONLY { return SourceExpr ? SourceExpr->getBeginLoc() : getLocation(); } SourceLocation getEndLoc() const LLVM_READONLY { return SourceExpr ? SourceExpr->getEndLoc() : getLocation(); } SourceLocation getExprLoc() const LLVM_READONLY { return SourceExpr ? SourceExpr->getExprLoc() : getLocation(); } child_range children() { return child_range(child_iterator(), child_iterator()); } const_child_range children() const { return const_child_range(const_child_iterator(), const_child_iterator()); } /// The source expression of an opaque value expression is the /// expression which originally generated the value. This is /// provided as a convenience for analyses that don't wish to /// precisely model the execution behavior of the program. /// /// The source expression is typically set when building the /// expression which binds the opaque value expression in the first /// place. Expr *getSourceExpr() const { return SourceExpr; } void setIsUnique(bool V) { assert((!V || SourceExpr) && "unique OVEs are expected to have source expressions"); OpaqueValueExprBits.IsUnique = V; } bool isUnique() const { return OpaqueValueExprBits.IsUnique; } static bool classof(const Stmt *T) { return T->getStmtClass() == OpaqueValueExprClass; } }; /// A reference to a declared variable, function, enum, etc. /// [C99 6.5.1p2] /// /// This encodes all the information about how a declaration is referenced /// within an expression. /// /// There are several optional constructs attached to DeclRefExprs only when /// they apply in order to conserve memory. These are laid out past the end of /// the object, and flags in the DeclRefExprBitfield track whether they exist: /// /// DeclRefExprBits.HasQualifier: /// Specifies when this declaration reference expression has a C++ /// nested-name-specifier. /// DeclRefExprBits.HasFoundDecl: /// Specifies when this declaration reference expression has a record of /// a NamedDecl (different from the referenced ValueDecl) which was found /// during name lookup and/or overload resolution. /// DeclRefExprBits.HasTemplateKWAndArgsInfo: /// Specifies when this declaration reference expression has an explicit /// C++ template keyword and/or template argument list. /// DeclRefExprBits.RefersToEnclosingVariableOrCapture /// Specifies when this declaration reference expression (validly) /// refers to an enclosed local or a captured variable. class DeclRefExpr final : public Expr, private llvm::TrailingObjects { friend class ASTStmtReader; friend class ASTStmtWriter; friend TrailingObjects; /// The declaration that we are referencing. ValueDecl *D; /// Provides source/type location info for the declaration name /// embedded in D. DeclarationNameLoc DNLoc; size_t numTrailingObjects(OverloadToken) const { return hasQualifier(); } size_t numTrailingObjects(OverloadToken) const { return hasFoundDecl(); } size_t numTrailingObjects(OverloadToken) const { return hasTemplateKWAndArgsInfo(); } /// Test whether there is a distinct FoundDecl attached to the end of /// this DRE. bool hasFoundDecl() const { return DeclRefExprBits.HasFoundDecl; } DeclRefExpr(const ASTContext &Ctx, NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateKWLoc, ValueDecl *D, bool RefersToEnlosingVariableOrCapture, const DeclarationNameInfo &NameInfo, NamedDecl *FoundD, const TemplateArgumentListInfo *TemplateArgs, QualType T, ExprValueKind VK, NonOdrUseReason NOUR); /// Construct an empty declaration reference expression. explicit DeclRefExpr(EmptyShell Empty) : Expr(DeclRefExprClass, Empty) {} /// Computes the type- and value-dependence flags for this /// declaration reference expression. void computeDependence(const ASTContext &Ctx); public: DeclRefExpr(const ASTContext &Ctx, ValueDecl *D, bool RefersToEnclosingVariableOrCapture, QualType T, ExprValueKind VK, SourceLocation L, const DeclarationNameLoc &LocInfo = DeclarationNameLoc(), NonOdrUseReason NOUR = NOUR_None); static DeclRefExpr * Create(const ASTContext &Context, NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateKWLoc, ValueDecl *D, bool RefersToEnclosingVariableOrCapture, SourceLocation NameLoc, QualType T, ExprValueKind VK, NamedDecl *FoundD = nullptr, const TemplateArgumentListInfo *TemplateArgs = nullptr, NonOdrUseReason NOUR = NOUR_None); static DeclRefExpr * Create(const ASTContext &Context, NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateKWLoc, ValueDecl *D, bool RefersToEnclosingVariableOrCapture, const DeclarationNameInfo &NameInfo, QualType T, ExprValueKind VK, NamedDecl *FoundD = nullptr, const TemplateArgumentListInfo *TemplateArgs = nullptr, NonOdrUseReason NOUR = NOUR_None); /// Construct an empty declaration reference expression. static DeclRefExpr *CreateEmpty(const ASTContext &Context, bool HasQualifier, bool HasFoundDecl, bool HasTemplateKWAndArgsInfo, unsigned NumTemplateArgs); ValueDecl *getDecl() { return D; } const ValueDecl *getDecl() const { return D; } void setDecl(ValueDecl *NewD) { D = NewD; } DeclarationNameInfo getNameInfo() const { return DeclarationNameInfo(getDecl()->getDeclName(), getLocation(), DNLoc); } SourceLocation getLocation() const { return DeclRefExprBits.Loc; } void setLocation(SourceLocation L) { DeclRefExprBits.Loc = L; } SourceLocation getBeginLoc() const LLVM_READONLY; SourceLocation getEndLoc() const LLVM_READONLY; /// Determine whether this declaration reference was preceded by a /// C++ nested-name-specifier, e.g., \c N::foo. bool hasQualifier() const { return DeclRefExprBits.HasQualifier; } /// If the name was qualified, retrieves the nested-name-specifier /// that precedes the name, with source-location information. NestedNameSpecifierLoc getQualifierLoc() const { if (!hasQualifier()) return NestedNameSpecifierLoc(); return *getTrailingObjects(); } /// If the name was qualified, retrieves the nested-name-specifier /// that precedes the name. Otherwise, returns NULL. NestedNameSpecifier *getQualifier() const { return getQualifierLoc().getNestedNameSpecifier(); } /// Get the NamedDecl through which this reference occurred. /// /// This Decl may be different from the ValueDecl actually referred to in the /// presence of using declarations, etc. It always returns non-NULL, and may /// simple return the ValueDecl when appropriate. NamedDecl *getFoundDecl() { return hasFoundDecl() ? *getTrailingObjects() : D; } /// Get the NamedDecl through which this reference occurred. /// See non-const variant. const NamedDecl *getFoundDecl() const { return hasFoundDecl() ? *getTrailingObjects() : D; } bool hasTemplateKWAndArgsInfo() const { return DeclRefExprBits.HasTemplateKWAndArgsInfo; } /// Retrieve the location of the template keyword preceding /// this name, if any. SourceLocation getTemplateKeywordLoc() const { if (!hasTemplateKWAndArgsInfo()) return SourceLocation(); return getTrailingObjects()->TemplateKWLoc; } /// Retrieve the location of the left angle bracket starting the /// explicit template argument list following the name, if any. SourceLocation getLAngleLoc() const { if (!hasTemplateKWAndArgsInfo()) return SourceLocation(); return getTrailingObjects()->LAngleLoc; } /// Retrieve the location of the right angle bracket ending the /// explicit template argument list following the name, if any. SourceLocation getRAngleLoc() const { if (!hasTemplateKWAndArgsInfo()) return SourceLocation(); return getTrailingObjects()->RAngleLoc; } /// Determines whether the name in this declaration reference /// was preceded by the template keyword. bool hasTemplateKeyword() const { return getTemplateKeywordLoc().isValid(); } /// Determines whether this declaration reference was followed by an /// explicit template argument list. bool hasExplicitTemplateArgs() const { return getLAngleLoc().isValid(); } /// Copies the template arguments (if present) into the given /// structure. void copyTemplateArgumentsInto(TemplateArgumentListInfo &List) const { if (hasExplicitTemplateArgs()) getTrailingObjects()->copyInto( getTrailingObjects(), List); } /// Retrieve the template arguments provided as part of this /// template-id. const TemplateArgumentLoc *getTemplateArgs() const { if (!hasExplicitTemplateArgs()) return nullptr; return getTrailingObjects(); } /// Retrieve the number of template arguments provided as part of this /// template-id. unsigned getNumTemplateArgs() const { if (!hasExplicitTemplateArgs()) return 0; return getTrailingObjects()->NumTemplateArgs; } ArrayRef template_arguments() const { return {getTemplateArgs(), getNumTemplateArgs()}; } /// Returns true if this expression refers to a function that /// was resolved from an overloaded set having size greater than 1. bool hadMultipleCandidates() const { return DeclRefExprBits.HadMultipleCandidates; } /// Sets the flag telling whether this expression refers to /// a function that was resolved from an overloaded set having size /// greater than 1. void setHadMultipleCandidates(bool V = true) { DeclRefExprBits.HadMultipleCandidates = V; } /// Is this expression a non-odr-use reference, and if so, why? NonOdrUseReason isNonOdrUse() const { return static_cast(DeclRefExprBits.NonOdrUseReason); } /// Does this DeclRefExpr refer to an enclosing local or a captured /// variable? bool refersToEnclosingVariableOrCapture() const { return DeclRefExprBits.RefersToEnclosingVariableOrCapture; } static bool classof(const Stmt *T) { return T->getStmtClass() == DeclRefExprClass; } // Iterators child_range children() { return child_range(child_iterator(), child_iterator()); } const_child_range children() const { return const_child_range(const_child_iterator(), const_child_iterator()); } }; /// 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 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); } }; class APFloatStorage : private APNumericStorage { public: llvm::APFloat getValue(const llvm::fltSemantics &Semantics) const { return llvm::APFloat(Semantics, getIntValue()); } void setValue(const ASTContext &C, const llvm::APFloat &Val) { setIntValue(C, Val.bitcastToAPInt()); } }; class IntegerLiteral : public Expr, public APIntStorage { SourceLocation Loc; /// Construct an empty integer literal. explicit IntegerLiteral(EmptyShell Empty) : Expr(IntegerLiteralClass, Empty) { } public: // type should be IntTy, LongTy, LongLongTy, UnsignedIntTy, UnsignedLongTy, // or UnsignedLongLongTy IntegerLiteral(const ASTContext &C, const llvm::APInt &V, QualType type, SourceLocation l); /// Returns a new integer literal with value 'V' and type 'type'. /// \param type - either IntTy, LongTy, LongLongTy, UnsignedIntTy, /// UnsignedLongTy, or UnsignedLongLongTy which should match the size of V /// \param V - the value that the returned integer literal contains. static IntegerLiteral *Create(const ASTContext &C, const llvm::APInt &V, QualType type, SourceLocation l); /// Returns a new empty integer literal. static IntegerLiteral *Create(const ASTContext &C, EmptyShell Empty); SourceLocation getBeginLoc() const LLVM_READONLY { return Loc; } SourceLocation getEndLoc() const LLVM_READONLY { return Loc; } /// Retrieve the location of the literal. SourceLocation getLocation() const { return Loc; } void setLocation(SourceLocation Location) { Loc = Location; } static bool classof(const Stmt *T) { return T->getStmtClass() == IntegerLiteralClass; } // Iterators child_range children() { return child_range(child_iterator(), child_iterator()); } const_child_range children() const { return const_child_range(const_child_iterator(), const_child_iterator()); } }; class FixedPointLiteral : public Expr, public APIntStorage { SourceLocation Loc; unsigned Scale; /// \brief Construct an empty integer literal. explicit FixedPointLiteral(EmptyShell Empty) : Expr(FixedPointLiteralClass, Empty) {} public: FixedPointLiteral(const ASTContext &C, const llvm::APInt &V, QualType type, SourceLocation l, unsigned Scale); // Store the int as is without any bit shifting. static FixedPointLiteral *CreateFromRawInt(const ASTContext &C, const llvm::APInt &V, QualType type, SourceLocation l, unsigned Scale); SourceLocation getBeginLoc() const LLVM_READONLY { return Loc; } SourceLocation getEndLoc() const LLVM_READONLY { return Loc; } /// \brief Retrieve the location of the literal. SourceLocation getLocation() const { return Loc; } void setLocation(SourceLocation Location) { Loc = Location; } static bool classof(const Stmt *T) { return T->getStmtClass() == FixedPointLiteralClass; } std::string getValueAsString(unsigned Radix) const; // Iterators child_range children() { return child_range(child_iterator(), child_iterator()); } const_child_range children() const { return const_child_range(const_child_iterator(), const_child_iterator()); } }; class CharacterLiteral : public Expr { public: enum CharacterKind { Ascii, Wide, UTF8, UTF16, UTF32 }; private: unsigned Value; SourceLocation Loc; public: // type should be IntTy CharacterLiteral(unsigned value, CharacterKind kind, QualType type, SourceLocation l) : Expr(CharacterLiteralClass, type, VK_RValue, OK_Ordinary, false, false, false, false), Value(value), Loc(l) { CharacterLiteralBits.Kind = kind; } /// Construct an empty character literal. CharacterLiteral(EmptyShell Empty) : Expr(CharacterLiteralClass, Empty) { } SourceLocation getLocation() const { return Loc; } CharacterKind getKind() const { return static_cast(CharacterLiteralBits.Kind); } SourceLocation getBeginLoc() const LLVM_READONLY { return Loc; } SourceLocation getEndLoc() const LLVM_READONLY { return Loc; } unsigned getValue() const { return Value; } void setLocation(SourceLocation Location) { Loc = Location; } void setKind(CharacterKind kind) { CharacterLiteralBits.Kind = kind; } void setValue(unsigned Val) { Value = Val; } static bool classof(const Stmt *T) { return T->getStmtClass() == CharacterLiteralClass; } // Iterators child_range children() { return child_range(child_iterator(), child_iterator()); } const_child_range children() const { return const_child_range(const_child_iterator(), const_child_iterator()); } }; class FloatingLiteral : public Expr, private APFloatStorage { SourceLocation Loc; FloatingLiteral(const ASTContext &C, const llvm::APFloat &V, bool isexact, QualType Type, SourceLocation L); /// Construct an empty floating-point literal. explicit FloatingLiteral(const ASTContext &C, EmptyShell Empty); public: static FloatingLiteral *Create(const ASTContext &C, const llvm::APFloat &V, bool isexact, QualType Type, SourceLocation L); static FloatingLiteral *Create(const ASTContext &C, EmptyShell Empty); llvm::APFloat getValue() const { return APFloatStorage::getValue(getSemantics()); } void setValue(const ASTContext &C, const llvm::APFloat &Val) { assert(&getSemantics() == &Val.getSemantics() && "Inconsistent semantics"); APFloatStorage::setValue(C, Val); } /// Get a raw enumeration value representing the floating-point semantics of /// this literal (32-bit IEEE, x87, ...), suitable for serialisation. llvm::APFloatBase::Semantics getRawSemantics() const { return static_cast( FloatingLiteralBits.Semantics); } /// Set the raw enumeration value representing the floating-point semantics of /// this literal (32-bit IEEE, x87, ...), suitable for serialisation. void setRawSemantics(llvm::APFloatBase::Semantics Sem) { FloatingLiteralBits.Semantics = Sem; } /// Return the APFloat semantics this literal uses. const llvm::fltSemantics &getSemantics() const { return llvm::APFloatBase::EnumToSemantics( static_cast( FloatingLiteralBits.Semantics)); } /// Set the APFloat semantics this literal uses. void setSemantics(const llvm::fltSemantics &Sem) { FloatingLiteralBits.Semantics = llvm::APFloatBase::SemanticsToEnum(Sem); } bool isExact() const { return FloatingLiteralBits.IsExact; } void setExact(bool E) { FloatingLiteralBits.IsExact = E; } /// getValueAsApproximateDouble - This returns the value as an inaccurate /// double. Note that this may cause loss of precision, but is useful for /// debugging dumps, etc. double getValueAsApproximateDouble() const; SourceLocation getLocation() const { return Loc; } void setLocation(SourceLocation L) { Loc = L; } SourceLocation getBeginLoc() const LLVM_READONLY { return Loc; } SourceLocation getEndLoc() const LLVM_READONLY { return Loc; } static bool classof(const Stmt *T) { return T->getStmtClass() == FloatingLiteralClass; } // Iterators child_range children() { return child_range(child_iterator(), child_iterator()); } const_child_range children() const { return const_child_range(const_child_iterator(), const_child_iterator()); } }; /// ImaginaryLiteral - We support imaginary integer and floating point literals, /// like "1.0i". We represent these as a wrapper around FloatingLiteral and /// IntegerLiteral classes. Instances of this class always have a Complex type /// whose element type matches the subexpression. /// class ImaginaryLiteral : public Expr { Stmt *Val; public: ImaginaryLiteral(Expr *val, QualType Ty) : Expr(ImaginaryLiteralClass, Ty, VK_RValue, OK_Ordinary, false, false, false, false), Val(val) {} /// Build an empty imaginary literal. explicit ImaginaryLiteral(EmptyShell Empty) : Expr(ImaginaryLiteralClass, Empty) { } const Expr *getSubExpr() const { return cast(Val); } Expr *getSubExpr() { return cast(Val); } void setSubExpr(Expr *E) { Val = E; } SourceLocation getBeginLoc() const LLVM_READONLY { return Val->getBeginLoc(); } SourceLocation getEndLoc() const LLVM_READONLY { return Val->getEndLoc(); } static bool classof(const Stmt *T) { return T->getStmtClass() == ImaginaryLiteralClass; } // Iterators child_range children() { return child_range(&Val, &Val+1); } const_child_range children() const { return const_child_range(&Val, &Val + 1); } }; /// 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 /// determined by calling getByteLength(). /// /// The C type for a string is always a ConstantArrayType. In C++, the char /// type is const qualified, in C it is not. /// /// Note that strings in C can be formed by concatenation of multiple string /// literal pptokens in translation phase #6. This keeps track of the locations /// of each of these pieces. /// /// Strings in C can also be truncated and extended by assigning into arrays, /// e.g. with constructs like: /// char X[2] = "foobar"; /// In this case, getByteLength() will return 6, but the string literal will /// have type "char[2]". class StringLiteral final : public Expr, private llvm::TrailingObjects { friend class ASTStmtReader; friend TrailingObjects; /// StringLiteral is followed by several trailing objects. They are in order: /// /// * A single unsigned storing the length in characters of this string. The /// length in bytes is this length times the width of a single character. /// Always present and stored as a trailing objects because storing it in /// StringLiteral would increase the size of StringLiteral by sizeof(void *) /// due to alignment requirements. If you add some data to StringLiteral, /// consider moving it inside StringLiteral. /// /// * An array of getNumConcatenated() SourceLocation, one for each of the /// token this string is made of. /// /// * An array of getByteLength() char used to store the string data. public: enum StringKind { Ascii, Wide, UTF8, UTF16, UTF32 }; private: unsigned numTrailingObjects(OverloadToken) const { return 1; } unsigned numTrailingObjects(OverloadToken) const { return getNumConcatenated(); } unsigned numTrailingObjects(OverloadToken) const { return getByteLength(); } char *getStrDataAsChar() { return getTrailingObjects(); } const char *getStrDataAsChar() const { return getTrailingObjects(); } const uint16_t *getStrDataAsUInt16() const { return reinterpret_cast(getTrailingObjects()); } const uint32_t *getStrDataAsUInt32() const { return reinterpret_cast(getTrailingObjects()); } /// Build a string literal. StringLiteral(const ASTContext &Ctx, StringRef Str, StringKind Kind, bool Pascal, QualType Ty, const SourceLocation *Loc, unsigned NumConcatenated); /// Build an empty string literal. StringLiteral(EmptyShell Empty, unsigned NumConcatenated, unsigned Length, unsigned CharByteWidth); /// Map a target and string kind to the appropriate character width. static unsigned mapCharByteWidth(TargetInfo const &Target, StringKind SK); /// Set one of the string literal token. void setStrTokenLoc(unsigned TokNum, SourceLocation L) { assert(TokNum < getNumConcatenated() && "Invalid tok number"); getTrailingObjects()[TokNum] = L; } 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, 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, SourceLocation Loc) { return Create(Ctx, Str, Kind, Pascal, Ty, &Loc, 1); } /// Construct an empty string literal. static StringLiteral *CreateEmpty(const ASTContext &Ctx, unsigned NumConcatenated, unsigned Length, unsigned CharByteWidth); StringRef getString() const { assert(getCharByteWidth() == 1 && "This function is used in places that assume strings use char"); return StringRef(getStrDataAsChar(), getByteLength()); } /// Allow access to clients that need the byte representation, such as /// ASTWriterStmt::VisitStringLiteral(). StringRef getBytes() const { // FIXME: StringRef may not be the right type to use as a result for this. return StringRef(getStrDataAsChar(), getByteLength()); } void outputString(raw_ostream &OS) const; uint32_t getCodeUnit(size_t i) const { assert(i < getLength() && "out of bounds access"); switch (getCharByteWidth()) { case 1: return static_cast(getStrDataAsChar()[i]); case 2: return getStrDataAsUInt16()[i]; case 4: return getStrDataAsUInt32()[i]; } llvm_unreachable("Unsupported character width!"); } unsigned getByteLength() const { return getCharByteWidth() * getLength(); } unsigned getLength() const { return *getTrailingObjects(); } unsigned getCharByteWidth() const { return StringLiteralBits.CharByteWidth; } StringKind getKind() const { return static_cast(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 isPascal() const { return StringLiteralBits.IsPascal; } bool containsNonAscii() const { for (auto c : getString()) if (!isASCII(c)) return true; return false; } bool containsNonAsciiOrNull() const { for (auto c : getString()) if (!isASCII(c) || !c) return true; return false; } /// getNumConcatenated - Get the number of string literal tokens that were /// concatenated in translation phase #6 to form this string literal. unsigned getNumConcatenated() const { return StringLiteralBits.NumConcatenated; } /// Get one of the string literal token. SourceLocation getStrTokenLoc(unsigned TokNum) const { assert(TokNum < getNumConcatenated() && "Invalid tok number"); return getTrailingObjects()[TokNum]; } /// getLocationOfByte - Return a source location that points to the specified /// byte of this string literal. /// /// Strings are amazingly complex. They can be formed from multiple tokens /// and can have escape sequences in them in addition to the usual trigraph /// and escaped newline business. This routine handles this complexity. /// SourceLocation getLocationOfByte(unsigned ByteNo, const SourceManager &SM, const LangOptions &Features, const TargetInfo &Target, unsigned *StartToken = nullptr, unsigned *StartTokenByteOffset = nullptr) const; typedef const SourceLocation *tokloc_iterator; tokloc_iterator tokloc_begin() const { return getTrailingObjects(); } tokloc_iterator tokloc_end() const { return getTrailingObjects() + getNumConcatenated(); } SourceLocation getBeginLoc() const LLVM_READONLY { return *tokloc_begin(); } SourceLocation getEndLoc() const LLVM_READONLY { return *(tokloc_end() - 1); } static bool classof(const Stmt *T) { return T->getStmtClass() == StringLiteralClass; } // Iterators child_range children() { return child_range(child_iterator(), child_iterator()); } const_child_range children() const { return const_child_range(const_child_iterator(), const_child_iterator()); } }; /// [C99 6.4.2.2] - A predefined identifier such as __func__. class PredefinedExpr final : public Expr, private llvm::TrailingObjects { friend class ASTStmtReader; friend TrailingObjects; // PredefinedExpr is optionally followed by a single trailing // "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); explicit PredefinedExpr(EmptyShell Empty, bool HasFunctionName); /// True if this PredefinedExpr has storage for a function name. bool hasFunctionName() const { return PredefinedExprBits.HasFunctionName; } void setFunctionName(StringLiteral *SL) { assert(hasFunctionName() && "This PredefinedExpr has no storage for a function name!"); *getTrailingObjects() = SL; } public: /// Create a PredefinedExpr. static PredefinedExpr *Create(const ASTContext &Ctx, SourceLocation L, QualType FNTy, IdentKind IK, StringLiteral *SL); /// Create an empty PredefinedExpr. static PredefinedExpr *CreateEmpty(const ASTContext &Ctx, bool HasFunctionName); IdentKind getIdentKind() const { return static_cast(PredefinedExprBits.Kind); } SourceLocation getLocation() const { return PredefinedExprBits.Loc; } void setLocation(SourceLocation L) { PredefinedExprBits.Loc = L; } StringLiteral *getFunctionName() { return hasFunctionName() ? static_cast(*getTrailingObjects()) : nullptr; } const StringLiteral *getFunctionName() const { return hasFunctionName() ? static_cast(*getTrailingObjects()) : nullptr; } static StringRef getIdentKindName(IdentKind IK); static std::string ComputeName(IdentKind IK, const Decl *CurrentDecl); SourceLocation getBeginLoc() const { return getLocation(); } SourceLocation getEndLoc() const { return getLocation(); } static bool classof(const Stmt *T) { return T->getStmtClass() == PredefinedExprClass; } // Iterators child_range children() { return child_range(getTrailingObjects(), getTrailingObjects() + hasFunctionName()); } const_child_range children() const { return const_child_range(getTrailingObjects(), getTrailingObjects() + hasFunctionName()); } }; /// ParenExpr - This represents a parethesized expression, e.g. "(1)". This /// AST node is only formed if full location information is requested. class ParenExpr : public Expr { SourceLocation L, R; Stmt *Val; public: ParenExpr(SourceLocation l, SourceLocation r, Expr *val) : Expr(ParenExprClass, val->getType(), val->getValueKind(), val->getObjectKind(), val->isTypeDependent(), val->isValueDependent(), val->isInstantiationDependent(), val->containsUnexpandedParameterPack()), L(l), R(r), Val(val) {} /// Construct an empty parenthesized expression. explicit ParenExpr(EmptyShell Empty) : Expr(ParenExprClass, Empty) { } const Expr *getSubExpr() const { return cast(Val); } Expr *getSubExpr() { return cast(Val); } void setSubExpr(Expr *E) { Val = E; } SourceLocation getBeginLoc() const LLVM_READONLY { return L; } SourceLocation getEndLoc() const LLVM_READONLY { return R; } /// Get the location of the left parentheses '('. SourceLocation getLParen() const { return L; } void setLParen(SourceLocation Loc) { L = Loc; } /// Get the location of the right parentheses ')'. SourceLocation getRParen() const { return R; } void setRParen(SourceLocation Loc) { R = Loc; } static bool classof(const Stmt *T) { return T->getStmtClass() == ParenExprClass; } // Iterators child_range children() { return child_range(&Val, &Val+1); } const_child_range children() const { return const_child_range(&Val, &Val + 1); } }; /// UnaryOperator - This represents the unary-expression's (except sizeof and /// alignof), the postinc/postdec operators from postfix-expression, and various /// extensions. /// /// Notes on various nodes: /// /// Real/Imag - These return the real/imag part of a complex operand. If /// applied to a non-complex value, the former returns its operand and the /// later returns zero in the type of the operand. /// class UnaryOperator : public Expr { Stmt *Val; public: typedef UnaryOperatorKind Opcode; UnaryOperator(Expr *input, Opcode opc, QualType type, ExprValueKind VK, ExprObjectKind OK, SourceLocation l, bool CanOverflow) : Expr(UnaryOperatorClass, type, VK, OK, input->isTypeDependent() || type->isDependentType(), input->isValueDependent(), (input->isInstantiationDependent() || type->isInstantiationDependentType()), input->containsUnexpandedParameterPack()), Val(input) { UnaryOperatorBits.Opc = opc; UnaryOperatorBits.CanOverflow = CanOverflow; UnaryOperatorBits.Loc = l; } /// Build an empty unary operator. explicit UnaryOperator(EmptyShell Empty) : Expr(UnaryOperatorClass, Empty) { UnaryOperatorBits.Opc = UO_AddrOf; } Opcode getOpcode() const { return static_cast(UnaryOperatorBits.Opc); } void setOpcode(Opcode Opc) { UnaryOperatorBits.Opc = Opc; } Expr *getSubExpr() const { return cast(Val); } void setSubExpr(Expr *E) { Val = E; } /// getOperatorLoc - Return the location of the operator. SourceLocation getOperatorLoc() const { return UnaryOperatorBits.Loc; } void setOperatorLoc(SourceLocation L) { UnaryOperatorBits.Loc = L; } /// Returns true if the unary operator can cause an overflow. For instance, /// signed int i = INT_MAX; i++; /// signed char c = CHAR_MAX; c++; /// Due to integer promotions, c++ is promoted to an int before the postfix /// increment, and the result is an int that cannot overflow. However, i++ /// can overflow. bool canOverflow() const { return UnaryOperatorBits.CanOverflow; } void setCanOverflow(bool C) { UnaryOperatorBits.CanOverflow = C; } /// isPostfix - Return true if this is a postfix operation, like x++. static bool isPostfix(Opcode Op) { return Op == UO_PostInc || Op == UO_PostDec; } /// isPrefix - Return true if this is a prefix operation, like --x. static bool isPrefix(Opcode Op) { return Op == UO_PreInc || Op == UO_PreDec; } bool isPrefix() const { return isPrefix(getOpcode()); } bool isPostfix() const { return isPostfix(getOpcode()); } static bool isIncrementOp(Opcode Op) { return Op == UO_PreInc || Op == UO_PostInc; } bool isIncrementOp() const { return isIncrementOp(getOpcode()); } static bool isDecrementOp(Opcode Op) { return Op == UO_PreDec || Op == UO_PostDec; } bool isDecrementOp() const { return isDecrementOp(getOpcode()); } static bool isIncrementDecrementOp(Opcode Op) { return Op <= UO_PreDec; } bool isIncrementDecrementOp() const { return isIncrementDecrementOp(getOpcode()); } static bool isArithmeticOp(Opcode Op) { return Op >= UO_Plus && Op <= UO_LNot; } bool isArithmeticOp() const { return isArithmeticOp(getOpcode()); } /// getOpcodeStr - Turn an Opcode enum value into the punctuation char it /// corresponds to, e.g. "sizeof" or "[pre]++" static StringRef getOpcodeStr(Opcode Op); /// Retrieve the unary opcode that corresponds to the given /// overloaded operator. static Opcode getOverloadedOpcode(OverloadedOperatorKind OO, bool Postfix); /// Retrieve the overloaded operator kind that corresponds to /// the given unary opcode. static OverloadedOperatorKind getOverloadedOperator(Opcode Opc); SourceLocation getBeginLoc() const LLVM_READONLY { return isPostfix() ? Val->getBeginLoc() : getOperatorLoc(); } SourceLocation getEndLoc() const LLVM_READONLY { return isPostfix() ? getOperatorLoc() : Val->getEndLoc(); } SourceLocation getExprLoc() const { return getOperatorLoc(); } static bool classof(const Stmt *T) { return T->getStmtClass() == UnaryOperatorClass; } // Iterators child_range children() { return child_range(&Val, &Val+1); } const_child_range children() const { return const_child_range(&Val, &Val + 1); } }; /// Helper class for OffsetOfExpr. // __builtin_offsetof(type, identifier(.identifier|[expr])*) class OffsetOfNode { public: /// The kind of offsetof node we have. enum Kind { /// An index into an array. Array = 0x00, /// A field. Field = 0x01, /// A field in a dependent type, known only by its name. Identifier = 0x02, /// An implicit indirection through a C++ base class, when the /// field found is in a base class. Base = 0x03 }; private: enum { MaskBits = 2, Mask = 0x03 }; /// The source range that covers this part of the designator. SourceRange Range; /// The data describing the designator, which comes in three /// different forms, depending on the lower two bits. /// - An unsigned index into the array of Expr*'s stored after this node /// in memory, for [constant-expression] designators. /// - A FieldDecl*, for references to a known field. /// - An IdentifierInfo*, for references to a field with a given name /// when the class type is dependent. /// - A CXXBaseSpecifier*, for references that look at a field in a /// base class. uintptr_t Data; public: /// Create an offsetof node that refers to an array element. OffsetOfNode(SourceLocation LBracketLoc, unsigned Index, SourceLocation RBracketLoc) : Range(LBracketLoc, RBracketLoc), Data((Index << 2) | Array) {} /// Create an offsetof node that refers to a field. OffsetOfNode(SourceLocation DotLoc, FieldDecl *Field, SourceLocation NameLoc) : Range(DotLoc.isValid() ? DotLoc : NameLoc, NameLoc), Data(reinterpret_cast(Field) | OffsetOfNode::Field) {} /// Create an offsetof node that refers to an identifier. OffsetOfNode(SourceLocation DotLoc, IdentifierInfo *Name, SourceLocation NameLoc) : Range(DotLoc.isValid() ? DotLoc : NameLoc, NameLoc), Data(reinterpret_cast(Name) | Identifier) {} /// Create an offsetof node that refers into a C++ base class. explicit OffsetOfNode(const CXXBaseSpecifier *Base) : Range(), Data(reinterpret_cast(Base) | OffsetOfNode::Base) {} /// Determine what kind of offsetof node this is. Kind getKind() const { return static_cast(Data & Mask); } /// For an array element node, returns the index into the array /// of expressions. unsigned getArrayExprIndex() const { assert(getKind() == Array); return Data >> 2; } /// For a field offsetof node, returns the field. FieldDecl *getField() const { assert(getKind() == Field); return reinterpret_cast(Data & ~(uintptr_t)Mask); } /// For a field or identifier offsetof node, returns the name of /// the field. IdentifierInfo *getFieldName() const; /// For a base class node, returns the base specifier. CXXBaseSpecifier *getBase() const { assert(getKind() == Base); return reinterpret_cast(Data & ~(uintptr_t)Mask); } /// Retrieve the source range that covers this offsetof node. /// /// For an array element node, the source range contains the locations of /// the square brackets. For a field or identifier node, the source range /// contains the location of the period (if there is one) and the /// identifier. SourceRange getSourceRange() const LLVM_READONLY { return Range; } SourceLocation getBeginLoc() const LLVM_READONLY { return Range.getBegin(); } SourceLocation getEndLoc() const LLVM_READONLY { return Range.getEnd(); } }; /// OffsetOfExpr - [C99 7.17] - This represents an expression of the form /// offsetof(record-type, member-designator). For example, given: /// @code /// struct S { /// float f; /// double d; /// }; /// struct T { /// int i; /// struct S s[10]; /// }; /// @endcode /// we can represent and evaluate the expression @c offsetof(struct T, s[2].d). class OffsetOfExpr final : public Expr, private llvm::TrailingObjects { SourceLocation OperatorLoc, RParenLoc; // Base type; TypeSourceInfo *TSInfo; // Number of sub-components (i.e. instances of OffsetOfNode). unsigned NumComps; // Number of sub-expressions (i.e. array subscript expressions). unsigned NumExprs; size_t numTrailingObjects(OverloadToken) const { return NumComps; } OffsetOfExpr(const ASTContext &C, QualType type, SourceLocation OperatorLoc, TypeSourceInfo *tsi, ArrayRef comps, ArrayRef exprs, SourceLocation RParenLoc); explicit OffsetOfExpr(unsigned numComps, unsigned numExprs) : Expr(OffsetOfExprClass, EmptyShell()), TSInfo(nullptr), NumComps(numComps), NumExprs(numExprs) {} public: static OffsetOfExpr *Create(const ASTContext &C, QualType type, SourceLocation OperatorLoc, TypeSourceInfo *tsi, ArrayRef comps, ArrayRef exprs, SourceLocation RParenLoc); static OffsetOfExpr *CreateEmpty(const ASTContext &C, unsigned NumComps, unsigned NumExprs); /// getOperatorLoc - Return the location of the operator. SourceLocation getOperatorLoc() const { return OperatorLoc; } void setOperatorLoc(SourceLocation L) { OperatorLoc = L; } /// Return the location of the right parentheses. SourceLocation getRParenLoc() const { return RParenLoc; } void setRParenLoc(SourceLocation R) { RParenLoc = R; } TypeSourceInfo *getTypeSourceInfo() const { return TSInfo; } void setTypeSourceInfo(TypeSourceInfo *tsi) { TSInfo = tsi; } const OffsetOfNode &getComponent(unsigned Idx) const { assert(Idx < NumComps && "Subscript out of range"); return getTrailingObjects()[Idx]; } void setComponent(unsigned Idx, OffsetOfNode ON) { assert(Idx < NumComps && "Subscript out of range"); getTrailingObjects()[Idx] = ON; } unsigned getNumComponents() const { return NumComps; } Expr* getIndexExpr(unsigned Idx) { assert(Idx < NumExprs && "Subscript out of range"); return getTrailingObjects()[Idx]; } const Expr *getIndexExpr(unsigned Idx) const { assert(Idx < NumExprs && "Subscript out of range"); return getTrailingObjects()[Idx]; } void setIndexExpr(unsigned Idx, Expr* E) { assert(Idx < NumComps && "Subscript out of range"); getTrailingObjects()[Idx] = E; } unsigned getNumExpressions() const { return NumExprs; } SourceLocation getBeginLoc() const LLVM_READONLY { return OperatorLoc; } SourceLocation getEndLoc() const LLVM_READONLY { return RParenLoc; } static bool classof(const Stmt *T) { return T->getStmtClass() == OffsetOfExprClass; } // Iterators child_range children() { Stmt **begin = reinterpret_cast(getTrailingObjects()); return child_range(begin, begin + NumExprs); } const_child_range children() const { Stmt *const *begin = reinterpret_cast(getTrailingObjects()); return const_child_range(begin, begin + NumExprs); } friend TrailingObjects; }; /// UnaryExprOrTypeTraitExpr - expression with either a type or (unevaluated) /// expression operand. Used for sizeof/alignof (C99 6.5.3.4) and /// vec_step (OpenCL 1.1 6.11.12). class UnaryExprOrTypeTraitExpr : public Expr { union { TypeSourceInfo *Ty; Stmt *Ex; } Argument; SourceLocation OpLoc, RParenLoc; public: UnaryExprOrTypeTraitExpr(UnaryExprOrTypeTrait ExprKind, TypeSourceInfo *TInfo, QualType resultType, SourceLocation op, SourceLocation rp) : Expr(UnaryExprOrTypeTraitExprClass, resultType, VK_RValue, OK_Ordinary, false, // Never type-dependent (C++ [temp.dep.expr]p3). // Value-dependent if the argument is type-dependent. TInfo->getType()->isDependentType(), TInfo->getType()->isInstantiationDependentType(), TInfo->getType()->containsUnexpandedParameterPack()), OpLoc(op), RParenLoc(rp) { UnaryExprOrTypeTraitExprBits.Kind = ExprKind; UnaryExprOrTypeTraitExprBits.IsType = true; Argument.Ty = TInfo; } UnaryExprOrTypeTraitExpr(UnaryExprOrTypeTrait ExprKind, Expr *E, QualType resultType, SourceLocation op, SourceLocation rp); /// Construct an empty sizeof/alignof expression. explicit UnaryExprOrTypeTraitExpr(EmptyShell Empty) : Expr(UnaryExprOrTypeTraitExprClass, Empty) { } UnaryExprOrTypeTrait getKind() const { return static_cast(UnaryExprOrTypeTraitExprBits.Kind); } void setKind(UnaryExprOrTypeTrait K) { UnaryExprOrTypeTraitExprBits.Kind = K;} bool isArgumentType() const { return UnaryExprOrTypeTraitExprBits.IsType; } QualType getArgumentType() const { return getArgumentTypeInfo()->getType(); } TypeSourceInfo *getArgumentTypeInfo() const { assert(isArgumentType() && "calling getArgumentType() when arg is expr"); return Argument.Ty; } Expr *getArgumentExpr() { assert(!isArgumentType() && "calling getArgumentExpr() when arg is type"); return static_cast(Argument.Ex); } const Expr *getArgumentExpr() const { return const_cast(this)->getArgumentExpr(); } void setArgument(Expr *E) { Argument.Ex = E; UnaryExprOrTypeTraitExprBits.IsType = false; } void setArgument(TypeSourceInfo *TInfo) { Argument.Ty = TInfo; UnaryExprOrTypeTraitExprBits.IsType = true; } /// Gets the argument type, or the type of the argument expression, whichever /// is appropriate. QualType getTypeOfArgument() const { return isArgumentType() ? getArgumentType() : getArgumentExpr()->getType(); } SourceLocation getOperatorLoc() const { return OpLoc; } void setOperatorLoc(SourceLocation L) { OpLoc = L; } SourceLocation getRParenLoc() const { return RParenLoc; } void setRParenLoc(SourceLocation L) { RParenLoc = L; } SourceLocation getBeginLoc() const LLVM_READONLY { return OpLoc; } SourceLocation getEndLoc() const LLVM_READONLY { return RParenLoc; } static bool classof(const Stmt *T) { return T->getStmtClass() == UnaryExprOrTypeTraitExprClass; } // Iterators child_range children(); const_child_range children() const; }; //===----------------------------------------------------------------------===// // Postfix Operators. //===----------------------------------------------------------------------===// /// ArraySubscriptExpr - [C99 6.5.2.1] Array Subscripting. class ArraySubscriptExpr : public Expr { enum { LHS, RHS, END_EXPR }; Stmt *SubExprs[END_EXPR]; bool lhsIsBase() const { return getRHS()->getType()->isIntegerType(); } public: ArraySubscriptExpr(Expr *lhs, Expr *rhs, QualType t, ExprValueKind VK, ExprObjectKind OK, SourceLocation rbracketloc) : Expr(ArraySubscriptExprClass, t, VK, OK, lhs->isTypeDependent() || rhs->isTypeDependent(), lhs->isValueDependent() || rhs->isValueDependent(), (lhs->isInstantiationDependent() || rhs->isInstantiationDependent()), (lhs->containsUnexpandedParameterPack() || rhs->containsUnexpandedParameterPack())) { SubExprs[LHS] = lhs; SubExprs[RHS] = rhs; ArraySubscriptExprBits.RBracketLoc = rbracketloc; } /// Create an empty array subscript expression. explicit ArraySubscriptExpr(EmptyShell Shell) : Expr(ArraySubscriptExprClass, Shell) { } /// An array access can be written A[4] or 4[A] (both are equivalent). /// - getBase() and getIdx() always present the normalized view: A[4]. /// In this case getBase() returns "A" and getIdx() returns "4". /// - getLHS() and getRHS() present the syntactic view. e.g. for /// 4[A] getLHS() returns "4". /// Note: Because vector element access is also written A[4] we must /// predicate the format conversion in getBase and getIdx only on the /// the type of the RHS, as it is possible for the LHS to be a vector of /// integer type Expr *getLHS() { return cast(SubExprs[LHS]); } const Expr *getLHS() const { return cast(SubExprs[LHS]); } void setLHS(Expr *E) { SubExprs[LHS] = E; } Expr *getRHS() { return cast(SubExprs[RHS]); } const Expr *getRHS() const { return cast(SubExprs[RHS]); } void setRHS(Expr *E) { SubExprs[RHS] = E; } Expr *getBase() { return lhsIsBase() ? getLHS() : getRHS(); } const Expr *getBase() const { return lhsIsBase() ? getLHS() : getRHS(); } Expr *getIdx() { return lhsIsBase() ? getRHS() : getLHS(); } const Expr *getIdx() const { return lhsIsBase() ? getRHS() : getLHS(); } SourceLocation getBeginLoc() const LLVM_READONLY { return getLHS()->getBeginLoc(); } SourceLocation getEndLoc() const { return getRBracketLoc(); } SourceLocation getRBracketLoc() const { return ArraySubscriptExprBits.RBracketLoc; } void setRBracketLoc(SourceLocation L) { ArraySubscriptExprBits.RBracketLoc = L; } SourceLocation getExprLoc() const LLVM_READONLY { return getBase()->getExprLoc(); } static bool classof(const Stmt *T) { return T->getStmtClass() == ArraySubscriptExprClass; } // Iterators child_range children() { return child_range(&SubExprs[0], &SubExprs[0]+END_EXPR); } const_child_range children() const { return const_child_range(&SubExprs[0], &SubExprs[0] + END_EXPR); } }; /// CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]). /// CallExpr itself represents a normal function call, e.g., "f(x, 2)", /// while its subclasses may represent alternative syntax that (semantically) /// results in a function call. For example, CXXOperatorCallExpr is /// a subclass for overloaded operator calls that use operator syntax, e.g., /// "str1 + str2" to resolve to a function call. class CallExpr : public Expr { enum { FN = 0, PREARGS_START = 1 }; /// The number of arguments in the call expression. unsigned NumArgs; /// The location of the right parenthese. This has a different meaning for /// the derived classes of CallExpr. SourceLocation RParenLoc; void updateDependenciesFromArg(Expr *Arg); // CallExpr store some data in trailing objects. However since CallExpr // is used a base of other expression classes we cannot use // llvm::TrailingObjects. Instead we manually perform the pointer arithmetic // and casts. // // The trailing objects are in order: // // * A single "Stmt *" for the callee expression. // // * An array of getNumPreArgs() "Stmt *" for the pre-argument expressions. // // * An array of getNumArgs() "Stmt *" for the argument expressions. // // Note that we store the offset in bytes from the this pointer to the start // of the trailing objects. It would be perfectly possible to compute it // based on the dynamic kind of the CallExpr. However 1.) we have plenty of // space in the bit-fields of Stmt. 2.) It was benchmarked to be faster to // compute this once and then load the offset from the bit-fields of Stmt, // instead of re-computing the offset each time the trailing objects are // accessed. /// Return a pointer to the start of the trailing array of "Stmt *". Stmt **getTrailingStmts() { return reinterpret_cast(reinterpret_cast(this) + CallExprBits.OffsetToTrailingObjects); } Stmt *const *getTrailingStmts() const { return const_cast(this)->getTrailingStmts(); } /// Map a statement class to the appropriate offset in bytes from the /// this pointer to the trailing objects. static unsigned offsetToTrailingObjects(StmtClass SC); public: enum class ADLCallKind : bool { NotADL, UsesADL }; static constexpr ADLCallKind NotADL = ADLCallKind::NotADL; static constexpr ADLCallKind UsesADL = ADLCallKind::UsesADL; protected: /// Build a call expression, assuming that appropriate storage has been /// allocated for the trailing objects. CallExpr(StmtClass SC, Expr *Fn, ArrayRef PreArgs, ArrayRef Args, QualType Ty, ExprValueKind VK, SourceLocation RParenLoc, unsigned MinNumArgs, ADLCallKind UsesADL); /// Build an empty call expression, for deserialization. CallExpr(StmtClass SC, unsigned NumPreArgs, unsigned NumArgs, EmptyShell Empty); /// Return the size in bytes needed for the trailing objects. /// Used by the derived classes to allocate the right amount of storage. static unsigned sizeOfTrailingObjects(unsigned NumPreArgs, unsigned NumArgs) { return (1 + NumPreArgs + NumArgs) * sizeof(Stmt *); } Stmt *getPreArg(unsigned I) { assert(I < getNumPreArgs() && "Prearg access out of range!"); return getTrailingStmts()[PREARGS_START + I]; } const Stmt *getPreArg(unsigned I) const { assert(I < getNumPreArgs() && "Prearg access out of range!"); return getTrailingStmts()[PREARGS_START + I]; } void setPreArg(unsigned I, Stmt *PreArg) { assert(I < getNumPreArgs() && "Prearg access out of range!"); getTrailingStmts()[PREARGS_START + I] = PreArg; } unsigned getNumPreArgs() const { return CallExprBits.NumPreArgs; } public: /// Create a call expression. Fn is the callee expression, Args is the /// argument array, Ty is the type of the call expression (which is *not* /// the return type in general), VK is the value kind of the call expression /// (lvalue, rvalue, ...), and RParenLoc is the location of the right /// parenthese in the call expression. MinNumArgs specifies the minimum /// number of arguments. The actual number of arguments will be the greater /// of Args.size() and MinNumArgs. This is used in a few places to allocate /// enough storage for the default arguments. UsesADL specifies whether the /// callee was found through argument-dependent lookup. /// /// Note that you can use CreateTemporary if you need a temporary call /// expression on the stack. static CallExpr *Create(const ASTContext &Ctx, Expr *Fn, ArrayRef Args, QualType Ty, ExprValueKind VK, SourceLocation RParenLoc, unsigned MinNumArgs = 0, ADLCallKind UsesADL = NotADL); /// Create a temporary call expression with no arguments in the memory /// pointed to by Mem. Mem must points to at least sizeof(CallExpr) /// + sizeof(Stmt *) bytes of storage, aligned to alignof(CallExpr): /// /// \code{.cpp} /// alignas(CallExpr) char Buffer[sizeof(CallExpr) + sizeof(Stmt *)]; /// CallExpr *TheCall = CallExpr::CreateTemporary(Buffer, etc); /// \endcode static CallExpr *CreateTemporary(void *Mem, Expr *Fn, QualType Ty, ExprValueKind VK, SourceLocation RParenLoc, ADLCallKind UsesADL = NotADL); /// Create an empty call expression, for deserialization. static CallExpr *CreateEmpty(const ASTContext &Ctx, unsigned NumArgs, EmptyShell Empty); Expr *getCallee() { return cast(getTrailingStmts()[FN]); } const Expr *getCallee() const { return cast(getTrailingStmts()[FN]); } void setCallee(Expr *F) { getTrailingStmts()[FN] = F; } ADLCallKind getADLCallKind() const { return static_cast(CallExprBits.UsesADL); } void setADLCallKind(ADLCallKind V = UsesADL) { CallExprBits.UsesADL = static_cast(V); } bool usesADL() const { return getADLCallKind() == UsesADL; } Decl *getCalleeDecl() { return getCallee()->getReferencedDeclOfCallee(); } const Decl *getCalleeDecl() const { return getCallee()->getReferencedDeclOfCallee(); } /// If the callee is a FunctionDecl, return it. Otherwise return null. FunctionDecl *getDirectCallee() { return dyn_cast_or_null(getCalleeDecl()); } const FunctionDecl *getDirectCallee() const { return dyn_cast_or_null(getCalleeDecl()); } /// getNumArgs - Return the number of actual arguments to this call. unsigned getNumArgs() const { return NumArgs; } /// Retrieve the call arguments. Expr **getArgs() { return reinterpret_cast(getTrailingStmts() + PREARGS_START + getNumPreArgs()); } const Expr *const *getArgs() const { return reinterpret_cast( getTrailingStmts() + PREARGS_START + getNumPreArgs()); } /// getArg - Return the specified argument. Expr *getArg(unsigned Arg) { assert(Arg < getNumArgs() && "Arg access out of range!"); return getArgs()[Arg]; } const Expr *getArg(unsigned Arg) const { assert(Arg < getNumArgs() && "Arg access out of range!"); return getArgs()[Arg]; } /// setArg - Set the specified argument. void setArg(unsigned Arg, Expr *ArgExpr) { assert(Arg < getNumArgs() && "Arg access out of range!"); getArgs()[Arg] = ArgExpr; } /// Reduce the number of arguments in this call expression. This is used for /// example during error recovery to drop extra arguments. There is no way /// to perform the opposite because: 1.) We don't track how much storage /// we have for the argument array 2.) This would potentially require growing /// the argument array, something we cannot support since the arguments are /// stored in a trailing array. void shrinkNumArgs(unsigned NewNumArgs) { assert((NewNumArgs <= getNumArgs()) && "shrinkNumArgs cannot increase the number of arguments!"); NumArgs = NewNumArgs; } /// Bluntly set a new number of arguments without doing any checks whatsoever. /// Only used during construction of a CallExpr in a few places in Sema. /// FIXME: Find a way to remove it. void setNumArgsUnsafe(unsigned NewNumArgs) { NumArgs = NewNumArgs; } typedef ExprIterator arg_iterator; typedef ConstExprIterator const_arg_iterator; typedef llvm::iterator_range arg_range; typedef llvm::iterator_range const_arg_range; arg_range arguments() { return arg_range(arg_begin(), arg_end()); } const_arg_range arguments() const { return const_arg_range(arg_begin(), arg_end()); } arg_iterator arg_begin() { return getTrailingStmts() + PREARGS_START + getNumPreArgs(); } arg_iterator arg_end() { return arg_begin() + getNumArgs(); } const_arg_iterator arg_begin() const { return getTrailingStmts() + PREARGS_START + getNumPreArgs(); } const_arg_iterator arg_end() const { return arg_begin() + getNumArgs(); } /// This method provides fast access to all the subexpressions of /// a CallExpr without going through the slower virtual child_iterator /// interface. This provides efficient reverse iteration of the /// subexpressions. This is currently used for CFG construction. ArrayRef getRawSubExprs() { return llvm::makeArrayRef(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; } /// getBuiltinCallee - If this is a call to a builtin, return the builtin ID /// of the callee. If not, return 0. unsigned getBuiltinCallee() const; /// Returns \c true if this is a call to a builtin which does not /// evaluate side-effects within its arguments. bool isUnevaluatedBuiltinCall(const ASTContext &Ctx) const; /// getCallReturnType - Get the return type of the call expr. This is not /// always the type of the expr itself, if the return type is a reference /// type. QualType getCallReturnType(const ASTContext &Ctx) const; /// Returns the WarnUnusedResultAttr that is either declared on the called /// function, or its return type declaration. const Attr *getUnusedResultAttr(const ASTContext &Ctx) const; /// Returns true if this call expression should warn on unused results. bool hasUnusedResultAttr(const ASTContext &Ctx) const { return getUnusedResultAttr(Ctx) != nullptr; } SourceLocation getRParenLoc() const { return RParenLoc; } void setRParenLoc(SourceLocation L) { RParenLoc = L; } SourceLocation getBeginLoc() const LLVM_READONLY; SourceLocation getEndLoc() const LLVM_READONLY; /// Return true if this is a call to __assume() or __builtin_assume() with /// a non-value-dependent constant parameter evaluating as false. bool isBuiltinAssumeFalse(const ASTContext &Ctx) const; bool isCallToStdMove() const { const FunctionDecl *FD = getDirectCallee(); return getNumArgs() == 1 && FD && FD->isInStdNamespace() && FD->getIdentifier() && FD->getIdentifier()->isStr("move"); } static bool classof(const Stmt *T) { return T->getStmtClass() >= firstCallExprConstant && T->getStmtClass() <= lastCallExprConstant; } // Iterators child_range children() { return child_range(getTrailingStmts(), getTrailingStmts() + PREARGS_START + getNumPreArgs() + getNumArgs()); } const_child_range children() const { return const_child_range(getTrailingStmts(), getTrailingStmts() + PREARGS_START + getNumPreArgs() + getNumArgs()); } }; /// Extra data stored in some MemberExpr objects. struct MemberExprNameQualifier { /// The nested-name-specifier that qualifies the name, including /// source-location information. NestedNameSpecifierLoc QualifierLoc; /// The DeclAccessPair through which the MemberDecl was found due to /// name qualifiers. DeclAccessPair FoundDecl; }; /// MemberExpr - [C99 6.5.2.3] Structure and Union Members. X->F and X.F. /// class MemberExpr final : public Expr, private llvm::TrailingObjects { friend class ASTReader; friend class ASTStmtReader; friend class ASTStmtWriter; friend TrailingObjects; /// Base - the expression for the base pointer or structure references. In /// X.F, this is "X". Stmt *Base; /// MemberDecl - This is the decl being referenced by the field/member name. /// In X.F, this is the decl referenced by F. ValueDecl *MemberDecl; /// MemberDNLoc - Provides source/type location info for the /// declaration name embedded in MemberDecl. DeclarationNameLoc MemberDNLoc; /// MemberLoc - This is the location of the member name. SourceLocation MemberLoc; size_t numTrailingObjects(OverloadToken) const { return hasQualifierOrFoundDecl(); } size_t numTrailingObjects(OverloadToken) const { return hasTemplateKWAndArgsInfo(); } bool hasQualifierOrFoundDecl() const { return MemberExprBits.HasQualifierOrFoundDecl; } bool hasTemplateKWAndArgsInfo() const { return MemberExprBits.HasTemplateKWAndArgsInfo; } MemberExpr(Expr *Base, bool IsArrow, SourceLocation OperatorLoc, ValueDecl *MemberDecl, const DeclarationNameInfo &NameInfo, QualType T, ExprValueKind VK, ExprObjectKind OK, NonOdrUseReason NOUR); MemberExpr(EmptyShell Empty) : Expr(MemberExprClass, Empty), Base(), MemberDecl() {} public: static MemberExpr *Create(const ASTContext &C, Expr *Base, bool IsArrow, SourceLocation OperatorLoc, NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateKWLoc, ValueDecl *MemberDecl, DeclAccessPair FoundDecl, DeclarationNameInfo MemberNameInfo, const TemplateArgumentListInfo *TemplateArgs, QualType T, ExprValueKind VK, ExprObjectKind OK, NonOdrUseReason NOUR); /// Create an implicit MemberExpr, with no location, qualifier, template /// arguments, and so on. Suitable only for non-static member access. static MemberExpr *CreateImplicit(const ASTContext &C, Expr *Base, bool IsArrow, ValueDecl *MemberDecl, QualType T, ExprValueKind VK, ExprObjectKind OK) { return Create(C, Base, IsArrow, SourceLocation(), NestedNameSpecifierLoc(), SourceLocation(), MemberDecl, DeclAccessPair::make(MemberDecl, MemberDecl->getAccess()), DeclarationNameInfo(), nullptr, T, VK, OK, NOUR_None); } static MemberExpr *CreateEmpty(const ASTContext &Context, bool HasQualifier, bool HasFoundDecl, bool HasTemplateKWAndArgsInfo, unsigned NumTemplateArgs); void setBase(Expr *E) { Base = E; } Expr *getBase() const { return cast(Base); } /// Retrieve the member declaration to which this expression refers. /// /// The returned declaration will be a FieldDecl or (in C++) a VarDecl (for /// static data members), a CXXMethodDecl, or an EnumConstantDecl. ValueDecl *getMemberDecl() const { return MemberDecl; } void setMemberDecl(ValueDecl *D) { MemberDecl = D; } /// Retrieves the declaration found by lookup. DeclAccessPair getFoundDecl() const { if (!hasQualifierOrFoundDecl()) return DeclAccessPair::make(getMemberDecl(), getMemberDecl()->getAccess()); return getTrailingObjects()->FoundDecl; } /// Determines whether this member expression actually had /// a C++ nested-name-specifier prior to the name of the member, e.g., /// x->Base::foo. bool hasQualifier() const { return getQualifier() != nullptr; } /// If the member name was qualified, retrieves the /// nested-name-specifier that precedes the member name, with source-location /// information. NestedNameSpecifierLoc getQualifierLoc() const { if (!hasQualifierOrFoundDecl()) return NestedNameSpecifierLoc(); return getTrailingObjects()->QualifierLoc; } /// If the member name was qualified, retrieves the /// nested-name-specifier that precedes the member name. Otherwise, returns /// NULL. NestedNameSpecifier *getQualifier() const { return getQualifierLoc().getNestedNameSpecifier(); } /// Retrieve the location of the template keyword preceding /// the member name, if any. SourceLocation getTemplateKeywordLoc() const { if (!hasTemplateKWAndArgsInfo()) return SourceLocation(); return getTrailingObjects()->TemplateKWLoc; } /// Retrieve the location of the left angle bracket starting the /// explicit template argument list following the member name, if any. SourceLocation getLAngleLoc() const { if (!hasTemplateKWAndArgsInfo()) return SourceLocation(); return getTrailingObjects()->LAngleLoc; } /// Retrieve the location of the right angle bracket ending the /// explicit template argument list following the member name, if any. SourceLocation getRAngleLoc() const { if (!hasTemplateKWAndArgsInfo()) return SourceLocation(); return getTrailingObjects()->RAngleLoc; } /// Determines whether the member name was preceded by the template keyword. bool hasTemplateKeyword() const { return getTemplateKeywordLoc().isValid(); } /// Determines whether the member name was followed by an /// explicit template argument list. bool hasExplicitTemplateArgs() const { return getLAngleLoc().isValid(); } /// Copies the template arguments (if present) into the given /// structure. void copyTemplateArgumentsInto(TemplateArgumentListInfo &List) const { if (hasExplicitTemplateArgs()) getTrailingObjects()->copyInto( getTrailingObjects(), List); } /// Retrieve the template arguments provided as part of this /// template-id. const TemplateArgumentLoc *getTemplateArgs() const { if (!hasExplicitTemplateArgs()) return nullptr; return getTrailingObjects(); } /// Retrieve the number of template arguments provided as part of this /// template-id. unsigned getNumTemplateArgs() const { if (!hasExplicitTemplateArgs()) return 0; return getTrailingObjects()->NumTemplateArgs; } ArrayRef template_arguments() const { return {getTemplateArgs(), getNumTemplateArgs()}; } /// Retrieve the member declaration name info. DeclarationNameInfo getMemberNameInfo() const { return DeclarationNameInfo(MemberDecl->getDeclName(), MemberLoc, MemberDNLoc); } SourceLocation getOperatorLoc() const { return MemberExprBits.OperatorLoc; } bool isArrow() const { return MemberExprBits.IsArrow; } void setArrow(bool A) { MemberExprBits.IsArrow = A; } /// getMemberLoc - Return the location of the "member", in X->F, it is the /// location of 'F'. SourceLocation getMemberLoc() const { return MemberLoc; } void setMemberLoc(SourceLocation L) { MemberLoc = L; } SourceLocation getBeginLoc() const LLVM_READONLY; SourceLocation getEndLoc() const LLVM_READONLY; SourceLocation getExprLoc() const LLVM_READONLY { return MemberLoc; } /// Determine whether the base of this explicit is implicit. bool isImplicitAccess() const { return getBase() && getBase()->isImplicitCXXThis(); } /// Returns true if this member expression refers to a method that /// was resolved from an overloaded set having size greater than 1. bool hadMultipleCandidates() const { return MemberExprBits.HadMultipleCandidates; } /// Sets the flag telling whether this expression refers to /// a method that was resolved from an overloaded set having size /// greater than 1. void setHadMultipleCandidates(bool V = true) { MemberExprBits.HadMultipleCandidates = V; } /// Returns true if virtual dispatch is performed. /// If the member access is fully qualified, (i.e. X::f()), virtual /// dispatching is not performed. In -fapple-kext mode qualified /// calls to virtual method will still go through the vtable. bool performsVirtualDispatch(const LangOptions &LO) const { return LO.AppleKext || !hasQualifier(); } /// Is this expression a non-odr-use reference, and if so, why? /// This is only meaningful if the named member is a static member. NonOdrUseReason isNonOdrUse() const { return static_cast(MemberExprBits.NonOdrUseReason); } static bool classof(const Stmt *T) { return T->getStmtClass() == MemberExprClass; } // Iterators child_range children() { return child_range(&Base, &Base+1); } const_child_range children() const { return const_child_range(&Base, &Base + 1); } }; /// CompoundLiteralExpr - [C99 6.5.2.5] /// class CompoundLiteralExpr : public Expr { /// LParenLoc - If non-null, this is the location of the left paren in a /// compound literal like "(int){4}". This can be null if this is a /// synthesized compound expression. SourceLocation LParenLoc; /// The type as written. This can be an incomplete array type, in /// which case the actual expression type will be different. /// The int part of the pair stores whether this expr is file scope. llvm::PointerIntPair TInfoAndScope; Stmt *Init; public: CompoundLiteralExpr(SourceLocation lparenloc, TypeSourceInfo *tinfo, QualType T, ExprValueKind VK, Expr *init, bool fileScope) : Expr(CompoundLiteralExprClass, T, VK, OK_Ordinary, tinfo->getType()->isDependentType(), init->isValueDependent(), (init->isInstantiationDependent() || tinfo->getType()->isInstantiationDependentType()), init->containsUnexpandedParameterPack()), LParenLoc(lparenloc), TInfoAndScope(tinfo, fileScope), Init(init) {} /// Construct an empty compound literal. explicit CompoundLiteralExpr(EmptyShell Empty) : Expr(CompoundLiteralExprClass, Empty) { } const Expr *getInitializer() const { return cast(Init); } Expr *getInitializer() { return cast(Init); } void setInitializer(Expr *E) { Init = E; } bool isFileScope() const { return TInfoAndScope.getInt(); } void setFileScope(bool FS) { TInfoAndScope.setInt(FS); } SourceLocation getLParenLoc() const { return LParenLoc; } void setLParenLoc(SourceLocation L) { LParenLoc = L; } TypeSourceInfo *getTypeSourceInfo() const { return TInfoAndScope.getPointer(); } void setTypeSourceInfo(TypeSourceInfo *tinfo) { TInfoAndScope.setPointer(tinfo); } SourceLocation getBeginLoc() const LLVM_READONLY { // FIXME: Init should never be null. if (!Init) return SourceLocation(); if (LParenLoc.isInvalid()) return Init->getBeginLoc(); return LParenLoc; } SourceLocation getEndLoc() const LLVM_READONLY { // FIXME: Init should never be null. if (!Init) return SourceLocation(); return Init->getEndLoc(); } static bool classof(const Stmt *T) { return T->getStmtClass() == CompoundLiteralExprClass; } // Iterators child_range children() { return child_range(&Init, &Init+1); } const_child_range children() const { return const_child_range(&Init, &Init + 1); } }; /// CastExpr - Base class for type casts, including both implicit /// casts (ImplicitCastExpr) and explicit casts that have some /// representation in the source code (ExplicitCastExpr's derived /// classes). class CastExpr : public Expr { Stmt *Op; bool CastConsistency() const; const CXXBaseSpecifier * const *path_buffer() const { return const_cast(this)->path_buffer(); } CXXBaseSpecifier **path_buffer(); protected: CastExpr(StmtClass SC, QualType ty, ExprValueKind VK, const CastKind kind, Expr *op, unsigned BasePathSize) : Expr(SC, ty, VK, OK_Ordinary, // Cast expressions are type-dependent if the type is // dependent (C++ [temp.dep.expr]p3). ty->isDependentType(), // Cast expressions are value-dependent if the type is // dependent or if the subexpression is value-dependent. ty->isDependentType() || (op && op->isValueDependent()), (ty->isInstantiationDependentType() || (op && op->isInstantiationDependent())), // An implicit cast expression doesn't (lexically) contain an // unexpanded pack, even if its target type does. ((SC != ImplicitCastExprClass && ty->containsUnexpandedParameterPack()) || (op && op->containsUnexpandedParameterPack()))), Op(op) { CastExprBits.Kind = kind; CastExprBits.PartOfExplicitCast = false; CastExprBits.BasePathSize = BasePathSize; assert((CastExprBits.BasePathSize == BasePathSize) && "BasePathSize overflow!"); assert(CastConsistency()); } /// Construct an empty cast. CastExpr(StmtClass SC, EmptyShell Empty, unsigned BasePathSize) : Expr(SC, Empty) { CastExprBits.PartOfExplicitCast = false; CastExprBits.BasePathSize = BasePathSize; assert((CastExprBits.BasePathSize == BasePathSize) && "BasePathSize overflow!"); } public: CastKind getCastKind() const { return (CastKind) CastExprBits.Kind; } void setCastKind(CastKind K) { CastExprBits.Kind = K; } static const char *getCastKindName(CastKind CK); const char *getCastKindName() const { return getCastKindName(getCastKind()); } Expr *getSubExpr() { return cast(Op); } const Expr *getSubExpr() const { return cast(Op); } void setSubExpr(Expr *E) { Op = E; } /// Retrieve the cast subexpression as it was written in the source /// code, looking through any implicit casts or other intermediate nodes /// introduced by semantic analysis. Expr *getSubExprAsWritten(); const Expr *getSubExprAsWritten() const { return const_cast(this)->getSubExprAsWritten(); } /// If this cast applies a user-defined conversion, retrieve the conversion /// function that it invokes. NamedDecl *getConversionFunction() const; typedef CXXBaseSpecifier **path_iterator; typedef const CXXBaseSpecifier *const *path_const_iterator; bool path_empty() const { return path_size() == 0; } unsigned path_size() const { return CastExprBits.BasePathSize; } path_iterator path_begin() { return path_buffer(); } path_iterator path_end() { return path_buffer() + path_size(); } path_const_iterator path_begin() const { return path_buffer(); } path_const_iterator path_end() const { return path_buffer() + path_size(); } llvm::iterator_range path() { return llvm::make_range(path_begin(), path_end()); } llvm::iterator_range path() const { return llvm::make_range(path_begin(), path_end()); } const FieldDecl *getTargetUnionField() const { assert(getCastKind() == CK_ToUnion); return getTargetFieldForToUnionCast(getType(), getSubExpr()->getType()); } static const FieldDecl *getTargetFieldForToUnionCast(QualType unionType, QualType opType); static const FieldDecl *getTargetFieldForToUnionCast(const RecordDecl *RD, QualType opType); static bool classof(const Stmt *T) { return T->getStmtClass() >= firstCastExprConstant && T->getStmtClass() <= lastCastExprConstant; } // Iterators child_range children() { return child_range(&Op, &Op+1); } const_child_range children() const { return const_child_range(&Op, &Op + 1); } }; /// ImplicitCastExpr - Allows us to explicitly represent implicit type /// conversions, which have no direct representation in the original /// source code. For example: converting T[]->T*, void f()->void /// (*f)(), float->double, short->int, etc. /// /// In C, implicit casts always produce rvalues. However, in C++, an /// implicit cast whose result is being bound to a reference will be /// an lvalue or xvalue. For example: /// /// @code /// class Base { }; /// class Derived : public Base { }; /// Derived &&ref(); /// void f(Derived d) { /// Base& b = d; // initializer is an ImplicitCastExpr /// // to an lvalue of type Base /// Base&& r = ref(); // initializer is an ImplicitCastExpr /// // to an xvalue of type Base /// } /// @endcode class ImplicitCastExpr final : public CastExpr, private llvm::TrailingObjects { ImplicitCastExpr(QualType ty, CastKind kind, Expr *op, unsigned BasePathLength, ExprValueKind VK) : CastExpr(ImplicitCastExprClass, ty, VK, kind, op, BasePathLength) { } /// Construct an empty implicit cast. explicit ImplicitCastExpr(EmptyShell Shell, unsigned PathSize) : CastExpr(ImplicitCastExprClass, Shell, PathSize) { } public: enum OnStack_t { OnStack }; ImplicitCastExpr(OnStack_t _, QualType ty, CastKind kind, Expr *op, ExprValueKind VK) : CastExpr(ImplicitCastExprClass, ty, VK, kind, op, 0) { } bool isPartOfExplicitCast() const { return CastExprBits.PartOfExplicitCast; } void setIsPartOfExplicitCast(bool PartOfExplicitCast) { CastExprBits.PartOfExplicitCast = PartOfExplicitCast; } static ImplicitCastExpr *Create(const ASTContext &Context, QualType T, CastKind Kind, Expr *Operand, const CXXCastPath *BasePath, ExprValueKind Cat); static ImplicitCastExpr *CreateEmpty(const ASTContext &Context, unsigned PathSize); SourceLocation getBeginLoc() const LLVM_READONLY { return getSubExpr()->getBeginLoc(); } SourceLocation getEndLoc() const LLVM_READONLY { return getSubExpr()->getEndLoc(); } static bool classof(const Stmt *T) { return T->getStmtClass() == ImplicitCastExprClass; } friend TrailingObjects; friend class CastExpr; }; /// ExplicitCastExpr - An explicit cast written in the source /// code. /// /// This class is effectively an abstract class, because it provides /// the basic representation of an explicitly-written cast without /// specifying which kind of cast (C cast, functional cast, static /// cast, etc.) was written; specific derived classes represent the /// particular style of cast and its location information. /// /// Unlike implicit casts, explicit cast nodes have two different /// types: the type that was written into the source code, and the /// actual type of the expression as determined by semantic /// analysis. These types may differ slightly. For example, in C++ one /// can cast to a reference type, which indicates that the resulting /// expression will be an lvalue or xvalue. The reference type, however, /// will not be used as the type of the expression. class ExplicitCastExpr : public CastExpr { /// TInfo - Source type info for the (written) type /// this expression is casting to. TypeSourceInfo *TInfo; protected: ExplicitCastExpr(StmtClass SC, QualType exprTy, ExprValueKind VK, CastKind kind, Expr *op, unsigned PathSize, TypeSourceInfo *writtenTy) : CastExpr(SC, exprTy, VK, kind, op, PathSize), TInfo(writtenTy) {} /// Construct an empty explicit cast. ExplicitCastExpr(StmtClass SC, EmptyShell Shell, unsigned PathSize) : CastExpr(SC, Shell, PathSize) { } public: /// getTypeInfoAsWritten - Returns the type source info for the type /// that this expression is casting to. TypeSourceInfo *getTypeInfoAsWritten() const { return TInfo; } void setTypeInfoAsWritten(TypeSourceInfo *writtenTy) { TInfo = writtenTy; } /// getTypeAsWritten - Returns the type that this expression is /// casting to, as written in the source code. QualType getTypeAsWritten() const { return TInfo->getType(); } static bool classof(const Stmt *T) { return T->getStmtClass() >= firstExplicitCastExprConstant && T->getStmtClass() <= lastExplicitCastExprConstant; } }; /// CStyleCastExpr - An explicit cast in C (C99 6.5.4) or a C-style /// cast in C++ (C++ [expr.cast]), which uses the syntax /// (Type)expr. For example: @c (int)f. class CStyleCastExpr final : public ExplicitCastExpr, private llvm::TrailingObjects { SourceLocation LPLoc; // the location of the left paren SourceLocation RPLoc; // the location of the right paren CStyleCastExpr(QualType exprTy, ExprValueKind vk, CastKind kind, Expr *op, unsigned PathSize, TypeSourceInfo *writtenTy, SourceLocation l, SourceLocation r) : ExplicitCastExpr(CStyleCastExprClass, exprTy, vk, kind, op, PathSize, writtenTy), LPLoc(l), RPLoc(r) {} /// Construct an empty C-style explicit cast. explicit CStyleCastExpr(EmptyShell Shell, unsigned PathSize) : ExplicitCastExpr(CStyleCastExprClass, Shell, PathSize) { } public: static CStyleCastExpr *Create(const ASTContext &Context, QualType T, ExprValueKind VK, CastKind K, Expr *Op, const CXXCastPath *BasePath, TypeSourceInfo *WrittenTy, SourceLocation L, SourceLocation R); static CStyleCastExpr *CreateEmpty(const ASTContext &Context, unsigned PathSize); SourceLocation getLParenLoc() const { return LPLoc; } void setLParenLoc(SourceLocation L) { LPLoc = L; } SourceLocation getRParenLoc() const { return RPLoc; } void setRParenLoc(SourceLocation L) { RPLoc = L; } SourceLocation getBeginLoc() const LLVM_READONLY { return LPLoc; } SourceLocation getEndLoc() const LLVM_READONLY { return getSubExpr()->getEndLoc(); } static bool classof(const Stmt *T) { return T->getStmtClass() == CStyleCastExprClass; } friend TrailingObjects; friend class CastExpr; }; /// A builtin binary operation expression such as "x + y" or "x <= y". /// /// This expression node kind describes a builtin binary operation, /// such as "x + y" for integer values "x" and "y". The operands will /// already have been converted to appropriate types (e.g., by /// performing promotions or conversions). /// /// In C++, where operators may be overloaded, a different kind of /// expression node (CXXOperatorCallExpr) is used to express the /// invocation of an overloaded operator with operator syntax. Within /// a C++ template, whether BinaryOperator or CXXOperatorCallExpr is /// used to store an expression "x + y" depends on the subexpressions /// for x and y. If neither x or y is type-dependent, and the "+" /// operator resolves to a built-in operation, BinaryOperator will be /// used to express the computation (x and y may still be /// value-dependent). If either x or y is type-dependent, or if the /// "+" resolves to an overloaded operator, CXXOperatorCallExpr will /// be used to express the computation. class BinaryOperator : public Expr { enum { LHS, RHS, END_EXPR }; Stmt *SubExprs[END_EXPR]; public: typedef BinaryOperatorKind Opcode; BinaryOperator(Expr *lhs, Expr *rhs, Opcode opc, QualType ResTy, ExprValueKind VK, ExprObjectKind OK, SourceLocation opLoc, FPOptions FPFeatures) : Expr(BinaryOperatorClass, ResTy, VK, OK, lhs->isTypeDependent() || rhs->isTypeDependent(), lhs->isValueDependent() || rhs->isValueDependent(), (lhs->isInstantiationDependent() || rhs->isInstantiationDependent()), (lhs->containsUnexpandedParameterPack() || rhs->containsUnexpandedParameterPack())) { BinaryOperatorBits.Opc = opc; BinaryOperatorBits.FPFeatures = FPFeatures.getInt(); BinaryOperatorBits.OpLoc = opLoc; SubExprs[LHS] = lhs; SubExprs[RHS] = rhs; assert(!isCompoundAssignmentOp() && "Use CompoundAssignOperator for compound assignments"); } /// Construct an empty binary operator. explicit BinaryOperator(EmptyShell Empty) : Expr(BinaryOperatorClass, Empty) { BinaryOperatorBits.Opc = BO_Comma; } SourceLocation getExprLoc() const { return getOperatorLoc(); } SourceLocation getOperatorLoc() const { return BinaryOperatorBits.OpLoc; } void setOperatorLoc(SourceLocation L) { BinaryOperatorBits.OpLoc = L; } Opcode getOpcode() const { return static_cast(BinaryOperatorBits.Opc); } void setOpcode(Opcode Opc) { BinaryOperatorBits.Opc = Opc; } Expr *getLHS() const { return cast(SubExprs[LHS]); } void setLHS(Expr *E) { SubExprs[LHS] = E; } Expr *getRHS() const { return cast(SubExprs[RHS]); } void setRHS(Expr *E) { SubExprs[RHS] = E; } SourceLocation getBeginLoc() const LLVM_READONLY { return getLHS()->getBeginLoc(); } SourceLocation getEndLoc() const LLVM_READONLY { return getRHS()->getEndLoc(); } /// getOpcodeStr - Turn an Opcode enum value into the punctuation char it /// corresponds to, e.g. "<<=". static StringRef getOpcodeStr(Opcode Op); StringRef getOpcodeStr() const { return getOpcodeStr(getOpcode()); } /// Retrieve the binary opcode that corresponds to the given /// overloaded operator. static Opcode getOverloadedOpcode(OverloadedOperatorKind OO); /// Retrieve the overloaded operator kind that corresponds to /// the given binary opcode. static OverloadedOperatorKind getOverloadedOperator(Opcode Opc); /// predicates to categorize the respective opcodes. static bool isPtrMemOp(Opcode Opc) { return Opc == BO_PtrMemD || Opc == BO_PtrMemI; } bool isPtrMemOp() const { return isPtrMemOp(getOpcode()); } static bool isMultiplicativeOp(Opcode Opc) { return Opc >= BO_Mul && Opc <= BO_Rem; } bool isMultiplicativeOp() const { return isMultiplicativeOp(getOpcode()); } static bool isAdditiveOp(Opcode Opc) { return Opc == BO_Add || Opc==BO_Sub; } bool isAdditiveOp() const { return isAdditiveOp(getOpcode()); } static bool isShiftOp(Opcode Opc) { return Opc == BO_Shl || Opc == BO_Shr; } bool isShiftOp() const { return isShiftOp(getOpcode()); } static bool isBitwiseOp(Opcode Opc) { return Opc >= BO_And && Opc <= BO_Or; } bool isBitwiseOp() const { return isBitwiseOp(getOpcode()); } static bool isRelationalOp(Opcode Opc) { return Opc >= BO_LT && Opc<=BO_GE; } bool isRelationalOp() const { return isRelationalOp(getOpcode()); } static bool isEqualityOp(Opcode Opc) { return Opc == BO_EQ || Opc == BO_NE; } bool isEqualityOp() const { return isEqualityOp(getOpcode()); } static bool isComparisonOp(Opcode Opc) { return Opc >= BO_Cmp && Opc<=BO_NE; } bool isComparisonOp() const { return isComparisonOp(getOpcode()); } static bool isCommaOp(Opcode Opc) { return Opc == BO_Comma; } bool isCommaOp() const { return isCommaOp(getOpcode()); } static Opcode negateComparisonOp(Opcode Opc) { switch (Opc) { default: llvm_unreachable("Not a comparison operator."); case BO_LT: return BO_GE; case BO_GT: return BO_LE; case BO_LE: return BO_GT; case BO_GE: return BO_LT; case BO_EQ: return BO_NE; case BO_NE: return BO_EQ; } } static Opcode reverseComparisonOp(Opcode Opc) { switch (Opc) { default: llvm_unreachable("Not a comparison operator."); case BO_LT: return BO_GT; case BO_GT: return BO_LT; case BO_LE: return BO_GE; case BO_GE: return BO_LE; case BO_EQ: case BO_NE: return Opc; } } static bool isLogicalOp(Opcode Opc) { return Opc == BO_LAnd || Opc==BO_LOr; } bool isLogicalOp() const { return isLogicalOp(getOpcode()); } static bool isAssignmentOp(Opcode Opc) { return Opc >= BO_Assign && Opc <= BO_OrAssign; } bool isAssignmentOp() const { return isAssignmentOp(getOpcode()); } static bool isCompoundAssignmentOp(Opcode Opc) { return Opc > BO_Assign && Opc <= BO_OrAssign; } bool isCompoundAssignmentOp() const { return isCompoundAssignmentOp(getOpcode()); } static Opcode getOpForCompoundAssignment(Opcode Opc) { assert(isCompoundAssignmentOp(Opc)); if (Opc >= BO_AndAssign) return Opcode(unsigned(Opc) - BO_AndAssign + BO_And); else return Opcode(unsigned(Opc) - BO_MulAssign + BO_Mul); } static bool isShiftAssignOp(Opcode Opc) { return Opc == BO_ShlAssign || Opc == BO_ShrAssign; } bool isShiftAssignOp() const { 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. static bool isNullPointerArithmeticExtension(ASTContext &Ctx, Opcode Opc, Expr *LHS, Expr *RHS); static bool classof(const Stmt *S) { return S->getStmtClass() >= firstBinaryOperatorConstant && S->getStmtClass() <= lastBinaryOperatorConstant; } // Iterators child_range children() { return child_range(&SubExprs[0], &SubExprs[0]+END_EXPR); } const_child_range children() const { return const_child_range(&SubExprs[0], &SubExprs[0] + END_EXPR); } // Set the FP contractability status of this operator. Only meaningful for // operations on floating point types. void setFPFeatures(FPOptions F) { BinaryOperatorBits.FPFeatures = F.getInt(); } FPOptions getFPFeatures() const { return FPOptions(BinaryOperatorBits.FPFeatures); } // Get the FP contractability status of this operator. Only meaningful for // operations on floating point types. bool isFPContractableWithinStatement() const { return getFPFeatures().allowFPContractWithinStatement(); } // Get the FENV_ACCESS status of this operator. Only meaningful for // operations on floating point types. bool isFEnvAccessOn() const { return getFPFeatures().allowFEnvAccess(); } protected: BinaryOperator(Expr *lhs, Expr *rhs, Opcode opc, QualType ResTy, ExprValueKind VK, ExprObjectKind OK, SourceLocation opLoc, FPOptions FPFeatures, bool dead2) : Expr(CompoundAssignOperatorClass, ResTy, VK, OK, lhs->isTypeDependent() || rhs->isTypeDependent(), lhs->isValueDependent() || rhs->isValueDependent(), (lhs->isInstantiationDependent() || rhs->isInstantiationDependent()), (lhs->containsUnexpandedParameterPack() || rhs->containsUnexpandedParameterPack())) { BinaryOperatorBits.Opc = opc; BinaryOperatorBits.FPFeatures = FPFeatures.getInt(); BinaryOperatorBits.OpLoc = opLoc; SubExprs[LHS] = lhs; SubExprs[RHS] = rhs; } BinaryOperator(StmtClass SC, EmptyShell Empty) : Expr(SC, Empty) { BinaryOperatorBits.Opc = BO_MulAssign; } }; /// CompoundAssignOperator - For compound assignments (e.g. +=), we keep /// track of the type the operation is performed in. Due to the semantics of /// these operators, the operands are promoted, the arithmetic performed, an /// implicit conversion back to the result type done, then the assignment takes /// place. This captures the intermediate type which the computation is done /// in. class CompoundAssignOperator : public BinaryOperator { QualType ComputationLHSType; QualType ComputationResultType; public: CompoundAssignOperator(Expr *lhs, Expr *rhs, Opcode opc, QualType ResType, ExprValueKind VK, ExprObjectKind OK, QualType CompLHSType, QualType CompResultType, SourceLocation OpLoc, FPOptions FPFeatures) : BinaryOperator(lhs, rhs, opc, ResType, VK, OK, OpLoc, FPFeatures, true), ComputationLHSType(CompLHSType), ComputationResultType(CompResultType) { assert(isCompoundAssignmentOp() && "Only should be used for compound assignments"); } /// Build an empty compound assignment operator expression. explicit CompoundAssignOperator(EmptyShell Empty) : BinaryOperator(CompoundAssignOperatorClass, Empty) { } // The two computation types are the type the LHS is converted // to for the computation and the type of the result; the two are // distinct in a few cases (specifically, int+=ptr and ptr-=ptr). QualType getComputationLHSType() const { return ComputationLHSType; } void setComputationLHSType(QualType T) { ComputationLHSType = T; } QualType getComputationResultType() const { return ComputationResultType; } void setComputationResultType(QualType T) { ComputationResultType = T; } static bool classof(const Stmt *S) { return S->getStmtClass() == CompoundAssignOperatorClass; } }; /// AbstractConditionalOperator - An abstract base class for /// ConditionalOperator and BinaryConditionalOperator. class AbstractConditionalOperator : public Expr { SourceLocation QuestionLoc, ColonLoc; friend class ASTStmtReader; protected: AbstractConditionalOperator(StmtClass SC, QualType T, ExprValueKind VK, ExprObjectKind OK, bool TD, bool VD, bool ID, bool ContainsUnexpandedParameterPack, SourceLocation qloc, SourceLocation cloc) : Expr(SC, T, VK, OK, TD, VD, ID, ContainsUnexpandedParameterPack), QuestionLoc(qloc), ColonLoc(cloc) {} AbstractConditionalOperator(StmtClass SC, EmptyShell Empty) : Expr(SC, Empty) { } public: // 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. 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. Expr *getFalseExpr() const; SourceLocation getQuestionLoc() const { return QuestionLoc; } SourceLocation getColonLoc() const { return ColonLoc; } static bool classof(const Stmt *T) { return T->getStmtClass() == ConditionalOperatorClass || T->getStmtClass() == BinaryConditionalOperatorClass; } }; /// ConditionalOperator - The ?: ternary operator. The GNU "missing /// middle" extension is a BinaryConditionalOperator. class ConditionalOperator : public AbstractConditionalOperator { enum { COND, LHS, RHS, END_EXPR }; Stmt* SubExprs[END_EXPR]; // Left/Middle/Right hand sides. friend class ASTStmtReader; public: ConditionalOperator(Expr *cond, SourceLocation QLoc, Expr *lhs, SourceLocation CLoc, Expr *rhs, QualType t, ExprValueKind VK, ExprObjectKind OK) : AbstractConditionalOperator( ConditionalOperatorClass, t, VK, OK, // The type of the conditional operator depends on the type // of the conditional to support the GCC vector conditional // extension. Additionally, [temp.dep.expr] does specify state that // this should be dependent on ALL sub expressions. (cond->isTypeDependent() || lhs->isTypeDependent() || rhs->isTypeDependent()), (cond->isValueDependent() || lhs->isValueDependent() || rhs->isValueDependent()), (cond->isInstantiationDependent() || lhs->isInstantiationDependent() || rhs->isInstantiationDependent()), (cond->containsUnexpandedParameterPack() || lhs->containsUnexpandedParameterPack() || rhs->containsUnexpandedParameterPack()), QLoc, CLoc) { SubExprs[COND] = cond; SubExprs[LHS] = lhs; SubExprs[RHS] = rhs; } /// Build an empty conditional operator. explicit ConditionalOperator(EmptyShell Empty) : AbstractConditionalOperator(ConditionalOperatorClass, Empty) { } // getCond - Return the expression representing the condition for // the ?: operator. Expr *getCond() const { return cast(SubExprs[COND]); } // getTrueExpr - Return the subexpression representing the value of // the expression if the condition evaluates to true. Expr *getTrueExpr() const { return cast(SubExprs[LHS]); } // 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(SubExprs[RHS]); } Expr *getLHS() const { return cast(SubExprs[LHS]); } Expr *getRHS() const { return cast(SubExprs[RHS]); } SourceLocation getBeginLoc() const LLVM_READONLY { return getCond()->getBeginLoc(); } SourceLocation getEndLoc() const LLVM_READONLY { return getRHS()->getEndLoc(); } static bool classof(const Stmt *T) { return T->getStmtClass() == ConditionalOperatorClass; } // Iterators child_range children() { return child_range(&SubExprs[0], &SubExprs[0]+END_EXPR); } const_child_range children() const { return const_child_range(&SubExprs[0], &SubExprs[0] + END_EXPR); } }; /// BinaryConditionalOperator - The GNU extension to the conditional /// operator which allows the middle operand to be omitted. /// /// This is a different expression kind on the assumption that almost /// every client ends up needing to know that these are different. class BinaryConditionalOperator : public AbstractConditionalOperator { enum { COMMON, COND, LHS, RHS, NUM_SUBEXPRS }; /// - the common condition/left-hand-side expression, which will be /// evaluated as the opaque value /// - the condition, expressed in terms of the opaque value /// - the left-hand-side, expressed in terms of the opaque value /// - the right-hand-side Stmt *SubExprs[NUM_SUBEXPRS]; OpaqueValueExpr *OpaqueValue; friend class ASTStmtReader; public: BinaryConditionalOperator(Expr *common, OpaqueValueExpr *opaqueValue, Expr *cond, Expr *lhs, Expr *rhs, SourceLocation qloc, SourceLocation cloc, QualType t, ExprValueKind VK, ExprObjectKind OK) : AbstractConditionalOperator(BinaryConditionalOperatorClass, t, VK, OK, (common->isTypeDependent() || rhs->isTypeDependent()), (common->isValueDependent() || rhs->isValueDependent()), (common->isInstantiationDependent() || rhs->isInstantiationDependent()), (common->containsUnexpandedParameterPack() || rhs->containsUnexpandedParameterPack()), qloc, cloc), OpaqueValue(opaqueValue) { SubExprs[COMMON] = common; SubExprs[COND] = cond; SubExprs[LHS] = lhs; SubExprs[RHS] = rhs; assert(OpaqueValue->getSourceExpr() == common && "Wrong opaque value"); } /// Build an empty conditional operator. explicit BinaryConditionalOperator(EmptyShell Empty) : AbstractConditionalOperator(BinaryConditionalOperatorClass, Empty) { } /// getCommon - Return the common expression, written to the /// left of the condition. The opaque value will be bound to the /// result of this expression. Expr *getCommon() const { return cast(SubExprs[COMMON]); } /// getOpaqueValue - Return the opaque value placeholder. OpaqueValueExpr *getOpaqueValue() const { return OpaqueValue; } /// getCond - Return the condition expression; this is defined /// in terms of the opaque value. Expr *getCond() const { return cast(SubExprs[COND]); } /// getTrueExpr - Return the subexpression which will be /// evaluated if the condition evaluates to true; this is defined /// in terms of the opaque value. Expr *getTrueExpr() const { return cast(SubExprs[LHS]); } /// getFalseExpr - Return the subexpression which will be /// evaluated if the condnition evaluates to false; this is /// defined in terms of the opaque value. Expr *getFalseExpr() const { return cast(SubExprs[RHS]); } SourceLocation getBeginLoc() const LLVM_READONLY { return getCommon()->getBeginLoc(); } SourceLocation getEndLoc() const LLVM_READONLY { return getFalseExpr()->getEndLoc(); } static bool classof(const Stmt *T) { return T->getStmtClass() == BinaryConditionalOperatorClass; } // Iterators child_range children() { return child_range(SubExprs, SubExprs + NUM_SUBEXPRS); } const_child_range children() const { return const_child_range(SubExprs, SubExprs + NUM_SUBEXPRS); } }; inline Expr *AbstractConditionalOperator::getCond() const { if (const ConditionalOperator *co = dyn_cast(this)) return co->getCond(); return cast(this)->getCond(); } inline Expr *AbstractConditionalOperator::getTrueExpr() const { if (const ConditionalOperator *co = dyn_cast(this)) return co->getTrueExpr(); return cast(this)->getTrueExpr(); } inline Expr *AbstractConditionalOperator::getFalseExpr() const { if (const ConditionalOperator *co = dyn_cast(this)) return co->getFalseExpr(); return cast(this)->getFalseExpr(); } /// AddrLabelExpr - The GNU address of label extension, representing &&label. class AddrLabelExpr : public Expr { SourceLocation AmpAmpLoc, LabelLoc; LabelDecl *Label; public: AddrLabelExpr(SourceLocation AALoc, SourceLocation LLoc, LabelDecl *L, QualType t) : Expr(AddrLabelExprClass, t, VK_RValue, OK_Ordinary, false, false, false, false), AmpAmpLoc(AALoc), LabelLoc(LLoc), Label(L) {} /// Build an empty address of a label expression. explicit AddrLabelExpr(EmptyShell Empty) : Expr(AddrLabelExprClass, Empty) { } SourceLocation getAmpAmpLoc() const { return AmpAmpLoc; } void setAmpAmpLoc(SourceLocation L) { AmpAmpLoc = L; } SourceLocation getLabelLoc() const { return LabelLoc; } void setLabelLoc(SourceLocation L) { LabelLoc = L; } SourceLocation getBeginLoc() const LLVM_READONLY { return AmpAmpLoc; } SourceLocation getEndLoc() const LLVM_READONLY { return LabelLoc; } LabelDecl *getLabel() const { return Label; } void setLabel(LabelDecl *L) { Label = L; } static bool classof(const Stmt *T) { return T->getStmtClass() == AddrLabelExprClass; } // Iterators child_range children() { return child_range(child_iterator(), child_iterator()); } const_child_range children() const { return const_child_range(const_child_iterator(), const_child_iterator()); } }; /// StmtExpr - This is the GNU Statement Expression extension: ({int X=4; X;}). /// The StmtExpr contains a single CompoundStmt node, which it evaluates and /// takes the value of the last subexpression. /// /// A StmtExpr is always an r-value; values "returned" out of a /// StmtExpr will be copied. class StmtExpr : public Expr { Stmt *SubStmt; SourceLocation LParenLoc, RParenLoc; public: - StmtExpr(CompoundStmt *substmt, QualType T, - SourceLocation lp, SourceLocation rp, bool InDependentContext) : - // Note: we treat a statement-expression in a dependent context as always - // being value- and instantiation-dependent. This matches the behavior of - // lambda-expressions and GCC. - Expr(StmtExprClass, T, VK_RValue, OK_Ordinary, - T->isDependentType(), InDependentContext, InDependentContext, false), - SubStmt(substmt), LParenLoc(lp), RParenLoc(rp) {} + StmtExpr(CompoundStmt *SubStmt, QualType T, SourceLocation LParenLoc, + SourceLocation RParenLoc, unsigned TemplateDepth) + : // We treat a statement-expression in a dependent context as + // always being value- and instantiation-dependent. This matches the + // behavior of lambda-expressions and GCC. + Expr(StmtExprClass, T, VK_RValue, OK_Ordinary, T->isDependentType(), + TemplateDepth != 0, TemplateDepth != 0, false), + SubStmt(SubStmt), LParenLoc(LParenLoc), RParenLoc(RParenLoc) { + // FIXME: A templated statement expression should have an associated + // DeclContext so that nested declarations always have a dependent context. + StmtExprBits.TemplateDepth = TemplateDepth; + } /// Build an empty statement expression. explicit StmtExpr(EmptyShell Empty) : Expr(StmtExprClass, Empty) { } CompoundStmt *getSubStmt() { return cast(SubStmt); } const CompoundStmt *getSubStmt() const { return cast(SubStmt); } void setSubStmt(CompoundStmt *S) { SubStmt = S; } SourceLocation getBeginLoc() const LLVM_READONLY { return LParenLoc; } SourceLocation getEndLoc() const LLVM_READONLY { return RParenLoc; } SourceLocation getLParenLoc() const { return LParenLoc; } void setLParenLoc(SourceLocation L) { LParenLoc = L; } SourceLocation getRParenLoc() const { return RParenLoc; } void setRParenLoc(SourceLocation L) { RParenLoc = L; } + + unsigned getTemplateDepth() const { return StmtExprBits.TemplateDepth; } static bool classof(const Stmt *T) { return T->getStmtClass() == StmtExprClass; } // Iterators child_range children() { return child_range(&SubStmt, &SubStmt+1); } const_child_range children() const { return const_child_range(&SubStmt, &SubStmt + 1); } }; /// ShuffleVectorExpr - clang-specific builtin-in function /// __builtin_shufflevector. /// This AST node represents a operator that does a constant /// shuffle, similar to LLVM's shufflevector instruction. It takes /// two vectors and a variable number of constant indices, /// and returns the appropriately shuffled vector. class ShuffleVectorExpr : public Expr { SourceLocation BuiltinLoc, RParenLoc; // SubExprs - the list of values passed to the __builtin_shufflevector // function. The first two are vectors, and the rest are constant // indices. The number of values in this list is always // 2+the number of indices in the vector type. Stmt **SubExprs; unsigned NumExprs; public: ShuffleVectorExpr(const ASTContext &C, ArrayRef args, QualType Type, SourceLocation BLoc, SourceLocation RP); /// Build an empty vector-shuffle expression. explicit ShuffleVectorExpr(EmptyShell Empty) : Expr(ShuffleVectorExprClass, Empty), SubExprs(nullptr) { } SourceLocation getBuiltinLoc() const { return BuiltinLoc; } void setBuiltinLoc(SourceLocation L) { BuiltinLoc = L; } SourceLocation getRParenLoc() const { return RParenLoc; } void setRParenLoc(SourceLocation L) { RParenLoc = L; } SourceLocation getBeginLoc() const LLVM_READONLY { return BuiltinLoc; } SourceLocation getEndLoc() const LLVM_READONLY { return RParenLoc; } static bool classof(const Stmt *T) { return T->getStmtClass() == ShuffleVectorExprClass; } /// getNumSubExprs - Return the size of the SubExprs array. This includes the /// constant expression, the actual arguments passed in, and the function /// pointers. unsigned getNumSubExprs() const { return NumExprs; } /// Retrieve the array of expressions. Expr **getSubExprs() { return reinterpret_cast(SubExprs); } /// getExpr - Return the Expr at the specified index. Expr *getExpr(unsigned Index) { assert((Index < NumExprs) && "Arg access out of range!"); return cast(SubExprs[Index]); } const Expr *getExpr(unsigned Index) const { assert((Index < NumExprs) && "Arg access out of range!"); return cast(SubExprs[Index]); } void setExprs(const ASTContext &C, ArrayRef Exprs); llvm::APSInt getShuffleMaskIdx(const ASTContext &Ctx, unsigned N) const { assert((N < NumExprs - 2) && "Shuffle idx out of range!"); return getExpr(N+2)->EvaluateKnownConstInt(Ctx); } // Iterators child_range children() { return child_range(&SubExprs[0], &SubExprs[0]+NumExprs); } const_child_range children() const { return const_child_range(&SubExprs[0], &SubExprs[0] + NumExprs); } }; /// ConvertVectorExpr - Clang builtin function __builtin_convertvector /// This AST node provides support for converting a vector type to another /// vector type of the same arity. class ConvertVectorExpr : public Expr { private: Stmt *SrcExpr; TypeSourceInfo *TInfo; SourceLocation BuiltinLoc, RParenLoc; friend class ASTReader; friend class ASTStmtReader; explicit ConvertVectorExpr(EmptyShell Empty) : Expr(ConvertVectorExprClass, Empty) {} public: ConvertVectorExpr(Expr* SrcExpr, TypeSourceInfo *TI, QualType DstType, ExprValueKind VK, ExprObjectKind OK, SourceLocation BuiltinLoc, SourceLocation RParenLoc) : Expr(ConvertVectorExprClass, DstType, VK, OK, DstType->isDependentType(), DstType->isDependentType() || SrcExpr->isValueDependent(), (DstType->isInstantiationDependentType() || SrcExpr->isInstantiationDependent()), (DstType->containsUnexpandedParameterPack() || SrcExpr->containsUnexpandedParameterPack())), SrcExpr(SrcExpr), TInfo(TI), BuiltinLoc(BuiltinLoc), RParenLoc(RParenLoc) {} /// getSrcExpr - Return the Expr to be converted. Expr *getSrcExpr() const { return cast(SrcExpr); } /// getTypeSourceInfo - Return the destination type. TypeSourceInfo *getTypeSourceInfo() const { return TInfo; } void setTypeSourceInfo(TypeSourceInfo *ti) { TInfo = ti; } /// getBuiltinLoc - Return the location of the __builtin_convertvector token. SourceLocation getBuiltinLoc() const { return BuiltinLoc; } /// getRParenLoc - Return the location of final right parenthesis. SourceLocation getRParenLoc() const { return RParenLoc; } SourceLocation getBeginLoc() const LLVM_READONLY { return BuiltinLoc; } SourceLocation getEndLoc() const LLVM_READONLY { return RParenLoc; } static bool classof(const Stmt *T) { return T->getStmtClass() == ConvertVectorExprClass; } // Iterators child_range children() { return child_range(&SrcExpr, &SrcExpr+1); } const_child_range children() const { return const_child_range(&SrcExpr, &SrcExpr + 1); } }; /// ChooseExpr - GNU builtin-in function __builtin_choose_expr. /// This AST node is similar to the conditional operator (?:) in C, with /// the following exceptions: /// - the test expression must be a integer constant expression. /// - the expression returned acts like the chosen subexpression in every /// visible way: the type is the same as that of the chosen subexpression, /// and all predicates (whether it's an l-value, whether it's an integer /// constant expression, etc.) return the same result as for the chosen /// sub-expression. class ChooseExpr : public Expr { enum { COND, LHS, RHS, END_EXPR }; Stmt* SubExprs[END_EXPR]; // Left/Middle/Right hand sides. SourceLocation BuiltinLoc, RParenLoc; bool CondIsTrue; public: ChooseExpr(SourceLocation BLoc, Expr *cond, Expr *lhs, Expr *rhs, QualType t, ExprValueKind VK, ExprObjectKind OK, SourceLocation RP, bool condIsTrue, bool TypeDependent, bool ValueDependent) : Expr(ChooseExprClass, t, VK, OK, TypeDependent, ValueDependent, (cond->isInstantiationDependent() || lhs->isInstantiationDependent() || rhs->isInstantiationDependent()), (cond->containsUnexpandedParameterPack() || lhs->containsUnexpandedParameterPack() || rhs->containsUnexpandedParameterPack())), BuiltinLoc(BLoc), RParenLoc(RP), CondIsTrue(condIsTrue) { SubExprs[COND] = cond; SubExprs[LHS] = lhs; SubExprs[RHS] = rhs; } /// Build an empty __builtin_choose_expr. explicit ChooseExpr(EmptyShell Empty) : Expr(ChooseExprClass, Empty) { } /// isConditionTrue - Return whether the condition is true (i.e. not /// equal to zero). bool isConditionTrue() const { assert(!isConditionDependent() && "Dependent condition isn't true or false"); return CondIsTrue; } void setIsConditionTrue(bool isTrue) { CondIsTrue = isTrue; } bool isConditionDependent() const { return getCond()->isTypeDependent() || getCond()->isValueDependent(); } /// getChosenSubExpr - Return the subexpression chosen according to the /// condition. Expr *getChosenSubExpr() const { return isConditionTrue() ? getLHS() : getRHS(); } Expr *getCond() const { return cast(SubExprs[COND]); } void setCond(Expr *E) { SubExprs[COND] = E; } Expr *getLHS() const { return cast(SubExprs[LHS]); } void setLHS(Expr *E) { SubExprs[LHS] = E; } Expr *getRHS() const { return cast(SubExprs[RHS]); } void setRHS(Expr *E) { SubExprs[RHS] = E; } SourceLocation getBuiltinLoc() const { return BuiltinLoc; } void setBuiltinLoc(SourceLocation L) { BuiltinLoc = L; } SourceLocation getRParenLoc() const { return RParenLoc; } void setRParenLoc(SourceLocation L) { RParenLoc = L; } SourceLocation getBeginLoc() const LLVM_READONLY { return BuiltinLoc; } SourceLocation getEndLoc() const LLVM_READONLY { return RParenLoc; } static bool classof(const Stmt *T) { return T->getStmtClass() == ChooseExprClass; } // Iterators child_range children() { return child_range(&SubExprs[0], &SubExprs[0]+END_EXPR); } const_child_range children() const { return const_child_range(&SubExprs[0], &SubExprs[0] + END_EXPR); } }; /// GNUNullExpr - Implements the GNU __null extension, which is a name /// for a null pointer constant that has integral type (e.g., int or /// long) and is the same size and alignment as a pointer. The __null /// extension is typically only used by system headers, which define /// NULL as __null in C++ rather than using 0 (which is an integer /// that may not match the size of a pointer). class GNUNullExpr : public Expr { /// TokenLoc - The location of the __null keyword. SourceLocation TokenLoc; public: GNUNullExpr(QualType Ty, SourceLocation Loc) : Expr(GNUNullExprClass, Ty, VK_RValue, OK_Ordinary, false, false, false, false), TokenLoc(Loc) { } /// Build an empty GNU __null expression. explicit GNUNullExpr(EmptyShell Empty) : Expr(GNUNullExprClass, Empty) { } /// getTokenLocation - The location of the __null token. SourceLocation getTokenLocation() const { return TokenLoc; } void setTokenLocation(SourceLocation L) { TokenLoc = L; } SourceLocation getBeginLoc() const LLVM_READONLY { return TokenLoc; } SourceLocation getEndLoc() const LLVM_READONLY { return TokenLoc; } static bool classof(const Stmt *T) { return T->getStmtClass() == GNUNullExprClass; } // Iterators child_range children() { return child_range(child_iterator(), child_iterator()); } const_child_range children() const { return const_child_range(const_child_iterator(), const_child_iterator()); } }; /// Represents a call to the builtin function \c __builtin_va_arg. class VAArgExpr : public Expr { Stmt *Val; llvm::PointerIntPair TInfo; SourceLocation BuiltinLoc, RParenLoc; public: VAArgExpr(SourceLocation BLoc, Expr *e, TypeSourceInfo *TInfo, SourceLocation RPLoc, QualType t, bool IsMS) : Expr(VAArgExprClass, t, VK_RValue, OK_Ordinary, t->isDependentType(), false, (TInfo->getType()->isInstantiationDependentType() || e->isInstantiationDependent()), (TInfo->getType()->containsUnexpandedParameterPack() || e->containsUnexpandedParameterPack())), Val(e), TInfo(TInfo, IsMS), BuiltinLoc(BLoc), RParenLoc(RPLoc) {} /// Create an empty __builtin_va_arg expression. explicit VAArgExpr(EmptyShell Empty) : Expr(VAArgExprClass, Empty), Val(nullptr), TInfo(nullptr, false) {} const Expr *getSubExpr() const { return cast(Val); } Expr *getSubExpr() { return cast(Val); } void setSubExpr(Expr *E) { Val = E; } /// Returns whether this is really a Win64 ABI va_arg expression. bool isMicrosoftABI() const { return TInfo.getInt(); } void setIsMicrosoftABI(bool IsMS) { TInfo.setInt(IsMS); } TypeSourceInfo *getWrittenTypeInfo() const { return TInfo.getPointer(); } void setWrittenTypeInfo(TypeSourceInfo *TI) { TInfo.setPointer(TI); } SourceLocation getBuiltinLoc() const { return BuiltinLoc; } void setBuiltinLoc(SourceLocation L) { BuiltinLoc = L; } SourceLocation getRParenLoc() const { return RParenLoc; } void setRParenLoc(SourceLocation L) { RParenLoc = L; } SourceLocation getBeginLoc() const LLVM_READONLY { return BuiltinLoc; } SourceLocation getEndLoc() const LLVM_READONLY { return RParenLoc; } static bool classof(const Stmt *T) { return T->getStmtClass() == VAArgExprClass; } // Iterators child_range children() { return child_range(&Val, &Val+1); } const_child_range children() const { return const_child_range(&Val, &Val + 1); } }; /// Represents a function call to one of __builtin_LINE(), __builtin_COLUMN(), /// __builtin_FUNCTION(), or __builtin_FILE(). 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, SourceLocation RParenLoc, DeclContext *Context); /// Build an empty call expression. explicit SourceLocExpr(EmptyShell Empty) : Expr(SourceLocExprClass, Empty) {} /// Return the result of evaluating this SourceLocExpr in the specified /// (and possibly null) default argument or initialization context. APValue EvaluateInContext(const ASTContext &Ctx, const Expr *DefaultExpr) const; /// Return a string representing the name of the specific builtin function. StringRef getBuiltinStr() const; IdentKind getIdentKind() const { return static_cast(SourceLocExprBits.Kind); } bool isStringType() const { switch (getIdentKind()) { case File: case Function: return true; case Line: case Column: return false; } 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. const DeclContext *getParentContext() const { return ParentContext; } DeclContext *getParentContext() { return ParentContext; } SourceLocation getLocation() const { return BuiltinLoc; } SourceLocation getBeginLoc() const { return BuiltinLoc; } SourceLocation getEndLoc() const { return RParenLoc; } child_range children() { return child_range(child_iterator(), child_iterator()); } const_child_range children() const { return const_child_range(child_iterator(), child_iterator()); } static bool classof(const Stmt *T) { return T->getStmtClass() == SourceLocExprClass; } private: friend class ASTStmtReader; }; /// Describes an C or C++ initializer list. /// /// InitListExpr describes an initializer list, which can be used to /// initialize objects of different types, including /// struct/class/union types, arrays, and vectors. For example: /// /// @code /// struct foo x = { 1, { 2, 3 } }; /// @endcode /// /// Prior to semantic analysis, an initializer list will represent the /// initializer list as written by the user, but will have the /// placeholder type "void". This initializer list is called the /// syntactic form of the initializer, and may contain C99 designated /// initializers (represented as DesignatedInitExprs), initializations /// of subobject members without explicit braces, and so on. Clients /// interested in the original syntax of the initializer list should /// use the syntactic form of the initializer list. /// /// After semantic analysis, the initializer list will represent the /// semantic form of the initializer, where the initializations of all /// subobjects are made explicit with nested InitListExpr nodes and /// C99 designators have been eliminated by placing the designated /// initializations into the subobject they initialize. Additionally, /// any "holes" in the initialization, where no initializer has been /// specified for a particular subobject, will be replaced with /// implicitly-generated ImplicitValueInitExpr expressions that /// value-initialize the subobjects. Note, however, that the /// initializer lists may still have fewer initializers than there are /// elements to initialize within the object. /// /// After semantic analysis has completed, given an initializer list, /// method isSemanticForm() returns true if and only if this is the /// semantic form of the initializer list (note: the same AST node /// may at the same time be the syntactic form). /// Given the semantic form of the initializer list, one can retrieve /// the syntactic form of that initializer list (when different) /// using method getSyntacticForm(); the method returns null if applied /// to a initializer list which is already in syntactic form. /// Similarly, given the syntactic form (i.e., an initializer list such /// that isSemanticForm() returns false), one can retrieve the semantic /// form using method getSemanticForm(). /// Since many initializer lists have the same syntactic and semantic forms, /// getSyntacticForm() may return NULL, indicating that the current /// semantic initializer list also serves as its syntactic form. class InitListExpr : public Expr { // FIXME: Eliminate this vector in favor of ASTContext allocation typedef ASTVector InitExprsTy; InitExprsTy InitExprs; SourceLocation LBraceLoc, RBraceLoc; /// The alternative form of the initializer list (if it exists). /// The int part of the pair stores whether this initializer list is /// in semantic form. If not null, the pointer points to: /// - the syntactic form, if this is in semantic form; /// - the semantic form, if this is in syntactic form. llvm::PointerIntPair AltForm; /// Either: /// If this initializer list initializes an array with more elements than /// there are initializers in the list, specifies an expression to be used /// for value initialization of the rest of the elements. /// Or /// If this initializer list initializes a union, specifies which /// field within the union will be initialized. llvm::PointerUnion ArrayFillerOrUnionFieldInit; public: InitListExpr(const ASTContext &C, SourceLocation lbraceloc, ArrayRef initExprs, SourceLocation rbraceloc); /// Build an empty initializer list. explicit InitListExpr(EmptyShell Empty) : Expr(InitListExprClass, Empty), AltForm(nullptr, true) { } unsigned getNumInits() const { return InitExprs.size(); } /// Retrieve the set of initializers. Expr **getInits() { return reinterpret_cast(InitExprs.data()); } /// Retrieve the set of initializers. Expr * const *getInits() const { return reinterpret_cast(InitExprs.data()); } ArrayRef inits() { return llvm::makeArrayRef(getInits(), getNumInits()); } ArrayRef inits() const { return llvm::makeArrayRef(getInits(), getNumInits()); } const Expr *getInit(unsigned Init) const { assert(Init < getNumInits() && "Initializer access out of range!"); return cast_or_null(InitExprs[Init]); } Expr *getInit(unsigned Init) { assert(Init < getNumInits() && "Initializer access out of range!"); return cast_or_null(InitExprs[Init]); } void setInit(unsigned Init, Expr *expr) { assert(Init < getNumInits() && "Initializer access out of range!"); InitExprs[Init] = expr; if (expr) { ExprBits.TypeDependent |= expr->isTypeDependent(); ExprBits.ValueDependent |= expr->isValueDependent(); ExprBits.InstantiationDependent |= expr->isInstantiationDependent(); ExprBits.ContainsUnexpandedParameterPack |= expr->containsUnexpandedParameterPack(); } } /// Reserve space for some number of initializers. void reserveInits(const ASTContext &C, unsigned NumInits); /// Specify the number of initializers /// /// If there are more than @p NumInits initializers, the remaining /// initializers will be destroyed. If there are fewer than @p /// NumInits initializers, NULL expressions will be added for the /// unknown initializers. void resizeInits(const ASTContext &Context, unsigned NumInits); /// Updates the initializer at index @p Init with the new /// expression @p expr, and returns the old expression at that /// location. /// /// When @p Init is out of range for this initializer list, the /// initializer list will be extended with NULL expressions to /// accommodate the new entry. Expr *updateInit(const ASTContext &C, unsigned Init, Expr *expr); /// If this initializer list initializes an array with more elements /// than there are initializers in the list, specifies an expression to be /// used for value initialization of the rest of the elements. Expr *getArrayFiller() { return ArrayFillerOrUnionFieldInit.dyn_cast(); } const Expr *getArrayFiller() const { return const_cast(this)->getArrayFiller(); } void setArrayFiller(Expr *filler); /// Return true if this is an array initializer and its array "filler" /// has been set. bool hasArrayFiller() const { return getArrayFiller(); } /// If this initializes a union, specifies which field in the /// union to initialize. /// /// Typically, this field is the first named field within the /// union. However, a designated initializer can specify the /// initialization of a different field within the union. FieldDecl *getInitializedFieldInUnion() { return ArrayFillerOrUnionFieldInit.dyn_cast(); } const FieldDecl *getInitializedFieldInUnion() const { return const_cast(this)->getInitializedFieldInUnion(); } void setInitializedFieldInUnion(FieldDecl *FD) { assert((FD == nullptr || getInitializedFieldInUnion() == nullptr || getInitializedFieldInUnion() == FD) && "Only one field of a union may be initialized at a time!"); ArrayFillerOrUnionFieldInit = FD; } // Explicit InitListExpr's originate from source code (and have valid source // locations). Implicit InitListExpr's are created by the semantic analyzer. // FIXME: This is wrong; InitListExprs created by semantic analysis have // valid source locations too! bool isExplicit() const { return LBraceLoc.isValid() && RBraceLoc.isValid(); } // 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 /// purely syntactic, and whose semantics are that of the sole contained /// initializer)? bool isTransparent() const; /// Is this the zero initializer {0} in a language which considers it /// idiomatic? bool isIdiomaticZeroInitializer(const LangOptions &LangOpts) const; SourceLocation getLBraceLoc() const { return LBraceLoc; } void setLBraceLoc(SourceLocation Loc) { LBraceLoc = Loc; } SourceLocation getRBraceLoc() const { return RBraceLoc; } void setRBraceLoc(SourceLocation Loc) { RBraceLoc = Loc; } bool isSemanticForm() const { return AltForm.getInt(); } InitListExpr *getSemanticForm() const { return isSemanticForm() ? nullptr : AltForm.getPointer(); } bool isSyntacticForm() const { return !AltForm.getInt() || !AltForm.getPointer(); } InitListExpr *getSyntacticForm() const { return isSemanticForm() ? AltForm.getPointer() : nullptr; } void setSyntacticForm(InitListExpr *Init) { AltForm.setPointer(Init); AltForm.setInt(true); Init->AltForm.setPointer(this); Init->AltForm.setInt(false); } bool hadArrayRangeDesignator() const { return InitListExprBits.HadArrayRangeDesignator != 0; } void sawArrayRangeDesignator(bool ARD = true) { InitListExprBits.HadArrayRangeDesignator = ARD; } SourceLocation getBeginLoc() const LLVM_READONLY; SourceLocation getEndLoc() const LLVM_READONLY; static bool classof(const Stmt *T) { return T->getStmtClass() == InitListExprClass; } // Iterators child_range children() { const_child_range CCR = const_cast(this)->children(); return child_range(cast_away_const(CCR.begin()), cast_away_const(CCR.end())); } const_child_range children() const { // FIXME: This does not include the array filler expression. if (InitExprs.empty()) return const_child_range(const_child_iterator(), const_child_iterator()); return const_child_range(&InitExprs[0], &InitExprs[0] + InitExprs.size()); } typedef InitExprsTy::iterator iterator; typedef InitExprsTy::const_iterator const_iterator; typedef InitExprsTy::reverse_iterator reverse_iterator; typedef InitExprsTy::const_reverse_iterator const_reverse_iterator; iterator begin() { return InitExprs.begin(); } const_iterator begin() const { return InitExprs.begin(); } iterator end() { return InitExprs.end(); } const_iterator end() const { return InitExprs.end(); } reverse_iterator rbegin() { return InitExprs.rbegin(); } const_reverse_iterator rbegin() const { return InitExprs.rbegin(); } reverse_iterator rend() { return InitExprs.rend(); } const_reverse_iterator rend() const { return InitExprs.rend(); } friend class ASTStmtReader; friend class ASTStmtWriter; }; /// Represents a C99 designated initializer expression. /// /// A designated initializer expression (C99 6.7.8) contains one or /// more designators (which can be field designators, array /// designators, or GNU array-range designators) followed by an /// expression that initializes the field or element(s) that the /// designators refer to. For example, given: /// /// @code /// struct point { /// double x; /// double y; /// }; /// struct point ptarray[10] = { [2].y = 1.0, [2].x = 2.0, [0].x = 1.0 }; /// @endcode /// /// The InitListExpr contains three DesignatedInitExprs, the first of /// which covers @c [2].y=1.0. This DesignatedInitExpr will have two /// designators, one array designator for @c [2] followed by one field /// designator for @c .y. The initialization expression will be 1.0. class DesignatedInitExpr final : public Expr, private llvm::TrailingObjects { public: /// Forward declaration of the Designator class. class Designator; private: /// The location of the '=' or ':' prior to the actual initializer /// expression. SourceLocation EqualOrColonLoc; /// Whether this designated initializer used the GNU deprecated /// syntax rather than the C99 '=' syntax. unsigned GNUSyntax : 1; /// The number of designators in this initializer expression. unsigned NumDesignators : 15; /// The number of subexpressions of this initializer expression, /// which contains both the initializer and any additional /// expressions used by array and array-range designators. unsigned NumSubExprs : 16; /// The designators in this designated initialization /// expression. Designator *Designators; DesignatedInitExpr(const ASTContext &C, QualType Ty, llvm::ArrayRef Designators, SourceLocation EqualOrColonLoc, bool GNUSyntax, ArrayRef IndexExprs, Expr *Init); explicit DesignatedInitExpr(unsigned NumSubExprs) : Expr(DesignatedInitExprClass, EmptyShell()), 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. unsigned DotLoc; /// The location of the field name in the designated initializer. unsigned 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. unsigned LBracketLoc; /// The location of the ellipsis separating the start and end /// indices. Only valid for GNU array-range designators. unsigned EllipsisLoc; /// The location of the ']' terminating the array range designator. unsigned RBracketLoc; }; /// Represents a single C99 designator. /// /// @todo This class is infuriatingly similar to clang::Designator, /// but minor differences (storing indices vs. storing pointers) /// keep us from reusing it. Try harder, later, to rectify these /// differences. class Designator { /// The kind of designator this describes. enum { FieldDesignator, ArrayDesignator, ArrayRangeDesignator } Kind; union { /// A field designator, e.g., ".x". struct FieldDesignator Field; /// An array or GNU array-range designator, e.g., "[9]" or "[10..15]". struct ArrayOrRangeDesignator ArrayOrRange; }; friend class DesignatedInitExpr; public: Designator() {} /// Initializes a field designator. Designator(const IdentifierInfo *FieldName, SourceLocation DotLoc, SourceLocation FieldLoc) : Kind(FieldDesignator) { Field.NameOrField = reinterpret_cast(FieldName) | 0x01; Field.DotLoc = DotLoc.getRawEncoding(); Field.FieldLoc = FieldLoc.getRawEncoding(); } /// Initializes an array designator. Designator(unsigned Index, SourceLocation LBracketLoc, SourceLocation RBracketLoc) : Kind(ArrayDesignator) { ArrayOrRange.Index = Index; ArrayOrRange.LBracketLoc = LBracketLoc.getRawEncoding(); ArrayOrRange.EllipsisLoc = SourceLocation().getRawEncoding(); ArrayOrRange.RBracketLoc = RBracketLoc.getRawEncoding(); } /// Initializes a GNU array-range designator. Designator(unsigned Index, SourceLocation LBracketLoc, SourceLocation EllipsisLoc, SourceLocation RBracketLoc) : Kind(ArrayRangeDesignator) { ArrayOrRange.Index = Index; ArrayOrRange.LBracketLoc = LBracketLoc.getRawEncoding(); ArrayOrRange.EllipsisLoc = EllipsisLoc.getRawEncoding(); ArrayOrRange.RBracketLoc = RBracketLoc.getRawEncoding(); } bool isFieldDesignator() const { return Kind == FieldDesignator; } bool isArrayDesignator() const { return Kind == ArrayDesignator; } bool isArrayRangeDesignator() const { return Kind == ArrayRangeDesignator; } IdentifierInfo *getFieldName() const; FieldDecl *getField() const { assert(Kind == FieldDesignator && "Only valid on a field designator"); if (Field.NameOrField & 0x01) return nullptr; else return reinterpret_cast(Field.NameOrField); } void setField(FieldDecl *FD) { assert(Kind == FieldDesignator && "Only valid on a field designator"); Field.NameOrField = reinterpret_cast(FD); } SourceLocation getDotLoc() const { assert(Kind == FieldDesignator && "Only valid on a field designator"); return SourceLocation::getFromRawEncoding(Field.DotLoc); } SourceLocation getFieldLoc() const { assert(Kind == FieldDesignator && "Only valid on a field designator"); return SourceLocation::getFromRawEncoding(Field.FieldLoc); } SourceLocation getLBracketLoc() const { assert((Kind == ArrayDesignator || Kind == ArrayRangeDesignator) && "Only valid on an array or array-range designator"); return SourceLocation::getFromRawEncoding(ArrayOrRange.LBracketLoc); } SourceLocation getRBracketLoc() const { assert((Kind == ArrayDesignator || Kind == ArrayRangeDesignator) && "Only valid on an array or array-range designator"); return SourceLocation::getFromRawEncoding(ArrayOrRange.RBracketLoc); } SourceLocation getEllipsisLoc() const { assert(Kind == ArrayRangeDesignator && "Only valid on an array-range designator"); return SourceLocation::getFromRawEncoding(ArrayOrRange.EllipsisLoc); } unsigned getFirstExprIndex() const { assert((Kind == ArrayDesignator || Kind == ArrayRangeDesignator) && "Only valid on an array or array-range designator"); return ArrayOrRange.Index; } SourceLocation getBeginLoc() const LLVM_READONLY { if (Kind == FieldDesignator) return getDotLoc().isInvalid()? getFieldLoc() : getDotLoc(); else return getLBracketLoc(); } SourceLocation getEndLoc() const LLVM_READONLY { return Kind == FieldDesignator ? getFieldLoc() : getRBracketLoc(); } SourceRange getSourceRange() const LLVM_READONLY { return SourceRange(getBeginLoc(), getEndLoc()); } }; static DesignatedInitExpr *Create(const ASTContext &C, llvm::ArrayRef Designators, ArrayRef IndexExprs, SourceLocation EqualOrColonLoc, bool GNUSyntax, Expr *Init); static DesignatedInitExpr *CreateEmpty(const ASTContext &C, unsigned NumIndexExprs); /// Returns the number of designators in this initializer. unsigned size() const { return NumDesignators; } // Iterator access to the designators. llvm::MutableArrayRef designators() { return {Designators, NumDesignators}; } llvm::ArrayRef designators() const { return {Designators, NumDesignators}; } Designator *getDesignator(unsigned Idx) { return &designators()[Idx]; } const Designator *getDesignator(unsigned Idx) const { return &designators()[Idx]; } void setDesignators(const ASTContext &C, const Designator *Desigs, unsigned NumDesigs); Expr *getArrayIndex(const Designator &D) const; Expr *getArrayRangeStart(const Designator &D) const; Expr *getArrayRangeEnd(const Designator &D) const; /// Retrieve the location of the '=' that precedes the /// initializer value itself, if present. SourceLocation getEqualOrColonLoc() const { return EqualOrColonLoc; } void setEqualOrColonLoc(SourceLocation L) { EqualOrColonLoc = L; } /// Whether this designated initializer should result in direct-initialization /// of the designated subobject (eg, '{.foo{1, 2, 3}}'). bool isDirectInit() const { return EqualOrColonLoc.isInvalid(); } /// Determines whether this designated initializer used the /// deprecated GNU syntax for designated initializers. bool usesGNUSyntax() const { return GNUSyntax; } void setGNUSyntax(bool GNU) { GNUSyntax = GNU; } /// Retrieve the initializer value. Expr *getInit() const { return cast(*const_cast(this)->child_begin()); } void setInit(Expr *init) { *child_begin() = init; } /// Retrieve the total number of subexpressions in this /// designated initializer expression, including the actual /// initialized value and any expressions that occur within array /// and array-range designators. unsigned getNumSubExprs() const { return NumSubExprs; } Expr *getSubExpr(unsigned Idx) const { assert(Idx < NumSubExprs && "Subscript out of range"); return cast(getTrailingObjects()[Idx]); } void setSubExpr(unsigned Idx, Expr *E) { assert(Idx < NumSubExprs && "Subscript out of range"); getTrailingObjects()[Idx] = E; } /// Replaces the designator at index @p Idx with the series /// of designators in [First, Last). void ExpandDesignator(const ASTContext &C, unsigned Idx, const Designator *First, const Designator *Last); SourceRange getDesignatorsSourceRange() const; SourceLocation getBeginLoc() const LLVM_READONLY; SourceLocation getEndLoc() const LLVM_READONLY; static bool classof(const Stmt *T) { return T->getStmtClass() == DesignatedInitExprClass; } // Iterators child_range children() { Stmt **begin = getTrailingObjects(); return child_range(begin, begin + NumSubExprs); } const_child_range children() const { Stmt * const *begin = getTrailingObjects(); return const_child_range(begin, begin + NumSubExprs); } friend TrailingObjects; }; /// Represents a place-holder for an object not to be initialized by /// anything. /// /// This only makes sense when it appears as part of an updater of a /// DesignatedInitUpdateExpr (see below). The base expression of a DIUE /// initializes a big object, and the NoInitExpr's mark the spots within the /// big object not to be overwritten by the updater. /// /// \see DesignatedInitUpdateExpr class NoInitExpr : public Expr { public: explicit NoInitExpr(QualType ty) : Expr(NoInitExprClass, ty, VK_RValue, OK_Ordinary, false, false, ty->isInstantiationDependentType(), false) { } explicit NoInitExpr(EmptyShell Empty) : Expr(NoInitExprClass, Empty) { } static bool classof(const Stmt *T) { return T->getStmtClass() == NoInitExprClass; } SourceLocation getBeginLoc() const LLVM_READONLY { return SourceLocation(); } SourceLocation getEndLoc() const LLVM_READONLY { return SourceLocation(); } // Iterators child_range children() { return child_range(child_iterator(), child_iterator()); } const_child_range children() const { return const_child_range(const_child_iterator(), const_child_iterator()); } }; // In cases like: // struct Q { int a, b, c; }; // Q *getQ(); // void foo() { // struct A { Q q; } a = { *getQ(), .q.b = 3 }; // } // // We will have an InitListExpr for a, with type A, and then a // DesignatedInitUpdateExpr for "a.q" with type Q. The "base" for this DIUE // is the call expression *getQ(); the "updater" for the DIUE is ".q.b = 3" // class DesignatedInitUpdateExpr : public Expr { // BaseAndUpdaterExprs[0] is the base expression; // BaseAndUpdaterExprs[1] is an InitListExpr overwriting part of the base. Stmt *BaseAndUpdaterExprs[2]; public: DesignatedInitUpdateExpr(const ASTContext &C, SourceLocation lBraceLoc, Expr *baseExprs, SourceLocation rBraceLoc); explicit DesignatedInitUpdateExpr(EmptyShell Empty) : Expr(DesignatedInitUpdateExprClass, Empty) { } SourceLocation getBeginLoc() const LLVM_READONLY; SourceLocation getEndLoc() const LLVM_READONLY; static bool classof(const Stmt *T) { return T->getStmtClass() == DesignatedInitUpdateExprClass; } Expr *getBase() const { return cast(BaseAndUpdaterExprs[0]); } void setBase(Expr *Base) { BaseAndUpdaterExprs[0] = Base; } InitListExpr *getUpdater() const { return cast(BaseAndUpdaterExprs[1]); } void setUpdater(Expr *Updater) { BaseAndUpdaterExprs[1] = Updater; } // Iterators // children = the base and the updater child_range children() { return child_range(&BaseAndUpdaterExprs[0], &BaseAndUpdaterExprs[0] + 2); } const_child_range children() const { return const_child_range(&BaseAndUpdaterExprs[0], &BaseAndUpdaterExprs[0] + 2); } }; /// Represents a loop initializing the elements of an array. /// /// The need to initialize the elements of an array occurs in a number of /// contexts: /// /// * in the implicit copy/move constructor for a class with an array member /// * when a lambda-expression captures an array by value /// * when a decomposition declaration decomposes an array /// /// There are two subexpressions: a common expression (the source array) /// that is evaluated once up-front, and a per-element initializer that /// runs once for each array element. /// /// Within the per-element initializer, the common expression may be referenced /// via an OpaqueValueExpr, and the current index may be obtained via an /// ArrayInitIndexExpr. class ArrayInitLoopExpr : public Expr { Stmt *SubExprs[2]; explicit ArrayInitLoopExpr(EmptyShell Empty) : Expr(ArrayInitLoopExprClass, Empty), SubExprs{} {} public: explicit ArrayInitLoopExpr(QualType T, Expr *CommonInit, Expr *ElementInit) : Expr(ArrayInitLoopExprClass, T, VK_RValue, OK_Ordinary, false, CommonInit->isValueDependent() || ElementInit->isValueDependent(), T->isInstantiationDependentType(), CommonInit->containsUnexpandedParameterPack() || ElementInit->containsUnexpandedParameterPack()), SubExprs{CommonInit, ElementInit} {} /// Get the common subexpression shared by all initializations (the source /// array). OpaqueValueExpr *getCommonExpr() const { return cast(SubExprs[0]); } /// Get the initializer to use for each array element. Expr *getSubExpr() const { return cast(SubExprs[1]); } llvm::APInt getArraySize() const { return cast(getType()->castAsArrayTypeUnsafe()) ->getSize(); } static bool classof(const Stmt *S) { return S->getStmtClass() == ArrayInitLoopExprClass; } SourceLocation getBeginLoc() const LLVM_READONLY { return getCommonExpr()->getBeginLoc(); } SourceLocation getEndLoc() const LLVM_READONLY { return getCommonExpr()->getEndLoc(); } child_range children() { return child_range(SubExprs, SubExprs + 2); } const_child_range children() const { return const_child_range(SubExprs, SubExprs + 2); } friend class ASTReader; friend class ASTStmtReader; friend class ASTStmtWriter; }; /// Represents the index of the current element of an array being /// initialized by an ArrayInitLoopExpr. This can only appear within the /// subexpression of an ArrayInitLoopExpr. class ArrayInitIndexExpr : public Expr { explicit ArrayInitIndexExpr(EmptyShell Empty) : Expr(ArrayInitIndexExprClass, Empty) {} public: explicit ArrayInitIndexExpr(QualType T) : Expr(ArrayInitIndexExprClass, T, VK_RValue, OK_Ordinary, false, false, false, false) {} static bool classof(const Stmt *S) { return S->getStmtClass() == ArrayInitIndexExprClass; } SourceLocation getBeginLoc() const LLVM_READONLY { return SourceLocation(); } SourceLocation getEndLoc() const LLVM_READONLY { return SourceLocation(); } child_range children() { return child_range(child_iterator(), child_iterator()); } const_child_range children() const { return const_child_range(const_child_iterator(), const_child_iterator()); } friend class ASTReader; friend class ASTStmtReader; }; /// Represents an implicitly-generated value initialization of /// an object of a given type. /// /// Implicit value initializations occur within semantic initializer /// list expressions (InitListExpr) as placeholders for subobject /// initializations not explicitly specified by the user. /// /// \see InitListExpr class ImplicitValueInitExpr : public Expr { public: explicit ImplicitValueInitExpr(QualType ty) : Expr(ImplicitValueInitExprClass, ty, VK_RValue, OK_Ordinary, false, false, ty->isInstantiationDependentType(), false) { } /// Construct an empty implicit value initialization. explicit ImplicitValueInitExpr(EmptyShell Empty) : Expr(ImplicitValueInitExprClass, Empty) { } static bool classof(const Stmt *T) { return T->getStmtClass() == ImplicitValueInitExprClass; } SourceLocation getBeginLoc() const LLVM_READONLY { return SourceLocation(); } SourceLocation getEndLoc() const LLVM_READONLY { return SourceLocation(); } // Iterators child_range children() { return child_range(child_iterator(), child_iterator()); } const_child_range children() const { return const_child_range(const_child_iterator(), const_child_iterator()); } }; class ParenListExpr final : public Expr, private llvm::TrailingObjects { friend class ASTStmtReader; friend TrailingObjects; /// The location of the left and right parentheses. SourceLocation LParenLoc, RParenLoc; /// Build a paren list. ParenListExpr(SourceLocation LParenLoc, ArrayRef Exprs, SourceLocation RParenLoc); /// Build an empty paren list. ParenListExpr(EmptyShell Empty, unsigned NumExprs); public: /// Create a paren list. static ParenListExpr *Create(const ASTContext &Ctx, SourceLocation LParenLoc, ArrayRef Exprs, SourceLocation RParenLoc); /// Create an empty paren list. static ParenListExpr *CreateEmpty(const ASTContext &Ctx, unsigned NumExprs); /// Return the number of expressions in this paren list. unsigned getNumExprs() const { return ParenListExprBits.NumExprs; } Expr *getExpr(unsigned Init) { assert(Init < getNumExprs() && "Initializer access out of range!"); return getExprs()[Init]; } const Expr *getExpr(unsigned Init) const { return const_cast(this)->getExpr(Init); } Expr **getExprs() { return reinterpret_cast(getTrailingObjects()); } ArrayRef exprs() { return llvm::makeArrayRef(getExprs(), getNumExprs()); } SourceLocation getLParenLoc() const { return LParenLoc; } SourceLocation getRParenLoc() const { return RParenLoc; } SourceLocation getBeginLoc() const { return getLParenLoc(); } SourceLocation getEndLoc() const { return getRParenLoc(); } static bool classof(const Stmt *T) { return T->getStmtClass() == ParenListExprClass; } // Iterators child_range children() { return child_range(getTrailingObjects(), getTrailingObjects() + getNumExprs()); } const_child_range children() const { return const_child_range(getTrailingObjects(), getTrailingObjects() + getNumExprs()); } }; /// Represents a C11 generic selection. /// /// A generic selection (C11 6.5.1.1) contains an unevaluated controlling /// expression, followed by one or more generic associations. Each generic /// association specifies a type name and an expression, or "default" and an /// expression (in which case it is known as a default generic association). /// The type and value of the generic selection are identical to those of its /// result expression, which is defined as the expression in the generic /// association with a type name that is compatible with the type of the /// controlling expression, or the expression in the default generic association /// if no types are compatible. For example: /// /// @code /// _Generic(X, double: 1, float: 2, default: 3) /// @endcode /// /// The above expression evaluates to 1 if 1.0 is substituted for X, 2 if 1.0f /// or 3 if "hello". /// /// As an extension, generic selections are allowed in C++, where the following /// additional semantics apply: /// /// Any generic selection whose controlling expression is type-dependent or /// 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. class GenericSelectionExpr final : public Expr, private llvm::TrailingObjects { friend class ASTStmtReader; friend class ASTStmtWriter; friend TrailingObjects; /// The number of association expressions and the index of the result /// 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; enum : unsigned { ResultDependentIndex = std::numeric_limits::max(), ControllingIndex = 0, AssocExprStartIndex = 1 }; /// 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. // * An array of getNumAssocs() Stmt * for the association expressions. // * An array of getNumAssocs() TypeSourceInfo *, one for each of the // association expressions. unsigned numTrailingObjects(OverloadToken) const { // Add one to account for the controlling expression; the remainder // are the associated expressions. return 1 + getNumAssocs(); } unsigned numTrailingObjects(OverloadToken) const { return getNumAssocs(); } template class AssociationIteratorTy; /// Bundle together an association expression and its TypeSourceInfo. /// The Const template parameter is for the const and non-const versions /// of AssociationTy. template class AssociationTy { friend class GenericSelectionExpr; template friend class AssociationIteratorTy; using ExprPtrTy = typename std::conditional::type; using TSIPtrTy = typename std::conditional::type; ExprPtrTy E; TSIPtrTy TSI; bool Selected; AssociationTy(ExprPtrTy E, TSIPtrTy TSI, bool Selected) : E(E), TSI(TSI), Selected(Selected) {} public: ExprPtrTy getAssociationExpr() const { return E; } TSIPtrTy getTypeSourceInfo() const { return TSI; } QualType getType() const { return TSI ? TSI->getType() : QualType(); } bool isSelected() const { return Selected; } AssociationTy *operator->() { return this; } const AssociationTy *operator->() const { return this; } }; // class AssociationTy /// Iterator over const and non-const Association objects. The Association /// objects are created on the fly when the iterator is dereferenced. /// This abstract over how exactly the association expressions and the /// corresponding TypeSourceInfo * are stored. template class AssociationIteratorTy : public llvm::iterator_facade_base< AssociationIteratorTy, std::input_iterator_tag, AssociationTy, std::ptrdiff_t, AssociationTy, AssociationTy> { friend class GenericSelectionExpr; // FIXME: This iterator could conceptually be a random access iterator, and // it would be nice if we could strengthen the iterator category someday. // However this iterator does not satisfy two requirements of forward // iterators: // a) reference = T& or reference = const T& // b) If It1 and It2 are both dereferenceable, then It1 == It2 if and only // if *It1 and *It2 are bound to the same objects. // An alternative design approach was discussed during review; // store an Association object inside the iterator, and return a reference // to it when dereferenced. This idea was discarded beacuse of nasty // lifetime issues: // AssociationIterator It = ...; // const Association &Assoc = *It++; // Oops, Assoc is dangling. using BaseTy = typename AssociationIteratorTy::iterator_facade_base; using StmtPtrPtrTy = typename std::conditional::type; using TSIPtrPtrTy = typename std::conditional::type; StmtPtrPtrTy E; // = nullptr; FIXME: Once support for gcc 4.8 is dropped. TSIPtrPtrTy TSI; // Kept in sync with E. unsigned Offset = 0, SelectedOffset = 0; AssociationIteratorTy(StmtPtrPtrTy E, TSIPtrPtrTy TSI, unsigned Offset, unsigned SelectedOffset) : E(E), TSI(TSI), Offset(Offset), SelectedOffset(SelectedOffset) {} public: AssociationIteratorTy() : E(nullptr), TSI(nullptr) {} typename BaseTy::reference operator*() const { return AssociationTy(cast(*E), *TSI, Offset == SelectedOffset); } typename BaseTy::pointer operator->() const { return **this; } using BaseTy::operator++; AssociationIteratorTy &operator++() { ++E; ++TSI; ++Offset; return *this; } bool operator==(AssociationIteratorTy Other) const { return E == Other.E; } }; // class AssociationIterator /// Build a non-result-dependent generic selection expression. GenericSelectionExpr(const ASTContext &Context, SourceLocation GenericLoc, Expr *ControllingExpr, ArrayRef AssocTypes, ArrayRef AssocExprs, SourceLocation DefaultLoc, SourceLocation RParenLoc, bool ContainsUnexpandedParameterPack, unsigned ResultIndex); /// Build a result-dependent generic selection expression. GenericSelectionExpr(const ASTContext &Context, SourceLocation GenericLoc, Expr *ControllingExpr, ArrayRef AssocTypes, ArrayRef 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. static GenericSelectionExpr * Create(const ASTContext &Context, SourceLocation GenericLoc, Expr *ControllingExpr, ArrayRef AssocTypes, ArrayRef AssocExprs, SourceLocation DefaultLoc, SourceLocation RParenLoc, bool ContainsUnexpandedParameterPack, unsigned ResultIndex); /// Create a result-dependent generic selection expression. static GenericSelectionExpr * Create(const ASTContext &Context, SourceLocation GenericLoc, Expr *ControllingExpr, ArrayRef AssocTypes, ArrayRef AssocExprs, SourceLocation DefaultLoc, SourceLocation RParenLoc, bool ContainsUnexpandedParameterPack); /// Create an empty generic selection expression for deserialization. static GenericSelectionExpr *CreateEmpty(const ASTContext &Context, unsigned NumAssocs); using Association = AssociationTy; using ConstAssociation = AssociationTy; using AssociationIterator = AssociationIteratorTy; using ConstAssociationIterator = AssociationIteratorTy; using association_range = llvm::iterator_range; using const_association_range = llvm::iterator_range; /// The number of association expressions. unsigned getNumAssocs() const { return NumAssocs; } /// The zero-based index of the result expression's generic association in /// the generic selection's association list. Defined only if the /// generic selection is not result-dependent. unsigned getResultIndex() const { assert(!isResultDependent() && "Generic selection is result-dependent but getResultIndex called!"); return ResultIndex; } /// Whether this generic selection is result-dependent. bool isResultDependent() const { return ResultIndex == ResultDependentIndex; } /// Return the controlling expression of this generic selection expression. Expr *getControllingExpr() { return cast(getTrailingObjects()[ControllingIndex]); } const Expr *getControllingExpr() const { return cast(getTrailingObjects()[ControllingIndex]); } /// 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( getTrailingObjects()[AssocExprStartIndex + getResultIndex()]); } const Expr *getResultExpr() const { return cast( getTrailingObjects()[AssocExprStartIndex + getResultIndex()]); } ArrayRef getAssocExprs() const { return {reinterpret_cast(getTrailingObjects() + AssocExprStartIndex), NumAssocs}; } ArrayRef getAssocTypeSourceInfos() const { return {getTrailingObjects(), NumAssocs}; } /// Return the Ith association expression with its TypeSourceInfo, /// bundled together in GenericSelectionExpr::(Const)Association. Association getAssociation(unsigned I) { assert(I < getNumAssocs() && "Out-of-range index in GenericSelectionExpr::getAssociation!"); return Association( cast(getTrailingObjects()[AssocExprStartIndex + I]), getTrailingObjects()[I], !isResultDependent() && (getResultIndex() == I)); } ConstAssociation getAssociation(unsigned I) const { assert(I < getNumAssocs() && "Out-of-range index in GenericSelectionExpr::getAssociation!"); return ConstAssociation( cast(getTrailingObjects()[AssocExprStartIndex + I]), getTrailingObjects()[I], !isResultDependent() && (getResultIndex() == I)); } association_range associations() { AssociationIterator Begin(getTrailingObjects() + AssocExprStartIndex, getTrailingObjects(), /*Offset=*/0, ResultIndex); AssociationIterator End(Begin.E + NumAssocs, Begin.TSI + NumAssocs, /*Offset=*/NumAssocs, ResultIndex); return llvm::make_range(Begin, End); } const_association_range associations() const { ConstAssociationIterator Begin(getTrailingObjects() + AssocExprStartIndex, getTrailingObjects(), /*Offset=*/0, ResultIndex); ConstAssociationIterator End(Begin.E + NumAssocs, Begin.TSI + NumAssocs, /*Offset=*/NumAssocs, ResultIndex); return llvm::make_range(Begin, End); } SourceLocation getGenericLoc() const { return GenericSelectionExprBits.GenericLoc; } SourceLocation getDefaultLoc() const { return DefaultLoc; } SourceLocation getRParenLoc() const { return RParenLoc; } SourceLocation getBeginLoc() const { return getGenericLoc(); } SourceLocation getEndLoc() const { return getRParenLoc(); } static bool classof(const Stmt *T) { return T->getStmtClass() == GenericSelectionExprClass; } child_range children() { return child_range(getTrailingObjects(), getTrailingObjects() + numTrailingObjects(OverloadToken())); } const_child_range children() const { return const_child_range(getTrailingObjects(), getTrailingObjects() + numTrailingObjects(OverloadToken())); } }; //===----------------------------------------------------------------------===// // Clang Extensions //===----------------------------------------------------------------------===// /// ExtVectorElementExpr - This represents access to specific elements of a /// vector, and may occur on the left hand side or right hand side. For example /// the following is legal: "V.xy = V.zw" if V is a 4 element extended vector. /// /// Note that the base may have either vector or pointer to vector type, just /// like a struct field reference. /// class ExtVectorElementExpr : public Expr { Stmt *Base; IdentifierInfo *Accessor; SourceLocation AccessorLoc; public: ExtVectorElementExpr(QualType ty, ExprValueKind VK, Expr *base, IdentifierInfo &accessor, SourceLocation loc) : Expr(ExtVectorElementExprClass, ty, VK, (VK == VK_RValue ? OK_Ordinary : OK_VectorComponent), base->isTypeDependent(), base->isValueDependent(), base->isInstantiationDependent(), base->containsUnexpandedParameterPack()), Base(base), Accessor(&accessor), AccessorLoc(loc) {} /// Build an empty vector element expression. explicit ExtVectorElementExpr(EmptyShell Empty) : Expr(ExtVectorElementExprClass, Empty) { } const Expr *getBase() const { return cast(Base); } Expr *getBase() { return cast(Base); } void setBase(Expr *E) { Base = E; } IdentifierInfo &getAccessor() const { return *Accessor; } void setAccessor(IdentifierInfo *II) { Accessor = II; } SourceLocation getAccessorLoc() const { return AccessorLoc; } void setAccessorLoc(SourceLocation L) { AccessorLoc = L; } /// getNumElements - Get the number of components being selected. unsigned getNumElements() const; /// containsDuplicateElements - Return true if any element access is /// repeated. bool containsDuplicateElements() const; /// getEncodedElementAccess - Encode the elements accessed into an llvm /// aggregate Constant of ConstantInt(s). void getEncodedElementAccess(SmallVectorImpl &Elts) const; SourceLocation getBeginLoc() const LLVM_READONLY { return getBase()->getBeginLoc(); } SourceLocation getEndLoc() const LLVM_READONLY { return AccessorLoc; } /// isArrow - Return true if the base expression is a pointer to vector, /// return false if the base expression is a vector. bool isArrow() const; static bool classof(const Stmt *T) { return T->getStmtClass() == ExtVectorElementExprClass; } // Iterators child_range children() { return child_range(&Base, &Base+1); } const_child_range children() const { return const_child_range(&Base, &Base + 1); } }; /// BlockExpr - Adaptor class for mixing a BlockDecl with expressions. /// ^{ statement-body } or ^(int arg1, float arg2){ statement-body } class BlockExpr : public Expr { protected: BlockDecl *TheBlock; public: BlockExpr(BlockDecl *BD, QualType ty) : Expr(BlockExprClass, ty, VK_RValue, OK_Ordinary, ty->isDependentType(), ty->isDependentType(), ty->isInstantiationDependentType() || BD->isDependentContext(), false), TheBlock(BD) {} /// Build an empty block expression. explicit BlockExpr(EmptyShell Empty) : Expr(BlockExprClass, Empty) { } const BlockDecl *getBlockDecl() const { return TheBlock; } BlockDecl *getBlockDecl() { return TheBlock; } void setBlockDecl(BlockDecl *BD) { TheBlock = BD; } // Convenience functions for probing the underlying BlockDecl. SourceLocation getCaretLocation() const; const Stmt *getBody() const; Stmt *getBody(); SourceLocation getBeginLoc() const LLVM_READONLY { return getCaretLocation(); } SourceLocation getEndLoc() const LLVM_READONLY { return getBody()->getEndLoc(); } /// getFunctionType - Return the underlying function type for this block. const FunctionProtoType *getFunctionType() const; static bool classof(const Stmt *T) { return T->getStmtClass() == BlockExprClass; } // Iterators child_range children() { return child_range(child_iterator(), child_iterator()); } const_child_range children() const { return const_child_range(const_child_iterator(), const_child_iterator()); } }; /// Copy initialization expr of a __block variable and a boolean flag that /// indicates whether the expression can throw. struct BlockVarCopyInit { BlockVarCopyInit() = default; BlockVarCopyInit(Expr *CopyExpr, bool CanThrow) : ExprAndFlag(CopyExpr, CanThrow) {} void setExprAndFlag(Expr *CopyExpr, bool CanThrow) { ExprAndFlag.setPointerAndInt(CopyExpr, CanThrow); } Expr *getCopyExpr() const { return ExprAndFlag.getPointer(); } bool canThrow() const { return ExprAndFlag.getInt(); } llvm::PointerIntPair ExprAndFlag; }; /// AsTypeExpr - Clang builtin function __builtin_astype [OpenCL 6.2.4.2] /// This AST node provides support for reinterpreting a type to another /// type of the same size. class AsTypeExpr : public Expr { private: Stmt *SrcExpr; SourceLocation BuiltinLoc, RParenLoc; friend class ASTReader; friend class ASTStmtReader; explicit AsTypeExpr(EmptyShell Empty) : Expr(AsTypeExprClass, Empty) {} public: AsTypeExpr(Expr* SrcExpr, QualType DstType, ExprValueKind VK, ExprObjectKind OK, SourceLocation BuiltinLoc, SourceLocation RParenLoc) : Expr(AsTypeExprClass, DstType, VK, OK, DstType->isDependentType(), DstType->isDependentType() || SrcExpr->isValueDependent(), (DstType->isInstantiationDependentType() || SrcExpr->isInstantiationDependent()), (DstType->containsUnexpandedParameterPack() || SrcExpr->containsUnexpandedParameterPack())), SrcExpr(SrcExpr), BuiltinLoc(BuiltinLoc), RParenLoc(RParenLoc) {} /// getSrcExpr - Return the Expr to be converted. Expr *getSrcExpr() const { return cast(SrcExpr); } /// getBuiltinLoc - Return the location of the __builtin_astype token. SourceLocation getBuiltinLoc() const { return BuiltinLoc; } /// getRParenLoc - Return the location of final right parenthesis. SourceLocation getRParenLoc() const { return RParenLoc; } SourceLocation getBeginLoc() const LLVM_READONLY { return BuiltinLoc; } SourceLocation getEndLoc() const LLVM_READONLY { return RParenLoc; } static bool classof(const Stmt *T) { return T->getStmtClass() == AsTypeExprClass; } // Iterators child_range children() { return child_range(&SrcExpr, &SrcExpr+1); } const_child_range children() const { return const_child_range(&SrcExpr, &SrcExpr + 1); } }; /// PseudoObjectExpr - An expression which accesses a pseudo-object /// l-value. A pseudo-object is an abstract object, accesses to which /// are translated to calls. The pseudo-object expression has a /// syntactic form, which shows how the expression was actually /// written in the source code, and a semantic form, which is a series /// of expressions to be executed in order which detail how the /// operation is actually evaluated. Optionally, one of the semantic /// forms may also provide a result value for the expression. /// /// If any of the semantic-form expressions is an OpaqueValueExpr, /// that OVE is required to have a source expression, and it is bound /// to the result of that source expression. Such OVEs may appear /// only in subsequent semantic-form expressions and as /// sub-expressions of the syntactic form. /// /// PseudoObjectExpr should be used only when an operation can be /// usefully described in terms of fairly simple rewrite rules on /// objects and functions that are meant to be used by end-developers. /// For example, under the Itanium ABI, dynamic casts are implemented /// as a call to a runtime function called __dynamic_cast; using this /// class to describe that would be inappropriate because that call is /// not really part of the user-visible semantics, and instead the /// cast is properly reflected in the AST and IR-generation has been /// taught to generate the call as necessary. In contrast, an /// Objective-C property access is semantically defined to be /// equivalent to a particular message send, and this is very much /// part of the user model. The name of this class encourages this /// modelling design. class PseudoObjectExpr final : public Expr, private llvm::TrailingObjects { // PseudoObjectExprBits.NumSubExprs - The number of sub-expressions. // Always at least two, because the first sub-expression is the // syntactic form. // PseudoObjectExprBits.ResultIndex - The index of the // sub-expression holding the result. 0 means the result is void, // which is unambiguous because it's the index of the syntactic // form. Note that this is therefore 1 higher than the value passed // in to Create, which is an index within the semantic forms. // Note also that ASTStmtWriter assumes this encoding. Expr **getSubExprsBuffer() { return getTrailingObjects(); } const Expr * const *getSubExprsBuffer() const { return getTrailingObjects(); } PseudoObjectExpr(QualType type, ExprValueKind VK, Expr *syntactic, ArrayRef semantic, unsigned resultIndex); PseudoObjectExpr(EmptyShell shell, unsigned numSemanticExprs); unsigned getNumSubExprs() const { return PseudoObjectExprBits.NumSubExprs; } public: /// NoResult - A value for the result index indicating that there is /// no semantic result. enum : unsigned { NoResult = ~0U }; static PseudoObjectExpr *Create(const ASTContext &Context, Expr *syntactic, ArrayRef semantic, unsigned resultIndex); static PseudoObjectExpr *Create(const ASTContext &Context, EmptyShell shell, unsigned numSemanticExprs); /// Return the syntactic form of this expression, i.e. the /// expression it actually looks like. Likely to be expressed in /// terms of OpaqueValueExprs bound in the semantic form. Expr *getSyntacticForm() { return getSubExprsBuffer()[0]; } const Expr *getSyntacticForm() const { return getSubExprsBuffer()[0]; } /// Return the index of the result-bearing expression into the semantics /// expressions, or PseudoObjectExpr::NoResult if there is none. unsigned getResultExprIndex() const { if (PseudoObjectExprBits.ResultIndex == 0) return NoResult; return PseudoObjectExprBits.ResultIndex - 1; } /// Return the result-bearing expression, or null if there is none. Expr *getResultExpr() { if (PseudoObjectExprBits.ResultIndex == 0) return nullptr; return getSubExprsBuffer()[PseudoObjectExprBits.ResultIndex]; } const Expr *getResultExpr() const { return const_cast(this)->getResultExpr(); } unsigned getNumSemanticExprs() const { return getNumSubExprs() - 1; } typedef Expr * const *semantics_iterator; typedef const Expr * const *const_semantics_iterator; semantics_iterator semantics_begin() { return getSubExprsBuffer() + 1; } const_semantics_iterator semantics_begin() const { return getSubExprsBuffer() + 1; } semantics_iterator semantics_end() { return getSubExprsBuffer() + getNumSubExprs(); } const_semantics_iterator semantics_end() const { return getSubExprsBuffer() + getNumSubExprs(); } llvm::iterator_range semantics() { return llvm::make_range(semantics_begin(), semantics_end()); } llvm::iterator_range semantics() const { return llvm::make_range(semantics_begin(), semantics_end()); } Expr *getSemanticExpr(unsigned index) { assert(index + 1 < getNumSubExprs()); return getSubExprsBuffer()[index + 1]; } const Expr *getSemanticExpr(unsigned index) const { return const_cast(this)->getSemanticExpr(index); } SourceLocation getExprLoc() const LLVM_READONLY { return getSyntacticForm()->getExprLoc(); } SourceLocation getBeginLoc() const LLVM_READONLY { return getSyntacticForm()->getBeginLoc(); } SourceLocation getEndLoc() const LLVM_READONLY { return getSyntacticForm()->getEndLoc(); } child_range children() { const_child_range CCR = const_cast(this)->children(); return child_range(cast_away_const(CCR.begin()), cast_away_const(CCR.end())); } const_child_range children() const { Stmt *const *cs = const_cast( reinterpret_cast(getSubExprsBuffer())); return const_child_range(cs, cs + getNumSubExprs()); } static bool classof(const Stmt *T) { return T->getStmtClass() == PseudoObjectExprClass; } friend TrailingObjects; friend class ASTStmtReader; }; /// AtomicExpr - Variadic atomic builtins: __atomic_exchange, __atomic_fetch_*, /// __atomic_load, __atomic_store, and __atomic_compare_exchange_*, for the /// similarly-named C++11 instructions, and __c11 variants for , /// and corresponding __opencl_atomic_* for OpenCL 2.0. /// All of these instructions take one primary pointer, at least one memory /// order. The instructions for which getScopeModel returns non-null value /// take one synch scope. class AtomicExpr : public Expr { public: enum AtomicOp { #define BUILTIN(ID, TYPE, ATTRS) #define ATOMIC_BUILTIN(ID, TYPE, ATTRS) AO ## ID, #include "clang/Basic/Builtins.def" // Avoid trailing comma BI_First = 0 }; private: /// Location of sub-expressions. /// The location of Scope sub-expression is NumSubExprs - 1, which is /// not fixed, therefore is not defined in enum. enum { PTR, ORDER, VAL1, ORDER_FAIL, VAL2, WEAK, END_EXPR }; Stmt *SubExprs[END_EXPR + 1]; unsigned NumSubExprs; SourceLocation BuiltinLoc, RParenLoc; AtomicOp Op; friend class ASTStmtReader; public: AtomicExpr(SourceLocation BLoc, ArrayRef args, QualType t, AtomicOp op, SourceLocation RP); /// Determine the number of arguments the specified atomic builtin /// should have. static unsigned getNumSubExprs(AtomicOp Op); /// Build an empty AtomicExpr. explicit AtomicExpr(EmptyShell Empty) : Expr(AtomicExprClass, Empty) { } Expr *getPtr() const { return cast(SubExprs[PTR]); } Expr *getOrder() const { return cast(SubExprs[ORDER]); } Expr *getScope() const { assert(getScopeModel() && "No scope"); return cast(SubExprs[NumSubExprs - 1]); } Expr *getVal1() const { if (Op == AO__c11_atomic_init || Op == AO__opencl_atomic_init) return cast(SubExprs[ORDER]); assert(NumSubExprs > VAL1); return cast(SubExprs[VAL1]); } Expr *getOrderFail() const { assert(NumSubExprs > ORDER_FAIL); return cast(SubExprs[ORDER_FAIL]); } Expr *getVal2() const { if (Op == AO__atomic_exchange) return cast(SubExprs[ORDER_FAIL]); assert(NumSubExprs > VAL2); return cast(SubExprs[VAL2]); } Expr *getWeak() const { assert(NumSubExprs > WEAK); return cast(SubExprs[WEAK]); } QualType getValueType() const; AtomicOp getOp() const { return Op; } unsigned getNumSubExprs() const { return NumSubExprs; } Expr **getSubExprs() { return reinterpret_cast(SubExprs); } const Expr * const *getSubExprs() const { return reinterpret_cast(SubExprs); } bool isVolatile() const { return getPtr()->getType()->getPointeeType().isVolatileQualified(); } bool isCmpXChg() const { return getOp() == AO__c11_atomic_compare_exchange_strong || getOp() == AO__c11_atomic_compare_exchange_weak || getOp() == AO__opencl_atomic_compare_exchange_strong || getOp() == AO__opencl_atomic_compare_exchange_weak || getOp() == AO__atomic_compare_exchange || getOp() == AO__atomic_compare_exchange_n; } bool isOpenCL() const { return getOp() >= AO__opencl_atomic_init && getOp() <= AO__opencl_atomic_fetch_max; } SourceLocation getBuiltinLoc() const { return BuiltinLoc; } SourceLocation getRParenLoc() const { return RParenLoc; } SourceLocation getBeginLoc() const LLVM_READONLY { return BuiltinLoc; } SourceLocation getEndLoc() const LLVM_READONLY { return RParenLoc; } static bool classof(const Stmt *T) { return T->getStmtClass() == AtomicExprClass; } // Iterators child_range children() { return child_range(SubExprs, SubExprs+NumSubExprs); } const_child_range children() const { return const_child_range(SubExprs, SubExprs + NumSubExprs); } /// Get atomic scope model for the atomic op code. /// \return empty atomic scope model if the atomic op code does not have /// scope operand. static std::unique_ptr getScopeModel(AtomicOp Op) { auto Kind = (Op >= AO__opencl_atomic_load && Op <= AO__opencl_atomic_fetch_max) ? AtomicScopeModelKind::OpenCL : AtomicScopeModelKind::None; return AtomicScopeModel::create(Kind); } /// Get atomic scope model. /// \return empty atomic scope model if this atomic expression does not have /// scope operand. std::unique_ptr getScopeModel() const { return getScopeModel(getOp()); } }; /// TypoExpr - Internal placeholder for expressions where typo correction /// still needs to be performed and/or an error diagnostic emitted. class TypoExpr : public Expr { public: TypoExpr(QualType T) : Expr(TypoExprClass, T, VK_LValue, OK_Ordinary, /*isTypeDependent*/ true, /*isValueDependent*/ true, /*isInstantiationDependent*/ true, /*containsUnexpandedParameterPack*/ false) { assert(T->isDependentType() && "TypoExpr given a non-dependent type"); } child_range children() { return child_range(child_iterator(), child_iterator()); } const_child_range children() const { return const_child_range(const_child_iterator(), const_child_iterator()); } SourceLocation getBeginLoc() const LLVM_READONLY { return SourceLocation(); } SourceLocation getEndLoc() const LLVM_READONLY { return SourceLocation(); } static bool classof(const Stmt *T) { return T->getStmtClass() == TypoExprClass; } }; } // end namespace clang #endif // LLVM_CLANG_AST_EXPR_H Index: vendor/llvm-project/release-10.x/clang/include/clang/AST/Stmt.h =================================================================== --- vendor/llvm-project/release-10.x/clang/include/clang/AST/Stmt.h (revision 359078) +++ vendor/llvm-project/release-10.x/clang/include/clang/AST/Stmt.h (revision 359079) @@ -1,3591 +1,3606 @@ //===- Stmt.h - Classes for representing statements -------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This file defines the Stmt interface and subclasses. // //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_AST_STMT_H #define LLVM_CLANG_AST_STMT_H #include "clang/AST/DeclGroup.h" #include "clang/AST/StmtIterator.h" #include "clang/Basic/CapturedStmt.h" #include "clang/Basic/IdentifierTable.h" #include "clang/Basic/LLVM.h" #include "clang/Basic/SourceLocation.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/PointerIntPair.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/iterator.h" #include "llvm/ADT/iterator_range.h" #include "llvm/Support/Casting.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/ErrorHandling.h" #include #include #include #include #include namespace llvm { class FoldingSetNodeID; } // namespace llvm namespace clang { class ASTContext; class Attr; class CapturedDecl; class Decl; class Expr; class AddrLabelExpr; class LabelDecl; class ODRHash; class PrinterHelper; struct PrintingPolicy; class RecordDecl; class SourceManager; class StringLiteral; class Token; class VarDecl; //===----------------------------------------------------------------------===// // AST classes for statements. //===----------------------------------------------------------------------===// /// Stmt - This represents one statement. /// class alignas(void *) Stmt { public: enum StmtClass { NoStmtClass = 0, #define STMT(CLASS, PARENT) CLASS##Class, #define STMT_RANGE(BASE, FIRST, LAST) \ first##BASE##Constant=FIRST##Class, last##BASE##Constant=LAST##Class, #define LAST_STMT_RANGE(BASE, FIRST, LAST) \ first##BASE##Constant=FIRST##Class, last##BASE##Constant=LAST##Class #define ABSTRACT_STMT(STMT) #include "clang/AST/StmtNodes.inc" }; // Make vanilla 'new' and 'delete' illegal for Stmts. protected: friend class ASTStmtReader; friend class ASTStmtWriter; void *operator new(size_t bytes) noexcept { llvm_unreachable("Stmts cannot be allocated with regular 'new'."); } void operator delete(void *data) noexcept { llvm_unreachable("Stmts cannot be released with regular 'delete'."); } //===--- Statement bitfields classes ---===// class StmtBitfields { friend class ASTStmtReader; friend class ASTStmtWriter; friend class Stmt; /// The statement class. unsigned sClass : 8; /// This bit is set only for the Stmts that are the structured-block of /// OpenMP executable directives. Directives that have a structured block /// are called "non-standalone" directives. /// I.e. those returned by OMPExecutableDirective::getStructuredBlock(). unsigned IsOMPStructuredBlock : 1; }; enum { NumStmtBits = 9 }; class NullStmtBitfields { friend class ASTStmtReader; friend class ASTStmtWriter; friend class NullStmt; unsigned : NumStmtBits; /// True if the null statement was preceded by an empty macro, e.g: /// @code /// #define CALL(x) /// CALL(0); /// @endcode unsigned HasLeadingEmptyMacro : 1; /// The location of the semi-colon. SourceLocation SemiLoc; }; class CompoundStmtBitfields { friend class ASTStmtReader; friend class CompoundStmt; unsigned : NumStmtBits; unsigned NumStmts : 32 - NumStmtBits; /// The location of the opening "{". SourceLocation LBraceLoc; }; class LabelStmtBitfields { friend class LabelStmt; unsigned : NumStmtBits; SourceLocation IdentLoc; }; class AttributedStmtBitfields { friend class ASTStmtReader; friend class AttributedStmt; unsigned : NumStmtBits; /// Number of attributes. unsigned NumAttrs : 32 - NumStmtBits; /// The location of the attribute. SourceLocation AttrLoc; }; class IfStmtBitfields { friend class ASTStmtReader; friend class IfStmt; unsigned : NumStmtBits; /// True if this if statement is a constexpr if. unsigned IsConstexpr : 1; /// True if this if statement has storage for an else statement. unsigned HasElse : 1; /// True if this if statement has storage for a variable declaration. unsigned HasVar : 1; /// True if this if statement has storage for an init statement. unsigned HasInit : 1; /// The location of the "if". SourceLocation IfLoc; }; class SwitchStmtBitfields { friend class SwitchStmt; unsigned : NumStmtBits; /// True if the SwitchStmt has storage for an init statement. unsigned HasInit : 1; /// True if the SwitchStmt has storage for a condition variable. unsigned HasVar : 1; /// If the SwitchStmt is a switch on an enum value, records whether all /// the enum values were covered by CaseStmts. The coverage information /// value is meant to be a hint for possible clients. unsigned AllEnumCasesCovered : 1; /// The location of the "switch". SourceLocation SwitchLoc; }; class WhileStmtBitfields { friend class ASTStmtReader; friend class WhileStmt; unsigned : NumStmtBits; /// True if the WhileStmt has storage for a condition variable. unsigned HasVar : 1; /// The location of the "while". SourceLocation WhileLoc; }; class DoStmtBitfields { friend class DoStmt; unsigned : NumStmtBits; /// The location of the "do". SourceLocation DoLoc; }; class ForStmtBitfields { friend class ForStmt; unsigned : NumStmtBits; /// The location of the "for". SourceLocation ForLoc; }; class GotoStmtBitfields { friend class GotoStmt; friend class IndirectGotoStmt; unsigned : NumStmtBits; /// The location of the "goto". SourceLocation GotoLoc; }; class ContinueStmtBitfields { friend class ContinueStmt; unsigned : NumStmtBits; /// The location of the "continue". SourceLocation ContinueLoc; }; class BreakStmtBitfields { friend class BreakStmt; unsigned : NumStmtBits; /// The location of the "break". SourceLocation BreakLoc; }; class ReturnStmtBitfields { friend class ReturnStmt; unsigned : NumStmtBits; /// True if this ReturnStmt has storage for an NRVO candidate. unsigned HasNRVOCandidate : 1; /// The location of the "return". SourceLocation RetLoc; }; class SwitchCaseBitfields { friend class SwitchCase; friend class CaseStmt; unsigned : NumStmtBits; /// Used by CaseStmt to store whether it is a case statement /// of the form case LHS ... RHS (a GNU extension). unsigned CaseStmtIsGNURange : 1; /// The location of the "case" or "default" keyword. SourceLocation KeywordLoc; }; //===--- Expression bitfields classes ---===// class ExprBitfields { friend class ASTStmtReader; // deserialization friend class AtomicExpr; // ctor friend class BlockDeclRefExpr; // ctor friend class CallExpr; // ctor friend class CXXConstructExpr; // ctor friend class CXXDependentScopeMemberExpr; // ctor friend class CXXNewExpr; // ctor friend class CXXUnresolvedConstructExpr; // ctor friend class DeclRefExpr; // computeDependence friend class DependentScopeDeclRefExpr; // ctor friend class DesignatedInitExpr; // ctor friend class Expr; friend class InitListExpr; // ctor friend class ObjCArrayLiteral; // ctor friend class ObjCDictionaryLiteral; // ctor friend class ObjCMessageExpr; // ctor friend class OffsetOfExpr; // ctor friend class OpaqueValueExpr; // ctor friend class OverloadExpr; // ctor friend class ParenListExpr; // ctor friend class PseudoObjectExpr; // ctor friend class ShuffleVectorExpr; // ctor unsigned : NumStmtBits; unsigned ValueKind : 2; unsigned ObjectKind : 3; unsigned TypeDependent : 1; unsigned ValueDependent : 1; unsigned InstantiationDependent : 1; unsigned ContainsUnexpandedParameterPack : 1; }; enum { NumExprBits = NumStmtBits + 9 }; class ConstantExprBitfields { friend class ASTStmtReader; friend class ASTStmtWriter; friend class ConstantExpr; unsigned : NumExprBits; /// The kind of result that is trail-allocated. unsigned ResultKind : 2; /// Kind of Result as defined by APValue::Kind unsigned APValueKind : 4; /// When ResultKind == RSK_Int64. whether the trail-allocated integer is /// signed. unsigned IsUnsigned : 1; /// When ResultKind == RSK_Int64. the BitWidth of the trail-allocated /// integer. 7 bits because it is the minimal number of bit to represent a /// value from 0 to 64 (the size of the trail-allocated number). unsigned BitWidth : 7; /// When ResultKind == RSK_APValue. Wether the ASTContext will cleanup the /// destructor on the trail-allocated APValue. unsigned HasCleanup : 1; }; class PredefinedExprBitfields { friend class ASTStmtReader; friend class PredefinedExpr; unsigned : NumExprBits; /// The kind of this PredefinedExpr. One of the enumeration values /// in PredefinedExpr::IdentKind. unsigned Kind : 4; /// True if this PredefinedExpr has a trailing "StringLiteral *" /// for the predefined identifier. unsigned HasFunctionName : 1; /// The location of this PredefinedExpr. SourceLocation Loc; }; class DeclRefExprBitfields { friend class ASTStmtReader; // deserialization friend class DeclRefExpr; unsigned : NumExprBits; unsigned HasQualifier : 1; unsigned HasTemplateKWAndArgsInfo : 1; unsigned HasFoundDecl : 1; unsigned HadMultipleCandidates : 1; unsigned RefersToEnclosingVariableOrCapture : 1; unsigned NonOdrUseReason : 2; /// The location of the declaration name itself. SourceLocation Loc; }; class FloatingLiteralBitfields { friend class FloatingLiteral; unsigned : NumExprBits; unsigned Semantics : 3; // Provides semantics for APFloat construction unsigned IsExact : 1; }; class StringLiteralBitfields { friend class ASTStmtReader; friend class StringLiteral; unsigned : NumExprBits; /// The kind of this string literal. /// One of the enumeration values of StringLiteral::StringKind. unsigned Kind : 3; /// The width of a single character in bytes. Only values of 1, 2, /// and 4 bytes are supported. StringLiteral::mapCharByteWidth maps /// the target + string kind to the appropriate CharByteWidth. unsigned CharByteWidth : 3; unsigned IsPascal : 1; /// The number of concatenated token this string is made of. /// This is the number of trailing SourceLocation. unsigned NumConcatenated; }; class CharacterLiteralBitfields { friend class CharacterLiteral; unsigned : NumExprBits; unsigned Kind : 3; }; class UnaryOperatorBitfields { friend class UnaryOperator; unsigned : NumExprBits; unsigned Opc : 5; unsigned CanOverflow : 1; SourceLocation Loc; }; class UnaryExprOrTypeTraitExprBitfields { friend class UnaryExprOrTypeTraitExpr; unsigned : NumExprBits; unsigned Kind : 3; unsigned IsType : 1; // true if operand is a type, false if an expression. }; class ArraySubscriptExprBitfields { friend class ArraySubscriptExpr; unsigned : NumExprBits; SourceLocation RBracketLoc; }; class CallExprBitfields { friend class CallExpr; unsigned : NumExprBits; unsigned NumPreArgs : 1; /// True if the callee of the call expression was found using ADL. unsigned UsesADL : 1; /// Padding used to align OffsetToTrailingObjects to a byte multiple. unsigned : 24 - 2 - NumExprBits; /// The offset in bytes from the this pointer to the start of the /// trailing objects belonging to CallExpr. Intentionally byte sized /// for faster access. unsigned OffsetToTrailingObjects : 8; }; enum { NumCallExprBits = 32 }; class MemberExprBitfields { friend class ASTStmtReader; friend class MemberExpr; unsigned : NumExprBits; /// IsArrow - True if this is "X->F", false if this is "X.F". unsigned IsArrow : 1; /// True if this member expression used a nested-name-specifier to /// refer to the member, e.g., "x->Base::f", or found its member via /// a using declaration. When true, a MemberExprNameQualifier /// structure is allocated immediately after the MemberExpr. unsigned HasQualifierOrFoundDecl : 1; /// True if this member expression specified a template keyword /// and/or a template argument list explicitly, e.g., x->f, /// x->template f, x->template f. /// When true, an ASTTemplateKWAndArgsInfo structure and its /// TemplateArguments (if any) are present. unsigned HasTemplateKWAndArgsInfo : 1; /// True if this member expression refers to a method that /// was resolved from an overloaded set having size greater than 1. unsigned HadMultipleCandidates : 1; /// Value of type NonOdrUseReason indicating why this MemberExpr does /// not constitute an odr-use of the named declaration. Meaningful only /// when naming a static member. unsigned NonOdrUseReason : 2; /// This is the location of the -> or . in the expression. SourceLocation OperatorLoc; }; class CastExprBitfields { friend class CastExpr; friend class ImplicitCastExpr; unsigned : NumExprBits; unsigned Kind : 6; unsigned PartOfExplicitCast : 1; // Only set for ImplicitCastExpr. /// The number of CXXBaseSpecifiers in the cast. 14 bits would be enough /// here. ([implimits] Direct and indirect base classes [16384]). unsigned BasePathSize; }; class BinaryOperatorBitfields { friend class BinaryOperator; unsigned : NumExprBits; unsigned Opc : 6; /// This is only meaningful for operations on floating point /// types and 0 otherwise. unsigned FPFeatures : 3; SourceLocation OpLoc; }; class InitListExprBitfields { friend class InitListExpr; unsigned : NumExprBits; /// Whether this initializer list originally had a GNU array-range /// designator in it. This is a temporary marker used by CodeGen. unsigned HadArrayRangeDesignator : 1; }; class ParenListExprBitfields { friend class ASTStmtReader; friend class ParenListExpr; unsigned : NumExprBits; /// The number of expressions in the paren list. unsigned NumExprs; }; class GenericSelectionExprBitfields { friend class ASTStmtReader; friend class GenericSelectionExpr; unsigned : NumExprBits; /// The location of the "_Generic". SourceLocation GenericLoc; }; class PseudoObjectExprBitfields { friend class ASTStmtReader; // deserialization friend class PseudoObjectExpr; unsigned : NumExprBits; // These don't need to be particularly wide, because they're // strictly limited by the forms of expressions we permit. unsigned NumSubExprs : 8; unsigned ResultIndex : 32 - 8 - NumExprBits; }; class SourceLocExprBitfields { friend class ASTStmtReader; friend class SourceLocExpr; unsigned : NumExprBits; /// The kind of source location builtin represented by the SourceLocExpr. /// Ex. __builtin_LINE, __builtin_FUNCTION, ect. unsigned Kind : 2; }; + class StmtExprBitfields { + friend class ASTStmtReader; + friend class StmtExpr; + + unsigned : NumExprBits; + + /// The number of levels of template parameters enclosing this statement + /// expression. Used to determine if a statement expression remains + /// dependent after instantiation. + unsigned TemplateDepth; + }; + //===--- C++ Expression bitfields classes ---===// class CXXOperatorCallExprBitfields { friend class ASTStmtReader; friend class CXXOperatorCallExpr; unsigned : NumCallExprBits; /// The kind of this overloaded operator. One of the enumerator /// value of OverloadedOperatorKind. unsigned OperatorKind : 6; // Only meaningful for floating point types. unsigned FPFeatures : 3; }; class CXXRewrittenBinaryOperatorBitfields { friend class ASTStmtReader; friend class CXXRewrittenBinaryOperator; unsigned : NumCallExprBits; unsigned IsReversed : 1; }; class CXXBoolLiteralExprBitfields { friend class CXXBoolLiteralExpr; unsigned : NumExprBits; /// The value of the boolean literal. unsigned Value : 1; /// The location of the boolean literal. SourceLocation Loc; }; class CXXNullPtrLiteralExprBitfields { friend class CXXNullPtrLiteralExpr; unsigned : NumExprBits; /// The location of the null pointer literal. SourceLocation Loc; }; class CXXThisExprBitfields { friend class CXXThisExpr; unsigned : NumExprBits; /// Whether this is an implicit "this". unsigned IsImplicit : 1; /// The location of the "this". SourceLocation Loc; }; class CXXThrowExprBitfields { friend class ASTStmtReader; friend class CXXThrowExpr; unsigned : NumExprBits; /// Whether the thrown variable (if any) is in scope. unsigned IsThrownVariableInScope : 1; /// The location of the "throw". SourceLocation ThrowLoc; }; class CXXDefaultArgExprBitfields { friend class ASTStmtReader; friend class CXXDefaultArgExpr; unsigned : NumExprBits; /// The location where the default argument expression was used. SourceLocation Loc; }; class CXXDefaultInitExprBitfields { friend class ASTStmtReader; friend class CXXDefaultInitExpr; unsigned : NumExprBits; /// The location where the default initializer expression was used. SourceLocation Loc; }; class CXXScalarValueInitExprBitfields { friend class ASTStmtReader; friend class CXXScalarValueInitExpr; unsigned : NumExprBits; SourceLocation RParenLoc; }; class CXXNewExprBitfields { friend class ASTStmtReader; friend class ASTStmtWriter; friend class CXXNewExpr; unsigned : NumExprBits; /// Was the usage ::new, i.e. is the global new to be used? unsigned IsGlobalNew : 1; /// Do we allocate an array? If so, the first trailing "Stmt *" is the /// size expression. unsigned IsArray : 1; /// Should the alignment be passed to the allocation function? unsigned ShouldPassAlignment : 1; /// If this is an array allocation, does the usual deallocation /// function for the allocated type want to know the allocated size? unsigned UsualArrayDeleteWantsSize : 1; /// What kind of initializer do we have? Could be none, parens, or braces. /// In storage, we distinguish between "none, and no initializer expr", and /// "none, but an implicit initializer expr". unsigned StoredInitializationStyle : 2; /// True if the allocated type was expressed as a parenthesized type-id. unsigned IsParenTypeId : 1; /// The number of placement new arguments. unsigned NumPlacementArgs; }; class CXXDeleteExprBitfields { friend class ASTStmtReader; friend class CXXDeleteExpr; unsigned : NumExprBits; /// Is this a forced global delete, i.e. "::delete"? unsigned GlobalDelete : 1; /// Is this the array form of delete, i.e. "delete[]"? unsigned ArrayForm : 1; /// ArrayFormAsWritten can be different from ArrayForm if 'delete' is /// applied to pointer-to-array type (ArrayFormAsWritten will be false /// while ArrayForm will be true). unsigned ArrayFormAsWritten : 1; /// Does the usual deallocation function for the element type require /// a size_t argument? unsigned UsualArrayDeleteWantsSize : 1; /// Location of the expression. SourceLocation Loc; }; class TypeTraitExprBitfields { friend class ASTStmtReader; friend class ASTStmtWriter; friend class TypeTraitExpr; unsigned : NumExprBits; /// The kind of type trait, which is a value of a TypeTrait enumerator. unsigned Kind : 8; /// If this expression is not value-dependent, this indicates whether /// the trait evaluated true or false. unsigned Value : 1; /// The number of arguments to this type trait. unsigned NumArgs : 32 - 8 - 1 - NumExprBits; }; class DependentScopeDeclRefExprBitfields { friend class ASTStmtReader; friend class ASTStmtWriter; friend class DependentScopeDeclRefExpr; unsigned : NumExprBits; /// Whether the name includes info for explicit template /// keyword and arguments. unsigned HasTemplateKWAndArgsInfo : 1; }; class CXXConstructExprBitfields { friend class ASTStmtReader; friend class CXXConstructExpr; unsigned : NumExprBits; unsigned Elidable : 1; unsigned HadMultipleCandidates : 1; unsigned ListInitialization : 1; unsigned StdInitListInitialization : 1; unsigned ZeroInitialization : 1; unsigned ConstructionKind : 3; SourceLocation Loc; }; class ExprWithCleanupsBitfields { friend class ASTStmtReader; // deserialization friend class ExprWithCleanups; unsigned : NumExprBits; // When false, it must not have side effects. unsigned CleanupsHaveSideEffects : 1; unsigned NumObjects : 32 - 1 - NumExprBits; }; class CXXUnresolvedConstructExprBitfields { friend class ASTStmtReader; friend class CXXUnresolvedConstructExpr; unsigned : NumExprBits; /// The number of arguments used to construct the type. unsigned NumArgs; }; class CXXDependentScopeMemberExprBitfields { friend class ASTStmtReader; friend class CXXDependentScopeMemberExpr; unsigned : NumExprBits; /// Whether this member expression used the '->' operator or /// the '.' operator. unsigned IsArrow : 1; /// Whether this member expression has info for explicit template /// keyword and arguments. unsigned HasTemplateKWAndArgsInfo : 1; /// See getFirstQualifierFoundInScope() and the comment listing /// the trailing objects. unsigned HasFirstQualifierFoundInScope : 1; /// The location of the '->' or '.' operator. SourceLocation OperatorLoc; }; class OverloadExprBitfields { friend class ASTStmtReader; friend class OverloadExpr; unsigned : NumExprBits; /// Whether the name includes info for explicit template /// keyword and arguments. unsigned HasTemplateKWAndArgsInfo : 1; /// Padding used by the derived classes to store various bits. If you /// need to add some data here, shrink this padding and add your data /// above. NumOverloadExprBits also needs to be updated. unsigned : 32 - NumExprBits - 1; /// The number of results. unsigned NumResults; }; enum { NumOverloadExprBits = NumExprBits + 1 }; class UnresolvedLookupExprBitfields { friend class ASTStmtReader; friend class UnresolvedLookupExpr; unsigned : NumOverloadExprBits; /// True if these lookup results should be extended by /// argument-dependent lookup if this is the operand of a function call. unsigned RequiresADL : 1; /// True if these lookup results are overloaded. This is pretty trivially /// rederivable if we urgently need to kill this field. unsigned Overloaded : 1; }; static_assert(sizeof(UnresolvedLookupExprBitfields) <= 4, "UnresolvedLookupExprBitfields must be <= than 4 bytes to" "avoid trashing OverloadExprBitfields::NumResults!"); class UnresolvedMemberExprBitfields { friend class ASTStmtReader; friend class UnresolvedMemberExpr; unsigned : NumOverloadExprBits; /// Whether this member expression used the '->' operator or /// the '.' operator. unsigned IsArrow : 1; /// Whether the lookup results contain an unresolved using declaration. unsigned HasUnresolvedUsing : 1; }; static_assert(sizeof(UnresolvedMemberExprBitfields) <= 4, "UnresolvedMemberExprBitfields must be <= than 4 bytes to" "avoid trashing OverloadExprBitfields::NumResults!"); class CXXNoexceptExprBitfields { friend class ASTStmtReader; friend class CXXNoexceptExpr; unsigned : NumExprBits; unsigned Value : 1; }; class SubstNonTypeTemplateParmExprBitfields { friend class ASTStmtReader; friend class SubstNonTypeTemplateParmExpr; unsigned : NumExprBits; /// The location of the non-type template parameter reference. SourceLocation NameLoc; }; class RequiresExprBitfields { friend class ASTStmtReader; friend class ASTStmtWriter; friend class RequiresExpr; unsigned : NumExprBits; unsigned IsSatisfied : 1; SourceLocation RequiresKWLoc; }; //===--- C++ Coroutines TS bitfields classes ---===// class CoawaitExprBitfields { friend class CoawaitExpr; unsigned : NumExprBits; unsigned IsImplicit : 1; }; //===--- Obj-C Expression bitfields classes ---===// class ObjCIndirectCopyRestoreExprBitfields { friend class ObjCIndirectCopyRestoreExpr; unsigned : NumExprBits; unsigned ShouldCopy : 1; }; //===--- Clang Extensions bitfields classes ---===// class OpaqueValueExprBitfields { friend class ASTStmtReader; friend class OpaqueValueExpr; unsigned : NumExprBits; /// The OVE is a unique semantic reference to its source expression if this /// bit is set to true. unsigned IsUnique : 1; SourceLocation Loc; }; union { // Same order as in StmtNodes.td. // Statements StmtBitfields StmtBits; NullStmtBitfields NullStmtBits; CompoundStmtBitfields CompoundStmtBits; LabelStmtBitfields LabelStmtBits; AttributedStmtBitfields AttributedStmtBits; IfStmtBitfields IfStmtBits; SwitchStmtBitfields SwitchStmtBits; WhileStmtBitfields WhileStmtBits; DoStmtBitfields DoStmtBits; ForStmtBitfields ForStmtBits; GotoStmtBitfields GotoStmtBits; ContinueStmtBitfields ContinueStmtBits; BreakStmtBitfields BreakStmtBits; ReturnStmtBitfields ReturnStmtBits; SwitchCaseBitfields SwitchCaseBits; // Expressions ExprBitfields ExprBits; ConstantExprBitfields ConstantExprBits; PredefinedExprBitfields PredefinedExprBits; DeclRefExprBitfields DeclRefExprBits; FloatingLiteralBitfields FloatingLiteralBits; StringLiteralBitfields StringLiteralBits; CharacterLiteralBitfields CharacterLiteralBits; UnaryOperatorBitfields UnaryOperatorBits; UnaryExprOrTypeTraitExprBitfields UnaryExprOrTypeTraitExprBits; ArraySubscriptExprBitfields ArraySubscriptExprBits; CallExprBitfields CallExprBits; MemberExprBitfields MemberExprBits; CastExprBitfields CastExprBits; BinaryOperatorBitfields BinaryOperatorBits; InitListExprBitfields InitListExprBits; ParenListExprBitfields ParenListExprBits; GenericSelectionExprBitfields GenericSelectionExprBits; PseudoObjectExprBitfields PseudoObjectExprBits; SourceLocExprBitfields SourceLocExprBits; + + // GNU Extensions. + StmtExprBitfields StmtExprBits; // C++ Expressions CXXOperatorCallExprBitfields CXXOperatorCallExprBits; CXXRewrittenBinaryOperatorBitfields CXXRewrittenBinaryOperatorBits; CXXBoolLiteralExprBitfields CXXBoolLiteralExprBits; CXXNullPtrLiteralExprBitfields CXXNullPtrLiteralExprBits; CXXThisExprBitfields CXXThisExprBits; CXXThrowExprBitfields CXXThrowExprBits; CXXDefaultArgExprBitfields CXXDefaultArgExprBits; CXXDefaultInitExprBitfields CXXDefaultInitExprBits; CXXScalarValueInitExprBitfields CXXScalarValueInitExprBits; CXXNewExprBitfields CXXNewExprBits; CXXDeleteExprBitfields CXXDeleteExprBits; TypeTraitExprBitfields TypeTraitExprBits; DependentScopeDeclRefExprBitfields DependentScopeDeclRefExprBits; CXXConstructExprBitfields CXXConstructExprBits; ExprWithCleanupsBitfields ExprWithCleanupsBits; CXXUnresolvedConstructExprBitfields CXXUnresolvedConstructExprBits; CXXDependentScopeMemberExprBitfields CXXDependentScopeMemberExprBits; OverloadExprBitfields OverloadExprBits; UnresolvedLookupExprBitfields UnresolvedLookupExprBits; UnresolvedMemberExprBitfields UnresolvedMemberExprBits; CXXNoexceptExprBitfields CXXNoexceptExprBits; SubstNonTypeTemplateParmExprBitfields SubstNonTypeTemplateParmExprBits; RequiresExprBitfields RequiresExprBits; // C++ Coroutines TS expressions CoawaitExprBitfields CoawaitBits; // Obj-C Expressions ObjCIndirectCopyRestoreExprBitfields ObjCIndirectCopyRestoreExprBits; // Clang Extensions OpaqueValueExprBitfields OpaqueValueExprBits; }; public: // Only allow allocation of Stmts using the allocator in ASTContext // or by doing a placement new. void* operator new(size_t bytes, const ASTContext& C, unsigned alignment = 8); void* operator new(size_t bytes, const ASTContext* C, unsigned alignment = 8) { return operator new(bytes, *C, alignment); } void *operator new(size_t bytes, void *mem) noexcept { return mem; } void operator delete(void *, const ASTContext &, unsigned) noexcept {} void operator delete(void *, const ASTContext *, unsigned) noexcept {} void operator delete(void *, size_t) noexcept {} void operator delete(void *, void *) noexcept {} public: /// A placeholder type used to construct an empty shell of a /// type, that will be filled in later (e.g., by some /// de-serialization). struct EmptyShell {}; protected: /// Iterator for iterating over Stmt * arrays that contain only T *. /// /// This is needed because AST nodes use Stmt* arrays to store /// references to children (to be compatible with StmtIterator). template struct CastIterator : llvm::iterator_adaptor_base, StmtPtr *, std::random_access_iterator_tag, TPtr> { using Base = typename CastIterator::iterator_adaptor_base; CastIterator() : Base(nullptr) {} CastIterator(StmtPtr *I) : Base(I) {} typename Base::value_type operator*() const { return cast_or_null(*this->I); } }; /// Const iterator for iterating over Stmt * arrays that contain only T *. template using ConstCastIterator = CastIterator; using ExprIterator = CastIterator; using ConstExprIterator = ConstCastIterator; private: /// Whether statistic collection is enabled. static bool StatisticsEnabled; protected: /// Construct an empty statement. explicit Stmt(StmtClass SC, EmptyShell) : Stmt(SC) {} public: Stmt() = delete; Stmt(const Stmt &) = delete; Stmt(Stmt &&) = delete; Stmt &operator=(const Stmt &) = delete; Stmt &operator=(Stmt &&) = delete; Stmt(StmtClass SC) { static_assert(sizeof(*this) <= 8, "changing bitfields changed sizeof(Stmt)"); static_assert(sizeof(*this) % alignof(void *) == 0, "Insufficient alignment!"); StmtBits.sClass = SC; StmtBits.IsOMPStructuredBlock = false; if (StatisticsEnabled) Stmt::addStmtClass(SC); } StmtClass getStmtClass() const { return static_cast(StmtBits.sClass); } const char *getStmtClassName() const; bool isOMPStructuredBlock() const { return StmtBits.IsOMPStructuredBlock; } void setIsOMPStructuredBlock(bool IsOMPStructuredBlock) { StmtBits.IsOMPStructuredBlock = IsOMPStructuredBlock; } /// SourceLocation tokens are not useful in isolation - they are low level /// value objects created/interpreted by SourceManager. We assume AST /// clients will have a pointer to the respective SourceManager. SourceRange getSourceRange() const LLVM_READONLY; SourceLocation getBeginLoc() const LLVM_READONLY; SourceLocation getEndLoc() const LLVM_READONLY; // global temp stats (until we have a per-module visitor) static void addStmtClass(const StmtClass s); static void EnableStatistics(); static void PrintStats(); /// Dumps the specified AST fragment and all subtrees to /// \c llvm::errs(). void dump() const; void dump(SourceManager &SM) const; void dump(raw_ostream &OS, SourceManager &SM) const; void dump(raw_ostream &OS) const; /// \return Unique reproducible object identifier int64_t getID(const ASTContext &Context) const; /// dumpColor - same as dump(), but forces color highlighting. void dumpColor() const; /// dumpPretty/printPretty - These two methods do a "pretty print" of the AST /// back to its original source language syntax. void dumpPretty(const ASTContext &Context) const; void printPretty(raw_ostream &OS, PrinterHelper *Helper, const PrintingPolicy &Policy, unsigned Indentation = 0, StringRef NewlineSymbol = "\n", const ASTContext *Context = nullptr) const; /// Pretty-prints in JSON format. void printJson(raw_ostream &Out, PrinterHelper *Helper, const PrintingPolicy &Policy, bool AddQuotes) const; /// viewAST - Visualize an AST rooted at this Stmt* using GraphViz. Only /// works on systems with GraphViz (Mac OS X) or dot+gv installed. void viewAST() const; /// Skip no-op (attributed, compound) container stmts and skip captured /// stmt at the top, if \a IgnoreCaptured is true. Stmt *IgnoreContainers(bool IgnoreCaptured = false); const Stmt *IgnoreContainers(bool IgnoreCaptured = false) const { return const_cast(this)->IgnoreContainers(IgnoreCaptured); } const Stmt *stripLabelLikeStatements() const; Stmt *stripLabelLikeStatements() { return const_cast( const_cast(this)->stripLabelLikeStatements()); } /// Child Iterators: All subclasses must implement 'children' /// to permit easy iteration over the substatements/subexpessions of an /// AST node. This permits easy iteration over all nodes in the AST. using child_iterator = StmtIterator; using const_child_iterator = ConstStmtIterator; using child_range = llvm::iterator_range; using const_child_range = llvm::iterator_range; child_range children(); const_child_range children() const { auto Children = const_cast(this)->children(); return const_child_range(Children.begin(), Children.end()); } child_iterator child_begin() { return children().begin(); } child_iterator child_end() { return children().end(); } const_child_iterator child_begin() const { return children().begin(); } const_child_iterator child_end() const { return children().end(); } /// Produce a unique representation of the given statement. /// /// \param ID once the profiling operation is complete, will contain /// the unique representation of the given statement. /// /// \param Context the AST context in which the statement resides /// /// \param Canonical whether the profile should be based on the canonical /// representation of this statement (e.g., where non-type template /// parameters are identified by index/level rather than their /// declaration pointers) or the exact representation of the statement as /// written in the source. void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context, bool Canonical) const; /// Calculate a unique representation for a statement that is /// stable across compiler invocations. /// /// \param ID profile information will be stored in ID. /// /// \param Hash an ODRHash object which will be called where pointers would /// have been used in the Profile function. void ProcessODRHash(llvm::FoldingSetNodeID &ID, ODRHash& Hash) const; }; /// DeclStmt - Adaptor class for mixing declarations with statements and /// expressions. For example, CompoundStmt mixes statements, expressions /// and declarations (variables, types). Another example is ForStmt, where /// the first statement can be an expression or a declaration. class DeclStmt : public Stmt { DeclGroupRef DG; SourceLocation StartLoc, EndLoc; public: DeclStmt(DeclGroupRef dg, SourceLocation startLoc, SourceLocation endLoc) : Stmt(DeclStmtClass), DG(dg), StartLoc(startLoc), EndLoc(endLoc) {} /// Build an empty declaration statement. explicit DeclStmt(EmptyShell Empty) : Stmt(DeclStmtClass, Empty) {} /// isSingleDecl - This method returns true if this DeclStmt refers /// to a single Decl. bool isSingleDecl() const { return DG.isSingleDecl(); } const Decl *getSingleDecl() const { return DG.getSingleDecl(); } Decl *getSingleDecl() { return DG.getSingleDecl(); } const DeclGroupRef getDeclGroup() const { return DG; } DeclGroupRef getDeclGroup() { return DG; } void setDeclGroup(DeclGroupRef DGR) { DG = DGR; } void setStartLoc(SourceLocation L) { StartLoc = L; } SourceLocation getEndLoc() const { return EndLoc; } void setEndLoc(SourceLocation L) { EndLoc = L; } SourceLocation getBeginLoc() const LLVM_READONLY { return StartLoc; } static bool classof(const Stmt *T) { return T->getStmtClass() == DeclStmtClass; } // Iterators over subexpressions. child_range children() { return child_range(child_iterator(DG.begin(), DG.end()), child_iterator(DG.end(), DG.end())); } const_child_range children() const { auto Children = const_cast(this)->children(); return const_child_range(Children); } using decl_iterator = DeclGroupRef::iterator; using const_decl_iterator = DeclGroupRef::const_iterator; using decl_range = llvm::iterator_range; using decl_const_range = llvm::iterator_range; decl_range decls() { return decl_range(decl_begin(), decl_end()); } decl_const_range decls() const { return decl_const_range(decl_begin(), decl_end()); } decl_iterator decl_begin() { return DG.begin(); } decl_iterator decl_end() { return DG.end(); } const_decl_iterator decl_begin() const { return DG.begin(); } const_decl_iterator decl_end() const { return DG.end(); } using reverse_decl_iterator = std::reverse_iterator; reverse_decl_iterator decl_rbegin() { return reverse_decl_iterator(decl_end()); } reverse_decl_iterator decl_rend() { return reverse_decl_iterator(decl_begin()); } }; /// NullStmt - This is the null statement ";": C99 6.8.3p3. /// class NullStmt : public Stmt { public: NullStmt(SourceLocation L, bool hasLeadingEmptyMacro = false) : Stmt(NullStmtClass) { NullStmtBits.HasLeadingEmptyMacro = hasLeadingEmptyMacro; setSemiLoc(L); } /// Build an empty null statement. explicit NullStmt(EmptyShell Empty) : Stmt(NullStmtClass, Empty) {} SourceLocation getSemiLoc() const { return NullStmtBits.SemiLoc; } void setSemiLoc(SourceLocation L) { NullStmtBits.SemiLoc = L; } bool hasLeadingEmptyMacro() const { return NullStmtBits.HasLeadingEmptyMacro; } SourceLocation getBeginLoc() const { return getSemiLoc(); } SourceLocation getEndLoc() const { return getSemiLoc(); } static bool classof(const Stmt *T) { return T->getStmtClass() == NullStmtClass; } child_range children() { return child_range(child_iterator(), child_iterator()); } const_child_range children() const { return const_child_range(const_child_iterator(), const_child_iterator()); } }; /// CompoundStmt - This represents a group of statements like { stmt stmt }. class CompoundStmt final : public Stmt, private llvm::TrailingObjects { friend class ASTStmtReader; friend TrailingObjects; /// The location of the closing "}". LBraceLoc is stored in CompoundStmtBits. SourceLocation RBraceLoc; CompoundStmt(ArrayRef Stmts, SourceLocation LB, SourceLocation RB); explicit CompoundStmt(EmptyShell Empty) : Stmt(CompoundStmtClass, Empty) {} void setStmts(ArrayRef Stmts); public: static CompoundStmt *Create(const ASTContext &C, ArrayRef Stmts, SourceLocation LB, SourceLocation RB); // Build an empty compound statement with a location. explicit CompoundStmt(SourceLocation Loc) : Stmt(CompoundStmtClass), RBraceLoc(Loc) { CompoundStmtBits.NumStmts = 0; CompoundStmtBits.LBraceLoc = Loc; } // Build an empty compound statement. static CompoundStmt *CreateEmpty(const ASTContext &C, unsigned NumStmts); bool body_empty() const { return CompoundStmtBits.NumStmts == 0; } unsigned size() const { return CompoundStmtBits.NumStmts; } using body_iterator = Stmt **; using body_range = llvm::iterator_range; body_range body() { return body_range(body_begin(), body_end()); } body_iterator body_begin() { return getTrailingObjects(); } body_iterator body_end() { return body_begin() + size(); } Stmt *body_front() { return !body_empty() ? body_begin()[0] : nullptr; } Stmt *body_back() { return !body_empty() ? body_begin()[size() - 1] : nullptr; } using const_body_iterator = Stmt *const *; using body_const_range = llvm::iterator_range; body_const_range body() const { return body_const_range(body_begin(), body_end()); } const_body_iterator body_begin() const { return getTrailingObjects(); } const_body_iterator body_end() const { return body_begin() + size(); } const Stmt *body_front() const { return !body_empty() ? body_begin()[0] : nullptr; } const Stmt *body_back() const { return !body_empty() ? body_begin()[size() - 1] : nullptr; } using reverse_body_iterator = std::reverse_iterator; reverse_body_iterator body_rbegin() { return reverse_body_iterator(body_end()); } reverse_body_iterator body_rend() { return reverse_body_iterator(body_begin()); } using const_reverse_body_iterator = std::reverse_iterator; const_reverse_body_iterator body_rbegin() const { return const_reverse_body_iterator(body_end()); } const_reverse_body_iterator body_rend() const { return const_reverse_body_iterator(body_begin()); } // Get the Stmt that StmtExpr would consider to be the result of this // compound statement. This is used by StmtExpr to properly emulate the GCC // compound expression extension, which ignores trailing NullStmts when // getting the result of the expression. // i.e. ({ 5;;; }) // ^^ ignored // If we don't find something that isn't a NullStmt, just return the last // Stmt. Stmt *getStmtExprResult() { for (auto *B : llvm::reverse(body())) { if (!isa(B)) return B; } return body_back(); } const Stmt *getStmtExprResult() const { return const_cast(this)->getStmtExprResult(); } SourceLocation getBeginLoc() const { return CompoundStmtBits.LBraceLoc; } SourceLocation getEndLoc() const { return RBraceLoc; } SourceLocation getLBracLoc() const { return CompoundStmtBits.LBraceLoc; } SourceLocation getRBracLoc() const { return RBraceLoc; } static bool classof(const Stmt *T) { return T->getStmtClass() == CompoundStmtClass; } // Iterators child_range children() { return child_range(body_begin(), body_end()); } const_child_range children() const { return const_child_range(body_begin(), body_end()); } }; // SwitchCase is the base class for CaseStmt and DefaultStmt, class SwitchCase : public Stmt { protected: /// The location of the ":". SourceLocation ColonLoc; // The location of the "case" or "default" keyword. Stored in SwitchCaseBits. // SourceLocation KeywordLoc; /// A pointer to the following CaseStmt or DefaultStmt class, /// used by SwitchStmt. SwitchCase *NextSwitchCase = nullptr; SwitchCase(StmtClass SC, SourceLocation KWLoc, SourceLocation ColonLoc) : Stmt(SC), ColonLoc(ColonLoc) { setKeywordLoc(KWLoc); } SwitchCase(StmtClass SC, EmptyShell) : Stmt(SC) {} public: const SwitchCase *getNextSwitchCase() const { return NextSwitchCase; } SwitchCase *getNextSwitchCase() { return NextSwitchCase; } void setNextSwitchCase(SwitchCase *SC) { NextSwitchCase = SC; } SourceLocation getKeywordLoc() const { return SwitchCaseBits.KeywordLoc; } void setKeywordLoc(SourceLocation L) { SwitchCaseBits.KeywordLoc = L; } SourceLocation getColonLoc() const { return ColonLoc; } void setColonLoc(SourceLocation L) { ColonLoc = L; } inline Stmt *getSubStmt(); const Stmt *getSubStmt() const { return const_cast(this)->getSubStmt(); } SourceLocation getBeginLoc() const { return getKeywordLoc(); } inline SourceLocation getEndLoc() const LLVM_READONLY; static bool classof(const Stmt *T) { return T->getStmtClass() == CaseStmtClass || T->getStmtClass() == DefaultStmtClass; } }; /// CaseStmt - Represent a case statement. It can optionally be a GNU case /// statement of the form LHS ... RHS representing a range of cases. class CaseStmt final : public SwitchCase, private llvm::TrailingObjects { friend TrailingObjects; // CaseStmt is followed by several trailing objects, some of which optional. // Note that it would be more convenient to put the optional trailing objects // at the end but this would impact children(). // The trailing objects are in order: // // * A "Stmt *" for the LHS of the case statement. Always present. // // * A "Stmt *" for the RHS of the case statement. This is a GNU extension // which allow ranges in cases statement of the form LHS ... RHS. // Present if and only if caseStmtIsGNURange() is true. // // * A "Stmt *" for the substatement of the case statement. Always present. // // * A SourceLocation for the location of the ... if this is a case statement // with a range. Present if and only if caseStmtIsGNURange() is true. enum { LhsOffset = 0, SubStmtOffsetFromRhs = 1 }; enum { NumMandatoryStmtPtr = 2 }; unsigned numTrailingObjects(OverloadToken) const { return NumMandatoryStmtPtr + caseStmtIsGNURange(); } unsigned numTrailingObjects(OverloadToken) const { return caseStmtIsGNURange(); } unsigned lhsOffset() const { return LhsOffset; } unsigned rhsOffset() const { return LhsOffset + caseStmtIsGNURange(); } unsigned subStmtOffset() const { return rhsOffset() + SubStmtOffsetFromRhs; } /// Build a case statement assuming that the storage for the /// trailing objects has been properly allocated. CaseStmt(Expr *lhs, Expr *rhs, SourceLocation caseLoc, SourceLocation ellipsisLoc, SourceLocation colonLoc) : SwitchCase(CaseStmtClass, caseLoc, colonLoc) { // Handle GNU case statements of the form LHS ... RHS. bool IsGNURange = rhs != nullptr; SwitchCaseBits.CaseStmtIsGNURange = IsGNURange; setLHS(lhs); setSubStmt(nullptr); if (IsGNURange) { setRHS(rhs); setEllipsisLoc(ellipsisLoc); } } /// Build an empty switch case statement. explicit CaseStmt(EmptyShell Empty, bool CaseStmtIsGNURange) : SwitchCase(CaseStmtClass, Empty) { SwitchCaseBits.CaseStmtIsGNURange = CaseStmtIsGNURange; } public: /// Build a case statement. static CaseStmt *Create(const ASTContext &Ctx, Expr *lhs, Expr *rhs, SourceLocation caseLoc, SourceLocation ellipsisLoc, SourceLocation colonLoc); /// Build an empty case statement. static CaseStmt *CreateEmpty(const ASTContext &Ctx, bool CaseStmtIsGNURange); /// True if this case statement is of the form case LHS ... RHS, which /// is a GNU extension. In this case the RHS can be obtained with getRHS() /// and the location of the ellipsis can be obtained with getEllipsisLoc(). bool caseStmtIsGNURange() const { return SwitchCaseBits.CaseStmtIsGNURange; } SourceLocation getCaseLoc() const { return getKeywordLoc(); } void setCaseLoc(SourceLocation L) { setKeywordLoc(L); } /// Get the location of the ... in a case statement of the form LHS ... RHS. SourceLocation getEllipsisLoc() const { return caseStmtIsGNURange() ? *getTrailingObjects() : SourceLocation(); } /// Set the location of the ... in a case statement of the form LHS ... RHS. /// Assert that this case statement is of this form. void setEllipsisLoc(SourceLocation L) { assert( caseStmtIsGNURange() && "setEllipsisLoc but this is not a case stmt of the form LHS ... RHS!"); *getTrailingObjects() = L; } Expr *getLHS() { return reinterpret_cast(getTrailingObjects()[lhsOffset()]); } const Expr *getLHS() const { return reinterpret_cast(getTrailingObjects()[lhsOffset()]); } void setLHS(Expr *Val) { getTrailingObjects()[lhsOffset()] = reinterpret_cast(Val); } Expr *getRHS() { return caseStmtIsGNURange() ? reinterpret_cast( getTrailingObjects()[rhsOffset()]) : nullptr; } const Expr *getRHS() const { return caseStmtIsGNURange() ? reinterpret_cast( getTrailingObjects()[rhsOffset()]) : nullptr; } void setRHS(Expr *Val) { assert(caseStmtIsGNURange() && "setRHS but this is not a case stmt of the form LHS ... RHS!"); getTrailingObjects()[rhsOffset()] = reinterpret_cast(Val); } Stmt *getSubStmt() { return getTrailingObjects()[subStmtOffset()]; } const Stmt *getSubStmt() const { return getTrailingObjects()[subStmtOffset()]; } void setSubStmt(Stmt *S) { getTrailingObjects()[subStmtOffset()] = S; } SourceLocation getBeginLoc() const { return getKeywordLoc(); } SourceLocation getEndLoc() const LLVM_READONLY { // Handle deeply nested case statements with iteration instead of recursion. const CaseStmt *CS = this; while (const auto *CS2 = dyn_cast(CS->getSubStmt())) CS = CS2; return CS->getSubStmt()->getEndLoc(); } static bool classof(const Stmt *T) { return T->getStmtClass() == CaseStmtClass; } // Iterators child_range children() { return child_range(getTrailingObjects(), getTrailingObjects() + numTrailingObjects(OverloadToken())); } const_child_range children() const { return const_child_range(getTrailingObjects(), getTrailingObjects() + numTrailingObjects(OverloadToken())); } }; class DefaultStmt : public SwitchCase { Stmt *SubStmt; public: DefaultStmt(SourceLocation DL, SourceLocation CL, Stmt *substmt) : SwitchCase(DefaultStmtClass, DL, CL), SubStmt(substmt) {} /// Build an empty default statement. explicit DefaultStmt(EmptyShell Empty) : SwitchCase(DefaultStmtClass, Empty) {} Stmt *getSubStmt() { return SubStmt; } const Stmt *getSubStmt() const { return SubStmt; } void setSubStmt(Stmt *S) { SubStmt = S; } SourceLocation getDefaultLoc() const { return getKeywordLoc(); } void setDefaultLoc(SourceLocation L) { setKeywordLoc(L); } SourceLocation getBeginLoc() const { return getKeywordLoc(); } SourceLocation getEndLoc() const LLVM_READONLY { return SubStmt->getEndLoc(); } static bool classof(const Stmt *T) { return T->getStmtClass() == DefaultStmtClass; } // Iterators child_range children() { return child_range(&SubStmt, &SubStmt + 1); } const_child_range children() const { return const_child_range(&SubStmt, &SubStmt + 1); } }; SourceLocation SwitchCase::getEndLoc() const { if (const auto *CS = dyn_cast(this)) return CS->getEndLoc(); else if (const auto *DS = dyn_cast(this)) return DS->getEndLoc(); llvm_unreachable("SwitchCase is neither a CaseStmt nor a DefaultStmt!"); } Stmt *SwitchCase::getSubStmt() { if (auto *CS = dyn_cast(this)) return CS->getSubStmt(); else if (auto *DS = dyn_cast(this)) return DS->getSubStmt(); llvm_unreachable("SwitchCase is neither a CaseStmt nor a DefaultStmt!"); } /// Represents a statement that could possibly have a value and type. This /// covers expression-statements, as well as labels and attributed statements. /// /// Value statements have a special meaning when they are the last non-null /// statement in a GNU statement expression, where they determine the value /// of the statement expression. class ValueStmt : public Stmt { protected: using Stmt::Stmt; public: const Expr *getExprStmt() const; Expr *getExprStmt() { const ValueStmt *ConstThis = this; return const_cast(ConstThis->getExprStmt()); } static bool classof(const Stmt *T) { return T->getStmtClass() >= firstValueStmtConstant && T->getStmtClass() <= lastValueStmtConstant; } }; /// LabelStmt - Represents a label, which has a substatement. For example: /// foo: return; class LabelStmt : public ValueStmt { LabelDecl *TheDecl; Stmt *SubStmt; public: /// Build a label statement. LabelStmt(SourceLocation IL, LabelDecl *D, Stmt *substmt) : ValueStmt(LabelStmtClass), TheDecl(D), SubStmt(substmt) { setIdentLoc(IL); } /// Build an empty label statement. explicit LabelStmt(EmptyShell Empty) : ValueStmt(LabelStmtClass, Empty) {} SourceLocation getIdentLoc() const { return LabelStmtBits.IdentLoc; } void setIdentLoc(SourceLocation L) { LabelStmtBits.IdentLoc = L; } LabelDecl *getDecl() const { return TheDecl; } void setDecl(LabelDecl *D) { TheDecl = D; } const char *getName() const; Stmt *getSubStmt() { return SubStmt; } const Stmt *getSubStmt() const { return SubStmt; } void setSubStmt(Stmt *SS) { SubStmt = SS; } SourceLocation getBeginLoc() const { return getIdentLoc(); } SourceLocation getEndLoc() const LLVM_READONLY { return SubStmt->getEndLoc();} child_range children() { return child_range(&SubStmt, &SubStmt + 1); } const_child_range children() const { return const_child_range(&SubStmt, &SubStmt + 1); } static bool classof(const Stmt *T) { return T->getStmtClass() == LabelStmtClass; } }; /// Represents an attribute applied to a statement. /// /// Represents an attribute applied to a statement. For example: /// [[omp::for(...)]] for (...) { ... } class AttributedStmt final : public ValueStmt, private llvm::TrailingObjects { friend class ASTStmtReader; friend TrailingObjects; Stmt *SubStmt; AttributedStmt(SourceLocation Loc, ArrayRef Attrs, Stmt *SubStmt) : ValueStmt(AttributedStmtClass), SubStmt(SubStmt) { AttributedStmtBits.NumAttrs = Attrs.size(); AttributedStmtBits.AttrLoc = Loc; std::copy(Attrs.begin(), Attrs.end(), getAttrArrayPtr()); } explicit AttributedStmt(EmptyShell Empty, unsigned NumAttrs) : ValueStmt(AttributedStmtClass, Empty) { AttributedStmtBits.NumAttrs = NumAttrs; AttributedStmtBits.AttrLoc = SourceLocation{}; std::fill_n(getAttrArrayPtr(), NumAttrs, nullptr); } const Attr *const *getAttrArrayPtr() const { return getTrailingObjects(); } const Attr **getAttrArrayPtr() { return getTrailingObjects(); } public: static AttributedStmt *Create(const ASTContext &C, SourceLocation Loc, ArrayRef Attrs, Stmt *SubStmt); // Build an empty attributed statement. static AttributedStmt *CreateEmpty(const ASTContext &C, unsigned NumAttrs); SourceLocation getAttrLoc() const { return AttributedStmtBits.AttrLoc; } ArrayRef getAttrs() const { return llvm::makeArrayRef(getAttrArrayPtr(), AttributedStmtBits.NumAttrs); } Stmt *getSubStmt() { return SubStmt; } const Stmt *getSubStmt() const { return SubStmt; } SourceLocation getBeginLoc() const { return getAttrLoc(); } SourceLocation getEndLoc() const LLVM_READONLY { return SubStmt->getEndLoc();} child_range children() { return child_range(&SubStmt, &SubStmt + 1); } const_child_range children() const { return const_child_range(&SubStmt, &SubStmt + 1); } static bool classof(const Stmt *T) { return T->getStmtClass() == AttributedStmtClass; } }; /// IfStmt - This represents an if/then/else. class IfStmt final : public Stmt, private llvm::TrailingObjects { friend TrailingObjects; // IfStmt is followed by several trailing objects, some of which optional. // Note that it would be more convenient to put the optional trailing // objects at then end but this would change the order of the children. // The trailing objects are in order: // // * A "Stmt *" for the init statement. // Present if and only if hasInitStorage(). // // * A "Stmt *" for the condition variable. // Present if and only if hasVarStorage(). This is in fact a "DeclStmt *". // // * A "Stmt *" for the condition. // Always present. This is in fact a "Expr *". // // * A "Stmt *" for the then statement. // Always present. // // * A "Stmt *" for the else statement. // Present if and only if hasElseStorage(). // // * A "SourceLocation" for the location of the "else". // Present if and only if hasElseStorage(). enum { InitOffset = 0, ThenOffsetFromCond = 1, ElseOffsetFromCond = 2 }; enum { NumMandatoryStmtPtr = 2 }; unsigned numTrailingObjects(OverloadToken) const { return NumMandatoryStmtPtr + hasElseStorage() + hasVarStorage() + hasInitStorage(); } unsigned numTrailingObjects(OverloadToken) const { return hasElseStorage(); } unsigned initOffset() const { return InitOffset; } unsigned varOffset() const { return InitOffset + hasInitStorage(); } unsigned condOffset() const { return InitOffset + hasInitStorage() + hasVarStorage(); } unsigned thenOffset() const { return condOffset() + ThenOffsetFromCond; } unsigned elseOffset() const { return condOffset() + ElseOffsetFromCond; } /// Build an if/then/else statement. IfStmt(const ASTContext &Ctx, SourceLocation IL, bool IsConstexpr, Stmt *Init, VarDecl *Var, Expr *Cond, Stmt *Then, SourceLocation EL, Stmt *Else); /// Build an empty if/then/else statement. explicit IfStmt(EmptyShell Empty, bool HasElse, bool HasVar, bool HasInit); public: /// Create an IfStmt. static IfStmt *Create(const ASTContext &Ctx, SourceLocation IL, bool IsConstexpr, Stmt *Init, VarDecl *Var, Expr *Cond, Stmt *Then, SourceLocation EL = SourceLocation(), Stmt *Else = nullptr); /// Create an empty IfStmt optionally with storage for an else statement, /// condition variable and init expression. static IfStmt *CreateEmpty(const ASTContext &Ctx, bool HasElse, bool HasVar, bool HasInit); /// True if this IfStmt has the storage for an init statement. bool hasInitStorage() const { return IfStmtBits.HasInit; } /// True if this IfStmt has storage for a variable declaration. bool hasVarStorage() const { return IfStmtBits.HasVar; } /// True if this IfStmt has storage for an else statement. bool hasElseStorage() const { return IfStmtBits.HasElse; } Expr *getCond() { return reinterpret_cast(getTrailingObjects()[condOffset()]); } const Expr *getCond() const { return reinterpret_cast(getTrailingObjects()[condOffset()]); } void setCond(Expr *Cond) { getTrailingObjects()[condOffset()] = reinterpret_cast(Cond); } Stmt *getThen() { return getTrailingObjects()[thenOffset()]; } const Stmt *getThen() const { return getTrailingObjects()[thenOffset()]; } void setThen(Stmt *Then) { getTrailingObjects()[thenOffset()] = Then; } Stmt *getElse() { return hasElseStorage() ? getTrailingObjects()[elseOffset()] : nullptr; } const Stmt *getElse() const { return hasElseStorage() ? getTrailingObjects()[elseOffset()] : nullptr; } void setElse(Stmt *Else) { assert(hasElseStorage() && "This if statement has no storage for an else statement!"); getTrailingObjects()[elseOffset()] = Else; } /// Retrieve the variable declared in this "if" statement, if any. /// /// In the following example, "x" is the condition variable. /// \code /// if (int x = foo()) { /// printf("x is %d", x); /// } /// \endcode VarDecl *getConditionVariable(); const VarDecl *getConditionVariable() const { return const_cast(this)->getConditionVariable(); } /// Set the condition variable for this if statement. /// The if statement must have storage for the condition variable. void setConditionVariable(const ASTContext &Ctx, VarDecl *V); /// If this IfStmt has a condition variable, return the faux DeclStmt /// associated with the creation of that condition variable. DeclStmt *getConditionVariableDeclStmt() { return hasVarStorage() ? static_cast( getTrailingObjects()[varOffset()]) : nullptr; } const DeclStmt *getConditionVariableDeclStmt() const { return hasVarStorage() ? static_cast( getTrailingObjects()[varOffset()]) : nullptr; } Stmt *getInit() { return hasInitStorage() ? getTrailingObjects()[initOffset()] : nullptr; } const Stmt *getInit() const { return hasInitStorage() ? getTrailingObjects()[initOffset()] : nullptr; } void setInit(Stmt *Init) { assert(hasInitStorage() && "This if statement has no storage for an init statement!"); getTrailingObjects()[initOffset()] = Init; } SourceLocation getIfLoc() const { return IfStmtBits.IfLoc; } void setIfLoc(SourceLocation IfLoc) { IfStmtBits.IfLoc = IfLoc; } SourceLocation getElseLoc() const { return hasElseStorage() ? *getTrailingObjects() : SourceLocation(); } void setElseLoc(SourceLocation ElseLoc) { assert(hasElseStorage() && "This if statement has no storage for an else statement!"); *getTrailingObjects() = ElseLoc; } bool isConstexpr() const { return IfStmtBits.IsConstexpr; } void setConstexpr(bool C) { IfStmtBits.IsConstexpr = C; } /// If this is an 'if constexpr', determine which substatement will be taken. /// Otherwise, or if the condition is value-dependent, returns None. Optional getNondiscardedCase(const ASTContext &Ctx) const; bool isObjCAvailabilityCheck() const; SourceLocation getBeginLoc() const { return getIfLoc(); } SourceLocation getEndLoc() const LLVM_READONLY { if (getElse()) return getElse()->getEndLoc(); return getThen()->getEndLoc(); } // Iterators over subexpressions. The iterators will include iterating // over the initialization expression referenced by the condition variable. child_range children() { return child_range(getTrailingObjects(), getTrailingObjects() + numTrailingObjects(OverloadToken())); } const_child_range children() const { return const_child_range(getTrailingObjects(), getTrailingObjects() + numTrailingObjects(OverloadToken())); } static bool classof(const Stmt *T) { return T->getStmtClass() == IfStmtClass; } }; /// SwitchStmt - This represents a 'switch' stmt. class SwitchStmt final : public Stmt, private llvm::TrailingObjects { friend TrailingObjects; /// Points to a linked list of case and default statements. SwitchCase *FirstCase; // SwitchStmt is followed by several trailing objects, // some of which optional. Note that it would be more convenient to // put the optional trailing objects at the end but this would change // the order in children(). // The trailing objects are in order: // // * A "Stmt *" for the init statement. // Present if and only if hasInitStorage(). // // * A "Stmt *" for the condition variable. // Present if and only if hasVarStorage(). This is in fact a "DeclStmt *". // // * A "Stmt *" for the condition. // Always present. This is in fact an "Expr *". // // * A "Stmt *" for the body. // Always present. enum { InitOffset = 0, BodyOffsetFromCond = 1 }; enum { NumMandatoryStmtPtr = 2 }; unsigned numTrailingObjects(OverloadToken) const { return NumMandatoryStmtPtr + hasInitStorage() + hasVarStorage(); } unsigned initOffset() const { return InitOffset; } unsigned varOffset() const { return InitOffset + hasInitStorage(); } unsigned condOffset() const { return InitOffset + hasInitStorage() + hasVarStorage(); } unsigned bodyOffset() const { return condOffset() + BodyOffsetFromCond; } /// Build a switch statement. SwitchStmt(const ASTContext &Ctx, Stmt *Init, VarDecl *Var, Expr *Cond); /// Build a empty switch statement. explicit SwitchStmt(EmptyShell Empty, bool HasInit, bool HasVar); public: /// Create a switch statement. static SwitchStmt *Create(const ASTContext &Ctx, Stmt *Init, VarDecl *Var, Expr *Cond); /// Create an empty switch statement optionally with storage for /// an init expression and a condition variable. static SwitchStmt *CreateEmpty(const ASTContext &Ctx, bool HasInit, bool HasVar); /// True if this SwitchStmt has storage for an init statement. bool hasInitStorage() const { return SwitchStmtBits.HasInit; } /// True if this SwitchStmt has storage for a condition variable. bool hasVarStorage() const { return SwitchStmtBits.HasVar; } Expr *getCond() { return reinterpret_cast(getTrailingObjects()[condOffset()]); } const Expr *getCond() const { return reinterpret_cast(getTrailingObjects()[condOffset()]); } void setCond(Expr *Cond) { getTrailingObjects()[condOffset()] = reinterpret_cast(Cond); } Stmt *getBody() { return getTrailingObjects()[bodyOffset()]; } const Stmt *getBody() const { return getTrailingObjects()[bodyOffset()]; } void setBody(Stmt *Body) { getTrailingObjects()[bodyOffset()] = Body; } Stmt *getInit() { return hasInitStorage() ? getTrailingObjects()[initOffset()] : nullptr; } const Stmt *getInit() const { return hasInitStorage() ? getTrailingObjects()[initOffset()] : nullptr; } void setInit(Stmt *Init) { assert(hasInitStorage() && "This switch statement has no storage for an init statement!"); getTrailingObjects()[initOffset()] = Init; } /// Retrieve the variable declared in this "switch" statement, if any. /// /// In the following example, "x" is the condition variable. /// \code /// switch (int x = foo()) { /// case 0: break; /// // ... /// } /// \endcode VarDecl *getConditionVariable(); const VarDecl *getConditionVariable() const { return const_cast(this)->getConditionVariable(); } /// Set the condition variable in this switch statement. /// The switch statement must have storage for it. void setConditionVariable(const ASTContext &Ctx, VarDecl *VD); /// If this SwitchStmt has a condition variable, return the faux DeclStmt /// associated with the creation of that condition variable. DeclStmt *getConditionVariableDeclStmt() { return hasVarStorage() ? static_cast( getTrailingObjects()[varOffset()]) : nullptr; } const DeclStmt *getConditionVariableDeclStmt() const { return hasVarStorage() ? static_cast( getTrailingObjects()[varOffset()]) : nullptr; } SwitchCase *getSwitchCaseList() { return FirstCase; } const SwitchCase *getSwitchCaseList() const { return FirstCase; } void setSwitchCaseList(SwitchCase *SC) { FirstCase = SC; } SourceLocation getSwitchLoc() const { return SwitchStmtBits.SwitchLoc; } void setSwitchLoc(SourceLocation L) { SwitchStmtBits.SwitchLoc = L; } void setBody(Stmt *S, SourceLocation SL) { setBody(S); setSwitchLoc(SL); } void addSwitchCase(SwitchCase *SC) { assert(!SC->getNextSwitchCase() && "case/default already added to a switch"); SC->setNextSwitchCase(FirstCase); FirstCase = SC; } /// Set a flag in the SwitchStmt indicating that if the 'switch (X)' is a /// switch over an enum value then all cases have been explicitly covered. void setAllEnumCasesCovered() { SwitchStmtBits.AllEnumCasesCovered = true; } /// Returns true if the SwitchStmt is a switch of an enum value and all cases /// have been explicitly covered. bool isAllEnumCasesCovered() const { return SwitchStmtBits.AllEnumCasesCovered; } SourceLocation getBeginLoc() const { return getSwitchLoc(); } SourceLocation getEndLoc() const LLVM_READONLY { return getBody() ? getBody()->getEndLoc() : reinterpret_cast(getCond())->getEndLoc(); } // Iterators child_range children() { return child_range(getTrailingObjects(), getTrailingObjects() + numTrailingObjects(OverloadToken())); } const_child_range children() const { return const_child_range(getTrailingObjects(), getTrailingObjects() + numTrailingObjects(OverloadToken())); } static bool classof(const Stmt *T) { return T->getStmtClass() == SwitchStmtClass; } }; /// WhileStmt - This represents a 'while' stmt. class WhileStmt final : public Stmt, private llvm::TrailingObjects { friend TrailingObjects; // WhileStmt is followed by several trailing objects, // some of which optional. Note that it would be more // convenient to put the optional trailing object at the end // but this would affect children(). // The trailing objects are in order: // // * A "Stmt *" for the condition variable. // Present if and only if hasVarStorage(). This is in fact a "DeclStmt *". // // * A "Stmt *" for the condition. // Always present. This is in fact an "Expr *". // // * A "Stmt *" for the body. // Always present. // enum { VarOffset = 0, BodyOffsetFromCond = 1 }; enum { NumMandatoryStmtPtr = 2 }; unsigned varOffset() const { return VarOffset; } unsigned condOffset() const { return VarOffset + hasVarStorage(); } unsigned bodyOffset() const { return condOffset() + BodyOffsetFromCond; } unsigned numTrailingObjects(OverloadToken) const { return NumMandatoryStmtPtr + hasVarStorage(); } /// Build a while statement. WhileStmt(const ASTContext &Ctx, VarDecl *Var, Expr *Cond, Stmt *Body, SourceLocation WL); /// Build an empty while statement. explicit WhileStmt(EmptyShell Empty, bool HasVar); public: /// Create a while statement. static WhileStmt *Create(const ASTContext &Ctx, VarDecl *Var, Expr *Cond, Stmt *Body, SourceLocation WL); /// Create an empty while statement optionally with storage for /// a condition variable. static WhileStmt *CreateEmpty(const ASTContext &Ctx, bool HasVar); /// True if this WhileStmt has storage for a condition variable. bool hasVarStorage() const { return WhileStmtBits.HasVar; } Expr *getCond() { return reinterpret_cast(getTrailingObjects()[condOffset()]); } const Expr *getCond() const { return reinterpret_cast(getTrailingObjects()[condOffset()]); } void setCond(Expr *Cond) { getTrailingObjects()[condOffset()] = reinterpret_cast(Cond); } Stmt *getBody() { return getTrailingObjects()[bodyOffset()]; } const Stmt *getBody() const { return getTrailingObjects()[bodyOffset()]; } void setBody(Stmt *Body) { getTrailingObjects()[bodyOffset()] = Body; } /// Retrieve the variable declared in this "while" statement, if any. /// /// In the following example, "x" is the condition variable. /// \code /// while (int x = random()) { /// // ... /// } /// \endcode VarDecl *getConditionVariable(); const VarDecl *getConditionVariable() const { return const_cast(this)->getConditionVariable(); } /// Set the condition variable of this while statement. /// The while statement must have storage for it. void setConditionVariable(const ASTContext &Ctx, VarDecl *V); /// If this WhileStmt has a condition variable, return the faux DeclStmt /// associated with the creation of that condition variable. DeclStmt *getConditionVariableDeclStmt() { return hasVarStorage() ? static_cast( getTrailingObjects()[varOffset()]) : nullptr; } const DeclStmt *getConditionVariableDeclStmt() const { return hasVarStorage() ? static_cast( getTrailingObjects()[varOffset()]) : nullptr; } SourceLocation getWhileLoc() const { return WhileStmtBits.WhileLoc; } void setWhileLoc(SourceLocation L) { WhileStmtBits.WhileLoc = L; } SourceLocation getBeginLoc() const { return getWhileLoc(); } SourceLocation getEndLoc() const LLVM_READONLY { return getBody()->getEndLoc(); } static bool classof(const Stmt *T) { return T->getStmtClass() == WhileStmtClass; } // Iterators child_range children() { return child_range(getTrailingObjects(), getTrailingObjects() + numTrailingObjects(OverloadToken())); } const_child_range children() const { return const_child_range(getTrailingObjects(), getTrailingObjects() + numTrailingObjects(OverloadToken())); } }; /// DoStmt - This represents a 'do/while' stmt. class DoStmt : public Stmt { enum { BODY, COND, END_EXPR }; Stmt *SubExprs[END_EXPR]; SourceLocation WhileLoc; SourceLocation RParenLoc; // Location of final ')' in do stmt condition. public: DoStmt(Stmt *Body, Expr *Cond, SourceLocation DL, SourceLocation WL, SourceLocation RP) : Stmt(DoStmtClass), WhileLoc(WL), RParenLoc(RP) { setCond(Cond); setBody(Body); setDoLoc(DL); } /// Build an empty do-while statement. explicit DoStmt(EmptyShell Empty) : Stmt(DoStmtClass, Empty) {} Expr *getCond() { return reinterpret_cast(SubExprs[COND]); } const Expr *getCond() const { return reinterpret_cast(SubExprs[COND]); } void setCond(Expr *Cond) { SubExprs[COND] = reinterpret_cast(Cond); } Stmt *getBody() { return SubExprs[BODY]; } const Stmt *getBody() const { return SubExprs[BODY]; } void setBody(Stmt *Body) { SubExprs[BODY] = Body; } SourceLocation getDoLoc() const { return DoStmtBits.DoLoc; } void setDoLoc(SourceLocation L) { DoStmtBits.DoLoc = L; } SourceLocation getWhileLoc() const { return WhileLoc; } void setWhileLoc(SourceLocation L) { WhileLoc = L; } SourceLocation getRParenLoc() const { return RParenLoc; } void setRParenLoc(SourceLocation L) { RParenLoc = L; } SourceLocation getBeginLoc() const { return getDoLoc(); } SourceLocation getEndLoc() const { return getRParenLoc(); } static bool classof(const Stmt *T) { return T->getStmtClass() == DoStmtClass; } // Iterators child_range children() { return child_range(&SubExprs[0], &SubExprs[0] + END_EXPR); } const_child_range children() const { return const_child_range(&SubExprs[0], &SubExprs[0] + END_EXPR); } }; /// ForStmt - This represents a 'for (init;cond;inc)' stmt. Note that any of /// the init/cond/inc parts of the ForStmt will be null if they were not /// specified in the source. class ForStmt : public Stmt { enum { INIT, CONDVAR, COND, INC, BODY, END_EXPR }; Stmt* SubExprs[END_EXPR]; // SubExprs[INIT] is an expression or declstmt. SourceLocation LParenLoc, RParenLoc; public: ForStmt(const ASTContext &C, Stmt *Init, Expr *Cond, VarDecl *condVar, Expr *Inc, Stmt *Body, SourceLocation FL, SourceLocation LP, SourceLocation RP); /// Build an empty for statement. explicit ForStmt(EmptyShell Empty) : Stmt(ForStmtClass, Empty) {} Stmt *getInit() { return SubExprs[INIT]; } /// Retrieve the variable declared in this "for" statement, if any. /// /// In the following example, "y" is the condition variable. /// \code /// for (int x = random(); int y = mangle(x); ++x) { /// // ... /// } /// \endcode VarDecl *getConditionVariable() const; void setConditionVariable(const ASTContext &C, VarDecl *V); /// If this ForStmt has a condition variable, return the faux DeclStmt /// associated with the creation of that condition variable. const DeclStmt *getConditionVariableDeclStmt() const { return reinterpret_cast(SubExprs[CONDVAR]); } Expr *getCond() { return reinterpret_cast(SubExprs[COND]); } Expr *getInc() { return reinterpret_cast(SubExprs[INC]); } Stmt *getBody() { return SubExprs[BODY]; } const Stmt *getInit() const { return SubExprs[INIT]; } const Expr *getCond() const { return reinterpret_cast(SubExprs[COND]);} const Expr *getInc() const { return reinterpret_cast(SubExprs[INC]); } const Stmt *getBody() const { return SubExprs[BODY]; } void setInit(Stmt *S) { SubExprs[INIT] = S; } void setCond(Expr *E) { SubExprs[COND] = reinterpret_cast(E); } void setInc(Expr *E) { SubExprs[INC] = reinterpret_cast(E); } void setBody(Stmt *S) { SubExprs[BODY] = S; } SourceLocation getForLoc() const { return ForStmtBits.ForLoc; } void setForLoc(SourceLocation L) { ForStmtBits.ForLoc = L; } SourceLocation getLParenLoc() const { return LParenLoc; } void setLParenLoc(SourceLocation L) { LParenLoc = L; } SourceLocation getRParenLoc() const { return RParenLoc; } void setRParenLoc(SourceLocation L) { RParenLoc = L; } SourceLocation getBeginLoc() const { return getForLoc(); } SourceLocation getEndLoc() const { return getBody()->getEndLoc(); } static bool classof(const Stmt *T) { return T->getStmtClass() == ForStmtClass; } // Iterators child_range children() { return child_range(&SubExprs[0], &SubExprs[0]+END_EXPR); } const_child_range children() const { return const_child_range(&SubExprs[0], &SubExprs[0] + END_EXPR); } }; /// GotoStmt - This represents a direct goto. class GotoStmt : public Stmt { LabelDecl *Label; SourceLocation LabelLoc; public: GotoStmt(LabelDecl *label, SourceLocation GL, SourceLocation LL) : Stmt(GotoStmtClass), Label(label), LabelLoc(LL) { setGotoLoc(GL); } /// Build an empty goto statement. explicit GotoStmt(EmptyShell Empty) : Stmt(GotoStmtClass, Empty) {} LabelDecl *getLabel() const { return Label; } void setLabel(LabelDecl *D) { Label = D; } SourceLocation getGotoLoc() const { return GotoStmtBits.GotoLoc; } void setGotoLoc(SourceLocation L) { GotoStmtBits.GotoLoc = L; } SourceLocation getLabelLoc() const { return LabelLoc; } void setLabelLoc(SourceLocation L) { LabelLoc = L; } SourceLocation getBeginLoc() const { return getGotoLoc(); } SourceLocation getEndLoc() const { return getLabelLoc(); } static bool classof(const Stmt *T) { return T->getStmtClass() == GotoStmtClass; } // Iterators child_range children() { return child_range(child_iterator(), child_iterator()); } const_child_range children() const { return const_child_range(const_child_iterator(), const_child_iterator()); } }; /// IndirectGotoStmt - This represents an indirect goto. class IndirectGotoStmt : public Stmt { SourceLocation StarLoc; Stmt *Target; public: IndirectGotoStmt(SourceLocation gotoLoc, SourceLocation starLoc, Expr *target) : Stmt(IndirectGotoStmtClass), StarLoc(starLoc) { setTarget(target); setGotoLoc(gotoLoc); } /// Build an empty indirect goto statement. explicit IndirectGotoStmt(EmptyShell Empty) : Stmt(IndirectGotoStmtClass, Empty) {} void setGotoLoc(SourceLocation L) { GotoStmtBits.GotoLoc = L; } SourceLocation getGotoLoc() const { return GotoStmtBits.GotoLoc; } void setStarLoc(SourceLocation L) { StarLoc = L; } SourceLocation getStarLoc() const { return StarLoc; } Expr *getTarget() { return reinterpret_cast(Target); } const Expr *getTarget() const { return reinterpret_cast(Target); } void setTarget(Expr *E) { Target = reinterpret_cast(E); } /// getConstantTarget - Returns the fixed target of this indirect /// goto, if one exists. LabelDecl *getConstantTarget(); const LabelDecl *getConstantTarget() const { return const_cast(this)->getConstantTarget(); } SourceLocation getBeginLoc() const { return getGotoLoc(); } SourceLocation getEndLoc() const LLVM_READONLY { return Target->getEndLoc(); } static bool classof(const Stmt *T) { return T->getStmtClass() == IndirectGotoStmtClass; } // Iterators child_range children() { return child_range(&Target, &Target + 1); } const_child_range children() const { return const_child_range(&Target, &Target + 1); } }; /// ContinueStmt - This represents a continue. class ContinueStmt : public Stmt { public: ContinueStmt(SourceLocation CL) : Stmt(ContinueStmtClass) { setContinueLoc(CL); } /// Build an empty continue statement. explicit ContinueStmt(EmptyShell Empty) : Stmt(ContinueStmtClass, Empty) {} SourceLocation getContinueLoc() const { return ContinueStmtBits.ContinueLoc; } void setContinueLoc(SourceLocation L) { ContinueStmtBits.ContinueLoc = L; } SourceLocation getBeginLoc() const { return getContinueLoc(); } SourceLocation getEndLoc() const { return getContinueLoc(); } static bool classof(const Stmt *T) { return T->getStmtClass() == ContinueStmtClass; } // Iterators child_range children() { return child_range(child_iterator(), child_iterator()); } const_child_range children() const { return const_child_range(const_child_iterator(), const_child_iterator()); } }; /// BreakStmt - This represents a break. class BreakStmt : public Stmt { public: BreakStmt(SourceLocation BL) : Stmt(BreakStmtClass) { setBreakLoc(BL); } /// Build an empty break statement. explicit BreakStmt(EmptyShell Empty) : Stmt(BreakStmtClass, Empty) {} SourceLocation getBreakLoc() const { return BreakStmtBits.BreakLoc; } void setBreakLoc(SourceLocation L) { BreakStmtBits.BreakLoc = L; } SourceLocation getBeginLoc() const { return getBreakLoc(); } SourceLocation getEndLoc() const { return getBreakLoc(); } static bool classof(const Stmt *T) { return T->getStmtClass() == BreakStmtClass; } // Iterators child_range children() { return child_range(child_iterator(), child_iterator()); } const_child_range children() const { return const_child_range(const_child_iterator(), const_child_iterator()); } }; /// ReturnStmt - This represents a return, optionally of an expression: /// return; /// return 4; /// /// Note that GCC allows return with no argument in a function declared to /// return a value, and it allows returning a value in functions declared to /// return void. We explicitly model this in the AST, which means you can't /// depend on the return type of the function and the presence of an argument. class ReturnStmt final : public Stmt, private llvm::TrailingObjects { friend TrailingObjects; /// The return expression. Stmt *RetExpr; // ReturnStmt is followed optionally by a trailing "const VarDecl *" // for the NRVO candidate. Present if and only if hasNRVOCandidate(). /// True if this ReturnStmt has storage for an NRVO candidate. bool hasNRVOCandidate() const { return ReturnStmtBits.HasNRVOCandidate; } unsigned numTrailingObjects(OverloadToken) const { return hasNRVOCandidate(); } /// Build a return statement. ReturnStmt(SourceLocation RL, Expr *E, const VarDecl *NRVOCandidate); /// Build an empty return statement. explicit ReturnStmt(EmptyShell Empty, bool HasNRVOCandidate); public: /// Create a return statement. static ReturnStmt *Create(const ASTContext &Ctx, SourceLocation RL, Expr *E, const VarDecl *NRVOCandidate); /// Create an empty return statement, optionally with /// storage for an NRVO candidate. static ReturnStmt *CreateEmpty(const ASTContext &Ctx, bool HasNRVOCandidate); Expr *getRetValue() { return reinterpret_cast(RetExpr); } const Expr *getRetValue() const { return reinterpret_cast(RetExpr); } void setRetValue(Expr *E) { RetExpr = reinterpret_cast(E); } /// Retrieve the variable that might be used for the named return /// value optimization. /// /// The optimization itself can only be performed if the variable is /// also marked as an NRVO object. const VarDecl *getNRVOCandidate() const { return hasNRVOCandidate() ? *getTrailingObjects() : nullptr; } /// Set the variable that might be used for the named return value /// optimization. The return statement must have storage for it, /// which is the case if and only if hasNRVOCandidate() is true. void setNRVOCandidate(const VarDecl *Var) { assert(hasNRVOCandidate() && "This return statement has no storage for an NRVO candidate!"); *getTrailingObjects() = Var; } SourceLocation getReturnLoc() const { return ReturnStmtBits.RetLoc; } void setReturnLoc(SourceLocation L) { ReturnStmtBits.RetLoc = L; } SourceLocation getBeginLoc() const { return getReturnLoc(); } SourceLocation getEndLoc() const LLVM_READONLY { return RetExpr ? RetExpr->getEndLoc() : getReturnLoc(); } static bool classof(const Stmt *T) { return T->getStmtClass() == ReturnStmtClass; } // Iterators child_range children() { if (RetExpr) return child_range(&RetExpr, &RetExpr + 1); return child_range(child_iterator(), child_iterator()); } const_child_range children() const { if (RetExpr) return const_child_range(&RetExpr, &RetExpr + 1); return const_child_range(const_child_iterator(), const_child_iterator()); } }; /// AsmStmt is the base class for GCCAsmStmt and MSAsmStmt. class AsmStmt : public Stmt { protected: friend class ASTStmtReader; SourceLocation AsmLoc; /// True if the assembly statement does not have any input or output /// operands. bool IsSimple; /// If true, treat this inline assembly as having side effects. /// This assembly statement should not be optimized, deleted or moved. bool IsVolatile; unsigned NumOutputs; unsigned NumInputs; unsigned NumClobbers; Stmt **Exprs = nullptr; AsmStmt(StmtClass SC, SourceLocation asmloc, bool issimple, bool isvolatile, unsigned numoutputs, unsigned numinputs, unsigned numclobbers) : Stmt (SC), AsmLoc(asmloc), IsSimple(issimple), IsVolatile(isvolatile), NumOutputs(numoutputs), NumInputs(numinputs), NumClobbers(numclobbers) {} public: /// Build an empty inline-assembly statement. explicit AsmStmt(StmtClass SC, EmptyShell Empty) : Stmt(SC, Empty) {} SourceLocation getAsmLoc() const { return AsmLoc; } void setAsmLoc(SourceLocation L) { AsmLoc = L; } bool isSimple() const { return IsSimple; } void setSimple(bool V) { IsSimple = V; } bool isVolatile() const { return IsVolatile; } void setVolatile(bool V) { IsVolatile = V; } SourceLocation getBeginLoc() const LLVM_READONLY { return {}; } SourceLocation getEndLoc() const LLVM_READONLY { return {}; } //===--- Asm String Analysis ---===// /// Assemble final IR asm string. std::string generateAsmString(const ASTContext &C) const; //===--- Output operands ---===// unsigned getNumOutputs() const { return NumOutputs; } /// getOutputConstraint - Return the constraint string for the specified /// output operand. All output constraints are known to be non-empty (either /// '=' or '+'). StringRef getOutputConstraint(unsigned i) const; /// isOutputPlusConstraint - Return true if the specified output constraint /// is a "+" constraint (which is both an input and an output) or false if it /// is an "=" constraint (just an output). bool isOutputPlusConstraint(unsigned i) const { return getOutputConstraint(i)[0] == '+'; } const Expr *getOutputExpr(unsigned i) const; /// getNumPlusOperands - Return the number of output operands that have a "+" /// constraint. unsigned getNumPlusOperands() const; //===--- Input operands ---===// unsigned getNumInputs() const { return NumInputs; } /// getInputConstraint - Return the specified input constraint. Unlike output /// constraints, these can be empty. StringRef getInputConstraint(unsigned i) const; const Expr *getInputExpr(unsigned i) const; //===--- Other ---===// unsigned getNumClobbers() const { return NumClobbers; } StringRef getClobber(unsigned i) const; static bool classof(const Stmt *T) { return T->getStmtClass() == GCCAsmStmtClass || T->getStmtClass() == MSAsmStmtClass; } // Input expr iterators. using inputs_iterator = ExprIterator; using const_inputs_iterator = ConstExprIterator; using inputs_range = llvm::iterator_range; using inputs_const_range = llvm::iterator_range; inputs_iterator begin_inputs() { return &Exprs[0] + NumOutputs; } inputs_iterator end_inputs() { return &Exprs[0] + NumOutputs + NumInputs; } inputs_range inputs() { return inputs_range(begin_inputs(), end_inputs()); } const_inputs_iterator begin_inputs() const { return &Exprs[0] + NumOutputs; } const_inputs_iterator end_inputs() const { return &Exprs[0] + NumOutputs + NumInputs; } inputs_const_range inputs() const { return inputs_const_range(begin_inputs(), end_inputs()); } // Output expr iterators. using outputs_iterator = ExprIterator; using const_outputs_iterator = ConstExprIterator; using outputs_range = llvm::iterator_range; using outputs_const_range = llvm::iterator_range; outputs_iterator begin_outputs() { return &Exprs[0]; } outputs_iterator end_outputs() { return &Exprs[0] + NumOutputs; } outputs_range outputs() { return outputs_range(begin_outputs(), end_outputs()); } const_outputs_iterator begin_outputs() const { return &Exprs[0]; } const_outputs_iterator end_outputs() const { return &Exprs[0] + NumOutputs; } outputs_const_range outputs() const { return outputs_const_range(begin_outputs(), end_outputs()); } child_range children() { return child_range(&Exprs[0], &Exprs[0] + NumOutputs + NumInputs); } const_child_range children() const { return const_child_range(&Exprs[0], &Exprs[0] + NumOutputs + NumInputs); } }; /// This represents a GCC inline-assembly statement extension. class GCCAsmStmt : public AsmStmt { friend class ASTStmtReader; SourceLocation RParenLoc; StringLiteral *AsmStr; // FIXME: If we wanted to, we could allocate all of these in one big array. StringLiteral **Constraints = nullptr; StringLiteral **Clobbers = nullptr; IdentifierInfo **Names = nullptr; unsigned NumLabels = 0; public: GCCAsmStmt(const ASTContext &C, SourceLocation asmloc, bool issimple, bool isvolatile, unsigned numoutputs, unsigned numinputs, IdentifierInfo **names, StringLiteral **constraints, Expr **exprs, StringLiteral *asmstr, unsigned numclobbers, StringLiteral **clobbers, unsigned numlabels, SourceLocation rparenloc); /// Build an empty inline-assembly statement. explicit GCCAsmStmt(EmptyShell Empty) : AsmStmt(GCCAsmStmtClass, Empty) {} SourceLocation getRParenLoc() const { return RParenLoc; } void setRParenLoc(SourceLocation L) { RParenLoc = L; } //===--- Asm String Analysis ---===// const StringLiteral *getAsmString() const { return AsmStr; } StringLiteral *getAsmString() { return AsmStr; } void setAsmString(StringLiteral *E) { AsmStr = E; } /// AsmStringPiece - this is part of a decomposed asm string specification /// (for use with the AnalyzeAsmString function below). An asm string is /// considered to be a concatenation of these parts. class AsmStringPiece { public: enum Kind { String, // String in .ll asm string form, "$" -> "$$" and "%%" -> "%". Operand // Operand reference, with optional modifier %c4. }; private: Kind MyKind; std::string Str; unsigned OperandNo; // Source range for operand references. CharSourceRange Range; public: AsmStringPiece(const std::string &S) : MyKind(String), Str(S) {} AsmStringPiece(unsigned OpNo, const std::string &S, SourceLocation Begin, SourceLocation End) : MyKind(Operand), Str(S), OperandNo(OpNo), Range(CharSourceRange::getCharRange(Begin, End)) {} bool isString() const { return MyKind == String; } bool isOperand() const { return MyKind == Operand; } const std::string &getString() const { return Str; } unsigned getOperandNo() const { assert(isOperand()); return OperandNo; } CharSourceRange getRange() const { assert(isOperand() && "Range is currently used only for Operands."); return Range; } /// getModifier - Get the modifier for this operand, if present. This /// returns '\0' if there was no modifier. char getModifier() const; }; /// AnalyzeAsmString - Analyze the asm string of the current asm, decomposing /// it into pieces. If the asm string is erroneous, emit errors and return /// true, otherwise return false. This handles canonicalization and /// translation of strings from GCC syntax to LLVM IR syntax, and handles //// flattening of named references like %[foo] to Operand AsmStringPiece's. unsigned AnalyzeAsmString(SmallVectorImpl &Pieces, const ASTContext &C, unsigned &DiagOffs) const; /// Assemble final IR asm string. std::string generateAsmString(const ASTContext &C) const; //===--- Output operands ---===// IdentifierInfo *getOutputIdentifier(unsigned i) const { return Names[i]; } StringRef getOutputName(unsigned i) const { if (IdentifierInfo *II = getOutputIdentifier(i)) return II->getName(); return {}; } StringRef getOutputConstraint(unsigned i) const; const StringLiteral *getOutputConstraintLiteral(unsigned i) const { return Constraints[i]; } StringLiteral *getOutputConstraintLiteral(unsigned i) { return Constraints[i]; } Expr *getOutputExpr(unsigned i); const Expr *getOutputExpr(unsigned i) const { return const_cast(this)->getOutputExpr(i); } //===--- Input operands ---===// IdentifierInfo *getInputIdentifier(unsigned i) const { return Names[i + NumOutputs]; } StringRef getInputName(unsigned i) const { if (IdentifierInfo *II = getInputIdentifier(i)) return II->getName(); return {}; } StringRef getInputConstraint(unsigned i) const; const StringLiteral *getInputConstraintLiteral(unsigned i) const { return Constraints[i + NumOutputs]; } StringLiteral *getInputConstraintLiteral(unsigned i) { return Constraints[i + NumOutputs]; } Expr *getInputExpr(unsigned i); void setInputExpr(unsigned i, Expr *E); const Expr *getInputExpr(unsigned i) const { return const_cast(this)->getInputExpr(i); } //===--- Labels ---===// bool isAsmGoto() const { return NumLabels > 0; } unsigned getNumLabels() const { return NumLabels; } IdentifierInfo *getLabelIdentifier(unsigned i) const { return Names[i + NumInputs]; } AddrLabelExpr *getLabelExpr(unsigned i) const; StringRef getLabelName(unsigned i) const; using labels_iterator = CastIterator; using const_labels_iterator = ConstCastIterator; using labels_range = llvm::iterator_range; using labels_const_range = llvm::iterator_range; labels_iterator begin_labels() { return &Exprs[0] + NumInputs; } labels_iterator end_labels() { return &Exprs[0] + NumInputs + NumLabels; } labels_range labels() { return labels_range(begin_labels(), end_labels()); } const_labels_iterator begin_labels() const { return &Exprs[0] + NumInputs; } const_labels_iterator end_labels() const { return &Exprs[0] + NumInputs + NumLabels; } labels_const_range labels() const { return labels_const_range(begin_labels(), end_labels()); } private: void setOutputsAndInputsAndClobbers(const ASTContext &C, IdentifierInfo **Names, StringLiteral **Constraints, Stmt **Exprs, unsigned NumOutputs, unsigned NumInputs, unsigned NumLabels, StringLiteral **Clobbers, unsigned NumClobbers); public: //===--- Other ---===// /// getNamedOperand - Given a symbolic operand reference like %[foo], /// translate this into a numeric value needed to reference the same operand. /// This returns -1 if the operand name is invalid. int getNamedOperand(StringRef SymbolicName) const; StringRef getClobber(unsigned i) const; StringLiteral *getClobberStringLiteral(unsigned i) { return Clobbers[i]; } const StringLiteral *getClobberStringLiteral(unsigned i) const { return Clobbers[i]; } SourceLocation getBeginLoc() const LLVM_READONLY { return AsmLoc; } SourceLocation getEndLoc() const LLVM_READONLY { return RParenLoc; } static bool classof(const Stmt *T) { return T->getStmtClass() == GCCAsmStmtClass; } }; /// This represents a Microsoft inline-assembly statement extension. class MSAsmStmt : public AsmStmt { friend class ASTStmtReader; SourceLocation LBraceLoc, EndLoc; StringRef AsmStr; unsigned NumAsmToks = 0; Token *AsmToks = nullptr; StringRef *Constraints = nullptr; StringRef *Clobbers = nullptr; public: MSAsmStmt(const ASTContext &C, SourceLocation asmloc, SourceLocation lbraceloc, bool issimple, bool isvolatile, ArrayRef asmtoks, unsigned numoutputs, unsigned numinputs, ArrayRef constraints, ArrayRef exprs, StringRef asmstr, ArrayRef clobbers, SourceLocation endloc); /// Build an empty MS-style inline-assembly statement. explicit MSAsmStmt(EmptyShell Empty) : AsmStmt(MSAsmStmtClass, Empty) {} SourceLocation getLBraceLoc() const { return LBraceLoc; } void setLBraceLoc(SourceLocation L) { LBraceLoc = L; } SourceLocation getEndLoc() const { return EndLoc; } void setEndLoc(SourceLocation L) { EndLoc = L; } bool hasBraces() const { return LBraceLoc.isValid(); } unsigned getNumAsmToks() { return NumAsmToks; } Token *getAsmToks() { return AsmToks; } //===--- Asm String Analysis ---===// StringRef getAsmString() const { return AsmStr; } /// Assemble final IR asm string. std::string generateAsmString(const ASTContext &C) const; //===--- Output operands ---===// StringRef getOutputConstraint(unsigned i) const { assert(i < NumOutputs); return Constraints[i]; } Expr *getOutputExpr(unsigned i); const Expr *getOutputExpr(unsigned i) const { return const_cast(this)->getOutputExpr(i); } //===--- Input operands ---===// StringRef getInputConstraint(unsigned i) const { assert(i < NumInputs); return Constraints[i + NumOutputs]; } Expr *getInputExpr(unsigned i); void setInputExpr(unsigned i, Expr *E); const Expr *getInputExpr(unsigned i) const { return const_cast(this)->getInputExpr(i); } //===--- Other ---===// ArrayRef getAllConstraints() const { return llvm::makeArrayRef(Constraints, NumInputs + NumOutputs); } ArrayRef getClobbers() const { return llvm::makeArrayRef(Clobbers, NumClobbers); } ArrayRef getAllExprs() const { return llvm::makeArrayRef(reinterpret_cast(Exprs), NumInputs + NumOutputs); } StringRef getClobber(unsigned i) const { return getClobbers()[i]; } private: void initialize(const ASTContext &C, StringRef AsmString, ArrayRef AsmToks, ArrayRef Constraints, ArrayRef Exprs, ArrayRef Clobbers); public: SourceLocation getBeginLoc() const LLVM_READONLY { return AsmLoc; } static bool classof(const Stmt *T) { return T->getStmtClass() == MSAsmStmtClass; } child_range children() { return child_range(&Exprs[0], &Exprs[NumInputs + NumOutputs]); } const_child_range children() const { return const_child_range(&Exprs[0], &Exprs[NumInputs + NumOutputs]); } }; class SEHExceptStmt : public Stmt { friend class ASTReader; friend class ASTStmtReader; SourceLocation Loc; Stmt *Children[2]; enum { FILTER_EXPR, BLOCK }; SEHExceptStmt(SourceLocation Loc, Expr *FilterExpr, Stmt *Block); explicit SEHExceptStmt(EmptyShell E) : Stmt(SEHExceptStmtClass, E) {} public: static SEHExceptStmt* Create(const ASTContext &C, SourceLocation ExceptLoc, Expr *FilterExpr, Stmt *Block); SourceLocation getBeginLoc() const LLVM_READONLY { return getExceptLoc(); } SourceLocation getExceptLoc() const { return Loc; } SourceLocation getEndLoc() const { return getBlock()->getEndLoc(); } Expr *getFilterExpr() const { return reinterpret_cast(Children[FILTER_EXPR]); } CompoundStmt *getBlock() const { return cast(Children[BLOCK]); } child_range children() { return child_range(Children, Children+2); } const_child_range children() const { return const_child_range(Children, Children + 2); } static bool classof(const Stmt *T) { return T->getStmtClass() == SEHExceptStmtClass; } }; class SEHFinallyStmt : public Stmt { friend class ASTReader; friend class ASTStmtReader; SourceLocation Loc; Stmt *Block; SEHFinallyStmt(SourceLocation Loc, Stmt *Block); explicit SEHFinallyStmt(EmptyShell E) : Stmt(SEHFinallyStmtClass, E) {} public: static SEHFinallyStmt* Create(const ASTContext &C, SourceLocation FinallyLoc, Stmt *Block); SourceLocation getBeginLoc() const LLVM_READONLY { return getFinallyLoc(); } SourceLocation getFinallyLoc() const { return Loc; } SourceLocation getEndLoc() const { return Block->getEndLoc(); } CompoundStmt *getBlock() const { return cast(Block); } child_range children() { return child_range(&Block,&Block+1); } const_child_range children() const { return const_child_range(&Block, &Block + 1); } static bool classof(const Stmt *T) { return T->getStmtClass() == SEHFinallyStmtClass; } }; class SEHTryStmt : public Stmt { friend class ASTReader; friend class ASTStmtReader; bool IsCXXTry; SourceLocation TryLoc; Stmt *Children[2]; enum { TRY = 0, HANDLER = 1 }; SEHTryStmt(bool isCXXTry, // true if 'try' otherwise '__try' SourceLocation TryLoc, Stmt *TryBlock, Stmt *Handler); explicit SEHTryStmt(EmptyShell E) : Stmt(SEHTryStmtClass, E) {} public: static SEHTryStmt* Create(const ASTContext &C, bool isCXXTry, SourceLocation TryLoc, Stmt *TryBlock, Stmt *Handler); SourceLocation getBeginLoc() const LLVM_READONLY { return getTryLoc(); } SourceLocation getTryLoc() const { return TryLoc; } SourceLocation getEndLoc() const { return Children[HANDLER]->getEndLoc(); } bool getIsCXXTry() const { return IsCXXTry; } CompoundStmt* getTryBlock() const { return cast(Children[TRY]); } Stmt *getHandler() const { return Children[HANDLER]; } /// Returns 0 if not defined SEHExceptStmt *getExceptHandler() const; SEHFinallyStmt *getFinallyHandler() const; child_range children() { return child_range(Children, Children+2); } const_child_range children() const { return const_child_range(Children, Children + 2); } static bool classof(const Stmt *T) { return T->getStmtClass() == SEHTryStmtClass; } }; /// Represents a __leave statement. class SEHLeaveStmt : public Stmt { SourceLocation LeaveLoc; public: explicit SEHLeaveStmt(SourceLocation LL) : Stmt(SEHLeaveStmtClass), LeaveLoc(LL) {} /// Build an empty __leave statement. explicit SEHLeaveStmt(EmptyShell Empty) : Stmt(SEHLeaveStmtClass, Empty) {} SourceLocation getLeaveLoc() const { return LeaveLoc; } void setLeaveLoc(SourceLocation L) { LeaveLoc = L; } SourceLocation getBeginLoc() const LLVM_READONLY { return LeaveLoc; } SourceLocation getEndLoc() const LLVM_READONLY { return LeaveLoc; } static bool classof(const Stmt *T) { return T->getStmtClass() == SEHLeaveStmtClass; } // Iterators child_range children() { return child_range(child_iterator(), child_iterator()); } const_child_range children() const { return const_child_range(const_child_iterator(), const_child_iterator()); } }; /// This captures a statement into a function. For example, the following /// pragma annotated compound statement can be represented as a CapturedStmt, /// and this compound statement is the body of an anonymous outlined function. /// @code /// #pragma omp parallel /// { /// compute(); /// } /// @endcode class CapturedStmt : public Stmt { public: /// The different capture forms: by 'this', by reference, capture for /// variable-length array type etc. enum VariableCaptureKind { VCK_This, VCK_ByRef, VCK_ByCopy, VCK_VLAType, }; /// Describes the capture of either a variable, or 'this', or /// variable-length array type. class Capture { llvm::PointerIntPair VarAndKind; SourceLocation Loc; public: friend class ASTStmtReader; /// Create a new capture. /// /// \param Loc The source location associated with this capture. /// /// \param Kind The kind of capture (this, ByRef, ...). /// /// \param Var The variable being captured, or null if capturing this. Capture(SourceLocation Loc, VariableCaptureKind Kind, VarDecl *Var = nullptr); /// Determine the kind of capture. VariableCaptureKind getCaptureKind() const; /// Retrieve the source location at which the variable or 'this' was /// first used. SourceLocation getLocation() const { return Loc; } /// Determine whether this capture handles the C++ 'this' pointer. bool capturesThis() const { return getCaptureKind() == VCK_This; } /// Determine whether this capture handles a variable (by reference). bool capturesVariable() const { return getCaptureKind() == VCK_ByRef; } /// Determine whether this capture handles a variable by copy. bool capturesVariableByCopy() const { return getCaptureKind() == VCK_ByCopy; } /// Determine whether this capture handles a variable-length array /// type. bool capturesVariableArrayType() const { return getCaptureKind() == VCK_VLAType; } /// Retrieve the declaration of the variable being captured. /// /// This operation is only valid if this capture captures a variable. VarDecl *getCapturedVar() const; }; private: /// The number of variable captured, including 'this'. unsigned NumCaptures; /// The pointer part is the implicit the outlined function and the /// int part is the captured region kind, 'CR_Default' etc. llvm::PointerIntPair CapDeclAndKind; /// The record for captured variables, a RecordDecl or CXXRecordDecl. RecordDecl *TheRecordDecl = nullptr; /// Construct a captured statement. CapturedStmt(Stmt *S, CapturedRegionKind Kind, ArrayRef Captures, ArrayRef CaptureInits, CapturedDecl *CD, RecordDecl *RD); /// Construct an empty captured statement. CapturedStmt(EmptyShell Empty, unsigned NumCaptures); Stmt **getStoredStmts() { return reinterpret_cast(this + 1); } Stmt *const *getStoredStmts() const { return reinterpret_cast(this + 1); } Capture *getStoredCaptures() const; void setCapturedStmt(Stmt *S) { getStoredStmts()[NumCaptures] = S; } public: friend class ASTStmtReader; static CapturedStmt *Create(const ASTContext &Context, Stmt *S, CapturedRegionKind Kind, ArrayRef Captures, ArrayRef CaptureInits, CapturedDecl *CD, RecordDecl *RD); static CapturedStmt *CreateDeserialized(const ASTContext &Context, unsigned NumCaptures); /// Retrieve the statement being captured. Stmt *getCapturedStmt() { return getStoredStmts()[NumCaptures]; } const Stmt *getCapturedStmt() const { return getStoredStmts()[NumCaptures]; } /// Retrieve the outlined function declaration. CapturedDecl *getCapturedDecl(); const CapturedDecl *getCapturedDecl() const; /// Set the outlined function declaration. void setCapturedDecl(CapturedDecl *D); /// Retrieve the captured region kind. CapturedRegionKind getCapturedRegionKind() const; /// Set the captured region kind. void setCapturedRegionKind(CapturedRegionKind Kind); /// Retrieve the record declaration for captured variables. const RecordDecl *getCapturedRecordDecl() const { return TheRecordDecl; } /// Set the record declaration for captured variables. void setCapturedRecordDecl(RecordDecl *D) { assert(D && "null RecordDecl"); TheRecordDecl = D; } /// True if this variable has been captured. bool capturesVariable(const VarDecl *Var) const; /// An iterator that walks over the captures. using capture_iterator = Capture *; using const_capture_iterator = const Capture *; using capture_range = llvm::iterator_range; using capture_const_range = llvm::iterator_range; capture_range captures() { return capture_range(capture_begin(), capture_end()); } capture_const_range captures() const { return capture_const_range(capture_begin(), capture_end()); } /// Retrieve an iterator pointing to the first capture. capture_iterator capture_begin() { return getStoredCaptures(); } const_capture_iterator capture_begin() const { return getStoredCaptures(); } /// Retrieve an iterator pointing past the end of the sequence of /// captures. capture_iterator capture_end() const { return getStoredCaptures() + NumCaptures; } /// Retrieve the number of captures, including 'this'. unsigned capture_size() const { return NumCaptures; } /// Iterator that walks over the capture initialization arguments. using capture_init_iterator = Expr **; using capture_init_range = llvm::iterator_range; /// Const iterator that walks over the capture initialization /// arguments. using const_capture_init_iterator = Expr *const *; using const_capture_init_range = llvm::iterator_range; capture_init_range capture_inits() { return capture_init_range(capture_init_begin(), capture_init_end()); } const_capture_init_range capture_inits() const { return const_capture_init_range(capture_init_begin(), capture_init_end()); } /// Retrieve the first initialization argument. capture_init_iterator capture_init_begin() { return reinterpret_cast(getStoredStmts()); } const_capture_init_iterator capture_init_begin() const { return reinterpret_cast(getStoredStmts()); } /// Retrieve the iterator pointing one past the last initialization /// argument. capture_init_iterator capture_init_end() { return capture_init_begin() + NumCaptures; } const_capture_init_iterator capture_init_end() const { return capture_init_begin() + NumCaptures; } SourceLocation getBeginLoc() const LLVM_READONLY { return getCapturedStmt()->getBeginLoc(); } SourceLocation getEndLoc() const LLVM_READONLY { return getCapturedStmt()->getEndLoc(); } SourceRange getSourceRange() const LLVM_READONLY { return getCapturedStmt()->getSourceRange(); } static bool classof(const Stmt *T) { return T->getStmtClass() == CapturedStmtClass; } child_range children(); const_child_range children() const; }; } // namespace clang #endif // LLVM_CLANG_AST_STMT_H Index: vendor/llvm-project/release-10.x/clang/include/clang/Sema/Sema.h =================================================================== --- vendor/llvm-project/release-10.x/clang/include/clang/Sema/Sema.h (revision 359078) +++ vendor/llvm-project/release-10.x/clang/include/clang/Sema/Sema.h (revision 359079) @@ -1,12117 +1,12154 @@ //===--- Sema.h - Semantic Analysis & AST Building --------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This file defines the Sema class, which performs semantic analysis and // builds ASTs. // //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_SEMA_SEMA_H #define LLVM_CLANG_SEMA_SEMA_H #include "clang/AST/ASTConcept.h" #include "clang/AST/Attr.h" #include "clang/AST/Availability.h" #include "clang/AST/ComparisonCategories.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/DeclarationName.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprConcepts.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/ExprObjC.h" #include "clang/AST/ExternalASTSource.h" #include "clang/AST/LocInfoType.h" #include "clang/AST/MangleNumberingContext.h" #include "clang/AST/NSAPI.h" #include "clang/AST/PrettyPrinter.h" #include "clang/AST/StmtCXX.h" #include "clang/AST/TypeLoc.h" #include "clang/AST/TypeOrdering.h" #include "clang/Basic/BitmaskEnum.h" #include "clang/Basic/ExpressionTraits.h" #include "clang/Basic/Module.h" #include "clang/Basic/OpenMPKinds.h" #include "clang/Basic/PragmaKinds.h" #include "clang/Basic/Specifiers.h" #include "clang/Basic/TemplateKinds.h" #include "clang/Basic/TypeTraits.h" #include "clang/Sema/AnalysisBasedWarnings.h" #include "clang/Sema/CleanupInfo.h" #include "clang/Sema/DeclSpec.h" #include "clang/Sema/ExternalSemaSource.h" #include "clang/Sema/IdentifierResolver.h" #include "clang/Sema/ObjCMethodList.h" #include "clang/Sema/Ownership.h" #include "clang/Sema/Scope.h" #include "clang/Sema/SemaConcept.h" #include "clang/Sema/TypoCorrection.h" #include "clang/Sema/Weak.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/SetVector.h" #include "llvm/ADT/SmallBitVector.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/TinyPtrVector.h" #include "llvm/Frontend/OpenMP/OMPConstants.h" #include #include #include #include #include namespace llvm { class APSInt; template struct DenseMapInfo; template class DenseSet; class SmallBitVector; struct InlineAsmIdentifierInfo; } namespace clang { class ADLResult; class ASTConsumer; class ASTContext; class ASTMutationListener; class ASTReader; class ASTWriter; class ArrayType; class ParsedAttr; class BindingDecl; class BlockDecl; class CapturedDecl; class CXXBasePath; class CXXBasePaths; class CXXBindTemporaryExpr; typedef SmallVector CXXCastPath; class CXXConstructorDecl; class CXXConversionDecl; class CXXDeleteExpr; class CXXDestructorDecl; class CXXFieldCollector; class CXXMemberCallExpr; class CXXMethodDecl; class CXXScopeSpec; class CXXTemporary; class CXXTryStmt; class CallExpr; class ClassTemplateDecl; class ClassTemplatePartialSpecializationDecl; class ClassTemplateSpecializationDecl; class VarTemplatePartialSpecializationDecl; class CodeCompleteConsumer; class CodeCompletionAllocator; class CodeCompletionTUInfo; class CodeCompletionResult; class CoroutineBodyStmt; class Decl; class DeclAccessPair; class DeclContext; class DeclRefExpr; class DeclaratorDecl; class DeducedTemplateArgument; class DependentDiagnostic; class DesignatedInitExpr; class Designation; class EnableIfAttr; class EnumConstantDecl; class Expr; class ExtVectorType; class FormatAttr; class FriendDecl; class FunctionDecl; class FunctionProtoType; class FunctionTemplateDecl; class ImplicitConversionSequence; typedef MutableArrayRef ConversionSequenceList; class InitListExpr; class InitializationKind; class InitializationSequence; class InitializedEntity; class IntegerLiteral; class LabelStmt; class LambdaExpr; class LangOptions; class LocalInstantiationScope; class LookupResult; class MacroInfo; typedef ArrayRef> ModuleIdPath; class ModuleLoader; class MultiLevelTemplateArgumentList; class NamedDecl; class ObjCCategoryDecl; class ObjCCategoryImplDecl; class ObjCCompatibleAliasDecl; class ObjCContainerDecl; class ObjCImplDecl; class ObjCImplementationDecl; class ObjCInterfaceDecl; class ObjCIvarDecl; template class ObjCList; class ObjCMessageExpr; class ObjCMethodDecl; class ObjCPropertyDecl; class ObjCProtocolDecl; class OMPThreadPrivateDecl; class OMPRequiresDecl; class OMPDeclareReductionDecl; class OMPDeclareSimdDecl; class OMPClause; struct OMPVarListLocTy; struct OverloadCandidate; enum class OverloadCandidateParamOrder : char; enum OverloadCandidateRewriteKind : unsigned; class OverloadCandidateSet; class OverloadExpr; class ParenListExpr; class ParmVarDecl; class Preprocessor; class PseudoDestructorTypeStorage; class PseudoObjectExpr; class QualType; class StandardConversionSequence; class Stmt; class StringLiteral; class SwitchStmt; class TemplateArgument; class TemplateArgumentList; class TemplateArgumentLoc; class TemplateDecl; class TemplateInstantiationCallback; class TemplateParameterList; class TemplatePartialOrderingContext; class TemplateTemplateParmDecl; class Token; class TypeAliasDecl; class TypedefDecl; class TypedefNameDecl; class TypeLoc; class TypoCorrectionConsumer; class UnqualifiedId; class UnresolvedLookupExpr; class UnresolvedMemberExpr; class UnresolvedSetImpl; class UnresolvedSetIterator; class UsingDecl; class UsingShadowDecl; class ValueDecl; class VarDecl; class VarTemplateSpecializationDecl; class VisibilityAttr; class VisibleDeclConsumer; class IndirectFieldDecl; struct DeductionFailureInfo; class TemplateSpecCandidateSet; namespace sema { class AccessedEntity; class BlockScopeInfo; class Capture; class CapturedRegionScopeInfo; class CapturingScopeInfo; class CompoundScopeInfo; class DelayedDiagnostic; class DelayedDiagnosticPool; class FunctionScopeInfo; class LambdaScopeInfo; class PossiblyUnreachableDiag; class SemaPPCallbacks; class TemplateDeductionInfo; } namespace threadSafety { class BeforeSet; void threadSafetyCleanup(BeforeSet* Cache); } // FIXME: No way to easily map from TemplateTypeParmTypes to // TemplateTypeParmDecls, so we have this horrible PointerUnion. typedef std::pair, SourceLocation> UnexpandedParameterPack; /// Describes whether we've seen any nullability information for the given /// file. struct FileNullability { /// The first pointer declarator (of any pointer kind) in the file that does /// not have a corresponding nullability annotation. SourceLocation PointerLoc; /// The end location for the first pointer declarator in the file. Used for /// placing fix-its. SourceLocation PointerEndLoc; /// Which kind of pointer declarator we saw. uint8_t PointerKind; /// Whether we saw any type nullability annotations in the given file. bool SawTypeNullability = false; }; /// A mapping from file IDs to a record of whether we've seen nullability /// information in that file. class FileNullabilityMap { /// A mapping from file IDs to the nullability information for each file ID. llvm::DenseMap Map; /// A single-element cache based on the file ID. struct { FileID File; FileNullability Nullability; } Cache; public: FileNullability &operator[](FileID file) { // Check the single-element cache. if (file == Cache.File) return Cache.Nullability; // It's not in the single-element cache; flush the cache if we have one. if (!Cache.File.isInvalid()) { Map[Cache.File] = Cache.Nullability; } // Pull this entry into the cache. Cache.File = file; Cache.Nullability = Map[file]; return Cache.Nullability; } }; /// Keeps track of expected type during expression parsing. The type is tied to /// a particular token, all functions that update or consume the type take a /// start location of the token they are looking at as a parameter. This allows /// to avoid updating the type on hot paths in the parser. class PreferredTypeBuilder { public: PreferredTypeBuilder() = default; explicit PreferredTypeBuilder(QualType Type) : Type(Type) {} void enterCondition(Sema &S, SourceLocation Tok); void enterReturn(Sema &S, SourceLocation Tok); void enterVariableInit(SourceLocation Tok, Decl *D); /// Computing a type for the function argument may require running /// overloading, so we postpone its computation until it is actually needed. /// /// Clients should be very careful when using this funciton, as it stores a /// function_ref, clients should make sure all calls to get() with the same /// location happen while function_ref is alive. void enterFunctionArgument(SourceLocation Tok, llvm::function_ref ComputeType); void enterParenExpr(SourceLocation Tok, SourceLocation LParLoc); void enterUnary(Sema &S, SourceLocation Tok, tok::TokenKind OpKind, SourceLocation OpLoc); void enterBinary(Sema &S, SourceLocation Tok, Expr *LHS, tok::TokenKind Op); void enterMemAccess(Sema &S, SourceLocation Tok, Expr *Base); void enterSubscript(Sema &S, SourceLocation Tok, Expr *LHS); /// Handles all type casts, including C-style cast, C++ casts, etc. void enterTypeCast(SourceLocation Tok, QualType CastType); QualType get(SourceLocation Tok) const { if (Tok != ExpectedLoc) return QualType(); if (!Type.isNull()) return Type; if (ComputeType) return ComputeType(); return QualType(); } private: /// Start position of a token for which we store expected type. SourceLocation ExpectedLoc; /// Expected type for a token starting at ExpectedLoc. QualType Type; /// A function to compute expected type at ExpectedLoc. It is only considered /// if Type is null. llvm::function_ref ComputeType; }; /// Sema - This implements semantic analysis and AST building for C. class Sema final { Sema(const Sema &) = delete; void operator=(const Sema &) = delete; /// A key method to reduce duplicate debug info from Sema. virtual void anchor(); ///Source of additional semantic information. ExternalSemaSource *ExternalSource; ///Whether Sema has generated a multiplexer and has to delete it. bool isMultiplexExternalSource; static bool mightHaveNonExternalLinkage(const DeclaratorDecl *FD); bool isVisibleSlow(const NamedDecl *D); /// Determine whether two declarations should be linked together, given that /// the old declaration might not be visible and the new declaration might /// not have external linkage. bool shouldLinkPossiblyHiddenDecl(const NamedDecl *Old, const NamedDecl *New) { if (isVisible(Old)) return true; // See comment in below overload for why it's safe to compute the linkage // of the new declaration here. if (New->isExternallyDeclarable()) { assert(Old->isExternallyDeclarable() && "should not have found a non-externally-declarable previous decl"); return true; } return false; } bool shouldLinkPossiblyHiddenDecl(LookupResult &Old, const NamedDecl *New); void setupImplicitSpecialMemberType(CXXMethodDecl *SpecialMem, QualType ResultTy, ArrayRef Args); public: typedef OpaquePtr DeclGroupPtrTy; typedef OpaquePtr TemplateTy; typedef OpaquePtr TypeTy; OpenCLOptions OpenCLFeatures; FPOptions FPFeatures; const LangOptions &LangOpts; Preprocessor &PP; ASTContext &Context; ASTConsumer &Consumer; DiagnosticsEngine &Diags; SourceManager &SourceMgr; /// Flag indicating whether or not to collect detailed statistics. bool CollectStats; /// Code-completion consumer. CodeCompleteConsumer *CodeCompleter; /// CurContext - This is the current declaration context of parsing. DeclContext *CurContext; /// Generally null except when we temporarily switch decl contexts, /// like in \see ActOnObjCTemporaryExitContainerContext. DeclContext *OriginalLexicalContext; /// VAListTagName - The declaration name corresponding to __va_list_tag. /// This is used as part of a hack to omit that class from ADL results. DeclarationName VAListTagName; bool MSStructPragmaOn; // True when \#pragma ms_struct on /// Controls member pointer representation format under the MS ABI. LangOptions::PragmaMSPointersToMembersKind MSPointerToMemberRepresentationMethod; /// Stack of active SEH __finally scopes. Can be empty. SmallVector CurrentSEHFinally; /// Source location for newly created implicit MSInheritanceAttrs SourceLocation ImplicitMSInheritanceAttrLoc; /// Holds TypoExprs that are created from `createDelayedTypo`. This is used by /// `TransformTypos` in order to keep track of any TypoExprs that are created /// recursively during typo correction and wipe them away if the correction /// fails. llvm::SmallVector TypoExprs; /// pragma clang section kind enum PragmaClangSectionKind { PCSK_Invalid = 0, PCSK_BSS = 1, PCSK_Data = 2, PCSK_Rodata = 3, PCSK_Text = 4, PCSK_Relro = 5 }; enum PragmaClangSectionAction { PCSA_Set = 0, PCSA_Clear = 1 }; struct PragmaClangSection { std::string SectionName; bool Valid = false; SourceLocation PragmaLocation; void Act(SourceLocation PragmaLocation, PragmaClangSectionAction Action, StringLiteral* Name); }; PragmaClangSection PragmaClangBSSSection; PragmaClangSection PragmaClangDataSection; PragmaClangSection PragmaClangRodataSection; PragmaClangSection PragmaClangRelroSection; PragmaClangSection PragmaClangTextSection; enum PragmaMsStackAction { PSK_Reset = 0x0, // #pragma () PSK_Set = 0x1, // #pragma (value) PSK_Push = 0x2, // #pragma (push[, id]) PSK_Pop = 0x4, // #pragma (pop[, id]) PSK_Show = 0x8, // #pragma (show) -- only for "pack"! PSK_Push_Set = PSK_Push | PSK_Set, // #pragma (push[, id], value) PSK_Pop_Set = PSK_Pop | PSK_Set, // #pragma (pop[, id], value) }; template struct PragmaStack { struct Slot { llvm::StringRef StackSlotLabel; ValueType Value; SourceLocation PragmaLocation; SourceLocation PragmaPushLocation; Slot(llvm::StringRef StackSlotLabel, ValueType Value, SourceLocation PragmaLocation, SourceLocation PragmaPushLocation) : StackSlotLabel(StackSlotLabel), Value(Value), PragmaLocation(PragmaLocation), PragmaPushLocation(PragmaPushLocation) {} }; void Act(SourceLocation PragmaLocation, PragmaMsStackAction Action, llvm::StringRef StackSlotLabel, ValueType Value); // MSVC seems to add artificial slots to #pragma stacks on entering a C++ // method body to restore the stacks on exit, so it works like this: // // struct S { // #pragma (push, InternalPragmaSlot, ) // void Method {} // #pragma (pop, InternalPragmaSlot) // }; // // It works even with #pragma vtordisp, although MSVC doesn't support // #pragma vtordisp(push [, id], n) // syntax. // // Push / pop a named sentinel slot. void SentinelAction(PragmaMsStackAction Action, StringRef Label) { assert((Action == PSK_Push || Action == PSK_Pop) && "Can only push / pop #pragma stack sentinels!"); Act(CurrentPragmaLocation, Action, Label, CurrentValue); } // Constructors. explicit PragmaStack(const ValueType &Default) : DefaultValue(Default), CurrentValue(Default) {} bool hasValue() const { return CurrentValue != DefaultValue; } SmallVector Stack; ValueType DefaultValue; // Value used for PSK_Reset action. ValueType CurrentValue; SourceLocation CurrentPragmaLocation; }; // FIXME: We should serialize / deserialize these if they occur in a PCH (but // we shouldn't do so if they're in a module). /// Whether to insert vtordisps prior to virtual bases in the Microsoft /// C++ ABI. Possible values are 0, 1, and 2, which mean: /// /// 0: Suppress all vtordisps /// 1: Insert vtordisps in the presence of vbase overrides and non-trivial /// structors /// 2: Always insert vtordisps to support RTTI on partially constructed /// objects PragmaStack VtorDispStack; // #pragma pack. // Sentinel to represent when the stack is set to mac68k alignment. static const unsigned kMac68kAlignmentSentinel = ~0U; PragmaStack PackStack; // The current #pragma pack values and locations at each #include. struct PackIncludeState { unsigned CurrentValue; SourceLocation CurrentPragmaLocation; bool HasNonDefaultValue, ShouldWarnOnInclude; }; SmallVector PackIncludeStack; // Segment #pragmas. PragmaStack DataSegStack; PragmaStack BSSSegStack; PragmaStack ConstSegStack; PragmaStack CodeSegStack; // RAII object to push / pop sentinel slots for all MS #pragma stacks. // Actions should be performed only if we enter / exit a C++ method body. class PragmaStackSentinelRAII { public: PragmaStackSentinelRAII(Sema &S, StringRef SlotLabel, bool ShouldAct); ~PragmaStackSentinelRAII(); private: Sema &S; StringRef SlotLabel; bool ShouldAct; }; /// A mapping that describes the nullability we've seen in each header file. FileNullabilityMap NullabilityMap; /// Last section used with #pragma init_seg. StringLiteral *CurInitSeg; SourceLocation CurInitSegLoc; /// VisContext - Manages the stack for \#pragma GCC visibility. void *VisContext; // Really a "PragmaVisStack*" /// This an attribute introduced by \#pragma clang attribute. struct PragmaAttributeEntry { SourceLocation Loc; ParsedAttr *Attribute; SmallVector MatchRules; bool IsUsed; }; /// A push'd group of PragmaAttributeEntries. struct PragmaAttributeGroup { /// The location of the push attribute. SourceLocation Loc; /// The namespace of this push group. const IdentifierInfo *Namespace; SmallVector Entries; }; SmallVector PragmaAttributeStack; /// The declaration that is currently receiving an attribute from the /// #pragma attribute stack. const Decl *PragmaAttributeCurrentTargetDecl; /// This represents the last location of a "#pragma clang optimize off" /// directive if such a directive has not been closed by an "on" yet. If /// optimizations are currently "on", this is set to an invalid location. SourceLocation OptimizeOffPragmaLocation; /// Flag indicating if Sema is building a recovery call expression. /// /// This flag is used to avoid building recovery call expressions /// if Sema is already doing so, which would cause infinite recursions. bool IsBuildingRecoveryCallExpr; /// Used to control the generation of ExprWithCleanups. CleanupInfo Cleanup; /// ExprCleanupObjects - This is the stack of objects requiring /// cleanup that are created by the current full expression. The /// element type here is ExprWithCleanups::Object. SmallVector ExprCleanupObjects; /// Store a set of either DeclRefExprs or MemberExprs that contain a reference /// to a variable (constant) that may or may not be odr-used in this Expr, and /// we won't know until all lvalue-to-rvalue and discarded value conversions /// have been applied to all subexpressions of the enclosing full expression. /// This is cleared at the end of each full expression. using MaybeODRUseExprSet = llvm::SmallPtrSet; MaybeODRUseExprSet MaybeODRUseExprs; std::unique_ptr CachedFunctionScope; /// Stack containing information about each of the nested /// function, block, and method scopes that are currently active. SmallVector FunctionScopes; + /// The index of the first FunctionScope that corresponds to the current + /// context. + unsigned FunctionScopesStart = 0; + + ArrayRef getFunctionScopes() const { + return llvm::makeArrayRef(FunctionScopes.begin() + FunctionScopesStart, + FunctionScopes.end()); + } + /// Stack containing information needed when in C++2a an 'auto' is encountered /// in a function declaration parameter type specifier in order to invent a /// corresponding template parameter in the enclosing abbreviated function /// template. This information is also present in LambdaScopeInfo, stored in /// the FunctionScopes stack. SmallVector InventedParameterInfos; + /// The index of the first InventedParameterInfo that refers to the current + /// context. + unsigned InventedParameterInfosStart = 0; + + ArrayRef getInventedParameterInfos() const { + return llvm::makeArrayRef(InventedParameterInfos.begin() + + InventedParameterInfosStart, + InventedParameterInfos.end()); + } + typedef LazyVector ExtVectorDeclsType; /// ExtVectorDecls - This is a list all the extended vector types. This allows /// us to associate a raw vector type with one of the ext_vector type names. /// This is only necessary for issuing pretty diagnostics. ExtVectorDeclsType ExtVectorDecls; /// FieldCollector - Collects CXXFieldDecls during parsing of C++ classes. std::unique_ptr FieldCollector; typedef llvm::SmallSetVector NamedDeclSetType; /// Set containing all declared private fields that are not used. NamedDeclSetType UnusedPrivateFields; /// Set containing all typedefs that are likely unused. llvm::SmallSetVector UnusedLocalTypedefNameCandidates; /// Delete-expressions to be analyzed at the end of translation unit /// /// This list contains class members, and locations of delete-expressions /// that could not be proven as to whether they mismatch with new-expression /// used in initializer of the field. typedef std::pair DeleteExprLoc; typedef llvm::SmallVector DeleteLocs; llvm::MapVector DeleteExprs; typedef llvm::SmallPtrSet RecordDeclSetTy; /// PureVirtualClassDiagSet - a set of class declarations which we have /// emitted a list of pure virtual functions. Used to prevent emitting the /// same list more than once. std::unique_ptr PureVirtualClassDiagSet; /// ParsingInitForAutoVars - a set of declarations with auto types for which /// we are currently parsing the initializer. llvm::SmallPtrSet ParsingInitForAutoVars; /// Look for a locally scoped extern "C" declaration by the given name. NamedDecl *findLocallyScopedExternCDecl(DeclarationName Name); typedef LazyVector TentativeDefinitionsType; /// All the tentative definitions encountered in the TU. TentativeDefinitionsType TentativeDefinitions; /// All the external declarations encoutered and used in the TU. SmallVector ExternalDeclarations; typedef LazyVector UnusedFileScopedDeclsType; /// The set of file scoped decls seen so far that have not been used /// and must warn if not used. Only contains the first declaration. UnusedFileScopedDeclsType UnusedFileScopedDecls; typedef LazyVector DelegatingCtorDeclsType; /// All the delegating constructors seen so far in the file, used for /// cycle detection at the end of the TU. DelegatingCtorDeclsType DelegatingCtorDecls; /// All the overriding functions seen during a class definition /// that had their exception spec checks delayed, plus the overridden /// function. SmallVector, 2> DelayedOverridingExceptionSpecChecks; /// All the function redeclarations seen during a class definition that had /// their exception spec checks delayed, plus the prior declaration they /// should be checked against. Except during error recovery, the new decl /// should always be a friend declaration, as that's the only valid way to /// redeclare a special member before its class is complete. SmallVector, 2> DelayedEquivalentExceptionSpecChecks; typedef llvm::MapVector> LateParsedTemplateMapT; LateParsedTemplateMapT LateParsedTemplateMap; /// Callback to the parser to parse templated functions when needed. typedef void LateTemplateParserCB(void *P, LateParsedTemplate &LPT); typedef void LateTemplateParserCleanupCB(void *P); LateTemplateParserCB *LateTemplateParser; LateTemplateParserCleanupCB *LateTemplateParserCleanup; void *OpaqueParser; void SetLateTemplateParser(LateTemplateParserCB *LTP, LateTemplateParserCleanupCB *LTPCleanup, void *P) { LateTemplateParser = LTP; LateTemplateParserCleanup = LTPCleanup; OpaqueParser = P; } class DelayedDiagnostics; class DelayedDiagnosticsState { sema::DelayedDiagnosticPool *SavedPool; friend class Sema::DelayedDiagnostics; }; typedef DelayedDiagnosticsState ParsingDeclState; typedef DelayedDiagnosticsState ProcessingContextState; /// A class which encapsulates the logic for delaying diagnostics /// during parsing and other processing. class DelayedDiagnostics { /// The current pool of diagnostics into which delayed /// diagnostics should go. sema::DelayedDiagnosticPool *CurPool; public: DelayedDiagnostics() : CurPool(nullptr) {} /// Adds a delayed diagnostic. void add(const sema::DelayedDiagnostic &diag); // in DelayedDiagnostic.h /// Determines whether diagnostics should be delayed. bool shouldDelayDiagnostics() { return CurPool != nullptr; } /// Returns the current delayed-diagnostics pool. sema::DelayedDiagnosticPool *getCurrentPool() const { return CurPool; } /// Enter a new scope. Access and deprecation diagnostics will be /// collected in this pool. DelayedDiagnosticsState push(sema::DelayedDiagnosticPool &pool) { DelayedDiagnosticsState state; state.SavedPool = CurPool; CurPool = &pool; return state; } /// Leave a delayed-diagnostic state that was previously pushed. /// Do not emit any of the diagnostics. This is performed as part /// of the bookkeeping of popping a pool "properly". void popWithoutEmitting(DelayedDiagnosticsState state) { CurPool = state.SavedPool; } /// Enter a new scope where access and deprecation diagnostics are /// not delayed. DelayedDiagnosticsState pushUndelayed() { DelayedDiagnosticsState state; state.SavedPool = CurPool; CurPool = nullptr; return state; } /// Undo a previous pushUndelayed(). void popUndelayed(DelayedDiagnosticsState state) { assert(CurPool == nullptr); CurPool = state.SavedPool; } } DelayedDiagnostics; /// A RAII object to temporarily push a declaration context. class ContextRAII { private: Sema &S; DeclContext *SavedContext; ProcessingContextState SavedContextState; QualType SavedCXXThisTypeOverride; + unsigned SavedFunctionScopesStart; + unsigned SavedInventedParameterInfosStart; public: ContextRAII(Sema &S, DeclContext *ContextToPush, bool NewThisContext = true) : S(S), SavedContext(S.CurContext), SavedContextState(S.DelayedDiagnostics.pushUndelayed()), - SavedCXXThisTypeOverride(S.CXXThisTypeOverride) + SavedCXXThisTypeOverride(S.CXXThisTypeOverride), + SavedFunctionScopesStart(S.FunctionScopesStart), + SavedInventedParameterInfosStart(S.InventedParameterInfosStart) { assert(ContextToPush && "pushing null context"); S.CurContext = ContextToPush; if (NewThisContext) S.CXXThisTypeOverride = QualType(); + // Any saved FunctionScopes do not refer to this context. + S.FunctionScopesStart = S.FunctionScopes.size(); + S.InventedParameterInfosStart = S.InventedParameterInfos.size(); } void pop() { if (!SavedContext) return; S.CurContext = SavedContext; S.DelayedDiagnostics.popUndelayed(SavedContextState); S.CXXThisTypeOverride = SavedCXXThisTypeOverride; + S.FunctionScopesStart = SavedFunctionScopesStart; + S.InventedParameterInfosStart = SavedInventedParameterInfosStart; SavedContext = nullptr; } ~ContextRAII() { pop(); } }; /// Used to change context to isConstantEvaluated without pushing a heavy /// ExpressionEvaluationContextRecord object. bool isConstantEvaluatedOverride; bool isConstantEvaluated() { return ExprEvalContexts.back().isConstantEvaluated() || isConstantEvaluatedOverride; } /// RAII object to handle the state changes required to synthesize /// a function body. class SynthesizedFunctionScope { Sema &S; Sema::ContextRAII SavedContext; bool PushedCodeSynthesisContext = false; public: SynthesizedFunctionScope(Sema &S, DeclContext *DC) : S(S), SavedContext(S, DC) { S.PushFunctionScope(); S.PushExpressionEvaluationContext( Sema::ExpressionEvaluationContext::PotentiallyEvaluated); if (auto *FD = dyn_cast(DC)) FD->setWillHaveBody(true); else assert(isa(DC)); } void addContextNote(SourceLocation UseLoc) { assert(!PushedCodeSynthesisContext); Sema::CodeSynthesisContext Ctx; Ctx.Kind = Sema::CodeSynthesisContext::DefiningSynthesizedFunction; Ctx.PointOfInstantiation = UseLoc; Ctx.Entity = cast(S.CurContext); S.pushCodeSynthesisContext(Ctx); PushedCodeSynthesisContext = true; } ~SynthesizedFunctionScope() { if (PushedCodeSynthesisContext) S.popCodeSynthesisContext(); if (auto *FD = dyn_cast(S.CurContext)) FD->setWillHaveBody(false); S.PopExpressionEvaluationContext(); S.PopFunctionScopeInfo(); } }; /// WeakUndeclaredIdentifiers - Identifiers contained in /// \#pragma weak before declared. rare. may alias another /// identifier, declared or undeclared llvm::MapVector WeakUndeclaredIdentifiers; /// ExtnameUndeclaredIdentifiers - Identifiers contained in /// \#pragma redefine_extname before declared. Used in Solaris system headers /// to define functions that occur in multiple standards to call the version /// in the currently selected standard. llvm::DenseMap ExtnameUndeclaredIdentifiers; /// Load weak undeclared identifiers from the external source. void LoadExternalWeakUndeclaredIdentifiers(); /// WeakTopLevelDecl - Translation-unit scoped declarations generated by /// \#pragma weak during processing of other Decls. /// I couldn't figure out a clean way to generate these in-line, so /// we store them here and handle separately -- which is a hack. /// It would be best to refactor this. SmallVector WeakTopLevelDecl; IdentifierResolver IdResolver; /// Translation Unit Scope - useful to Objective-C actions that need /// to lookup file scope declarations in the "ordinary" C decl namespace. /// For example, user-defined classes, built-in "id" type, etc. Scope *TUScope; /// The C++ "std" namespace, where the standard library resides. LazyDeclPtr StdNamespace; /// The C++ "std::bad_alloc" class, which is defined by the C++ /// standard library. LazyDeclPtr StdBadAlloc; /// The C++ "std::align_val_t" enum class, which is defined by the C++ /// standard library. LazyDeclPtr StdAlignValT; /// The C++ "std::experimental" namespace, where the experimental parts /// of the standard library resides. NamespaceDecl *StdExperimentalNamespaceCache; /// The C++ "std::initializer_list" template, which is defined in /// \. ClassTemplateDecl *StdInitializerList; /// The C++ "std::coroutine_traits" template, which is defined in /// \ ClassTemplateDecl *StdCoroutineTraitsCache; /// The C++ "type_info" declaration, which is defined in \. RecordDecl *CXXTypeInfoDecl; /// The MSVC "_GUID" struct, which is defined in MSVC header files. RecordDecl *MSVCGuidDecl; /// Caches identifiers/selectors for NSFoundation APIs. std::unique_ptr NSAPIObj; /// The declaration of the Objective-C NSNumber class. ObjCInterfaceDecl *NSNumberDecl; /// The declaration of the Objective-C NSValue class. ObjCInterfaceDecl *NSValueDecl; /// Pointer to NSNumber type (NSNumber *). QualType NSNumberPointer; /// Pointer to NSValue type (NSValue *). QualType NSValuePointer; /// The Objective-C NSNumber methods used to create NSNumber literals. ObjCMethodDecl *NSNumberLiteralMethods[NSAPI::NumNSNumberLiteralMethods]; /// The declaration of the Objective-C NSString class. ObjCInterfaceDecl *NSStringDecl; /// Pointer to NSString type (NSString *). QualType NSStringPointer; /// The declaration of the stringWithUTF8String: method. ObjCMethodDecl *StringWithUTF8StringMethod; /// The declaration of the valueWithBytes:objCType: method. ObjCMethodDecl *ValueWithBytesObjCTypeMethod; /// The declaration of the Objective-C NSArray class. ObjCInterfaceDecl *NSArrayDecl; /// The declaration of the arrayWithObjects:count: method. ObjCMethodDecl *ArrayWithObjectsMethod; /// The declaration of the Objective-C NSDictionary class. ObjCInterfaceDecl *NSDictionaryDecl; /// The declaration of the dictionaryWithObjects:forKeys:count: method. ObjCMethodDecl *DictionaryWithObjectsMethod; /// id type. QualType QIDNSCopying; /// will hold 'respondsToSelector:' Selector RespondsToSelectorSel; /// A flag to remember whether the implicit forms of operator new and delete /// have been declared. bool GlobalNewDeleteDeclared; /// A flag to indicate that we're in a context that permits abstract /// references to fields. This is really a bool AllowAbstractFieldReference; /// Describes how the expressions currently being parsed are /// evaluated at run-time, if at all. enum class ExpressionEvaluationContext { /// The current expression and its subexpressions occur within an /// unevaluated operand (C++11 [expr]p7), such as the subexpression of /// \c sizeof, where the type of the expression may be significant but /// no code will be generated to evaluate the value of the expression at /// run time. Unevaluated, /// The current expression occurs within a braced-init-list within /// an unevaluated operand. This is mostly like a regular unevaluated /// context, except that we still instantiate constexpr functions that are /// referenced here so that we can perform narrowing checks correctly. UnevaluatedList, /// The current expression occurs within a discarded statement. /// This behaves largely similarly to an unevaluated operand in preventing /// definitions from being required, but not in other ways. DiscardedStatement, /// The current expression occurs within an unevaluated /// operand that unconditionally permits abstract references to /// fields, such as a SIZE operator in MS-style inline assembly. UnevaluatedAbstract, /// The current context is "potentially evaluated" in C++11 terms, /// but the expression is evaluated at compile-time (like the values of /// cases in a switch statement). ConstantEvaluated, /// The current expression is potentially evaluated at run time, /// which means that code may be generated to evaluate the value of the /// expression at run time. PotentiallyEvaluated, /// The current expression is potentially evaluated, but any /// declarations referenced inside that expression are only used if /// in fact the current expression is used. /// /// This value is used when parsing default function arguments, for which /// we would like to provide diagnostics (e.g., passing non-POD arguments /// through varargs) but do not want to mark declarations as "referenced" /// until the default argument is used. PotentiallyEvaluatedIfUsed }; /// Data structure used to record current or nested /// expression evaluation contexts. struct ExpressionEvaluationContextRecord { /// The expression evaluation context. ExpressionEvaluationContext Context; /// Whether the enclosing context needed a cleanup. CleanupInfo ParentCleanup; /// Whether we are in a decltype expression. bool IsDecltype; /// The number of active cleanup objects when we entered /// this expression evaluation context. unsigned NumCleanupObjects; /// The number of typos encountered during this expression evaluation /// context (i.e. the number of TypoExprs created). unsigned NumTypos; MaybeODRUseExprSet SavedMaybeODRUseExprs; /// The lambdas that are present within this context, if it /// is indeed an unevaluated context. SmallVector Lambdas; /// The declaration that provides context for lambda expressions /// and block literals if the normal declaration context does not /// suffice, e.g., in a default function argument. Decl *ManglingContextDecl; /// If we are processing a decltype type, a set of call expressions /// for which we have deferred checking the completeness of the return type. SmallVector DelayedDecltypeCalls; /// If we are processing a decltype type, a set of temporary binding /// expressions for which we have deferred checking the destructor. SmallVector DelayedDecltypeBinds; llvm::SmallPtrSet PossibleDerefs; /// Expressions appearing as the LHS of a volatile assignment in this /// context. We produce a warning for these when popping the context if /// they are not discarded-value expressions nor unevaluated operands. SmallVector VolatileAssignmentLHSs; /// \brief Describes whether we are in an expression constext which we have /// to handle differently. enum ExpressionKind { EK_Decltype, EK_TemplateArgument, EK_Other } ExprContext; ExpressionEvaluationContextRecord(ExpressionEvaluationContext Context, unsigned NumCleanupObjects, CleanupInfo ParentCleanup, Decl *ManglingContextDecl, ExpressionKind ExprContext) : Context(Context), ParentCleanup(ParentCleanup), NumCleanupObjects(NumCleanupObjects), NumTypos(0), ManglingContextDecl(ManglingContextDecl), ExprContext(ExprContext) {} bool isUnevaluated() const { return Context == ExpressionEvaluationContext::Unevaluated || Context == ExpressionEvaluationContext::UnevaluatedAbstract || Context == ExpressionEvaluationContext::UnevaluatedList; } bool isConstantEvaluated() const { return Context == ExpressionEvaluationContext::ConstantEvaluated; } }; /// A stack of expression evaluation contexts. SmallVector ExprEvalContexts; /// Emit a warning for all pending noderef expressions that we recorded. void WarnOnPendingNoDerefs(ExpressionEvaluationContextRecord &Rec); /// Compute the mangling number context for a lambda expression or /// block literal. Also return the extra mangling decl if any. /// /// \param DC - The DeclContext containing the lambda expression or /// block literal. std::tuple getCurrentMangleNumberContext(const DeclContext *DC); /// SpecialMemberOverloadResult - The overloading result for a special member /// function. /// /// This is basically a wrapper around PointerIntPair. The lowest bits of the /// integer are used to determine whether overload resolution succeeded. class SpecialMemberOverloadResult { public: enum Kind { NoMemberOrDeleted, Ambiguous, Success }; private: llvm::PointerIntPair Pair; public: SpecialMemberOverloadResult() : Pair() {} SpecialMemberOverloadResult(CXXMethodDecl *MD) : Pair(MD, MD->isDeleted() ? NoMemberOrDeleted : Success) {} CXXMethodDecl *getMethod() const { return Pair.getPointer(); } void setMethod(CXXMethodDecl *MD) { Pair.setPointer(MD); } Kind getKind() const { return static_cast(Pair.getInt()); } void setKind(Kind K) { Pair.setInt(K); } }; class SpecialMemberOverloadResultEntry : public llvm::FastFoldingSetNode, public SpecialMemberOverloadResult { public: SpecialMemberOverloadResultEntry(const llvm::FoldingSetNodeID &ID) : FastFoldingSetNode(ID) {} }; /// A cache of special member function overload resolution results /// for C++ records. llvm::FoldingSet SpecialMemberCache; /// A cache of the flags available in enumerations with the flag_bits /// attribute. mutable llvm::DenseMap FlagBitsCache; /// The kind of translation unit we are processing. /// /// When we're processing a complete translation unit, Sema will perform /// end-of-translation-unit semantic tasks (such as creating /// initializers for tentative definitions in C) once parsing has /// completed. Modules and precompiled headers perform different kinds of /// checks. TranslationUnitKind TUKind; llvm::BumpPtrAllocator BumpAlloc; /// The number of SFINAE diagnostics that have been trapped. unsigned NumSFINAEErrors; typedef llvm::DenseMap> UnparsedDefaultArgInstantiationsMap; /// A mapping from parameters with unparsed default arguments to the /// set of instantiations of each parameter. /// /// This mapping is a temporary data structure used when parsing /// nested class templates or nested classes of class templates, /// where we might end up instantiating an inner class before the /// default arguments of its methods have been parsed. UnparsedDefaultArgInstantiationsMap UnparsedDefaultArgInstantiations; // Contains the locations of the beginning of unparsed default // argument locations. llvm::DenseMap UnparsedDefaultArgLocs; /// UndefinedInternals - all the used, undefined objects which require a /// definition in this translation unit. llvm::MapVector UndefinedButUsed; /// Determine if VD, which must be a variable or function, is an external /// symbol that nonetheless can't be referenced from outside this translation /// unit because its type has no linkage and it's not extern "C". bool isExternalWithNoLinkageType(ValueDecl *VD); /// Obtain a sorted list of functions that are undefined but ODR-used. void getUndefinedButUsed( SmallVectorImpl > &Undefined); /// Retrieves list of suspicious delete-expressions that will be checked at /// the end of translation unit. const llvm::MapVector & getMismatchingDeleteExpressions() const; typedef std::pair GlobalMethods; typedef llvm::DenseMap GlobalMethodPool; /// Method Pool - allows efficient lookup when typechecking messages to "id". /// We need to maintain a list, since selectors can have differing signatures /// across classes. In Cocoa, this happens to be extremely uncommon (only 1% /// of selectors are "overloaded"). /// At the head of the list it is recorded whether there were 0, 1, or >= 2 /// methods inside categories with a particular selector. GlobalMethodPool MethodPool; /// Method selectors used in a \@selector expression. Used for implementation /// of -Wselector. llvm::MapVector ReferencedSelectors; /// List of SourceLocations where 'self' is implicitly retained inside a /// block. llvm::SmallVector, 1> ImplicitlyRetainedSelfLocs; /// Kinds of C++ special members. enum CXXSpecialMember { CXXDefaultConstructor, CXXCopyConstructor, CXXMoveConstructor, CXXCopyAssignment, CXXMoveAssignment, CXXDestructor, CXXInvalid }; typedef llvm::PointerIntPair SpecialMemberDecl; /// The C++ special members which we are currently in the process of /// declaring. If this process recursively triggers the declaration of the /// same special member, we should act as if it is not yet declared. llvm::SmallPtrSet SpecialMembersBeingDeclared; /// Kinds of defaulted comparison operator functions. enum class DefaultedComparisonKind : unsigned char { /// This is not a defaultable comparison operator. None, /// This is an operator== that should be implemented as a series of /// subobject comparisons. Equal, /// This is an operator<=> that should be implemented as a series of /// subobject comparisons. ThreeWay, /// This is an operator!= that should be implemented as a rewrite in terms /// of a == comparison. NotEqual, /// This is an <, <=, >, or >= that should be implemented as a rewrite in /// terms of a <=> comparison. Relational, }; /// The function definitions which were renamed as part of typo-correction /// to match their respective declarations. We want to keep track of them /// to ensure that we don't emit a "redefinition" error if we encounter a /// correctly named definition after the renamed definition. llvm::SmallPtrSet TypoCorrectedFunctionDefinitions; /// Stack of types that correspond to the parameter entities that are /// currently being copy-initialized. Can be empty. llvm::SmallVector CurrentParameterCopyTypes; void ReadMethodPool(Selector Sel); void updateOutOfDateSelector(Selector Sel); /// Private Helper predicate to check for 'self'. bool isSelfExpr(Expr *RExpr); bool isSelfExpr(Expr *RExpr, const ObjCMethodDecl *Method); /// Cause the active diagnostic on the DiagosticsEngine to be /// emitted. This is closely coupled to the SemaDiagnosticBuilder class and /// should not be used elsewhere. void EmitCurrentDiagnostic(unsigned DiagID); /// Records and restores the FP_CONTRACT state on entry/exit of compound /// statements. class FPContractStateRAII { public: FPContractStateRAII(Sema &S) : S(S), OldFPFeaturesState(S.FPFeatures) {} ~FPContractStateRAII() { S.FPFeatures = OldFPFeaturesState; } private: Sema& S; FPOptions OldFPFeaturesState; }; void addImplicitTypedef(StringRef Name, QualType T); bool WarnedStackExhausted = false; public: Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, TranslationUnitKind TUKind = TU_Complete, CodeCompleteConsumer *CompletionConsumer = nullptr); ~Sema(); /// Perform initialization that occurs after the parser has been /// initialized but before it parses anything. void Initialize(); const LangOptions &getLangOpts() const { return LangOpts; } OpenCLOptions &getOpenCLOptions() { return OpenCLFeatures; } FPOptions &getFPOptions() { return FPFeatures; } DiagnosticsEngine &getDiagnostics() const { return Diags; } SourceManager &getSourceManager() const { return SourceMgr; } Preprocessor &getPreprocessor() const { return PP; } ASTContext &getASTContext() const { return Context; } ASTConsumer &getASTConsumer() const { return Consumer; } ASTMutationListener *getASTMutationListener() const; ExternalSemaSource* getExternalSource() const { return ExternalSource; } ///Registers an external source. If an external source already exists, /// creates a multiplex external source and appends to it. /// ///\param[in] E - A non-null external sema source. /// void addExternalSource(ExternalSemaSource *E); void PrintStats() const; /// Warn that the stack is nearly exhausted. void warnStackExhausted(SourceLocation Loc); /// Run some code with "sufficient" stack space. (Currently, at least 256K is /// guaranteed). Produces a warning if we're low on stack space and allocates /// more in that case. Use this in code that may recurse deeply (for example, /// in template instantiation) to avoid stack overflow. void runWithSufficientStackSpace(SourceLocation Loc, llvm::function_ref Fn); /// Helper class that creates diagnostics with optional /// template instantiation stacks. /// /// This class provides a wrapper around the basic DiagnosticBuilder /// class that emits diagnostics. SemaDiagnosticBuilder is /// responsible for emitting the diagnostic (as DiagnosticBuilder /// does) and, if the diagnostic comes from inside a template /// instantiation, printing the template instantiation stack as /// well. class SemaDiagnosticBuilder : public DiagnosticBuilder { Sema &SemaRef; unsigned DiagID; public: SemaDiagnosticBuilder(DiagnosticBuilder &DB, Sema &SemaRef, unsigned DiagID) : DiagnosticBuilder(DB), SemaRef(SemaRef), DiagID(DiagID) { } // This is a cunning lie. DiagnosticBuilder actually performs move // construction in its copy constructor (but due to varied uses, it's not // possible to conveniently express this as actual move construction). So // the default copy ctor here is fine, because the base class disables the // source anyway, so the user-defined ~SemaDiagnosticBuilder is a safe no-op // in that case anwyay. SemaDiagnosticBuilder(const SemaDiagnosticBuilder&) = default; ~SemaDiagnosticBuilder() { // If we aren't active, there is nothing to do. if (!isActive()) return; // Otherwise, we need to emit the diagnostic. First flush the underlying // DiagnosticBuilder data, and clear the diagnostic builder itself so it // won't emit the diagnostic in its own destructor. // // This seems wasteful, in that as written the DiagnosticBuilder dtor will // do its own needless checks to see if the diagnostic needs to be // emitted. However, because we take care to ensure that the builder // objects never escape, a sufficiently smart compiler will be able to // eliminate that code. FlushCounts(); Clear(); // Dispatch to Sema to emit the diagnostic. SemaRef.EmitCurrentDiagnostic(DiagID); } /// Teach operator<< to produce an object of the correct type. template friend const SemaDiagnosticBuilder &operator<<( const SemaDiagnosticBuilder &Diag, const T &Value) { const DiagnosticBuilder &BaseDiag = Diag; BaseDiag << Value; return Diag; } }; /// Emit a diagnostic. SemaDiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID) { DiagnosticBuilder DB = Diags.Report(Loc, DiagID); return SemaDiagnosticBuilder(DB, *this, DiagID); } /// Emit a partial diagnostic. SemaDiagnosticBuilder Diag(SourceLocation Loc, const PartialDiagnostic& PD); /// Build a partial diagnostic. PartialDiagnostic PDiag(unsigned DiagID = 0); // in SemaInternal.h bool findMacroSpelling(SourceLocation &loc, StringRef name); /// Get a string to suggest for zero-initialization of a type. std::string getFixItZeroInitializerForType(QualType T, SourceLocation Loc) const; std::string getFixItZeroLiteralForType(QualType T, SourceLocation Loc) const; /// Calls \c Lexer::getLocForEndOfToken() SourceLocation getLocForEndOfToken(SourceLocation Loc, unsigned Offset = 0); /// Retrieve the module loader associated with the preprocessor. ModuleLoader &getModuleLoader() const; /// Invent a new identifier for parameters of abbreviated templates. IdentifierInfo * InventAbbreviatedTemplateParameterTypeName(IdentifierInfo *ParamName, unsigned Index); void emitAndClearUnusedLocalTypedefWarnings(); enum TUFragmentKind { /// The global module fragment, between 'module;' and a module-declaration. Global, /// A normal translation unit fragment. For a non-module unit, this is the /// entire translation unit. Otherwise, it runs from the module-declaration /// to the private-module-fragment (if any) or the end of the TU (if not). Normal, /// The private module fragment, between 'module :private;' and the end of /// the translation unit. Private }; void ActOnStartOfTranslationUnit(); void ActOnEndOfTranslationUnit(); void ActOnEndOfTranslationUnitFragment(TUFragmentKind Kind); void CheckDelegatingCtorCycles(); Scope *getScopeForContext(DeclContext *Ctx); void PushFunctionScope(); void PushBlockScope(Scope *BlockScope, BlockDecl *Block); sema::LambdaScopeInfo *PushLambdaScope(); /// This is used to inform Sema what the current TemplateParameterDepth /// is during Parsing. Currently it is used to pass on the depth /// when parsing generic lambda 'auto' parameters. void RecordParsingTemplateParameterDepth(unsigned Depth); void PushCapturedRegionScope(Scope *RegionScope, CapturedDecl *CD, RecordDecl *RD, CapturedRegionKind K, unsigned OpenMPCaptureLevel = 0); /// Custom deleter to allow FunctionScopeInfos to be kept alive for a short /// time after they've been popped. class PoppedFunctionScopeDeleter { Sema *Self; public: explicit PoppedFunctionScopeDeleter(Sema *Self) : Self(Self) {} void operator()(sema::FunctionScopeInfo *Scope) const; }; using PoppedFunctionScopePtr = std::unique_ptr; PoppedFunctionScopePtr PopFunctionScopeInfo(const sema::AnalysisBasedWarnings::Policy *WP = nullptr, const Decl *D = nullptr, QualType BlockType = QualType()); sema::FunctionScopeInfo *getCurFunction() const { return FunctionScopes.empty() ? nullptr : FunctionScopes.back(); } sema::FunctionScopeInfo *getEnclosingFunction() const; void setFunctionHasBranchIntoScope(); void setFunctionHasBranchProtectedScope(); void setFunctionHasIndirectGoto(); void PushCompoundScope(bool IsStmtExpr); void PopCompoundScope(); sema::CompoundScopeInfo &getCurCompoundScope() const; bool hasAnyUnrecoverableErrorsInThisFunction() const; /// Retrieve the current block, if any. sema::BlockScopeInfo *getCurBlock(); /// Get the innermost lambda enclosing the current location, if any. This /// looks through intervening non-lambda scopes such as local functions and /// blocks. sema::LambdaScopeInfo *getEnclosingLambda() const; /// Retrieve the current lambda scope info, if any. /// \param IgnoreNonLambdaCapturingScope true if should find the top-most /// lambda scope info ignoring all inner capturing scopes that are not /// lambda scopes. sema::LambdaScopeInfo * getCurLambda(bool IgnoreNonLambdaCapturingScope = false); /// Retrieve the current generic lambda info, if any. sema::LambdaScopeInfo *getCurGenericLambda(); /// Retrieve the current captured region, if any. sema::CapturedRegionScopeInfo *getCurCapturedRegion(); /// WeakTopLevelDeclDecls - access to \#pragma weak-generated Decls SmallVectorImpl &WeakTopLevelDecls() { return WeakTopLevelDecl; } /// Called before parsing a function declarator belonging to a function /// declaration. void ActOnStartFunctionDeclarationDeclarator(Declarator &D, unsigned TemplateParameterDepth); /// Called after parsing a function declarator belonging to a function /// declaration. void ActOnFinishFunctionDeclarationDeclarator(Declarator &D); void ActOnComment(SourceRange Comment); //===--------------------------------------------------------------------===// // Type Analysis / Processing: SemaType.cpp. // QualType BuildQualifiedType(QualType T, SourceLocation Loc, Qualifiers Qs, const DeclSpec *DS = nullptr); QualType BuildQualifiedType(QualType T, SourceLocation Loc, unsigned CVRA, const DeclSpec *DS = nullptr); QualType BuildPointerType(QualType T, SourceLocation Loc, DeclarationName Entity); QualType BuildReferenceType(QualType T, bool LValueRef, SourceLocation Loc, DeclarationName Entity); QualType BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM, Expr *ArraySize, unsigned Quals, SourceRange Brackets, DeclarationName Entity); QualType BuildVectorType(QualType T, Expr *VecSize, SourceLocation AttrLoc); QualType BuildExtVectorType(QualType T, Expr *ArraySize, SourceLocation AttrLoc); QualType BuildAddressSpaceAttr(QualType &T, LangAS ASIdx, Expr *AddrSpace, SourceLocation AttrLoc); /// Same as above, but constructs the AddressSpace index if not provided. QualType BuildAddressSpaceAttr(QualType &T, Expr *AddrSpace, SourceLocation AttrLoc); bool CheckQualifiedFunctionForTypeId(QualType T, SourceLocation Loc); bool CheckFunctionReturnType(QualType T, SourceLocation Loc); /// Build a function type. /// /// This routine checks the function type according to C++ rules and /// under the assumption that the result type and parameter types have /// just been instantiated from a template. It therefore duplicates /// some of the behavior of GetTypeForDeclarator, but in a much /// simpler form that is only suitable for this narrow use case. /// /// \param T The return type of the function. /// /// \param ParamTypes The parameter types of the function. This array /// will be modified to account for adjustments to the types of the /// function parameters. /// /// \param Loc The location of the entity whose type involves this /// function type or, if there is no such entity, the location of the /// type that will have function type. /// /// \param Entity The name of the entity that involves the function /// type, if known. /// /// \param EPI Extra information about the function type. Usually this will /// be taken from an existing function with the same prototype. /// /// \returns A suitable function type, if there are no errors. The /// unqualified type will always be a FunctionProtoType. /// Otherwise, returns a NULL type. QualType BuildFunctionType(QualType T, MutableArrayRef ParamTypes, SourceLocation Loc, DeclarationName Entity, const FunctionProtoType::ExtProtoInfo &EPI); QualType BuildMemberPointerType(QualType T, QualType Class, SourceLocation Loc, DeclarationName Entity); QualType BuildBlockPointerType(QualType T, SourceLocation Loc, DeclarationName Entity); QualType BuildParenType(QualType T); QualType BuildAtomicType(QualType T, SourceLocation Loc); QualType BuildReadPipeType(QualType T, SourceLocation Loc); QualType BuildWritePipeType(QualType T, SourceLocation Loc); TypeSourceInfo *GetTypeForDeclarator(Declarator &D, Scope *S); TypeSourceInfo *GetTypeForDeclaratorCast(Declarator &D, QualType FromTy); /// Package the given type and TSI into a ParsedType. ParsedType CreateParsedType(QualType T, TypeSourceInfo *TInfo); DeclarationNameInfo GetNameForDeclarator(Declarator &D); DeclarationNameInfo GetNameFromUnqualifiedId(const UnqualifiedId &Name); static QualType GetTypeFromParser(ParsedType Ty, TypeSourceInfo **TInfo = nullptr); CanThrowResult canThrow(const Stmt *E); const FunctionProtoType *ResolveExceptionSpec(SourceLocation Loc, const FunctionProtoType *FPT); void UpdateExceptionSpec(FunctionDecl *FD, const FunctionProtoType::ExceptionSpecInfo &ESI); bool CheckSpecifiedExceptionType(QualType &T, SourceRange Range); bool CheckDistantExceptionSpec(QualType T); bool CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New); bool CheckEquivalentExceptionSpec( const FunctionProtoType *Old, SourceLocation OldLoc, const FunctionProtoType *New, SourceLocation NewLoc); bool CheckEquivalentExceptionSpec( const PartialDiagnostic &DiagID, const PartialDiagnostic & NoteID, const FunctionProtoType *Old, SourceLocation OldLoc, const FunctionProtoType *New, SourceLocation NewLoc); bool handlerCanCatch(QualType HandlerType, QualType ExceptionType); bool CheckExceptionSpecSubset(const PartialDiagnostic &DiagID, const PartialDiagnostic &NestedDiagID, const PartialDiagnostic &NoteID, const PartialDiagnostic &NoThrowDiagID, const FunctionProtoType *Superset, SourceLocation SuperLoc, const FunctionProtoType *Subset, SourceLocation SubLoc); bool CheckParamExceptionSpec(const PartialDiagnostic &NestedDiagID, const PartialDiagnostic &NoteID, const FunctionProtoType *Target, SourceLocation TargetLoc, const FunctionProtoType *Source, SourceLocation SourceLoc); TypeResult ActOnTypeName(Scope *S, Declarator &D); /// The parser has parsed the context-sensitive type 'instancetype' /// in an Objective-C message declaration. Return the appropriate type. ParsedType ActOnObjCInstanceType(SourceLocation Loc); /// Abstract class used to diagnose incomplete types. struct TypeDiagnoser { TypeDiagnoser() {} virtual void diagnose(Sema &S, SourceLocation Loc, QualType T) = 0; virtual ~TypeDiagnoser() {} }; static int getPrintable(int I) { return I; } static unsigned getPrintable(unsigned I) { return I; } static bool getPrintable(bool B) { return B; } static const char * getPrintable(const char *S) { return S; } static StringRef getPrintable(StringRef S) { return S; } static const std::string &getPrintable(const std::string &S) { return S; } static const IdentifierInfo *getPrintable(const IdentifierInfo *II) { return II; } static DeclarationName getPrintable(DeclarationName N) { return N; } static QualType getPrintable(QualType T) { return T; } static SourceRange getPrintable(SourceRange R) { return R; } static SourceRange getPrintable(SourceLocation L) { return L; } static SourceRange getPrintable(const Expr *E) { return E->getSourceRange(); } static SourceRange getPrintable(TypeLoc TL) { return TL.getSourceRange();} template class BoundTypeDiagnoser : public TypeDiagnoser { unsigned DiagID; std::tuple Args; template void emit(const SemaDiagnosticBuilder &DB, std::index_sequence) const { // Apply all tuple elements to the builder in order. bool Dummy[] = {false, (DB << getPrintable(std::get(Args)))...}; (void)Dummy; } public: BoundTypeDiagnoser(unsigned DiagID, const Ts &...Args) : TypeDiagnoser(), DiagID(DiagID), Args(Args...) { assert(DiagID != 0 && "no diagnostic for type diagnoser"); } void diagnose(Sema &S, SourceLocation Loc, QualType T) override { const SemaDiagnosticBuilder &DB = S.Diag(Loc, DiagID); emit(DB, std::index_sequence_for()); DB << T; } }; private: /// Methods for marking which expressions involve dereferencing a pointer /// marked with the 'noderef' attribute. Expressions are checked bottom up as /// they are parsed, meaning that a noderef pointer may not be accessed. For /// example, in `&*p` where `p` is a noderef pointer, we will first parse the /// `*p`, but need to check that `address of` is called on it. This requires /// keeping a container of all pending expressions and checking if the address /// of them are eventually taken. void CheckSubscriptAccessOfNoDeref(const ArraySubscriptExpr *E); void CheckAddressOfNoDeref(const Expr *E); void CheckMemberAccessOfNoDeref(const MemberExpr *E); bool RequireCompleteTypeImpl(SourceLocation Loc, QualType T, TypeDiagnoser *Diagnoser); struct ModuleScope { SourceLocation BeginLoc; clang::Module *Module = nullptr; bool ModuleInterface = false; bool ImplicitGlobalModuleFragment = false; VisibleModuleSet OuterVisibleModules; }; /// The modules we're currently parsing. llvm::SmallVector ModuleScopes; /// Namespace definitions that we will export when they finish. llvm::SmallPtrSet DeferredExportedNamespaces; /// Get the module whose scope we are currently within. Module *getCurrentModule() const { return ModuleScopes.empty() ? nullptr : ModuleScopes.back().Module; } VisibleModuleSet VisibleModules; public: /// Get the module owning an entity. Module *getOwningModule(const Decl *Entity) { return Entity->getOwningModule(); } /// Make a merged definition of an existing hidden definition \p ND /// visible at the specified location. void makeMergedDefinitionVisible(NamedDecl *ND); bool isModuleVisible(const Module *M, bool ModulePrivate = false); /// Determine whether a declaration is visible to name lookup. bool isVisible(const NamedDecl *D) { return !D->isHidden() || isVisibleSlow(D); } /// Determine whether any declaration of an entity is visible. bool hasVisibleDeclaration(const NamedDecl *D, llvm::SmallVectorImpl *Modules = nullptr) { return isVisible(D) || hasVisibleDeclarationSlow(D, Modules); } bool hasVisibleDeclarationSlow(const NamedDecl *D, llvm::SmallVectorImpl *Modules); bool hasVisibleMergedDefinition(NamedDecl *Def); bool hasMergedDefinitionInCurrentModule(NamedDecl *Def); /// Determine if \p D and \p Suggested have a structurally compatible /// layout as described in C11 6.2.7/1. bool hasStructuralCompatLayout(Decl *D, Decl *Suggested); /// Determine if \p D has a visible definition. If not, suggest a declaration /// that should be made visible to expose the definition. bool hasVisibleDefinition(NamedDecl *D, NamedDecl **Suggested, bool OnlyNeedComplete = false); bool hasVisibleDefinition(const NamedDecl *D) { NamedDecl *Hidden; return hasVisibleDefinition(const_cast(D), &Hidden); } /// Determine if the template parameter \p D has a visible default argument. bool hasVisibleDefaultArgument(const NamedDecl *D, llvm::SmallVectorImpl *Modules = nullptr); /// Determine if there is a visible declaration of \p D that is an explicit /// specialization declaration for a specialization of a template. (For a /// member specialization, use hasVisibleMemberSpecialization.) bool hasVisibleExplicitSpecialization( const NamedDecl *D, llvm::SmallVectorImpl *Modules = nullptr); /// Determine if there is a visible declaration of \p D that is a member /// specialization declaration (as opposed to an instantiated declaration). bool hasVisibleMemberSpecialization( const NamedDecl *D, llvm::SmallVectorImpl *Modules = nullptr); /// Determine if \p A and \p B are equivalent internal linkage declarations /// from different modules, and thus an ambiguity error can be downgraded to /// an extension warning. bool isEquivalentInternalLinkageDeclaration(const NamedDecl *A, const NamedDecl *B); void diagnoseEquivalentInternalLinkageDeclarations( SourceLocation Loc, const NamedDecl *D, ArrayRef Equiv); bool isUsualDeallocationFunction(const CXXMethodDecl *FD); bool isCompleteType(SourceLocation Loc, QualType T) { return !RequireCompleteTypeImpl(Loc, T, nullptr); } bool RequireCompleteType(SourceLocation Loc, QualType T, TypeDiagnoser &Diagnoser); bool RequireCompleteType(SourceLocation Loc, QualType T, unsigned DiagID); template bool RequireCompleteType(SourceLocation Loc, QualType T, unsigned DiagID, const Ts &...Args) { BoundTypeDiagnoser Diagnoser(DiagID, Args...); return RequireCompleteType(Loc, T, Diagnoser); } void completeExprArrayBound(Expr *E); bool RequireCompleteExprType(Expr *E, TypeDiagnoser &Diagnoser); bool RequireCompleteExprType(Expr *E, unsigned DiagID); template bool RequireCompleteExprType(Expr *E, unsigned DiagID, const Ts &...Args) { BoundTypeDiagnoser Diagnoser(DiagID, Args...); return RequireCompleteExprType(E, Diagnoser); } bool RequireLiteralType(SourceLocation Loc, QualType T, TypeDiagnoser &Diagnoser); bool RequireLiteralType(SourceLocation Loc, QualType T, unsigned DiagID); template bool RequireLiteralType(SourceLocation Loc, QualType T, unsigned DiagID, const Ts &...Args) { BoundTypeDiagnoser Diagnoser(DiagID, Args...); return RequireLiteralType(Loc, T, Diagnoser); } QualType getElaboratedType(ElaboratedTypeKeyword Keyword, const CXXScopeSpec &SS, QualType T, TagDecl *OwnedTagDecl = nullptr); QualType BuildTypeofExprType(Expr *E, SourceLocation Loc); /// If AsUnevaluated is false, E is treated as though it were an evaluated /// context, such as when building a type for decltype(auto). QualType BuildDecltypeType(Expr *E, SourceLocation Loc, bool AsUnevaluated = true); QualType BuildUnaryTransformType(QualType BaseType, UnaryTransformType::UTTKind UKind, SourceLocation Loc); //===--------------------------------------------------------------------===// // Symbol table / Decl tracking callbacks: SemaDecl.cpp. // struct SkipBodyInfo { SkipBodyInfo() : ShouldSkip(false), CheckSameAsPrevious(false), Previous(nullptr), New(nullptr) {} bool ShouldSkip; bool CheckSameAsPrevious; NamedDecl *Previous; NamedDecl *New; }; DeclGroupPtrTy ConvertDeclToDeclGroup(Decl *Ptr, Decl *OwnedType = nullptr); void DiagnoseUseOfUnimplementedSelectors(); bool isSimpleTypeSpecifier(tok::TokenKind Kind) const; ParsedType getTypeName(const IdentifierInfo &II, SourceLocation NameLoc, Scope *S, CXXScopeSpec *SS = nullptr, bool isClassName = false, bool HasTrailingDot = false, ParsedType ObjectType = nullptr, bool IsCtorOrDtorName = false, bool WantNontrivialTypeSourceInfo = false, bool IsClassTemplateDeductionContext = true, IdentifierInfo **CorrectedII = nullptr); TypeSpecifierType isTagName(IdentifierInfo &II, Scope *S); bool isMicrosoftMissingTypename(const CXXScopeSpec *SS, Scope *S); void DiagnoseUnknownTypeName(IdentifierInfo *&II, SourceLocation IILoc, Scope *S, CXXScopeSpec *SS, ParsedType &SuggestedType, bool IsTemplateName = false); /// Attempt to behave like MSVC in situations where lookup of an unqualified /// type name has failed in a dependent context. In these situations, we /// automatically form a DependentTypeName that will retry lookup in a related /// scope during instantiation. ParsedType ActOnMSVCUnknownTypeName(const IdentifierInfo &II, SourceLocation NameLoc, bool IsTemplateTypeArg); /// Describes the result of the name lookup and resolution performed /// by \c ClassifyName(). enum NameClassificationKind { /// This name is not a type or template in this context, but might be /// something else. NC_Unknown, /// Classification failed; an error has been produced. NC_Error, /// The name has been typo-corrected to a keyword. NC_Keyword, /// The name was classified as a type. NC_Type, /// The name was classified as a specific non-type, non-template /// declaration. ActOnNameClassifiedAsNonType should be called to /// convert the declaration to an expression. NC_NonType, /// The name was classified as an ADL-only function name. /// ActOnNameClassifiedAsUndeclaredNonType should be called to convert the /// result to an expression. NC_UndeclaredNonType, /// The name denotes a member of a dependent type that could not be /// resolved. ActOnNameClassifiedAsDependentNonType should be called to /// convert the result to an expression. NC_DependentNonType, /// The name was classified as a non-type, and an expression representing /// that name has been formed. NC_ContextIndependentExpr, /// The name was classified as a template whose specializations are types. NC_TypeTemplate, /// The name was classified as a variable template name. NC_VarTemplate, /// The name was classified as a function template name. NC_FunctionTemplate, /// The name was classified as an ADL-only function template name. NC_UndeclaredTemplate, /// The name was classified as a concept name. NC_Concept, }; class NameClassification { NameClassificationKind Kind; union { ExprResult Expr; NamedDecl *NonTypeDecl; TemplateName Template; ParsedType Type; }; explicit NameClassification(NameClassificationKind Kind) : Kind(Kind) {} public: NameClassification(ParsedType Type) : Kind(NC_Type), Type(Type) {} NameClassification(const IdentifierInfo *Keyword) : Kind(NC_Keyword) {} static NameClassification Error() { return NameClassification(NC_Error); } static NameClassification Unknown() { return NameClassification(NC_Unknown); } static NameClassification ContextIndependentExpr(ExprResult E) { NameClassification Result(NC_ContextIndependentExpr); Result.Expr = E; return Result; } static NameClassification NonType(NamedDecl *D) { NameClassification Result(NC_NonType); Result.NonTypeDecl = D; return Result; } static NameClassification UndeclaredNonType() { return NameClassification(NC_UndeclaredNonType); } static NameClassification DependentNonType() { return NameClassification(NC_DependentNonType); } static NameClassification TypeTemplate(TemplateName Name) { NameClassification Result(NC_TypeTemplate); Result.Template = Name; return Result; } static NameClassification VarTemplate(TemplateName Name) { NameClassification Result(NC_VarTemplate); Result.Template = Name; return Result; } static NameClassification FunctionTemplate(TemplateName Name) { NameClassification Result(NC_FunctionTemplate); Result.Template = Name; return Result; } static NameClassification Concept(TemplateName Name) { NameClassification Result(NC_Concept); Result.Template = Name; return Result; } static NameClassification UndeclaredTemplate(TemplateName Name) { NameClassification Result(NC_UndeclaredTemplate); Result.Template = Name; return Result; } NameClassificationKind getKind() const { return Kind; } ExprResult getExpression() const { assert(Kind == NC_ContextIndependentExpr); return Expr; } ParsedType getType() const { assert(Kind == NC_Type); return Type; } NamedDecl *getNonTypeDecl() const { assert(Kind == NC_NonType); return NonTypeDecl; } TemplateName getTemplateName() const { assert(Kind == NC_TypeTemplate || Kind == NC_FunctionTemplate || Kind == NC_VarTemplate || Kind == NC_Concept || Kind == NC_UndeclaredTemplate); return Template; } TemplateNameKind getTemplateNameKind() const { switch (Kind) { case NC_TypeTemplate: return TNK_Type_template; case NC_FunctionTemplate: return TNK_Function_template; case NC_VarTemplate: return TNK_Var_template; case NC_Concept: return TNK_Concept_template; case NC_UndeclaredTemplate: return TNK_Undeclared_template; default: llvm_unreachable("unsupported name classification."); } } }; /// Perform name lookup on the given name, classifying it based on /// the results of name lookup and the following token. /// /// This routine is used by the parser to resolve identifiers and help direct /// parsing. When the identifier cannot be found, this routine will attempt /// to correct the typo and classify based on the resulting name. /// /// \param S The scope in which we're performing name lookup. /// /// \param SS The nested-name-specifier that precedes the name. /// /// \param Name The identifier. If typo correction finds an alternative name, /// this pointer parameter will be updated accordingly. /// /// \param NameLoc The location of the identifier. /// /// \param NextToken The token following the identifier. Used to help /// disambiguate the name. /// /// \param CCC The correction callback, if typo correction is desired. NameClassification ClassifyName(Scope *S, CXXScopeSpec &SS, IdentifierInfo *&Name, SourceLocation NameLoc, const Token &NextToken, CorrectionCandidateCallback *CCC = nullptr); /// Act on the result of classifying a name as an undeclared (ADL-only) /// non-type declaration. ExprResult ActOnNameClassifiedAsUndeclaredNonType(IdentifierInfo *Name, SourceLocation NameLoc); /// Act on the result of classifying a name as an undeclared member of a /// dependent base class. ExprResult ActOnNameClassifiedAsDependentNonType(const CXXScopeSpec &SS, IdentifierInfo *Name, SourceLocation NameLoc, bool IsAddressOfOperand); /// Act on the result of classifying a name as a specific non-type /// declaration. ExprResult ActOnNameClassifiedAsNonType(Scope *S, const CXXScopeSpec &SS, NamedDecl *Found, SourceLocation NameLoc, const Token &NextToken); /// Describes the detailed kind of a template name. Used in diagnostics. enum class TemplateNameKindForDiagnostics { ClassTemplate, FunctionTemplate, VarTemplate, AliasTemplate, TemplateTemplateParam, Concept, DependentTemplate }; TemplateNameKindForDiagnostics getTemplateNameKindForDiagnostics(TemplateName Name); /// Determine whether it's plausible that E was intended to be a /// template-name. bool mightBeIntendedToBeTemplateName(ExprResult E, bool &Dependent) { if (!getLangOpts().CPlusPlus || E.isInvalid()) return false; Dependent = false; if (auto *DRE = dyn_cast(E.get())) return !DRE->hasExplicitTemplateArgs(); if (auto *ME = dyn_cast(E.get())) return !ME->hasExplicitTemplateArgs(); Dependent = true; if (auto *DSDRE = dyn_cast(E.get())) return !DSDRE->hasExplicitTemplateArgs(); if (auto *DSME = dyn_cast(E.get())) return !DSME->hasExplicitTemplateArgs(); // Any additional cases recognized here should also be handled by // diagnoseExprIntendedAsTemplateName. return false; } void diagnoseExprIntendedAsTemplateName(Scope *S, ExprResult TemplateName, SourceLocation Less, SourceLocation Greater); Decl *ActOnDeclarator(Scope *S, Declarator &D); NamedDecl *HandleDeclarator(Scope *S, Declarator &D, MultiTemplateParamsArg TemplateParameterLists); void RegisterLocallyScopedExternCDecl(NamedDecl *ND, Scope *S); bool DiagnoseClassNameShadow(DeclContext *DC, DeclarationNameInfo Info); bool diagnoseQualifiedDeclaration(CXXScopeSpec &SS, DeclContext *DC, DeclarationName Name, SourceLocation Loc, bool IsTemplateId); void diagnoseIgnoredQualifiers(unsigned DiagID, unsigned Quals, SourceLocation FallbackLoc, SourceLocation ConstQualLoc = SourceLocation(), SourceLocation VolatileQualLoc = SourceLocation(), SourceLocation RestrictQualLoc = SourceLocation(), SourceLocation AtomicQualLoc = SourceLocation(), SourceLocation UnalignedQualLoc = SourceLocation()); static bool adjustContextForLocalExternDecl(DeclContext *&DC); void DiagnoseFunctionSpecifiers(const DeclSpec &DS); NamedDecl *getShadowedDeclaration(const TypedefNameDecl *D, const LookupResult &R); NamedDecl *getShadowedDeclaration(const VarDecl *D, const LookupResult &R); void CheckShadow(NamedDecl *D, NamedDecl *ShadowedDecl, const LookupResult &R); void CheckShadow(Scope *S, VarDecl *D); /// Warn if 'E', which is an expression that is about to be modified, refers /// to a shadowing declaration. void CheckShadowingDeclModification(Expr *E, SourceLocation Loc); void DiagnoseShadowingLambdaDecls(const sema::LambdaScopeInfo *LSI); private: /// Map of current shadowing declarations to shadowed declarations. Warn if /// it looks like the user is trying to modify the shadowing declaration. llvm::DenseMap ShadowingDecls; public: void CheckCastAlign(Expr *Op, QualType T, SourceRange TRange); void handleTagNumbering(const TagDecl *Tag, Scope *TagScope); void setTagNameForLinkagePurposes(TagDecl *TagFromDeclSpec, TypedefNameDecl *NewTD); void CheckTypedefForVariablyModifiedType(Scope *S, TypedefNameDecl *D); NamedDecl* ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC, TypeSourceInfo *TInfo, LookupResult &Previous); NamedDecl* ActOnTypedefNameDecl(Scope* S, DeclContext* DC, TypedefNameDecl *D, LookupResult &Previous, bool &Redeclaration); NamedDecl *ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, TypeSourceInfo *TInfo, LookupResult &Previous, MultiTemplateParamsArg TemplateParamLists, bool &AddToScope, ArrayRef Bindings = None); NamedDecl * ActOnDecompositionDeclarator(Scope *S, Declarator &D, MultiTemplateParamsArg TemplateParamLists); // Returns true if the variable declaration is a redeclaration bool CheckVariableDeclaration(VarDecl *NewVD, LookupResult &Previous); void CheckVariableDeclarationType(VarDecl *NewVD); bool DeduceVariableDeclarationType(VarDecl *VDecl, bool DirectInit, Expr *Init); void CheckCompleteVariableDeclaration(VarDecl *VD); void CheckCompleteDecompositionDeclaration(DecompositionDecl *DD); void MaybeSuggestAddingStaticToDecl(const FunctionDecl *D); NamedDecl* ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, TypeSourceInfo *TInfo, LookupResult &Previous, MultiTemplateParamsArg TemplateParamLists, bool &AddToScope); bool AddOverriddenMethods(CXXRecordDecl *DC, CXXMethodDecl *MD); enum class CheckConstexprKind { /// Diagnose issues that are non-constant or that are extensions. Diagnose, /// Identify whether this function satisfies the formal rules for constexpr /// functions in the current lanugage mode (with no extensions). CheckValid }; bool CheckConstexprFunctionDefinition(const FunctionDecl *FD, CheckConstexprKind Kind); void DiagnoseHiddenVirtualMethods(CXXMethodDecl *MD); void FindHiddenVirtualMethods(CXXMethodDecl *MD, SmallVectorImpl &OverloadedMethods); void NoteHiddenVirtualMethods(CXXMethodDecl *MD, SmallVectorImpl &OverloadedMethods); // Returns true if the function declaration is a redeclaration bool CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, LookupResult &Previous, bool IsMemberSpecialization); bool shouldLinkDependentDeclWithPrevious(Decl *D, Decl *OldDecl); bool canFullyTypeCheckRedeclaration(ValueDecl *NewD, ValueDecl *OldD, QualType NewT, QualType OldT); void CheckMain(FunctionDecl *FD, const DeclSpec &D); void CheckMSVCRTEntryPoint(FunctionDecl *FD); Attr *getImplicitCodeSegOrSectionAttrForFunction(const FunctionDecl *FD, bool IsDefinition); void CheckFunctionOrTemplateParamDeclarator(Scope *S, Declarator &D); Decl *ActOnParamDeclarator(Scope *S, Declarator &D); ParmVarDecl *BuildParmVarDeclForTypedef(DeclContext *DC, SourceLocation Loc, QualType T); ParmVarDecl *CheckParameter(DeclContext *DC, SourceLocation StartLoc, SourceLocation NameLoc, IdentifierInfo *Name, QualType T, TypeSourceInfo *TSInfo, StorageClass SC); void ActOnParamDefaultArgument(Decl *param, SourceLocation EqualLoc, Expr *defarg); void ActOnParamUnparsedDefaultArgument(Decl *param, SourceLocation EqualLoc, SourceLocation ArgLoc); void ActOnParamDefaultArgumentError(Decl *param, SourceLocation EqualLoc); bool SetParamDefaultArgument(ParmVarDecl *Param, Expr *DefaultArg, SourceLocation EqualLoc); // Contexts where using non-trivial C union types can be disallowed. This is // passed to err_non_trivial_c_union_in_invalid_context. enum NonTrivialCUnionContext { // Function parameter. NTCUC_FunctionParam, // Function return. NTCUC_FunctionReturn, // Default-initialized object. NTCUC_DefaultInitializedObject, // Variable with automatic storage duration. NTCUC_AutoVar, // Initializer expression that might copy from another object. NTCUC_CopyInit, // Assignment. NTCUC_Assignment, // Compound literal. NTCUC_CompoundLiteral, // Block capture. NTCUC_BlockCapture, // lvalue-to-rvalue conversion of volatile type. NTCUC_LValueToRValueVolatile, }; /// Emit diagnostics if the initializer or any of its explicit or /// implicitly-generated subexpressions require copying or /// default-initializing a type that is or contains a C union type that is /// non-trivial to copy or default-initialize. void checkNonTrivialCUnionInInitializer(const Expr *Init, SourceLocation Loc); // These flags are passed to checkNonTrivialCUnion. enum NonTrivialCUnionKind { NTCUK_Init = 0x1, NTCUK_Destruct = 0x2, NTCUK_Copy = 0x4, }; /// Emit diagnostics if a non-trivial C union type or a struct that contains /// a non-trivial C union is used in an invalid context. void checkNonTrivialCUnion(QualType QT, SourceLocation Loc, NonTrivialCUnionContext UseContext, unsigned NonTrivialKind); void AddInitializerToDecl(Decl *dcl, Expr *init, bool DirectInit); void ActOnUninitializedDecl(Decl *dcl); void ActOnInitializerError(Decl *Dcl); void ActOnPureSpecifier(Decl *D, SourceLocation PureSpecLoc); void ActOnCXXForRangeDecl(Decl *D); StmtResult ActOnCXXForRangeIdentifier(Scope *S, SourceLocation IdentLoc, IdentifierInfo *Ident, ParsedAttributes &Attrs, SourceLocation AttrEnd); void SetDeclDeleted(Decl *dcl, SourceLocation DelLoc); void SetDeclDefaulted(Decl *dcl, SourceLocation DefaultLoc); void CheckStaticLocalForDllExport(VarDecl *VD); void FinalizeDeclaration(Decl *D); DeclGroupPtrTy FinalizeDeclaratorGroup(Scope *S, const DeclSpec &DS, ArrayRef Group); DeclGroupPtrTy BuildDeclaratorGroup(MutableArrayRef Group); /// Should be called on all declarations that might have attached /// documentation comments. void ActOnDocumentableDecl(Decl *D); void ActOnDocumentableDecls(ArrayRef Group); void ActOnFinishKNRParamDeclarations(Scope *S, Declarator &D, SourceLocation LocAfterDecls); void CheckForFunctionRedefinition( FunctionDecl *FD, const FunctionDecl *EffectiveDefinition = nullptr, SkipBodyInfo *SkipBody = nullptr); Decl *ActOnStartOfFunctionDef(Scope *S, Declarator &D, MultiTemplateParamsArg TemplateParamLists, SkipBodyInfo *SkipBody = nullptr); Decl *ActOnStartOfFunctionDef(Scope *S, Decl *D, SkipBodyInfo *SkipBody = nullptr); void ActOnStartTrailingRequiresClause(Scope *S, Declarator &D); ExprResult ActOnFinishTrailingRequiresClause(ExprResult ConstraintExpr); void ActOnStartOfObjCMethodDef(Scope *S, Decl *D); bool isObjCMethodDecl(Decl *D) { return D && isa(D); } /// Determine whether we can delay parsing the body of a function or /// function template until it is used, assuming we don't care about emitting /// code for that function. /// /// This will be \c false if we may need the body of the function in the /// middle of parsing an expression (where it's impractical to switch to /// parsing a different function), for instance, if it's constexpr in C++11 /// or has an 'auto' return type in C++14. These cases are essentially bugs. bool canDelayFunctionBody(const Declarator &D); /// Determine whether we can skip parsing the body of a function /// definition, assuming we don't care about analyzing its body or emitting /// code for that function. /// /// This will be \c false only if we may need the body of the function in /// order to parse the rest of the program (for instance, if it is /// \c constexpr in C++11 or has an 'auto' return type in C++14). bool canSkipFunctionBody(Decl *D); void computeNRVO(Stmt *Body, sema::FunctionScopeInfo *Scope); Decl *ActOnFinishFunctionBody(Decl *Decl, Stmt *Body); Decl *ActOnFinishFunctionBody(Decl *Decl, Stmt *Body, bool IsInstantiation); Decl *ActOnSkippedFunctionBody(Decl *Decl); void ActOnFinishInlineFunctionDef(FunctionDecl *D); /// ActOnFinishDelayedAttribute - Invoked when we have finished parsing an /// attribute for which parsing is delayed. void ActOnFinishDelayedAttribute(Scope *S, Decl *D, ParsedAttributes &Attrs); /// Diagnose any unused parameters in the given sequence of /// ParmVarDecl pointers. void DiagnoseUnusedParameters(ArrayRef Parameters); /// Diagnose whether the size of parameters or return value of a /// function or obj-c method definition is pass-by-value and larger than a /// specified threshold. void DiagnoseSizeOfParametersAndReturnValue(ArrayRef Parameters, QualType ReturnTy, NamedDecl *D); void DiagnoseInvalidJumps(Stmt *Body); Decl *ActOnFileScopeAsmDecl(Expr *expr, SourceLocation AsmLoc, SourceLocation RParenLoc); /// Handle a C++11 empty-declaration and attribute-declaration. Decl *ActOnEmptyDeclaration(Scope *S, const ParsedAttributesView &AttrList, SourceLocation SemiLoc); enum class ModuleDeclKind { Interface, ///< 'export module X;' Implementation, ///< 'module X;' }; /// The parser has processed a module-declaration that begins the definition /// of a module interface or implementation. DeclGroupPtrTy ActOnModuleDecl(SourceLocation StartLoc, SourceLocation ModuleLoc, ModuleDeclKind MDK, ModuleIdPath Path, bool IsFirstDecl); /// The parser has processed a global-module-fragment declaration that begins /// the definition of the global module fragment of the current module unit. /// \param ModuleLoc The location of the 'module' keyword. DeclGroupPtrTy ActOnGlobalModuleFragmentDecl(SourceLocation ModuleLoc); /// The parser has processed a private-module-fragment declaration that begins /// the definition of the private module fragment of the current module unit. /// \param ModuleLoc The location of the 'module' keyword. /// \param PrivateLoc The location of the 'private' keyword. DeclGroupPtrTy ActOnPrivateModuleFragmentDecl(SourceLocation ModuleLoc, SourceLocation PrivateLoc); /// The parser has processed a module import declaration. /// /// \param StartLoc The location of the first token in the declaration. This /// could be the location of an '@', 'export', or 'import'. /// \param ExportLoc The location of the 'export' keyword, if any. /// \param ImportLoc The location of the 'import' keyword. /// \param Path The module access path. DeclResult ActOnModuleImport(SourceLocation StartLoc, SourceLocation ExportLoc, SourceLocation ImportLoc, ModuleIdPath Path); DeclResult ActOnModuleImport(SourceLocation StartLoc, SourceLocation ExportLoc, SourceLocation ImportLoc, Module *M, ModuleIdPath Path = {}); /// The parser has processed a module import translated from a /// #include or similar preprocessing directive. void ActOnModuleInclude(SourceLocation DirectiveLoc, Module *Mod); void BuildModuleInclude(SourceLocation DirectiveLoc, Module *Mod); /// The parsed has entered a submodule. void ActOnModuleBegin(SourceLocation DirectiveLoc, Module *Mod); /// The parser has left a submodule. void ActOnModuleEnd(SourceLocation DirectiveLoc, Module *Mod); /// Create an implicit import of the given module at the given /// source location, for error recovery, if possible. /// /// This routine is typically used when an entity found by name lookup /// is actually hidden within a module that we know about but the user /// has forgotten to import. void createImplicitModuleImportForErrorRecovery(SourceLocation Loc, Module *Mod); /// Kinds of missing import. Note, the values of these enumerators correspond /// to %select values in diagnostics. enum class MissingImportKind { Declaration, Definition, DefaultArgument, ExplicitSpecialization, PartialSpecialization }; /// Diagnose that the specified declaration needs to be visible but /// isn't, and suggest a module import that would resolve the problem. void diagnoseMissingImport(SourceLocation Loc, NamedDecl *Decl, MissingImportKind MIK, bool Recover = true); void diagnoseMissingImport(SourceLocation Loc, NamedDecl *Decl, SourceLocation DeclLoc, ArrayRef Modules, MissingImportKind MIK, bool Recover); Decl *ActOnStartExportDecl(Scope *S, SourceLocation ExportLoc, SourceLocation LBraceLoc); Decl *ActOnFinishExportDecl(Scope *S, Decl *ExportDecl, SourceLocation RBraceLoc); /// We've found a use of a templated declaration that would trigger an /// implicit instantiation. Check that any relevant explicit specializations /// and partial specializations are visible, and diagnose if not. void checkSpecializationVisibility(SourceLocation Loc, NamedDecl *Spec); /// We've found a use of a template specialization that would select a /// partial specialization. Check that the partial specialization is visible, /// and diagnose if not. void checkPartialSpecializationVisibility(SourceLocation Loc, NamedDecl *Spec); /// Retrieve a suitable printing policy for diagnostics. PrintingPolicy getPrintingPolicy() const { return getPrintingPolicy(Context, PP); } /// Retrieve a suitable printing policy for diagnostics. static PrintingPolicy getPrintingPolicy(const ASTContext &Ctx, const Preprocessor &PP); /// Scope actions. void ActOnPopScope(SourceLocation Loc, Scope *S); void ActOnTranslationUnitScope(Scope *S); Decl *ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, DeclSpec &DS, RecordDecl *&AnonRecord); Decl *ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, DeclSpec &DS, MultiTemplateParamsArg TemplateParams, bool IsExplicitInstantiation, RecordDecl *&AnonRecord); Decl *BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, AccessSpecifier AS, RecordDecl *Record, const PrintingPolicy &Policy); Decl *BuildMicrosoftCAnonymousStruct(Scope *S, DeclSpec &DS, RecordDecl *Record); /// Common ways to introduce type names without a tag for use in diagnostics. /// Keep in sync with err_tag_reference_non_tag. enum NonTagKind { NTK_NonStruct, NTK_NonClass, NTK_NonUnion, NTK_NonEnum, NTK_Typedef, NTK_TypeAlias, NTK_Template, NTK_TypeAliasTemplate, NTK_TemplateTemplateArgument, }; /// Given a non-tag type declaration, returns an enum useful for indicating /// what kind of non-tag type this is. NonTagKind getNonTagTypeDeclKind(const Decl *D, TagTypeKind TTK); bool isAcceptableTagRedeclaration(const TagDecl *Previous, TagTypeKind NewTag, bool isDefinition, SourceLocation NewTagLoc, const IdentifierInfo *Name); enum TagUseKind { TUK_Reference, // Reference to a tag: 'struct foo *X;' TUK_Declaration, // Fwd decl of a tag: 'struct foo;' TUK_Definition, // Definition of a tag: 'struct foo { int X; } Y;' TUK_Friend // Friend declaration: 'friend struct foo;' }; Decl *ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc, CXXScopeSpec &SS, IdentifierInfo *Name, SourceLocation NameLoc, const ParsedAttributesView &Attr, AccessSpecifier AS, SourceLocation ModulePrivateLoc, MultiTemplateParamsArg TemplateParameterLists, bool &OwnedDecl, bool &IsDependent, SourceLocation ScopedEnumKWLoc, bool ScopedEnumUsesClassTag, TypeResult UnderlyingType, bool IsTypeSpecifier, bool IsTemplateParamOrArg, SkipBodyInfo *SkipBody = nullptr); Decl *ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc, unsigned TagSpec, SourceLocation TagLoc, CXXScopeSpec &SS, IdentifierInfo *Name, SourceLocation NameLoc, const ParsedAttributesView &Attr, MultiTemplateParamsArg TempParamLists); TypeResult ActOnDependentTag(Scope *S, unsigned TagSpec, TagUseKind TUK, const CXXScopeSpec &SS, IdentifierInfo *Name, SourceLocation TagLoc, SourceLocation NameLoc); void ActOnDefs(Scope *S, Decl *TagD, SourceLocation DeclStart, IdentifierInfo *ClassName, SmallVectorImpl &Decls); Decl *ActOnField(Scope *S, Decl *TagD, SourceLocation DeclStart, Declarator &D, Expr *BitfieldWidth); FieldDecl *HandleField(Scope *S, RecordDecl *TagD, SourceLocation DeclStart, Declarator &D, Expr *BitfieldWidth, InClassInitStyle InitStyle, AccessSpecifier AS); MSPropertyDecl *HandleMSProperty(Scope *S, RecordDecl *TagD, SourceLocation DeclStart, Declarator &D, Expr *BitfieldWidth, InClassInitStyle InitStyle, AccessSpecifier AS, const ParsedAttr &MSPropertyAttr); FieldDecl *CheckFieldDecl(DeclarationName Name, QualType T, TypeSourceInfo *TInfo, RecordDecl *Record, SourceLocation Loc, bool Mutable, Expr *BitfieldWidth, InClassInitStyle InitStyle, SourceLocation TSSL, AccessSpecifier AS, NamedDecl *PrevDecl, Declarator *D = nullptr); bool CheckNontrivialField(FieldDecl *FD); void DiagnoseNontrivial(const CXXRecordDecl *Record, CXXSpecialMember CSM); enum TrivialABIHandling { /// The triviality of a method unaffected by "trivial_abi". TAH_IgnoreTrivialABI, /// The triviality of a method affected by "trivial_abi". TAH_ConsiderTrivialABI }; bool SpecialMemberIsTrivial(CXXMethodDecl *MD, CXXSpecialMember CSM, TrivialABIHandling TAH = TAH_IgnoreTrivialABI, bool Diagnose = false); /// For a defaulted function, the kind of defaulted function that it is. class DefaultedFunctionKind { CXXSpecialMember SpecialMember : 8; DefaultedComparisonKind Comparison : 8; public: DefaultedFunctionKind() : SpecialMember(CXXInvalid), Comparison(DefaultedComparisonKind::None) { } DefaultedFunctionKind(CXXSpecialMember CSM) : SpecialMember(CSM), Comparison(DefaultedComparisonKind::None) {} DefaultedFunctionKind(DefaultedComparisonKind Comp) : SpecialMember(CXXInvalid), Comparison(Comp) {} bool isSpecialMember() const { return SpecialMember != CXXInvalid; } bool isComparison() const { return Comparison != DefaultedComparisonKind::None; } explicit operator bool() const { return isSpecialMember() || isComparison(); } CXXSpecialMember asSpecialMember() const { return SpecialMember; } DefaultedComparisonKind asComparison() const { return Comparison; } /// Get the index of this function kind for use in diagnostics. unsigned getDiagnosticIndex() const { static_assert(CXXInvalid > CXXDestructor, "invalid should have highest index"); static_assert((unsigned)DefaultedComparisonKind::None == 0, "none should be equal to zero"); return SpecialMember + (unsigned)Comparison; } }; DefaultedFunctionKind getDefaultedFunctionKind(const FunctionDecl *FD); CXXSpecialMember getSpecialMember(const CXXMethodDecl *MD) { return getDefaultedFunctionKind(MD).asSpecialMember(); } DefaultedComparisonKind getDefaultedComparisonKind(const FunctionDecl *FD) { return getDefaultedFunctionKind(FD).asComparison(); } void ActOnLastBitfield(SourceLocation DeclStart, SmallVectorImpl &AllIvarDecls); Decl *ActOnIvar(Scope *S, SourceLocation DeclStart, Declarator &D, Expr *BitfieldWidth, tok::ObjCKeywordKind visibility); // This is used for both record definitions and ObjC interface declarations. void ActOnFields(Scope *S, SourceLocation RecLoc, Decl *TagDecl, ArrayRef Fields, SourceLocation LBrac, SourceLocation RBrac, const ParsedAttributesView &AttrList); /// ActOnTagStartDefinition - Invoked when we have entered the /// scope of a tag's definition (e.g., for an enumeration, class, /// struct, or union). void ActOnTagStartDefinition(Scope *S, Decl *TagDecl); /// Perform ODR-like check for C/ObjC when merging tag types from modules. /// Differently from C++, actually parse the body and reject / error out /// in case of a structural mismatch. bool ActOnDuplicateDefinition(DeclSpec &DS, Decl *Prev, SkipBodyInfo &SkipBody); typedef void *SkippedDefinitionContext; /// Invoked when we enter a tag definition that we're skipping. SkippedDefinitionContext ActOnTagStartSkippedDefinition(Scope *S, Decl *TD); Decl *ActOnObjCContainerStartDefinition(Decl *IDecl); /// ActOnStartCXXMemberDeclarations - Invoked when we have parsed a /// C++ record definition's base-specifiers clause and are starting its /// member declarations. void ActOnStartCXXMemberDeclarations(Scope *S, Decl *TagDecl, SourceLocation FinalLoc, bool IsFinalSpelledSealed, SourceLocation LBraceLoc); /// ActOnTagFinishDefinition - Invoked once we have finished parsing /// the definition of a tag (enumeration, class, struct, or union). void ActOnTagFinishDefinition(Scope *S, Decl *TagDecl, SourceRange BraceRange); void ActOnTagFinishSkippedDefinition(SkippedDefinitionContext Context); void ActOnObjCContainerFinishDefinition(); /// Invoked when we must temporarily exit the objective-c container /// scope for parsing/looking-up C constructs. /// /// Must be followed by a call to \see ActOnObjCReenterContainerContext void ActOnObjCTemporaryExitContainerContext(DeclContext *DC); void ActOnObjCReenterContainerContext(DeclContext *DC); /// ActOnTagDefinitionError - Invoked when there was an unrecoverable /// error parsing the definition of a tag. void ActOnTagDefinitionError(Scope *S, Decl *TagDecl); EnumConstantDecl *CheckEnumConstant(EnumDecl *Enum, EnumConstantDecl *LastEnumConst, SourceLocation IdLoc, IdentifierInfo *Id, Expr *val); bool CheckEnumUnderlyingType(TypeSourceInfo *TI); bool CheckEnumRedeclaration(SourceLocation EnumLoc, bool IsScoped, QualType EnumUnderlyingTy, bool IsFixed, const EnumDecl *Prev); /// Determine whether the body of an anonymous enumeration should be skipped. /// \param II The name of the first enumerator. SkipBodyInfo shouldSkipAnonEnumBody(Scope *S, IdentifierInfo *II, SourceLocation IILoc); Decl *ActOnEnumConstant(Scope *S, Decl *EnumDecl, Decl *LastEnumConstant, SourceLocation IdLoc, IdentifierInfo *Id, const ParsedAttributesView &Attrs, SourceLocation EqualLoc, Expr *Val); void ActOnEnumBody(SourceLocation EnumLoc, SourceRange BraceRange, Decl *EnumDecl, ArrayRef Elements, Scope *S, const ParsedAttributesView &Attr); DeclContext *getContainingDC(DeclContext *DC); /// Set the current declaration context until it gets popped. void PushDeclContext(Scope *S, DeclContext *DC); void PopDeclContext(); /// EnterDeclaratorContext - Used when we must lookup names in the context /// of a declarator's nested name specifier. void EnterDeclaratorContext(Scope *S, DeclContext *DC); void ExitDeclaratorContext(Scope *S); /// Push the parameters of D, which must be a function, into scope. void ActOnReenterFunctionContext(Scope* S, Decl* D); void ActOnExitFunctionContext(); DeclContext *getFunctionLevelDeclContext(); /// getCurFunctionDecl - If inside of a function body, this returns a pointer /// to the function decl for the function being parsed. If we're currently /// in a 'block', this returns the containing context. FunctionDecl *getCurFunctionDecl(); /// getCurMethodDecl - If inside of a method body, this returns a pointer to /// the method decl for the method being parsed. If we're currently /// in a 'block', this returns the containing context. ObjCMethodDecl *getCurMethodDecl(); /// getCurFunctionOrMethodDecl - Return the Decl for the current ObjC method /// or C function we're in, otherwise return null. If we're currently /// in a 'block', this returns the containing context. NamedDecl *getCurFunctionOrMethodDecl(); /// Add this decl to the scope shadowed decl chains. void PushOnScopeChains(NamedDecl *D, Scope *S, bool AddToContext = true); /// isDeclInScope - If 'Ctx' is a function/method, isDeclInScope returns true /// if 'D' is in Scope 'S', otherwise 'S' is ignored and isDeclInScope returns /// true if 'D' belongs to the given declaration context. /// /// \param AllowInlineNamespace If \c true, allow the declaration to be in the /// enclosing namespace set of the context, rather than contained /// directly within it. bool isDeclInScope(NamedDecl *D, DeclContext *Ctx, Scope *S = nullptr, bool AllowInlineNamespace = false); /// Finds the scope corresponding to the given decl context, if it /// happens to be an enclosing scope. Otherwise return NULL. static Scope *getScopeForDeclContext(Scope *S, DeclContext *DC); /// Subroutines of ActOnDeclarator(). TypedefDecl *ParseTypedefDecl(Scope *S, Declarator &D, QualType T, TypeSourceInfo *TInfo); bool isIncompatibleTypedef(TypeDecl *Old, TypedefNameDecl *New); /// Describes the kind of merge to perform for availability /// attributes (including "deprecated", "unavailable", and "availability"). enum AvailabilityMergeKind { /// Don't merge availability attributes at all. AMK_None, /// Merge availability attributes for a redeclaration, which requires /// an exact match. AMK_Redeclaration, /// Merge availability attributes for an override, which requires /// an exact match or a weakening of constraints. AMK_Override, /// Merge availability attributes for an implementation of /// a protocol requirement. AMK_ProtocolImplementation, }; /// Describes the kind of priority given to an availability attribute. /// /// The sum of priorities deteremines the final priority of the attribute. /// The final priority determines how the attribute will be merged. /// An attribute with a lower priority will always remove higher priority /// attributes for the specified platform when it is being applied. An /// attribute with a higher priority will not be applied if the declaration /// already has an availability attribute with a lower priority for the /// specified platform. The final prirority values are not expected to match /// the values in this enumeration, but instead should be treated as a plain /// integer value. This enumeration just names the priority weights that are /// used to calculate that final vaue. enum AvailabilityPriority : int { /// The availability attribute was specified explicitly next to the /// declaration. AP_Explicit = 0, /// The availability attribute was applied using '#pragma clang attribute'. AP_PragmaClangAttribute = 1, /// The availability attribute for a specific platform was inferred from /// an availability attribute for another platform. AP_InferredFromOtherPlatform = 2 }; /// Attribute merging methods. Return true if a new attribute was added. AvailabilityAttr * mergeAvailabilityAttr(NamedDecl *D, const AttributeCommonInfo &CI, IdentifierInfo *Platform, bool Implicit, VersionTuple Introduced, VersionTuple Deprecated, VersionTuple Obsoleted, bool IsUnavailable, StringRef Message, bool IsStrict, StringRef Replacement, AvailabilityMergeKind AMK, int Priority); TypeVisibilityAttr * mergeTypeVisibilityAttr(Decl *D, const AttributeCommonInfo &CI, TypeVisibilityAttr::VisibilityType Vis); VisibilityAttr *mergeVisibilityAttr(Decl *D, const AttributeCommonInfo &CI, VisibilityAttr::VisibilityType Vis); UuidAttr *mergeUuidAttr(Decl *D, const AttributeCommonInfo &CI, StringRef Uuid); DLLImportAttr *mergeDLLImportAttr(Decl *D, const AttributeCommonInfo &CI); DLLExportAttr *mergeDLLExportAttr(Decl *D, const AttributeCommonInfo &CI); MSInheritanceAttr *mergeMSInheritanceAttr(Decl *D, const AttributeCommonInfo &CI, bool BestCase, MSInheritanceModel Model); FormatAttr *mergeFormatAttr(Decl *D, const AttributeCommonInfo &CI, IdentifierInfo *Format, int FormatIdx, int FirstArg); SectionAttr *mergeSectionAttr(Decl *D, const AttributeCommonInfo &CI, StringRef Name); CodeSegAttr *mergeCodeSegAttr(Decl *D, const AttributeCommonInfo &CI, StringRef Name); AlwaysInlineAttr *mergeAlwaysInlineAttr(Decl *D, const AttributeCommonInfo &CI, const IdentifierInfo *Ident); MinSizeAttr *mergeMinSizeAttr(Decl *D, const AttributeCommonInfo &CI); NoSpeculativeLoadHardeningAttr * mergeNoSpeculativeLoadHardeningAttr(Decl *D, const NoSpeculativeLoadHardeningAttr &AL); SpeculativeLoadHardeningAttr * mergeSpeculativeLoadHardeningAttr(Decl *D, const SpeculativeLoadHardeningAttr &AL); OptimizeNoneAttr *mergeOptimizeNoneAttr(Decl *D, const AttributeCommonInfo &CI); InternalLinkageAttr *mergeInternalLinkageAttr(Decl *D, const ParsedAttr &AL); InternalLinkageAttr *mergeInternalLinkageAttr(Decl *D, const InternalLinkageAttr &AL); CommonAttr *mergeCommonAttr(Decl *D, const ParsedAttr &AL); CommonAttr *mergeCommonAttr(Decl *D, const CommonAttr &AL); void mergeDeclAttributes(NamedDecl *New, Decl *Old, AvailabilityMergeKind AMK = AMK_Redeclaration); void MergeTypedefNameDecl(Scope *S, TypedefNameDecl *New, LookupResult &OldDecls); bool MergeFunctionDecl(FunctionDecl *New, NamedDecl *&Old, Scope *S, bool MergeTypeWithOld); bool MergeCompatibleFunctionDecls(FunctionDecl *New, FunctionDecl *Old, Scope *S, bool MergeTypeWithOld); void mergeObjCMethodDecls(ObjCMethodDecl *New, ObjCMethodDecl *Old); void MergeVarDecl(VarDecl *New, LookupResult &Previous); void MergeVarDeclTypes(VarDecl *New, VarDecl *Old, bool MergeTypeWithOld); void MergeVarDeclExceptionSpecs(VarDecl *New, VarDecl *Old); bool checkVarDeclRedefinition(VarDecl *OldDefn, VarDecl *NewDefn); void notePreviousDefinition(const NamedDecl *Old, SourceLocation New); bool MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old, Scope *S); // AssignmentAction - This is used by all the assignment diagnostic functions // to represent what is actually causing the operation enum AssignmentAction { AA_Assigning, AA_Passing, AA_Returning, AA_Converting, AA_Initializing, AA_Sending, AA_Casting, AA_Passing_CFAudited }; /// C++ Overloading. enum OverloadKind { /// This is a legitimate overload: the existing declarations are /// functions or function templates with different signatures. Ovl_Overload, /// This is not an overload because the signature exactly matches /// an existing declaration. Ovl_Match, /// This is not an overload because the lookup results contain a /// non-function. Ovl_NonFunction }; OverloadKind CheckOverload(Scope *S, FunctionDecl *New, const LookupResult &OldDecls, NamedDecl *&OldDecl, bool IsForUsingDecl); bool IsOverload(FunctionDecl *New, FunctionDecl *Old, bool IsForUsingDecl, bool ConsiderCudaAttrs = true, bool ConsiderRequiresClauses = true); ImplicitConversionSequence TryImplicitConversion(Expr *From, QualType ToType, bool SuppressUserConversions, bool AllowExplicit, bool InOverloadResolution, bool CStyle, bool AllowObjCWritebackConversion); bool IsIntegralPromotion(Expr *From, QualType FromType, QualType ToType); bool IsFloatingPointPromotion(QualType FromType, QualType ToType); bool IsComplexPromotion(QualType FromType, QualType ToType); bool IsPointerConversion(Expr *From, QualType FromType, QualType ToType, bool InOverloadResolution, QualType& ConvertedType, bool &IncompatibleObjC); bool isObjCPointerConversion(QualType FromType, QualType ToType, QualType& ConvertedType, bool &IncompatibleObjC); bool isObjCWritebackConversion(QualType FromType, QualType ToType, QualType &ConvertedType); bool IsBlockPointerConversion(QualType FromType, QualType ToType, QualType& ConvertedType); bool FunctionParamTypesAreEqual(const FunctionProtoType *OldType, const FunctionProtoType *NewType, unsigned *ArgPos = nullptr); void HandleFunctionTypeMismatch(PartialDiagnostic &PDiag, QualType FromType, QualType ToType); void maybeExtendBlockObject(ExprResult &E); CastKind PrepareCastToObjCObjectPointer(ExprResult &E); bool CheckPointerConversion(Expr *From, QualType ToType, CastKind &Kind, CXXCastPath& BasePath, bool IgnoreBaseAccess, bool Diagnose = true); bool IsMemberPointerConversion(Expr *From, QualType FromType, QualType ToType, bool InOverloadResolution, QualType &ConvertedType); bool CheckMemberPointerConversion(Expr *From, QualType ToType, CastKind &Kind, CXXCastPath &BasePath, bool IgnoreBaseAccess); bool IsQualificationConversion(QualType FromType, QualType ToType, bool CStyle, bool &ObjCLifetimeConversion); bool IsFunctionConversion(QualType FromType, QualType ToType, QualType &ResultTy); bool DiagnoseMultipleUserDefinedConversion(Expr *From, QualType ToType); bool isSameOrCompatibleFunctionType(CanQualType Param, CanQualType Arg); ExprResult PerformMoveOrCopyInitialization(const InitializedEntity &Entity, const VarDecl *NRVOCandidate, QualType ResultType, Expr *Value, bool AllowNRVO = true); bool CanPerformAggregateInitializationForOverloadResolution( const InitializedEntity &Entity, InitListExpr *From); bool CanPerformCopyInitialization(const InitializedEntity &Entity, ExprResult Init); ExprResult PerformCopyInitialization(const InitializedEntity &Entity, SourceLocation EqualLoc, ExprResult Init, bool TopLevelOfInitList = false, bool AllowExplicit = false); ExprResult PerformObjectArgumentInitialization(Expr *From, NestedNameSpecifier *Qualifier, NamedDecl *FoundDecl, CXXMethodDecl *Method); /// Check that the lifetime of the initializer (and its subobjects) is /// sufficient for initializing the entity, and perform lifetime extension /// (when permitted) if not. void checkInitializerLifetime(const InitializedEntity &Entity, Expr *Init); ExprResult PerformContextuallyConvertToBool(Expr *From); ExprResult PerformContextuallyConvertToObjCPointer(Expr *From); /// Contexts in which a converted constant expression is required. enum CCEKind { CCEK_CaseValue, ///< Expression in a case label. CCEK_Enumerator, ///< Enumerator value with fixed underlying type. CCEK_TemplateArg, ///< Value of a non-type template parameter. CCEK_NewExpr, ///< Constant expression in a noptr-new-declarator. CCEK_ConstexprIf, ///< Condition in a constexpr if statement. CCEK_ExplicitBool ///< Condition in an explicit(bool) specifier. }; ExprResult CheckConvertedConstantExpression(Expr *From, QualType T, llvm::APSInt &Value, CCEKind CCE); ExprResult CheckConvertedConstantExpression(Expr *From, QualType T, APValue &Value, CCEKind CCE); /// Abstract base class used to perform a contextual implicit /// conversion from an expression to any type passing a filter. class ContextualImplicitConverter { public: bool Suppress; bool SuppressConversion; ContextualImplicitConverter(bool Suppress = false, bool SuppressConversion = false) : Suppress(Suppress), SuppressConversion(SuppressConversion) {} /// Determine whether the specified type is a valid destination type /// for this conversion. virtual bool match(QualType T) = 0; /// Emits a diagnostic complaining that the expression does not have /// integral or enumeration type. virtual SemaDiagnosticBuilder diagnoseNoMatch(Sema &S, SourceLocation Loc, QualType T) = 0; /// Emits a diagnostic when the expression has incomplete class type. virtual SemaDiagnosticBuilder diagnoseIncomplete(Sema &S, SourceLocation Loc, QualType T) = 0; /// Emits a diagnostic when the only matching conversion function /// is explicit. virtual SemaDiagnosticBuilder diagnoseExplicitConv( Sema &S, SourceLocation Loc, QualType T, QualType ConvTy) = 0; /// Emits a note for the explicit conversion function. virtual SemaDiagnosticBuilder noteExplicitConv(Sema &S, CXXConversionDecl *Conv, QualType ConvTy) = 0; /// Emits a diagnostic when there are multiple possible conversion /// functions. virtual SemaDiagnosticBuilder diagnoseAmbiguous(Sema &S, SourceLocation Loc, QualType T) = 0; /// Emits a note for one of the candidate conversions. virtual SemaDiagnosticBuilder noteAmbiguous(Sema &S, CXXConversionDecl *Conv, QualType ConvTy) = 0; /// Emits a diagnostic when we picked a conversion function /// (for cases when we are not allowed to pick a conversion function). virtual SemaDiagnosticBuilder diagnoseConversion( Sema &S, SourceLocation Loc, QualType T, QualType ConvTy) = 0; virtual ~ContextualImplicitConverter() {} }; class ICEConvertDiagnoser : public ContextualImplicitConverter { bool AllowScopedEnumerations; public: ICEConvertDiagnoser(bool AllowScopedEnumerations, bool Suppress, bool SuppressConversion) : ContextualImplicitConverter(Suppress, SuppressConversion), AllowScopedEnumerations(AllowScopedEnumerations) {} /// Match an integral or (possibly scoped) enumeration type. bool match(QualType T) override; SemaDiagnosticBuilder diagnoseNoMatch(Sema &S, SourceLocation Loc, QualType T) override { return diagnoseNotInt(S, Loc, T); } /// Emits a diagnostic complaining that the expression does not have /// integral or enumeration type. virtual SemaDiagnosticBuilder diagnoseNotInt(Sema &S, SourceLocation Loc, QualType T) = 0; }; /// Perform a contextual implicit conversion. ExprResult PerformContextualImplicitConversion( SourceLocation Loc, Expr *FromE, ContextualImplicitConverter &Converter); enum ObjCSubscriptKind { OS_Array, OS_Dictionary, OS_Error }; ObjCSubscriptKind CheckSubscriptingKind(Expr *FromE); // Note that LK_String is intentionally after the other literals, as // this is used for diagnostics logic. enum ObjCLiteralKind { LK_Array, LK_Dictionary, LK_Numeric, LK_Boxed, LK_String, LK_Block, LK_None }; ObjCLiteralKind CheckLiteralKind(Expr *FromE); ExprResult PerformObjectMemberConversion(Expr *From, NestedNameSpecifier *Qualifier, NamedDecl *FoundDecl, NamedDecl *Member); // Members have to be NamespaceDecl* or TranslationUnitDecl*. // TODO: make this is a typesafe union. typedef llvm::SmallSetVector AssociatedNamespaceSet; typedef llvm::SmallSetVector AssociatedClassSet; using ADLCallKind = CallExpr::ADLCallKind; void AddOverloadCandidate(FunctionDecl *Function, DeclAccessPair FoundDecl, ArrayRef Args, OverloadCandidateSet &CandidateSet, bool SuppressUserConversions = false, bool PartialOverloading = false, bool AllowExplicit = true, bool AllowExplicitConversion = false, ADLCallKind IsADLCandidate = ADLCallKind::NotADL, ConversionSequenceList EarlyConversions = None, OverloadCandidateParamOrder PO = {}); void AddFunctionCandidates(const UnresolvedSetImpl &Functions, ArrayRef Args, OverloadCandidateSet &CandidateSet, TemplateArgumentListInfo *ExplicitTemplateArgs = nullptr, bool SuppressUserConversions = false, bool PartialOverloading = false, bool FirstArgumentIsBase = false); void AddMethodCandidate(DeclAccessPair FoundDecl, QualType ObjectType, Expr::Classification ObjectClassification, ArrayRef Args, OverloadCandidateSet& CandidateSet, bool SuppressUserConversion = false, OverloadCandidateParamOrder PO = {}); void AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl, CXXRecordDecl *ActingContext, QualType ObjectType, Expr::Classification ObjectClassification, ArrayRef Args, OverloadCandidateSet& CandidateSet, bool SuppressUserConversions = false, bool PartialOverloading = false, ConversionSequenceList EarlyConversions = None, OverloadCandidateParamOrder PO = {}); void AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl, DeclAccessPair FoundDecl, CXXRecordDecl *ActingContext, TemplateArgumentListInfo *ExplicitTemplateArgs, QualType ObjectType, Expr::Classification ObjectClassification, ArrayRef Args, OverloadCandidateSet& CandidateSet, bool SuppressUserConversions = false, bool PartialOverloading = false, OverloadCandidateParamOrder PO = {}); void AddTemplateOverloadCandidate( FunctionTemplateDecl *FunctionTemplate, DeclAccessPair FoundDecl, TemplateArgumentListInfo *ExplicitTemplateArgs, ArrayRef Args, OverloadCandidateSet &CandidateSet, bool SuppressUserConversions = false, bool PartialOverloading = false, bool AllowExplicit = true, ADLCallKind IsADLCandidate = ADLCallKind::NotADL, OverloadCandidateParamOrder PO = {}); bool CheckNonDependentConversions( FunctionTemplateDecl *FunctionTemplate, ArrayRef ParamTypes, ArrayRef Args, OverloadCandidateSet &CandidateSet, ConversionSequenceList &Conversions, bool SuppressUserConversions, CXXRecordDecl *ActingContext = nullptr, QualType ObjectType = QualType(), Expr::Classification ObjectClassification = {}, OverloadCandidateParamOrder PO = {}); void AddConversionCandidate( CXXConversionDecl *Conversion, DeclAccessPair FoundDecl, CXXRecordDecl *ActingContext, Expr *From, QualType ToType, OverloadCandidateSet &CandidateSet, bool AllowObjCConversionOnExplicit, bool AllowExplicit, bool AllowResultConversion = true); void AddTemplateConversionCandidate( FunctionTemplateDecl *FunctionTemplate, DeclAccessPair FoundDecl, CXXRecordDecl *ActingContext, Expr *From, QualType ToType, OverloadCandidateSet &CandidateSet, bool AllowObjCConversionOnExplicit, bool AllowExplicit, bool AllowResultConversion = true); void AddSurrogateCandidate(CXXConversionDecl *Conversion, DeclAccessPair FoundDecl, CXXRecordDecl *ActingContext, const FunctionProtoType *Proto, Expr *Object, ArrayRef Args, OverloadCandidateSet& CandidateSet); void AddNonMemberOperatorCandidates( const UnresolvedSetImpl &Functions, ArrayRef Args, OverloadCandidateSet &CandidateSet, TemplateArgumentListInfo *ExplicitTemplateArgs = nullptr); void AddMemberOperatorCandidates(OverloadedOperatorKind Op, SourceLocation OpLoc, ArrayRef Args, OverloadCandidateSet &CandidateSet, OverloadCandidateParamOrder PO = {}); void AddBuiltinCandidate(QualType *ParamTys, ArrayRef Args, OverloadCandidateSet& CandidateSet, bool IsAssignmentOperator = false, unsigned NumContextualBoolArguments = 0); void AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, SourceLocation OpLoc, ArrayRef Args, OverloadCandidateSet& CandidateSet); void AddArgumentDependentLookupCandidates(DeclarationName Name, SourceLocation Loc, ArrayRef Args, TemplateArgumentListInfo *ExplicitTemplateArgs, OverloadCandidateSet& CandidateSet, bool PartialOverloading = false); // Emit as a 'note' the specific overload candidate void NoteOverloadCandidate( NamedDecl *Found, FunctionDecl *Fn, OverloadCandidateRewriteKind RewriteKind = OverloadCandidateRewriteKind(), QualType DestType = QualType(), bool TakingAddress = false); // Emit as a series of 'note's all template and non-templates identified by // the expression Expr void NoteAllOverloadCandidates(Expr *E, QualType DestType = QualType(), bool TakingAddress = false); /// Check the enable_if expressions on the given function. Returns the first /// failing attribute, or NULL if they were all successful. EnableIfAttr *CheckEnableIf(FunctionDecl *Function, ArrayRef Args, bool MissingImplicitThis = false); /// Find the failed Boolean condition within a given Boolean /// constant expression, and describe it with a string. std::pair findFailedBooleanCondition(Expr *Cond); /// Emit diagnostics for the diagnose_if attributes on Function, ignoring any /// non-ArgDependent DiagnoseIfAttrs. /// /// Argument-dependent diagnose_if attributes should be checked each time a /// function is used as a direct callee of a function call. /// /// Returns true if any errors were emitted. bool diagnoseArgDependentDiagnoseIfAttrs(const FunctionDecl *Function, const Expr *ThisArg, ArrayRef Args, SourceLocation Loc); /// Emit diagnostics for the diagnose_if attributes on Function, ignoring any /// ArgDependent DiagnoseIfAttrs. /// /// Argument-independent diagnose_if attributes should be checked on every use /// of a function. /// /// Returns true if any errors were emitted. bool diagnoseArgIndependentDiagnoseIfAttrs(const NamedDecl *ND, SourceLocation Loc); /// Returns whether the given function's address can be taken or not, /// optionally emitting a diagnostic if the address can't be taken. /// /// Returns false if taking the address of the function is illegal. bool checkAddressOfFunctionIsAvailable(const FunctionDecl *Function, bool Complain = false, SourceLocation Loc = SourceLocation()); // [PossiblyAFunctionType] --> [Return] // NonFunctionType --> NonFunctionType // R (A) --> R(A) // R (*)(A) --> R (A) // R (&)(A) --> R (A) // R (S::*)(A) --> R (A) QualType ExtractUnqualifiedFunctionType(QualType PossiblyAFunctionType); FunctionDecl * ResolveAddressOfOverloadedFunction(Expr *AddressOfExpr, QualType TargetType, bool Complain, DeclAccessPair &Found, bool *pHadMultipleCandidates = nullptr); FunctionDecl * resolveAddressOfSingleOverloadCandidate(Expr *E, DeclAccessPair &FoundResult); bool resolveAndFixAddressOfSingleOverloadCandidate( ExprResult &SrcExpr, bool DoFunctionPointerConversion = false); FunctionDecl * ResolveSingleFunctionTemplateSpecialization(OverloadExpr *ovl, bool Complain = false, DeclAccessPair *Found = nullptr); bool ResolveAndFixSingleFunctionTemplateSpecialization( ExprResult &SrcExpr, bool DoFunctionPointerConverion = false, bool Complain = false, SourceRange OpRangeForComplaining = SourceRange(), QualType DestTypeForComplaining = QualType(), unsigned DiagIDForComplaining = 0); Expr *FixOverloadedFunctionReference(Expr *E, DeclAccessPair FoundDecl, FunctionDecl *Fn); ExprResult FixOverloadedFunctionReference(ExprResult, DeclAccessPair FoundDecl, FunctionDecl *Fn); void AddOverloadedCallCandidates(UnresolvedLookupExpr *ULE, ArrayRef Args, OverloadCandidateSet &CandidateSet, bool PartialOverloading = false); // An enum used to represent the different possible results of building a // range-based for loop. enum ForRangeStatus { FRS_Success, FRS_NoViableFunction, FRS_DiagnosticIssued }; ForRangeStatus BuildForRangeBeginEndCall(SourceLocation Loc, SourceLocation RangeLoc, const DeclarationNameInfo &NameInfo, LookupResult &MemberLookup, OverloadCandidateSet *CandidateSet, Expr *Range, ExprResult *CallExpr); ExprResult BuildOverloadedCallExpr(Scope *S, Expr *Fn, UnresolvedLookupExpr *ULE, SourceLocation LParenLoc, MultiExprArg Args, SourceLocation RParenLoc, Expr *ExecConfig, bool AllowTypoCorrection=true, bool CalleesAddressIsTaken=false); bool buildOverloadedCallSet(Scope *S, Expr *Fn, UnresolvedLookupExpr *ULE, MultiExprArg Args, SourceLocation RParenLoc, OverloadCandidateSet *CandidateSet, ExprResult *Result); ExprResult CreateOverloadedUnaryOp(SourceLocation OpLoc, UnaryOperatorKind Opc, const UnresolvedSetImpl &Fns, Expr *input, bool RequiresADL = true); void LookupOverloadedBinOp(OverloadCandidateSet &CandidateSet, OverloadedOperatorKind Op, const UnresolvedSetImpl &Fns, ArrayRef Args, bool RequiresADL = true); ExprResult CreateOverloadedBinOp(SourceLocation OpLoc, BinaryOperatorKind Opc, const UnresolvedSetImpl &Fns, Expr *LHS, Expr *RHS, bool RequiresADL = true, bool AllowRewrittenCandidates = true, FunctionDecl *DefaultedFn = nullptr); ExprResult BuildSynthesizedThreeWayComparison(SourceLocation OpLoc, const UnresolvedSetImpl &Fns, Expr *LHS, Expr *RHS, FunctionDecl *DefaultedFn); ExprResult CreateOverloadedArraySubscriptExpr(SourceLocation LLoc, SourceLocation RLoc, Expr *Base,Expr *Idx); ExprResult BuildCallToMemberFunction(Scope *S, Expr *MemExpr, SourceLocation LParenLoc, MultiExprArg Args, SourceLocation RParenLoc); ExprResult BuildCallToObjectOfClassType(Scope *S, Expr *Object, SourceLocation LParenLoc, MultiExprArg Args, SourceLocation RParenLoc); ExprResult BuildOverloadedArrowExpr(Scope *S, Expr *Base, SourceLocation OpLoc, bool *NoArrowOperatorFound = nullptr); /// CheckCallReturnType - Checks that a call expression's return type is /// complete. Returns true on failure. The location passed in is the location /// that best represents the call. bool CheckCallReturnType(QualType ReturnType, SourceLocation Loc, CallExpr *CE, FunctionDecl *FD); /// Helpers for dealing with blocks and functions. bool CheckParmsForFunctionDef(ArrayRef Parameters, bool CheckParameterNames); void CheckCXXDefaultArguments(FunctionDecl *FD); void CheckExtraCXXDefaultArguments(Declarator &D); Scope *getNonFieldDeclScope(Scope *S); /// \name Name lookup /// /// These routines provide name lookup that is used during semantic /// analysis to resolve the various kinds of names (identifiers, /// overloaded operator names, constructor names, etc.) into zero or /// more declarations within a particular scope. The major entry /// points are LookupName, which performs unqualified name lookup, /// and LookupQualifiedName, which performs qualified name lookup. /// /// All name lookup is performed based on some specific criteria, /// which specify what names will be visible to name lookup and how /// far name lookup should work. These criteria are important both /// for capturing language semantics (certain lookups will ignore /// certain names, for example) and for performance, since name /// lookup is often a bottleneck in the compilation of C++. Name /// lookup criteria is specified via the LookupCriteria enumeration. /// /// The results of name lookup can vary based on the kind of name /// lookup performed, the current language, and the translation /// unit. In C, for example, name lookup will either return nothing /// (no entity found) or a single declaration. In C++, name lookup /// can additionally refer to a set of overloaded functions or /// result in an ambiguity. All of the possible results of name /// lookup are captured by the LookupResult class, which provides /// the ability to distinguish among them. //@{ /// Describes the kind of name lookup to perform. enum LookupNameKind { /// Ordinary name lookup, which finds ordinary names (functions, /// variables, typedefs, etc.) in C and most kinds of names /// (functions, variables, members, types, etc.) in C++. LookupOrdinaryName = 0, /// Tag name lookup, which finds the names of enums, classes, /// structs, and unions. LookupTagName, /// Label name lookup. LookupLabel, /// Member name lookup, which finds the names of /// class/struct/union members. LookupMemberName, /// Look up of an operator name (e.g., operator+) for use with /// operator overloading. This lookup is similar to ordinary name /// lookup, but will ignore any declarations that are class members. LookupOperatorName, /// Look up of a name that precedes the '::' scope resolution /// operator in C++. This lookup completely ignores operator, object, /// function, and enumerator names (C++ [basic.lookup.qual]p1). LookupNestedNameSpecifierName, /// Look up a namespace name within a C++ using directive or /// namespace alias definition, ignoring non-namespace names (C++ /// [basic.lookup.udir]p1). LookupNamespaceName, /// Look up all declarations in a scope with the given name, /// including resolved using declarations. This is appropriate /// for checking redeclarations for a using declaration. LookupUsingDeclName, /// Look up an ordinary name that is going to be redeclared as a /// name with linkage. This lookup ignores any declarations that /// are outside of the current scope unless they have linkage. See /// C99 6.2.2p4-5 and C++ [basic.link]p6. LookupRedeclarationWithLinkage, /// Look up a friend of a local class. This lookup does not look /// outside the innermost non-class scope. See C++11 [class.friend]p11. LookupLocalFriendName, /// Look up the name of an Objective-C protocol. LookupObjCProtocolName, /// Look up implicit 'self' parameter of an objective-c method. LookupObjCImplicitSelfParam, /// Look up the name of an OpenMP user-defined reduction operation. LookupOMPReductionName, /// Look up the name of an OpenMP user-defined mapper. LookupOMPMapperName, /// Look up any declaration with any name. LookupAnyName }; /// Specifies whether (or how) name lookup is being performed for a /// redeclaration (vs. a reference). enum RedeclarationKind { /// The lookup is a reference to this name that is not for the /// purpose of redeclaring the name. NotForRedeclaration = 0, /// The lookup results will be used for redeclaration of a name, /// if an entity by that name already exists and is visible. ForVisibleRedeclaration, /// The lookup results will be used for redeclaration of a name /// with external linkage; non-visible lookup results with external linkage /// may also be found. ForExternalRedeclaration }; RedeclarationKind forRedeclarationInCurContext() { // A declaration with an owning module for linkage can never link against // anything that is not visible. We don't need to check linkage here; if // the context has internal linkage, redeclaration lookup won't find things // from other TUs, and we can't safely compute linkage yet in general. if (cast(CurContext) ->getOwningModuleForLinkage(/*IgnoreLinkage*/true)) return ForVisibleRedeclaration; return ForExternalRedeclaration; } /// The possible outcomes of name lookup for a literal operator. enum LiteralOperatorLookupResult { /// The lookup resulted in an error. LOLR_Error, /// The lookup found no match but no diagnostic was issued. LOLR_ErrorNoDiagnostic, /// The lookup found a single 'cooked' literal operator, which /// expects a normal literal to be built and passed to it. LOLR_Cooked, /// The lookup found a single 'raw' literal operator, which expects /// a string literal containing the spelling of the literal token. LOLR_Raw, /// The lookup found an overload set of literal operator templates, /// which expect the characters of the spelling of the literal token to be /// passed as a non-type template argument pack. LOLR_Template, /// The lookup found an overload set of literal operator templates, /// which expect the character type and characters of the spelling of the /// string literal token to be passed as template arguments. LOLR_StringTemplate }; SpecialMemberOverloadResult LookupSpecialMember(CXXRecordDecl *D, CXXSpecialMember SM, bool ConstArg, bool VolatileArg, bool RValueThis, bool ConstThis, bool VolatileThis); typedef std::function TypoDiagnosticGenerator; typedef std::function TypoRecoveryCallback; private: bool CppLookupName(LookupResult &R, Scope *S); struct TypoExprState { std::unique_ptr Consumer; TypoDiagnosticGenerator DiagHandler; TypoRecoveryCallback RecoveryHandler; TypoExprState(); TypoExprState(TypoExprState &&other) noexcept; TypoExprState &operator=(TypoExprState &&other) noexcept; }; /// The set of unhandled TypoExprs and their associated state. llvm::MapVector DelayedTypos; /// Creates a new TypoExpr AST node. TypoExpr *createDelayedTypo(std::unique_ptr TCC, TypoDiagnosticGenerator TDG, TypoRecoveryCallback TRC); // The set of known/encountered (unique, canonicalized) NamespaceDecls. // // The boolean value will be true to indicate that the namespace was loaded // from an AST/PCH file, or false otherwise. llvm::MapVector KnownNamespaces; /// Whether we have already loaded known namespaces from an extenal /// source. bool LoadedExternalKnownNamespaces; /// Helper for CorrectTypo and CorrectTypoDelayed used to create and /// populate a new TypoCorrectionConsumer. Returns nullptr if typo correction /// should be skipped entirely. std::unique_ptr makeTypoCorrectionConsumer(const DeclarationNameInfo &Typo, Sema::LookupNameKind LookupKind, Scope *S, CXXScopeSpec *SS, CorrectionCandidateCallback &CCC, DeclContext *MemberContext, bool EnteringContext, const ObjCObjectPointerType *OPT, bool ErrorRecovery); public: const TypoExprState &getTypoExprState(TypoExpr *TE) const; /// Clears the state of the given TypoExpr. void clearDelayedTypo(TypoExpr *TE); /// Look up a name, looking for a single declaration. Return /// null if the results were absent, ambiguous, or overloaded. /// /// It is preferable to use the elaborated form and explicitly handle /// ambiguity and overloaded. NamedDecl *LookupSingleName(Scope *S, DeclarationName Name, SourceLocation Loc, LookupNameKind NameKind, RedeclarationKind Redecl = NotForRedeclaration); bool LookupBuiltin(LookupResult &R); bool LookupName(LookupResult &R, Scope *S, bool AllowBuiltinCreation = false); bool LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, bool InUnqualifiedLookup = false); bool LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, CXXScopeSpec &SS); bool LookupParsedName(LookupResult &R, Scope *S, CXXScopeSpec *SS, bool AllowBuiltinCreation = false, bool EnteringContext = false); ObjCProtocolDecl *LookupProtocol(IdentifierInfo *II, SourceLocation IdLoc, RedeclarationKind Redecl = NotForRedeclaration); bool LookupInSuper(LookupResult &R, CXXRecordDecl *Class); void LookupOverloadedOperatorName(OverloadedOperatorKind Op, Scope *S, QualType T1, QualType T2, UnresolvedSetImpl &Functions); LabelDecl *LookupOrCreateLabel(IdentifierInfo *II, SourceLocation IdentLoc, SourceLocation GnuLabelLoc = SourceLocation()); DeclContextLookupResult LookupConstructors(CXXRecordDecl *Class); CXXConstructorDecl *LookupDefaultConstructor(CXXRecordDecl *Class); CXXConstructorDecl *LookupCopyingConstructor(CXXRecordDecl *Class, unsigned Quals); CXXMethodDecl *LookupCopyingAssignment(CXXRecordDecl *Class, unsigned Quals, bool RValueThis, unsigned ThisQuals); CXXConstructorDecl *LookupMovingConstructor(CXXRecordDecl *Class, unsigned Quals); CXXMethodDecl *LookupMovingAssignment(CXXRecordDecl *Class, unsigned Quals, bool RValueThis, unsigned ThisQuals); CXXDestructorDecl *LookupDestructor(CXXRecordDecl *Class); bool checkLiteralOperatorId(const CXXScopeSpec &SS, const UnqualifiedId &Id); LiteralOperatorLookupResult LookupLiteralOperator(Scope *S, LookupResult &R, ArrayRef ArgTys, bool AllowRaw, bool AllowTemplate, bool AllowStringTemplate, bool DiagnoseMissing); bool isKnownName(StringRef name); /// Status of the function emission on the CUDA/HIP/OpenMP host/device attrs. enum class FunctionEmissionStatus { Emitted, CUDADiscarded, // Discarded due to CUDA/HIP hostness OMPDiscarded, // Discarded due to OpenMP hostness TemplateDiscarded, // Discarded due to uninstantiated templates Unknown, }; FunctionEmissionStatus getEmissionStatus(FunctionDecl *Decl); // Whether the callee should be ignored in CUDA/HIP/OpenMP host/device check. bool shouldIgnoreInHostDeviceCheck(FunctionDecl *Callee); void ArgumentDependentLookup(DeclarationName Name, SourceLocation Loc, ArrayRef Args, ADLResult &Functions); void LookupVisibleDecls(Scope *S, LookupNameKind Kind, VisibleDeclConsumer &Consumer, bool IncludeGlobalScope = true, bool LoadExternal = true); void LookupVisibleDecls(DeclContext *Ctx, LookupNameKind Kind, VisibleDeclConsumer &Consumer, bool IncludeGlobalScope = true, bool IncludeDependentBases = false, bool LoadExternal = true); enum CorrectTypoKind { CTK_NonError, // CorrectTypo used in a non error recovery situation. CTK_ErrorRecovery // CorrectTypo used in normal error recovery. }; TypoCorrection CorrectTypo(const DeclarationNameInfo &Typo, Sema::LookupNameKind LookupKind, Scope *S, CXXScopeSpec *SS, CorrectionCandidateCallback &CCC, CorrectTypoKind Mode, DeclContext *MemberContext = nullptr, bool EnteringContext = false, const ObjCObjectPointerType *OPT = nullptr, bool RecordFailure = true); TypoExpr *CorrectTypoDelayed(const DeclarationNameInfo &Typo, Sema::LookupNameKind LookupKind, Scope *S, CXXScopeSpec *SS, CorrectionCandidateCallback &CCC, TypoDiagnosticGenerator TDG, TypoRecoveryCallback TRC, CorrectTypoKind Mode, DeclContext *MemberContext = nullptr, bool EnteringContext = false, const ObjCObjectPointerType *OPT = nullptr); /// Process any TypoExprs in the given Expr and its children, /// generating diagnostics as appropriate and returning a new Expr if there /// were typos that were all successfully corrected and ExprError if one or /// more typos could not be corrected. /// /// \param E The Expr to check for TypoExprs. /// /// \param InitDecl A VarDecl to avoid because the Expr being corrected is its /// initializer. /// /// \param Filter A function applied to a newly rebuilt Expr to determine if /// it is an acceptable/usable result from a single combination of typo /// corrections. As long as the filter returns ExprError, different /// combinations of corrections will be tried until all are exhausted. ExprResult CorrectDelayedTyposInExpr(Expr *E, VarDecl *InitDecl = nullptr, llvm::function_ref Filter = [](Expr *E) -> ExprResult { return E; }); ExprResult CorrectDelayedTyposInExpr(Expr *E, llvm::function_ref Filter) { return CorrectDelayedTyposInExpr(E, nullptr, Filter); } ExprResult CorrectDelayedTyposInExpr(ExprResult ER, VarDecl *InitDecl = nullptr, llvm::function_ref Filter = [](Expr *E) -> ExprResult { return E; }) { return ER.isInvalid() ? ER : CorrectDelayedTyposInExpr(ER.get(), Filter); } ExprResult CorrectDelayedTyposInExpr(ExprResult ER, llvm::function_ref Filter) { return CorrectDelayedTyposInExpr(ER, nullptr, Filter); } void diagnoseTypo(const TypoCorrection &Correction, const PartialDiagnostic &TypoDiag, bool ErrorRecovery = true); void diagnoseTypo(const TypoCorrection &Correction, const PartialDiagnostic &TypoDiag, const PartialDiagnostic &PrevNote, bool ErrorRecovery = true); void MarkTypoCorrectedFunctionDefinition(const NamedDecl *F); void FindAssociatedClassesAndNamespaces(SourceLocation InstantiationLoc, ArrayRef Args, AssociatedNamespaceSet &AssociatedNamespaces, AssociatedClassSet &AssociatedClasses); void FilterLookupForScope(LookupResult &R, DeclContext *Ctx, Scope *S, bool ConsiderLinkage, bool AllowInlineNamespace); bool CheckRedeclarationModuleOwnership(NamedDecl *New, NamedDecl *Old); void DiagnoseAmbiguousLookup(LookupResult &Result); //@} ObjCInterfaceDecl *getObjCInterfaceDecl(IdentifierInfo *&Id, SourceLocation IdLoc, bool TypoCorrection = false); NamedDecl *LazilyCreateBuiltin(IdentifierInfo *II, unsigned ID, Scope *S, bool ForRedeclaration, SourceLocation Loc); NamedDecl *ImplicitlyDefineFunction(SourceLocation Loc, IdentifierInfo &II, Scope *S); void AddKnownFunctionAttributes(FunctionDecl *FD); // More parsing and symbol table subroutines. void ProcessPragmaWeak(Scope *S, Decl *D); // Decl attributes - this routine is the top level dispatcher. void ProcessDeclAttributes(Scope *S, Decl *D, const Declarator &PD); // Helper for delayed processing of attributes. void ProcessDeclAttributeDelayed(Decl *D, const ParsedAttributesView &AttrList); void ProcessDeclAttributeList(Scope *S, Decl *D, const ParsedAttributesView &AL, bool IncludeCXX11Attributes = true); bool ProcessAccessDeclAttributeList(AccessSpecDecl *ASDecl, const ParsedAttributesView &AttrList); void checkUnusedDeclAttributes(Declarator &D); /// Determine if type T is a valid subject for a nonnull and similar /// attributes. By default, we look through references (the behavior used by /// nonnull), but if the second parameter is true, then we treat a reference /// type as valid. bool isValidPointerAttrType(QualType T, bool RefOkay = false); bool CheckRegparmAttr(const ParsedAttr &attr, unsigned &value); bool CheckCallingConvAttr(const ParsedAttr &attr, CallingConv &CC, const FunctionDecl *FD = nullptr); bool CheckAttrTarget(const ParsedAttr &CurrAttr); bool CheckAttrNoArgs(const ParsedAttr &CurrAttr); bool checkStringLiteralArgumentAttr(const ParsedAttr &Attr, unsigned ArgNum, StringRef &Str, SourceLocation *ArgLocation = nullptr); bool checkSectionName(SourceLocation LiteralLoc, StringRef Str); bool checkTargetAttr(SourceLocation LiteralLoc, StringRef Str); bool checkMSInheritanceAttrOnDefinition( CXXRecordDecl *RD, SourceRange Range, bool BestCase, MSInheritanceModel SemanticSpelling); void CheckAlignasUnderalignment(Decl *D); /// Adjust the calling convention of a method to be the ABI default if it /// wasn't specified explicitly. This handles method types formed from /// function type typedefs and typename template arguments. void adjustMemberFunctionCC(QualType &T, bool IsStatic, bool IsCtorOrDtor, SourceLocation Loc); // Check if there is an explicit attribute, but only look through parens. // The intent is to look for an attribute on the current declarator, but not // one that came from a typedef. bool hasExplicitCallingConv(QualType T); /// Get the outermost AttributedType node that sets a calling convention. /// Valid types should not have multiple attributes with different CCs. const AttributedType *getCallingConvAttributedType(QualType T) const; /// Stmt attributes - this routine is the top level dispatcher. StmtResult ProcessStmtAttributes(Stmt *Stmt, const ParsedAttributesView &Attrs, SourceRange Range); void WarnConflictingTypedMethods(ObjCMethodDecl *Method, ObjCMethodDecl *MethodDecl, bool IsProtocolMethodDecl); void CheckConflictingOverridingMethod(ObjCMethodDecl *Method, ObjCMethodDecl *Overridden, bool IsProtocolMethodDecl); /// WarnExactTypedMethods - This routine issues a warning if method /// implementation declaration matches exactly that of its declaration. void WarnExactTypedMethods(ObjCMethodDecl *Method, ObjCMethodDecl *MethodDecl, bool IsProtocolMethodDecl); typedef llvm::SmallPtrSet SelectorSet; /// CheckImplementationIvars - This routine checks if the instance variables /// listed in the implelementation match those listed in the interface. void CheckImplementationIvars(ObjCImplementationDecl *ImpDecl, ObjCIvarDecl **Fields, unsigned nIvars, SourceLocation Loc); /// ImplMethodsVsClassMethods - This is main routine to warn if any method /// remains unimplemented in the class or category \@implementation. void ImplMethodsVsClassMethods(Scope *S, ObjCImplDecl* IMPDecl, ObjCContainerDecl* IDecl, bool IncompleteImpl = false); /// DiagnoseUnimplementedProperties - This routine warns on those properties /// which must be implemented by this implementation. void DiagnoseUnimplementedProperties(Scope *S, ObjCImplDecl* IMPDecl, ObjCContainerDecl *CDecl, bool SynthesizeProperties); /// Diagnose any null-resettable synthesized setters. void diagnoseNullResettableSynthesizedSetters(const ObjCImplDecl *impDecl); /// DefaultSynthesizeProperties - This routine default synthesizes all /// properties which must be synthesized in the class's \@implementation. void DefaultSynthesizeProperties(Scope *S, ObjCImplDecl *IMPDecl, ObjCInterfaceDecl *IDecl, SourceLocation AtEnd); void DefaultSynthesizeProperties(Scope *S, Decl *D, SourceLocation AtEnd); /// IvarBacksCurrentMethodAccessor - This routine returns 'true' if 'IV' is /// an ivar synthesized for 'Method' and 'Method' is a property accessor /// declared in class 'IFace'. bool IvarBacksCurrentMethodAccessor(ObjCInterfaceDecl *IFace, ObjCMethodDecl *Method, ObjCIvarDecl *IV); /// DiagnoseUnusedBackingIvarInAccessor - Issue an 'unused' warning if ivar which /// backs the property is not used in the property's accessor. void DiagnoseUnusedBackingIvarInAccessor(Scope *S, const ObjCImplementationDecl *ImplD); /// GetIvarBackingPropertyAccessor - If method is a property setter/getter and /// it property has a backing ivar, returns this ivar; otherwise, returns NULL. /// It also returns ivar's property on success. ObjCIvarDecl *GetIvarBackingPropertyAccessor(const ObjCMethodDecl *Method, const ObjCPropertyDecl *&PDecl) const; /// Called by ActOnProperty to handle \@property declarations in /// class extensions. ObjCPropertyDecl *HandlePropertyInClassExtension(Scope *S, SourceLocation AtLoc, SourceLocation LParenLoc, FieldDeclarator &FD, Selector GetterSel, SourceLocation GetterNameLoc, Selector SetterSel, SourceLocation SetterNameLoc, const bool isReadWrite, unsigned &Attributes, const unsigned AttributesAsWritten, QualType T, TypeSourceInfo *TSI, tok::ObjCKeywordKind MethodImplKind); /// Called by ActOnProperty and HandlePropertyInClassExtension to /// handle creating the ObjcPropertyDecl for a category or \@interface. ObjCPropertyDecl *CreatePropertyDecl(Scope *S, ObjCContainerDecl *CDecl, SourceLocation AtLoc, SourceLocation LParenLoc, FieldDeclarator &FD, Selector GetterSel, SourceLocation GetterNameLoc, Selector SetterSel, SourceLocation SetterNameLoc, const bool isReadWrite, const unsigned Attributes, const unsigned AttributesAsWritten, QualType T, TypeSourceInfo *TSI, tok::ObjCKeywordKind MethodImplKind, DeclContext *lexicalDC = nullptr); /// AtomicPropertySetterGetterRules - This routine enforces the rule (via /// warning) when atomic property has one but not the other user-declared /// setter or getter. void AtomicPropertySetterGetterRules(ObjCImplDecl* IMPDecl, ObjCInterfaceDecl* IDecl); void DiagnoseOwningPropertyGetterSynthesis(const ObjCImplementationDecl *D); void DiagnoseMissingDesignatedInitOverrides( const ObjCImplementationDecl *ImplD, const ObjCInterfaceDecl *IFD); void DiagnoseDuplicateIvars(ObjCInterfaceDecl *ID, ObjCInterfaceDecl *SID); enum MethodMatchStrategy { MMS_loose, MMS_strict }; /// MatchTwoMethodDeclarations - Checks if two methods' type match and returns /// true, or false, accordingly. bool MatchTwoMethodDeclarations(const ObjCMethodDecl *Method, const ObjCMethodDecl *PrevMethod, MethodMatchStrategy strategy = MMS_strict); /// MatchAllMethodDeclarations - Check methods declaraed in interface or /// or protocol against those declared in their implementations. void MatchAllMethodDeclarations(const SelectorSet &InsMap, const SelectorSet &ClsMap, SelectorSet &InsMapSeen, SelectorSet &ClsMapSeen, ObjCImplDecl* IMPDecl, ObjCContainerDecl* IDecl, bool &IncompleteImpl, bool ImmediateClass, bool WarnCategoryMethodImpl=false); /// CheckCategoryVsClassMethodMatches - Checks that methods implemented in /// category matches with those implemented in its primary class and /// warns each time an exact match is found. void CheckCategoryVsClassMethodMatches(ObjCCategoryImplDecl *CatIMP); /// Add the given method to the list of globally-known methods. void addMethodToGlobalList(ObjCMethodList *List, ObjCMethodDecl *Method); /// Returns default addr space for method qualifiers. LangAS getDefaultCXXMethodAddrSpace() const; private: /// AddMethodToGlobalPool - Add an instance or factory method to the global /// pool. See descriptoin of AddInstanceMethodToGlobalPool. void AddMethodToGlobalPool(ObjCMethodDecl *Method, bool impl, bool instance); /// LookupMethodInGlobalPool - Returns the instance or factory method and /// optionally warns if there are multiple signatures. ObjCMethodDecl *LookupMethodInGlobalPool(Selector Sel, SourceRange R, bool receiverIdOrClass, bool instance); public: /// - Returns instance or factory methods in global method pool for /// given selector. It checks the desired kind first, if none is found, and /// parameter checkTheOther is set, it then checks the other kind. If no such /// method or only one method is found, function returns false; otherwise, it /// returns true. bool CollectMultipleMethodsInGlobalPool(Selector Sel, SmallVectorImpl& Methods, bool InstanceFirst, bool CheckTheOther, const ObjCObjectType *TypeBound = nullptr); bool AreMultipleMethodsInGlobalPool(Selector Sel, ObjCMethodDecl *BestMethod, SourceRange R, bool receiverIdOrClass, SmallVectorImpl& Methods); void DiagnoseMultipleMethodInGlobalPool(SmallVectorImpl &Methods, Selector Sel, SourceRange R, bool receiverIdOrClass); private: /// - Returns a selector which best matches given argument list or /// nullptr if none could be found ObjCMethodDecl *SelectBestMethod(Selector Sel, MultiExprArg Args, bool IsInstance, SmallVectorImpl& Methods); /// Record the typo correction failure and return an empty correction. TypoCorrection FailedCorrection(IdentifierInfo *Typo, SourceLocation TypoLoc, bool RecordFailure = true) { if (RecordFailure) TypoCorrectionFailures[Typo].insert(TypoLoc); return TypoCorrection(); } public: /// AddInstanceMethodToGlobalPool - All instance methods in a translation /// unit are added to a global pool. This allows us to efficiently associate /// a selector with a method declaraation for purposes of typechecking /// messages sent to "id" (where the class of the object is unknown). void AddInstanceMethodToGlobalPool(ObjCMethodDecl *Method, bool impl=false) { AddMethodToGlobalPool(Method, impl, /*instance*/true); } /// AddFactoryMethodToGlobalPool - Same as above, but for factory methods. void AddFactoryMethodToGlobalPool(ObjCMethodDecl *Method, bool impl=false) { AddMethodToGlobalPool(Method, impl, /*instance*/false); } /// AddAnyMethodToGlobalPool - Add any method, instance or factory to global /// pool. void AddAnyMethodToGlobalPool(Decl *D); /// LookupInstanceMethodInGlobalPool - Returns the method and warns if /// there are multiple signatures. ObjCMethodDecl *LookupInstanceMethodInGlobalPool(Selector Sel, SourceRange R, bool receiverIdOrClass=false) { return LookupMethodInGlobalPool(Sel, R, receiverIdOrClass, /*instance*/true); } /// LookupFactoryMethodInGlobalPool - Returns the method and warns if /// there are multiple signatures. ObjCMethodDecl *LookupFactoryMethodInGlobalPool(Selector Sel, SourceRange R, bool receiverIdOrClass=false) { return LookupMethodInGlobalPool(Sel, R, receiverIdOrClass, /*instance*/false); } const ObjCMethodDecl *SelectorsForTypoCorrection(Selector Sel, QualType ObjectType=QualType()); /// LookupImplementedMethodInGlobalPool - Returns the method which has an /// implementation. ObjCMethodDecl *LookupImplementedMethodInGlobalPool(Selector Sel); /// CollectIvarsToConstructOrDestruct - Collect those ivars which require /// initialization. void CollectIvarsToConstructOrDestruct(ObjCInterfaceDecl *OI, SmallVectorImpl &Ivars); //===--------------------------------------------------------------------===// // Statement Parsing Callbacks: SemaStmt.cpp. public: class FullExprArg { public: FullExprArg() : E(nullptr) { } FullExprArg(Sema &actions) : E(nullptr) { } ExprResult release() { return E; } Expr *get() const { return E; } Expr *operator->() { return E; } private: // FIXME: No need to make the entire Sema class a friend when it's just // Sema::MakeFullExpr that needs access to the constructor below. friend class Sema; explicit FullExprArg(Expr *expr) : E(expr) {} Expr *E; }; FullExprArg MakeFullExpr(Expr *Arg) { return MakeFullExpr(Arg, Arg ? Arg->getExprLoc() : SourceLocation()); } FullExprArg MakeFullExpr(Expr *Arg, SourceLocation CC) { return FullExprArg( ActOnFinishFullExpr(Arg, CC, /*DiscardedValue*/ false).get()); } FullExprArg MakeFullDiscardedValueExpr(Expr *Arg) { ExprResult FE = ActOnFinishFullExpr(Arg, Arg ? Arg->getExprLoc() : SourceLocation(), /*DiscardedValue*/ true); return FullExprArg(FE.get()); } StmtResult ActOnExprStmt(ExprResult Arg, bool DiscardedValue = true); StmtResult ActOnExprStmtError(); StmtResult ActOnNullStmt(SourceLocation SemiLoc, bool HasLeadingEmptyMacro = false); void ActOnStartOfCompoundStmt(bool IsStmtExpr); void ActOnFinishOfCompoundStmt(); StmtResult ActOnCompoundStmt(SourceLocation L, SourceLocation R, ArrayRef Elts, bool isStmtExpr); /// A RAII object to enter scope of a compound statement. class CompoundScopeRAII { public: CompoundScopeRAII(Sema &S, bool IsStmtExpr = false) : S(S) { S.ActOnStartOfCompoundStmt(IsStmtExpr); } ~CompoundScopeRAII() { S.ActOnFinishOfCompoundStmt(); } private: Sema &S; }; /// An RAII helper that pops function a function scope on exit. struct FunctionScopeRAII { Sema &S; bool Active; FunctionScopeRAII(Sema &S) : S(S), Active(true) {} ~FunctionScopeRAII() { if (Active) S.PopFunctionScopeInfo(); } void disable() { Active = false; } }; StmtResult ActOnDeclStmt(DeclGroupPtrTy Decl, SourceLocation StartLoc, SourceLocation EndLoc); void ActOnForEachDeclStmt(DeclGroupPtrTy Decl); StmtResult ActOnForEachLValueExpr(Expr *E); ExprResult ActOnCaseExpr(SourceLocation CaseLoc, ExprResult Val); StmtResult ActOnCaseStmt(SourceLocation CaseLoc, ExprResult LHS, SourceLocation DotDotDotLoc, ExprResult RHS, SourceLocation ColonLoc); void ActOnCaseStmtBody(Stmt *CaseStmt, Stmt *SubStmt); StmtResult ActOnDefaultStmt(SourceLocation DefaultLoc, SourceLocation ColonLoc, Stmt *SubStmt, Scope *CurScope); StmtResult ActOnLabelStmt(SourceLocation IdentLoc, LabelDecl *TheDecl, SourceLocation ColonLoc, Stmt *SubStmt); StmtResult ActOnAttributedStmt(SourceLocation AttrLoc, ArrayRef Attrs, Stmt *SubStmt); class ConditionResult; StmtResult ActOnIfStmt(SourceLocation IfLoc, bool IsConstexpr, Stmt *InitStmt, ConditionResult Cond, Stmt *ThenVal, SourceLocation ElseLoc, Stmt *ElseVal); StmtResult BuildIfStmt(SourceLocation IfLoc, bool IsConstexpr, Stmt *InitStmt, ConditionResult Cond, Stmt *ThenVal, SourceLocation ElseLoc, Stmt *ElseVal); StmtResult ActOnStartOfSwitchStmt(SourceLocation SwitchLoc, Stmt *InitStmt, ConditionResult Cond); StmtResult ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch, Stmt *Body); StmtResult ActOnWhileStmt(SourceLocation WhileLoc, ConditionResult Cond, Stmt *Body); StmtResult ActOnDoStmt(SourceLocation DoLoc, Stmt *Body, SourceLocation WhileLoc, SourceLocation CondLParen, Expr *Cond, SourceLocation CondRParen); StmtResult ActOnForStmt(SourceLocation ForLoc, SourceLocation LParenLoc, Stmt *First, ConditionResult Second, FullExprArg Third, SourceLocation RParenLoc, Stmt *Body); ExprResult CheckObjCForCollectionOperand(SourceLocation forLoc, Expr *collection); StmtResult ActOnObjCForCollectionStmt(SourceLocation ForColLoc, Stmt *First, Expr *collection, SourceLocation RParenLoc); StmtResult FinishObjCForCollectionStmt(Stmt *ForCollection, Stmt *Body); enum BuildForRangeKind { /// Initial building of a for-range statement. BFRK_Build, /// Instantiation or recovery rebuild of a for-range statement. Don't /// attempt any typo-correction. BFRK_Rebuild, /// Determining whether a for-range statement could be built. Avoid any /// unnecessary or irreversible actions. BFRK_Check }; StmtResult ActOnCXXForRangeStmt(Scope *S, SourceLocation ForLoc, SourceLocation CoawaitLoc, Stmt *InitStmt, Stmt *LoopVar, SourceLocation ColonLoc, Expr *Collection, SourceLocation RParenLoc, BuildForRangeKind Kind); StmtResult BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation CoawaitLoc, Stmt *InitStmt, SourceLocation ColonLoc, Stmt *RangeDecl, Stmt *Begin, Stmt *End, Expr *Cond, Expr *Inc, Stmt *LoopVarDecl, SourceLocation RParenLoc, BuildForRangeKind Kind); StmtResult FinishCXXForRangeStmt(Stmt *ForRange, Stmt *Body); StmtResult ActOnGotoStmt(SourceLocation GotoLoc, SourceLocation LabelLoc, LabelDecl *TheDecl); StmtResult ActOnIndirectGotoStmt(SourceLocation GotoLoc, SourceLocation StarLoc, Expr *DestExp); StmtResult ActOnContinueStmt(SourceLocation ContinueLoc, Scope *CurScope); StmtResult ActOnBreakStmt(SourceLocation BreakLoc, Scope *CurScope); void ActOnCapturedRegionStart(SourceLocation Loc, Scope *CurScope, CapturedRegionKind Kind, unsigned NumParams); typedef std::pair CapturedParamNameType; void ActOnCapturedRegionStart(SourceLocation Loc, Scope *CurScope, CapturedRegionKind Kind, ArrayRef Params, unsigned OpenMPCaptureLevel = 0); StmtResult ActOnCapturedRegionEnd(Stmt *S); void ActOnCapturedRegionError(); RecordDecl *CreateCapturedStmtRecordDecl(CapturedDecl *&CD, SourceLocation Loc, unsigned NumParams); enum CopyElisionSemanticsKind { CES_Strict = 0, CES_AllowParameters = 1, CES_AllowDifferentTypes = 2, CES_AllowExceptionVariables = 4, CES_FormerDefault = (CES_AllowParameters), CES_Default = (CES_AllowParameters | CES_AllowDifferentTypes), CES_AsIfByStdMove = (CES_AllowParameters | CES_AllowDifferentTypes | CES_AllowExceptionVariables), }; VarDecl *getCopyElisionCandidate(QualType ReturnType, Expr *E, CopyElisionSemanticsKind CESK); bool isCopyElisionCandidate(QualType ReturnType, const VarDecl *VD, CopyElisionSemanticsKind CESK); StmtResult ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp, Scope *CurScope); StmtResult BuildReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp); StmtResult ActOnCapScopeReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp); StmtResult ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple, bool IsVolatile, unsigned NumOutputs, unsigned NumInputs, IdentifierInfo **Names, MultiExprArg Constraints, MultiExprArg Exprs, Expr *AsmString, MultiExprArg Clobbers, unsigned NumLabels, SourceLocation RParenLoc); void FillInlineAsmIdentifierInfo(Expr *Res, llvm::InlineAsmIdentifierInfo &Info); ExprResult LookupInlineAsmIdentifier(CXXScopeSpec &SS, SourceLocation TemplateKWLoc, UnqualifiedId &Id, bool IsUnevaluatedContext); bool LookupInlineAsmField(StringRef Base, StringRef Member, unsigned &Offset, SourceLocation AsmLoc); ExprResult LookupInlineAsmVarDeclField(Expr *RefExpr, StringRef Member, SourceLocation AsmLoc); StmtResult ActOnMSAsmStmt(SourceLocation AsmLoc, SourceLocation LBraceLoc, ArrayRef AsmToks, StringRef AsmString, unsigned NumOutputs, unsigned NumInputs, ArrayRef Constraints, ArrayRef Clobbers, ArrayRef Exprs, SourceLocation EndLoc); LabelDecl *GetOrCreateMSAsmLabel(StringRef ExternalLabelName, SourceLocation Location, bool AlwaysCreate); VarDecl *BuildObjCExceptionDecl(TypeSourceInfo *TInfo, QualType ExceptionType, SourceLocation StartLoc, SourceLocation IdLoc, IdentifierInfo *Id, bool Invalid = false); Decl *ActOnObjCExceptionDecl(Scope *S, Declarator &D); StmtResult ActOnObjCAtCatchStmt(SourceLocation AtLoc, SourceLocation RParen, Decl *Parm, Stmt *Body); StmtResult ActOnObjCAtFinallyStmt(SourceLocation AtLoc, Stmt *Body); StmtResult ActOnObjCAtTryStmt(SourceLocation AtLoc, Stmt *Try, MultiStmtArg Catch, Stmt *Finally); StmtResult BuildObjCAtThrowStmt(SourceLocation AtLoc, Expr *Throw); StmtResult ActOnObjCAtThrowStmt(SourceLocation AtLoc, Expr *Throw, Scope *CurScope); ExprResult ActOnObjCAtSynchronizedOperand(SourceLocation atLoc, Expr *operand); StmtResult ActOnObjCAtSynchronizedStmt(SourceLocation AtLoc, Expr *SynchExpr, Stmt *SynchBody); StmtResult ActOnObjCAutoreleasePoolStmt(SourceLocation AtLoc, Stmt *Body); VarDecl *BuildExceptionDeclaration(Scope *S, TypeSourceInfo *TInfo, SourceLocation StartLoc, SourceLocation IdLoc, IdentifierInfo *Id); Decl *ActOnExceptionDeclarator(Scope *S, Declarator &D); StmtResult ActOnCXXCatchBlock(SourceLocation CatchLoc, Decl *ExDecl, Stmt *HandlerBlock); StmtResult ActOnCXXTryBlock(SourceLocation TryLoc, Stmt *TryBlock, ArrayRef Handlers); StmtResult ActOnSEHTryBlock(bool IsCXXTry, // try (true) or __try (false) ? SourceLocation TryLoc, Stmt *TryBlock, Stmt *Handler); StmtResult ActOnSEHExceptBlock(SourceLocation Loc, Expr *FilterExpr, Stmt *Block); void ActOnStartSEHFinallyBlock(); void ActOnAbortSEHFinallyBlock(); StmtResult ActOnFinishSEHFinallyBlock(SourceLocation Loc, Stmt *Block); StmtResult ActOnSEHLeaveStmt(SourceLocation Loc, Scope *CurScope); void DiagnoseReturnInConstructorExceptionHandler(CXXTryStmt *TryBlock); bool ShouldWarnIfUnusedFileScopedDecl(const DeclaratorDecl *D) const; /// If it's a file scoped decl that must warn if not used, keep track /// of it. void MarkUnusedFileScopedDecl(const DeclaratorDecl *D); /// DiagnoseUnusedExprResult - If the statement passed in is an expression /// whose result is unused, warn. void DiagnoseUnusedExprResult(const Stmt *S); void DiagnoseUnusedNestedTypedefs(const RecordDecl *D); void DiagnoseUnusedDecl(const NamedDecl *ND); /// Emit \p DiagID if statement located on \p StmtLoc has a suspicious null /// statement as a \p Body, and it is located on the same line. /// /// This helps prevent bugs due to typos, such as: /// if (condition); /// do_stuff(); void DiagnoseEmptyStmtBody(SourceLocation StmtLoc, const Stmt *Body, unsigned DiagID); /// Warn if a for/while loop statement \p S, which is followed by /// \p PossibleBody, has a suspicious null statement as a body. void DiagnoseEmptyLoopBody(const Stmt *S, const Stmt *PossibleBody); /// Warn if a value is moved to itself. void DiagnoseSelfMove(const Expr *LHSExpr, const Expr *RHSExpr, SourceLocation OpLoc); /// Warn if we're implicitly casting from a _Nullable pointer type to a /// _Nonnull one. void diagnoseNullableToNonnullConversion(QualType DstType, QualType SrcType, SourceLocation Loc); /// Warn when implicitly casting 0 to nullptr. void diagnoseZeroToNullptrConversion(CastKind Kind, const Expr *E); ParsingDeclState PushParsingDeclaration(sema::DelayedDiagnosticPool &pool) { return DelayedDiagnostics.push(pool); } void PopParsingDeclaration(ParsingDeclState state, Decl *decl); typedef ProcessingContextState ParsingClassState; ParsingClassState PushParsingClass() { ParsingClassDepth++; return DelayedDiagnostics.pushUndelayed(); } void PopParsingClass(ParsingClassState state) { ParsingClassDepth--; DelayedDiagnostics.popUndelayed(state); } void redelayDiagnostics(sema::DelayedDiagnosticPool &pool); void DiagnoseAvailabilityOfDecl(NamedDecl *D, ArrayRef Locs, const ObjCInterfaceDecl *UnknownObjCClass, bool ObjCPropertyAccess, bool AvoidPartialAvailabilityChecks = false, ObjCInterfaceDecl *ClassReceiver = nullptr); bool makeUnavailableInSystemHeader(SourceLocation loc, UnavailableAttr::ImplicitReason reason); /// Issue any -Wunguarded-availability warnings in \c FD void DiagnoseUnguardedAvailabilityViolations(Decl *FD); //===--------------------------------------------------------------------===// // Expression Parsing Callbacks: SemaExpr.cpp. bool CanUseDecl(NamedDecl *D, bool TreatUnavailableAsInvalid); bool DiagnoseUseOfDecl(NamedDecl *D, ArrayRef Locs, const ObjCInterfaceDecl *UnknownObjCClass = nullptr, bool ObjCPropertyAccess = false, bool AvoidPartialAvailabilityChecks = false, ObjCInterfaceDecl *ClassReciever = nullptr); void NoteDeletedFunction(FunctionDecl *FD); void NoteDeletedInheritingConstructor(CXXConstructorDecl *CD); bool DiagnosePropertyAccessorMismatch(ObjCPropertyDecl *PD, ObjCMethodDecl *Getter, SourceLocation Loc); void DiagnoseSentinelCalls(NamedDecl *D, SourceLocation Loc, ArrayRef Args); void PushExpressionEvaluationContext( ExpressionEvaluationContext NewContext, Decl *LambdaContextDecl = nullptr, ExpressionEvaluationContextRecord::ExpressionKind Type = ExpressionEvaluationContextRecord::EK_Other); enum ReuseLambdaContextDecl_t { ReuseLambdaContextDecl }; void PushExpressionEvaluationContext( ExpressionEvaluationContext NewContext, ReuseLambdaContextDecl_t, ExpressionEvaluationContextRecord::ExpressionKind Type = ExpressionEvaluationContextRecord::EK_Other); void PopExpressionEvaluationContext(); void DiscardCleanupsInEvaluationContext(); ExprResult TransformToPotentiallyEvaluated(Expr *E); ExprResult HandleExprEvaluationContextForTypeof(Expr *E); ExprResult CheckUnevaluatedOperand(Expr *E); void CheckUnusedVolatileAssignment(Expr *E); ExprResult ActOnConstantExpression(ExprResult Res); // Functions for marking a declaration referenced. These functions also // contain the relevant logic for marking if a reference to a function or // variable is an odr-use (in the C++11 sense). There are separate variants // for expressions referring to a decl; these exist because odr-use marking // needs to be delayed for some constant variables when we build one of the // named expressions. // // MightBeOdrUse indicates whether the use could possibly be an odr-use, and // should usually be true. This only needs to be set to false if the lack of // odr-use cannot be determined from the current context (for instance, // because the name denotes a virtual function and was written without an // explicit nested-name-specifier). void MarkAnyDeclReferenced(SourceLocation Loc, Decl *D, bool MightBeOdrUse); void MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func, bool MightBeOdrUse = true); void MarkVariableReferenced(SourceLocation Loc, VarDecl *Var); void MarkDeclRefReferenced(DeclRefExpr *E, const Expr *Base = nullptr); void MarkMemberReferenced(MemberExpr *E); void MarkFunctionParmPackReferenced(FunctionParmPackExpr *E); void MarkCaptureUsedInEnclosingContext(VarDecl *Capture, SourceLocation Loc, unsigned CapturingScopeIndex); ExprResult CheckLValueToRValueConversionOperand(Expr *E); void CleanupVarDeclMarking(); enum TryCaptureKind { TryCapture_Implicit, TryCapture_ExplicitByVal, TryCapture_ExplicitByRef }; /// Try to capture the given variable. /// /// \param Var The variable to capture. /// /// \param Loc The location at which the capture occurs. /// /// \param Kind The kind of capture, which may be implicit (for either a /// block or a lambda), or explicit by-value or by-reference (for a lambda). /// /// \param EllipsisLoc The location of the ellipsis, if one is provided in /// an explicit lambda capture. /// /// \param BuildAndDiagnose Whether we are actually supposed to add the /// captures or diagnose errors. If false, this routine merely check whether /// the capture can occur without performing the capture itself or complaining /// if the variable cannot be captured. /// /// \param CaptureType Will be set to the type of the field used to capture /// this variable in the innermost block or lambda. Only valid when the /// variable can be captured. /// /// \param DeclRefType Will be set to the type of a reference to the capture /// from within the current scope. Only valid when the variable can be /// captured. /// /// \param FunctionScopeIndexToStopAt If non-null, it points to the index /// of the FunctionScopeInfo stack beyond which we do not attempt to capture. /// This is useful when enclosing lambdas must speculatively capture /// variables that may or may not be used in certain specializations of /// a nested generic lambda. /// /// \returns true if an error occurred (i.e., the variable cannot be /// captured) and false if the capture succeeded. bool tryCaptureVariable(VarDecl *Var, SourceLocation Loc, TryCaptureKind Kind, SourceLocation EllipsisLoc, bool BuildAndDiagnose, QualType &CaptureType, QualType &DeclRefType, const unsigned *const FunctionScopeIndexToStopAt); /// Try to capture the given variable. bool tryCaptureVariable(VarDecl *Var, SourceLocation Loc, TryCaptureKind Kind = TryCapture_Implicit, SourceLocation EllipsisLoc = SourceLocation()); /// Checks if the variable must be captured. bool NeedToCaptureVariable(VarDecl *Var, SourceLocation Loc); /// Given a variable, determine the type that a reference to that /// variable will have in the given scope. QualType getCapturedDeclRefType(VarDecl *Var, SourceLocation Loc); /// Mark all of the declarations referenced within a particular AST node as /// referenced. Used when template instantiation instantiates a non-dependent /// type -- entities referenced by the type are now referenced. void MarkDeclarationsReferencedInType(SourceLocation Loc, QualType T); void MarkDeclarationsReferencedInExpr(Expr *E, bool SkipLocalVariables = false); /// Try to recover by turning the given expression into a /// call. Returns true if recovery was attempted or an error was /// emitted; this may also leave the ExprResult invalid. bool tryToRecoverWithCall(ExprResult &E, const PartialDiagnostic &PD, bool ForceComplain = false, bool (*IsPlausibleResult)(QualType) = nullptr); /// Figure out if an expression could be turned into a call. bool tryExprAsCall(Expr &E, QualType &ZeroArgCallReturnTy, UnresolvedSetImpl &NonTemplateOverloads); /// Conditionally issue a diagnostic based on the current /// evaluation context. /// /// \param Statement If Statement is non-null, delay reporting the /// diagnostic until the function body is parsed, and then do a basic /// reachability analysis to determine if the statement is reachable. /// If it is unreachable, the diagnostic will not be emitted. bool DiagRuntimeBehavior(SourceLocation Loc, const Stmt *Statement, const PartialDiagnostic &PD); /// Similar, but diagnostic is only produced if all the specified statements /// are reachable. bool DiagRuntimeBehavior(SourceLocation Loc, ArrayRef Stmts, const PartialDiagnostic &PD); // Primary Expressions. SourceRange getExprRange(Expr *E) const; ExprResult ActOnIdExpression( Scope *S, CXXScopeSpec &SS, SourceLocation TemplateKWLoc, UnqualifiedId &Id, bool HasTrailingLParen, bool IsAddressOfOperand, CorrectionCandidateCallback *CCC = nullptr, bool IsInlineAsmIdentifier = false, Token *KeywordReplacement = nullptr); void DecomposeUnqualifiedId(const UnqualifiedId &Id, TemplateArgumentListInfo &Buffer, DeclarationNameInfo &NameInfo, const TemplateArgumentListInfo *&TemplateArgs); bool DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R, CorrectionCandidateCallback &CCC, TemplateArgumentListInfo *ExplicitTemplateArgs = nullptr, ArrayRef Args = None, TypoExpr **Out = nullptr); DeclResult LookupIvarInObjCMethod(LookupResult &Lookup, Scope *S, IdentifierInfo *II); ExprResult BuildIvarRefExpr(Scope *S, SourceLocation Loc, ObjCIvarDecl *IV); ExprResult LookupInObjCMethod(LookupResult &LookUp, Scope *S, IdentifierInfo *II, bool AllowBuiltinCreation=false); ExprResult ActOnDependentIdExpression(const CXXScopeSpec &SS, SourceLocation TemplateKWLoc, const DeclarationNameInfo &NameInfo, bool isAddressOfOperand, const TemplateArgumentListInfo *TemplateArgs); /// If \p D cannot be odr-used in the current expression evaluation context, /// return a reason explaining why. Otherwise, return NOUR_None. NonOdrUseReason getNonOdrUseReasonInCurrentContext(ValueDecl *D); DeclRefExpr *BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK, SourceLocation Loc, const CXXScopeSpec *SS = nullptr); DeclRefExpr * BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK, const DeclarationNameInfo &NameInfo, const CXXScopeSpec *SS = nullptr, NamedDecl *FoundD = nullptr, SourceLocation TemplateKWLoc = SourceLocation(), const TemplateArgumentListInfo *TemplateArgs = nullptr); DeclRefExpr * BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK, const DeclarationNameInfo &NameInfo, NestedNameSpecifierLoc NNS, NamedDecl *FoundD = nullptr, SourceLocation TemplateKWLoc = SourceLocation(), const TemplateArgumentListInfo *TemplateArgs = nullptr); ExprResult BuildAnonymousStructUnionMemberReference( const CXXScopeSpec &SS, SourceLocation nameLoc, IndirectFieldDecl *indirectField, DeclAccessPair FoundDecl = DeclAccessPair::make(nullptr, AS_none), Expr *baseObjectExpr = nullptr, SourceLocation opLoc = SourceLocation()); ExprResult BuildPossibleImplicitMemberExpr(const CXXScopeSpec &SS, SourceLocation TemplateKWLoc, LookupResult &R, const TemplateArgumentListInfo *TemplateArgs, const Scope *S); ExprResult BuildImplicitMemberExpr(const CXXScopeSpec &SS, SourceLocation TemplateKWLoc, LookupResult &R, const TemplateArgumentListInfo *TemplateArgs, bool IsDefiniteInstance, const Scope *S); bool UseArgumentDependentLookup(const CXXScopeSpec &SS, const LookupResult &R, bool HasTrailingLParen); ExprResult BuildQualifiedDeclarationNameExpr(CXXScopeSpec &SS, const DeclarationNameInfo &NameInfo, bool IsAddressOfOperand, const Scope *S, TypeSourceInfo **RecoveryTSI = nullptr); ExprResult BuildDependentDeclRefExpr(const CXXScopeSpec &SS, SourceLocation TemplateKWLoc, const DeclarationNameInfo &NameInfo, const TemplateArgumentListInfo *TemplateArgs); ExprResult BuildDeclarationNameExpr(const CXXScopeSpec &SS, LookupResult &R, bool NeedsADL, bool AcceptInvalidDecl = false); ExprResult BuildDeclarationNameExpr( const CXXScopeSpec &SS, const DeclarationNameInfo &NameInfo, NamedDecl *D, NamedDecl *FoundD = nullptr, const TemplateArgumentListInfo *TemplateArgs = nullptr, bool AcceptInvalidDecl = false); ExprResult BuildLiteralOperatorCall(LookupResult &R, DeclarationNameInfo &SuffixInfo, ArrayRef Args, SourceLocation LitEndLoc, TemplateArgumentListInfo *ExplicitTemplateArgs = nullptr); ExprResult BuildPredefinedExpr(SourceLocation Loc, PredefinedExpr::IdentKind IK); ExprResult ActOnPredefinedExpr(SourceLocation Loc, tok::TokenKind Kind); ExprResult ActOnIntegerConstant(SourceLocation Loc, uint64_t Val); bool CheckLoopHintExpr(Expr *E, SourceLocation Loc); ExprResult ActOnNumericConstant(const Token &Tok, Scope *UDLScope = nullptr); ExprResult ActOnCharacterConstant(const Token &Tok, Scope *UDLScope = nullptr); ExprResult ActOnParenExpr(SourceLocation L, SourceLocation R, Expr *E); ExprResult ActOnParenListExpr(SourceLocation L, SourceLocation R, MultiExprArg Val); /// ActOnStringLiteral - The specified tokens were lexed as pasted string /// fragments (e.g. "foo" "bar" L"baz"). ExprResult ActOnStringLiteral(ArrayRef StringToks, Scope *UDLScope = nullptr); ExprResult ActOnGenericSelectionExpr(SourceLocation KeyLoc, SourceLocation DefaultLoc, SourceLocation RParenLoc, Expr *ControllingExpr, ArrayRef ArgTypes, ArrayRef ArgExprs); ExprResult CreateGenericSelectionExpr(SourceLocation KeyLoc, SourceLocation DefaultLoc, SourceLocation RParenLoc, Expr *ControllingExpr, ArrayRef Types, ArrayRef Exprs); // Binary/Unary Operators. 'Tok' is the token for the operator. ExprResult CreateBuiltinUnaryOp(SourceLocation OpLoc, UnaryOperatorKind Opc, Expr *InputExpr); ExprResult BuildUnaryOp(Scope *S, SourceLocation OpLoc, UnaryOperatorKind Opc, Expr *Input); ExprResult ActOnUnaryOp(Scope *S, SourceLocation OpLoc, tok::TokenKind Op, Expr *Input); bool isQualifiedMemberAccess(Expr *E); QualType CheckAddressOfOperand(ExprResult &Operand, SourceLocation OpLoc); ExprResult CreateUnaryExprOrTypeTraitExpr(TypeSourceInfo *TInfo, SourceLocation OpLoc, UnaryExprOrTypeTrait ExprKind, SourceRange R); ExprResult CreateUnaryExprOrTypeTraitExpr(Expr *E, SourceLocation OpLoc, UnaryExprOrTypeTrait ExprKind); ExprResult ActOnUnaryExprOrTypeTraitExpr(SourceLocation OpLoc, UnaryExprOrTypeTrait ExprKind, bool IsType, void *TyOrEx, SourceRange ArgRange); ExprResult CheckPlaceholderExpr(Expr *E); bool CheckVecStepExpr(Expr *E); bool CheckUnaryExprOrTypeTraitOperand(Expr *E, UnaryExprOrTypeTrait ExprKind); bool CheckUnaryExprOrTypeTraitOperand(QualType ExprType, SourceLocation OpLoc, SourceRange ExprRange, UnaryExprOrTypeTrait ExprKind); ExprResult ActOnSizeofParameterPackExpr(Scope *S, SourceLocation OpLoc, IdentifierInfo &Name, SourceLocation NameLoc, SourceLocation RParenLoc); ExprResult ActOnPostfixUnaryOp(Scope *S, SourceLocation OpLoc, tok::TokenKind Kind, Expr *Input); ExprResult ActOnArraySubscriptExpr(Scope *S, Expr *Base, SourceLocation LLoc, Expr *Idx, SourceLocation RLoc); ExprResult CreateBuiltinArraySubscriptExpr(Expr *Base, SourceLocation LLoc, Expr *Idx, SourceLocation RLoc); ExprResult ActOnOMPArraySectionExpr(Expr *Base, SourceLocation LBLoc, Expr *LowerBound, SourceLocation ColonLoc, Expr *Length, SourceLocation RBLoc); // This struct is for use by ActOnMemberAccess to allow // BuildMemberReferenceExpr to be able to reinvoke ActOnMemberAccess after // changing the access operator from a '.' to a '->' (to see if that is the // change needed to fix an error about an unknown member, e.g. when the class // defines a custom operator->). struct ActOnMemberAccessExtraArgs { Scope *S; UnqualifiedId &Id; Decl *ObjCImpDecl; }; ExprResult BuildMemberReferenceExpr( Expr *Base, QualType BaseType, SourceLocation OpLoc, bool IsArrow, CXXScopeSpec &SS, SourceLocation TemplateKWLoc, NamedDecl *FirstQualifierInScope, const DeclarationNameInfo &NameInfo, const TemplateArgumentListInfo *TemplateArgs, const Scope *S, ActOnMemberAccessExtraArgs *ExtraArgs = nullptr); ExprResult BuildMemberReferenceExpr(Expr *Base, QualType BaseType, SourceLocation OpLoc, bool IsArrow, const CXXScopeSpec &SS, SourceLocation TemplateKWLoc, NamedDecl *FirstQualifierInScope, LookupResult &R, const TemplateArgumentListInfo *TemplateArgs, const Scope *S, bool SuppressQualifierCheck = false, ActOnMemberAccessExtraArgs *ExtraArgs = nullptr); ExprResult BuildFieldReferenceExpr(Expr *BaseExpr, bool IsArrow, SourceLocation OpLoc, const CXXScopeSpec &SS, FieldDecl *Field, DeclAccessPair FoundDecl, const DeclarationNameInfo &MemberNameInfo); ExprResult PerformMemberExprBaseConversion(Expr *Base, bool IsArrow); bool CheckQualifiedMemberReference(Expr *BaseExpr, QualType BaseType, const CXXScopeSpec &SS, const LookupResult &R); ExprResult ActOnDependentMemberExpr(Expr *Base, QualType BaseType, bool IsArrow, SourceLocation OpLoc, const CXXScopeSpec &SS, SourceLocation TemplateKWLoc, NamedDecl *FirstQualifierInScope, const DeclarationNameInfo &NameInfo, const TemplateArgumentListInfo *TemplateArgs); ExprResult ActOnMemberAccessExpr(Scope *S, Expr *Base, SourceLocation OpLoc, tok::TokenKind OpKind, CXXScopeSpec &SS, SourceLocation TemplateKWLoc, UnqualifiedId &Member, Decl *ObjCImpDecl); MemberExpr * BuildMemberExpr(Expr *Base, bool IsArrow, SourceLocation OpLoc, const CXXScopeSpec *SS, SourceLocation TemplateKWLoc, ValueDecl *Member, DeclAccessPair FoundDecl, bool HadMultipleCandidates, const DeclarationNameInfo &MemberNameInfo, QualType Ty, ExprValueKind VK, ExprObjectKind OK, const TemplateArgumentListInfo *TemplateArgs = nullptr); MemberExpr * BuildMemberExpr(Expr *Base, bool IsArrow, SourceLocation OpLoc, NestedNameSpecifierLoc NNS, SourceLocation TemplateKWLoc, ValueDecl *Member, DeclAccessPair FoundDecl, bool HadMultipleCandidates, const DeclarationNameInfo &MemberNameInfo, QualType Ty, ExprValueKind VK, ExprObjectKind OK, const TemplateArgumentListInfo *TemplateArgs = nullptr); void ActOnDefaultCtorInitializers(Decl *CDtorDecl); bool ConvertArgumentsForCall(CallExpr *Call, Expr *Fn, FunctionDecl *FDecl, const FunctionProtoType *Proto, ArrayRef Args, SourceLocation RParenLoc, bool ExecConfig = false); void CheckStaticArrayArgument(SourceLocation CallLoc, ParmVarDecl *Param, const Expr *ArgExpr); /// ActOnCallExpr - Handle a call to Fn with the specified array of arguments. /// This provides the location of the left/right parens and a list of comma /// locations. ExprResult ActOnCallExpr(Scope *S, Expr *Fn, SourceLocation LParenLoc, MultiExprArg ArgExprs, SourceLocation RParenLoc, Expr *ExecConfig = nullptr); ExprResult BuildCallExpr(Scope *S, Expr *Fn, SourceLocation LParenLoc, MultiExprArg ArgExprs, SourceLocation RParenLoc, Expr *ExecConfig = nullptr, bool IsExecConfig = false); enum class AtomicArgumentOrder { API, AST }; ExprResult BuildAtomicExpr(SourceRange CallRange, SourceRange ExprRange, SourceLocation RParenLoc, MultiExprArg Args, AtomicExpr::AtomicOp Op, AtomicArgumentOrder ArgOrder = AtomicArgumentOrder::API); ExprResult BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl, SourceLocation LParenLoc, ArrayRef Arg, SourceLocation RParenLoc, Expr *Config = nullptr, bool IsExecConfig = false, ADLCallKind UsesADL = ADLCallKind::NotADL); ExprResult ActOnCUDAExecConfigExpr(Scope *S, SourceLocation LLLLoc, MultiExprArg ExecConfig, SourceLocation GGGLoc); ExprResult ActOnCastExpr(Scope *S, SourceLocation LParenLoc, Declarator &D, ParsedType &Ty, SourceLocation RParenLoc, Expr *CastExpr); ExprResult BuildCStyleCastExpr(SourceLocation LParenLoc, TypeSourceInfo *Ty, SourceLocation RParenLoc, Expr *Op); CastKind PrepareScalarCast(ExprResult &src, QualType destType); /// Build an altivec or OpenCL literal. ExprResult BuildVectorLiteral(SourceLocation LParenLoc, SourceLocation RParenLoc, Expr *E, TypeSourceInfo *TInfo); ExprResult MaybeConvertParenListExprToParenExpr(Scope *S, Expr *ME); ExprResult ActOnCompoundLiteral(SourceLocation LParenLoc, ParsedType Ty, SourceLocation RParenLoc, Expr *InitExpr); ExprResult BuildCompoundLiteralExpr(SourceLocation LParenLoc, TypeSourceInfo *TInfo, SourceLocation RParenLoc, Expr *LiteralExpr); ExprResult ActOnInitList(SourceLocation LBraceLoc, MultiExprArg InitArgList, SourceLocation RBraceLoc); ExprResult BuildInitList(SourceLocation LBraceLoc, MultiExprArg InitArgList, SourceLocation RBraceLoc); ExprResult ActOnDesignatedInitializer(Designation &Desig, SourceLocation EqualOrColonLoc, bool GNUSyntax, ExprResult Init); private: static BinaryOperatorKind ConvertTokenKindToBinaryOpcode(tok::TokenKind Kind); public: ExprResult ActOnBinOp(Scope *S, SourceLocation TokLoc, tok::TokenKind Kind, Expr *LHSExpr, Expr *RHSExpr); ExprResult BuildBinOp(Scope *S, SourceLocation OpLoc, BinaryOperatorKind Opc, Expr *LHSExpr, Expr *RHSExpr); ExprResult CreateBuiltinBinOp(SourceLocation OpLoc, BinaryOperatorKind Opc, Expr *LHSExpr, Expr *RHSExpr); void DiagnoseCommaOperator(const Expr *LHS, SourceLocation Loc); /// ActOnConditionalOp - Parse a ?: operation. Note that 'LHS' may be null /// in the case of a the GNU conditional expr extension. ExprResult ActOnConditionalOp(SourceLocation QuestionLoc, SourceLocation ColonLoc, Expr *CondExpr, Expr *LHSExpr, Expr *RHSExpr); /// ActOnAddrLabel - Parse the GNU address of label extension: "&&foo". ExprResult ActOnAddrLabel(SourceLocation OpLoc, SourceLocation LabLoc, LabelDecl *TheDecl); void ActOnStartStmtExpr(); ExprResult ActOnStmtExpr(Scope *S, SourceLocation LPLoc, Stmt *SubStmt, - SourceLocation RPLoc); // "({..})" + SourceLocation RPLoc); + ExprResult BuildStmtExpr(SourceLocation LPLoc, Stmt *SubStmt, + SourceLocation RPLoc, unsigned TemplateDepth); // Handle the final expression in a statement expression. ExprResult ActOnStmtExprResult(ExprResult E); void ActOnStmtExprError(); // __builtin_offsetof(type, identifier(.identifier|[expr])*) struct OffsetOfComponent { SourceLocation LocStart, LocEnd; bool isBrackets; // true if [expr], false if .ident union { IdentifierInfo *IdentInfo; Expr *E; } U; }; /// __builtin_offsetof(type, a.b[123][456].c) ExprResult BuildBuiltinOffsetOf(SourceLocation BuiltinLoc, TypeSourceInfo *TInfo, ArrayRef Components, SourceLocation RParenLoc); ExprResult ActOnBuiltinOffsetOf(Scope *S, SourceLocation BuiltinLoc, SourceLocation TypeLoc, ParsedType ParsedArgTy, ArrayRef Components, SourceLocation RParenLoc); // __builtin_choose_expr(constExpr, expr1, expr2) ExprResult ActOnChooseExpr(SourceLocation BuiltinLoc, Expr *CondExpr, Expr *LHSExpr, Expr *RHSExpr, SourceLocation RPLoc); // __builtin_va_arg(expr, type) ExprResult ActOnVAArg(SourceLocation BuiltinLoc, Expr *E, ParsedType Ty, SourceLocation RPLoc); ExprResult BuildVAArgExpr(SourceLocation BuiltinLoc, Expr *E, TypeSourceInfo *TInfo, SourceLocation RPLoc); // __builtin_LINE(), __builtin_FUNCTION(), __builtin_FILE(), // __builtin_COLUMN() ExprResult ActOnSourceLocExpr(SourceLocExpr::IdentKind Kind, SourceLocation BuiltinLoc, SourceLocation RPLoc); // Build a potentially resolved SourceLocExpr. ExprResult BuildSourceLocExpr(SourceLocExpr::IdentKind Kind, SourceLocation BuiltinLoc, SourceLocation RPLoc, DeclContext *ParentContext); // __null ExprResult ActOnGNUNullExpr(SourceLocation TokenLoc); bool CheckCaseExpression(Expr *E); /// Describes the result of an "if-exists" condition check. enum IfExistsResult { /// The symbol exists. IER_Exists, /// The symbol does not exist. IER_DoesNotExist, /// The name is a dependent name, so the results will differ /// from one instantiation to the next. IER_Dependent, /// An error occurred. IER_Error }; IfExistsResult CheckMicrosoftIfExistsSymbol(Scope *S, CXXScopeSpec &SS, const DeclarationNameInfo &TargetNameInfo); IfExistsResult CheckMicrosoftIfExistsSymbol(Scope *S, SourceLocation KeywordLoc, bool IsIfExists, CXXScopeSpec &SS, UnqualifiedId &Name); StmtResult BuildMSDependentExistsStmt(SourceLocation KeywordLoc, bool IsIfExists, NestedNameSpecifierLoc QualifierLoc, DeclarationNameInfo NameInfo, Stmt *Nested); StmtResult ActOnMSDependentExistsStmt(SourceLocation KeywordLoc, bool IsIfExists, CXXScopeSpec &SS, UnqualifiedId &Name, Stmt *Nested); //===------------------------- "Block" Extension ------------------------===// /// ActOnBlockStart - This callback is invoked when a block literal is /// started. void ActOnBlockStart(SourceLocation CaretLoc, Scope *CurScope); /// ActOnBlockArguments - This callback allows processing of block arguments. /// If there are no arguments, this is still invoked. void ActOnBlockArguments(SourceLocation CaretLoc, Declarator &ParamInfo, Scope *CurScope); /// ActOnBlockError - If there is an error parsing a block, this callback /// is invoked to pop the information about the block from the action impl. void ActOnBlockError(SourceLocation CaretLoc, Scope *CurScope); /// ActOnBlockStmtExpr - This is called when the body of a block statement /// literal was successfully completed. ^(int x){...} ExprResult ActOnBlockStmtExpr(SourceLocation CaretLoc, Stmt *Body, Scope *CurScope); //===---------------------------- Clang Extensions ----------------------===// /// __builtin_convertvector(...) ExprResult ActOnConvertVectorExpr(Expr *E, ParsedType ParsedDestTy, SourceLocation BuiltinLoc, SourceLocation RParenLoc); //===---------------------------- OpenCL Features -----------------------===// /// __builtin_astype(...) ExprResult ActOnAsTypeExpr(Expr *E, ParsedType ParsedDestTy, SourceLocation BuiltinLoc, SourceLocation RParenLoc); //===---------------------------- C++ Features --------------------------===// // Act on C++ namespaces Decl *ActOnStartNamespaceDef(Scope *S, SourceLocation InlineLoc, SourceLocation NamespaceLoc, SourceLocation IdentLoc, IdentifierInfo *Ident, SourceLocation LBrace, const ParsedAttributesView &AttrList, UsingDirectiveDecl *&UsingDecl); void ActOnFinishNamespaceDef(Decl *Dcl, SourceLocation RBrace); NamespaceDecl *getStdNamespace() const; NamespaceDecl *getOrCreateStdNamespace(); NamespaceDecl *lookupStdExperimentalNamespace(); CXXRecordDecl *getStdBadAlloc() const; EnumDecl *getStdAlignValT() const; private: // A cache representing if we've fully checked the various comparison category // types stored in ASTContext. The bit-index corresponds to the integer value // of a ComparisonCategoryType enumerator. llvm::SmallBitVector FullyCheckedComparisonCategories; ValueDecl *tryLookupCtorInitMemberDecl(CXXRecordDecl *ClassDecl, CXXScopeSpec &SS, ParsedType TemplateTypeTy, IdentifierInfo *MemberOrBase); public: enum class ComparisonCategoryUsage { /// The '<=>' operator was used in an expression and a builtin operator /// was selected. OperatorInExpression, /// A defaulted 'operator<=>' needed the comparison category. This /// typically only applies to 'std::strong_ordering', due to the implicit /// fallback return value. DefaultedOperator, }; /// Lookup the specified comparison category types in the standard /// library, an check the VarDecls possibly returned by the operator<=> /// builtins for that type. /// /// \return The type of the comparison category type corresponding to the /// specified Kind, or a null type if an error occurs QualType CheckComparisonCategoryType(ComparisonCategoryType Kind, SourceLocation Loc, ComparisonCategoryUsage Usage); /// Tests whether Ty is an instance of std::initializer_list and, if /// it is and Element is not NULL, assigns the element type to Element. bool isStdInitializerList(QualType Ty, QualType *Element); /// Looks for the std::initializer_list template and instantiates it /// with Element, or emits an error if it's not found. /// /// \returns The instantiated template, or null on error. QualType BuildStdInitializerList(QualType Element, SourceLocation Loc); /// Determine whether Ctor is an initializer-list constructor, as /// defined in [dcl.init.list]p2. bool isInitListConstructor(const FunctionDecl *Ctor); Decl *ActOnUsingDirective(Scope *CurScope, SourceLocation UsingLoc, SourceLocation NamespcLoc, CXXScopeSpec &SS, SourceLocation IdentLoc, IdentifierInfo *NamespcName, const ParsedAttributesView &AttrList); void PushUsingDirective(Scope *S, UsingDirectiveDecl *UDir); Decl *ActOnNamespaceAliasDef(Scope *CurScope, SourceLocation NamespaceLoc, SourceLocation AliasLoc, IdentifierInfo *Alias, CXXScopeSpec &SS, SourceLocation IdentLoc, IdentifierInfo *Ident); void HideUsingShadowDecl(Scope *S, UsingShadowDecl *Shadow); bool CheckUsingShadowDecl(UsingDecl *UD, NamedDecl *Target, const LookupResult &PreviousDecls, UsingShadowDecl *&PrevShadow); UsingShadowDecl *BuildUsingShadowDecl(Scope *S, UsingDecl *UD, NamedDecl *Target, UsingShadowDecl *PrevDecl); bool CheckUsingDeclRedeclaration(SourceLocation UsingLoc, bool HasTypenameKeyword, const CXXScopeSpec &SS, SourceLocation NameLoc, const LookupResult &Previous); bool CheckUsingDeclQualifier(SourceLocation UsingLoc, bool HasTypename, const CXXScopeSpec &SS, const DeclarationNameInfo &NameInfo, SourceLocation NameLoc); NamedDecl *BuildUsingDeclaration( Scope *S, AccessSpecifier AS, SourceLocation UsingLoc, bool HasTypenameKeyword, SourceLocation TypenameLoc, CXXScopeSpec &SS, DeclarationNameInfo NameInfo, SourceLocation EllipsisLoc, const ParsedAttributesView &AttrList, bool IsInstantiation); NamedDecl *BuildUsingPackDecl(NamedDecl *InstantiatedFrom, ArrayRef Expansions); bool CheckInheritingConstructorUsingDecl(UsingDecl *UD); /// Given a derived-class using shadow declaration for a constructor and the /// correspnding base class constructor, find or create the implicit /// synthesized derived class constructor to use for this initialization. CXXConstructorDecl * findInheritingConstructor(SourceLocation Loc, CXXConstructorDecl *BaseCtor, ConstructorUsingShadowDecl *DerivedShadow); Decl *ActOnUsingDeclaration(Scope *CurScope, AccessSpecifier AS, SourceLocation UsingLoc, SourceLocation TypenameLoc, CXXScopeSpec &SS, UnqualifiedId &Name, SourceLocation EllipsisLoc, const ParsedAttributesView &AttrList); Decl *ActOnAliasDeclaration(Scope *CurScope, AccessSpecifier AS, MultiTemplateParamsArg TemplateParams, SourceLocation UsingLoc, UnqualifiedId &Name, const ParsedAttributesView &AttrList, TypeResult Type, Decl *DeclFromDeclSpec); /// BuildCXXConstructExpr - Creates a complete call to a constructor, /// including handling of its default argument expressions. /// /// \param ConstructKind - a CXXConstructExpr::ConstructionKind ExprResult BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType, NamedDecl *FoundDecl, CXXConstructorDecl *Constructor, MultiExprArg Exprs, bool HadMultipleCandidates, bool IsListInitialization, bool IsStdInitListInitialization, bool RequiresZeroInit, unsigned ConstructKind, SourceRange ParenRange); /// Build a CXXConstructExpr whose constructor has already been resolved if /// it denotes an inherited constructor. ExprResult BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType, CXXConstructorDecl *Constructor, bool Elidable, MultiExprArg Exprs, bool HadMultipleCandidates, bool IsListInitialization, bool IsStdInitListInitialization, bool RequiresZeroInit, unsigned ConstructKind, SourceRange ParenRange); // FIXME: Can we remove this and have the above BuildCXXConstructExpr check if // the constructor can be elidable? ExprResult BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType, NamedDecl *FoundDecl, CXXConstructorDecl *Constructor, bool Elidable, MultiExprArg Exprs, bool HadMultipleCandidates, bool IsListInitialization, bool IsStdInitListInitialization, bool RequiresZeroInit, unsigned ConstructKind, SourceRange ParenRange); ExprResult BuildCXXDefaultInitExpr(SourceLocation Loc, FieldDecl *Field); /// Instantiate or parse a C++ default argument expression as necessary. /// Return true on error. bool CheckCXXDefaultArgExpr(SourceLocation CallLoc, FunctionDecl *FD, ParmVarDecl *Param); /// BuildCXXDefaultArgExpr - Creates a CXXDefaultArgExpr, instantiating /// the default expr if needed. ExprResult BuildCXXDefaultArgExpr(SourceLocation CallLoc, FunctionDecl *FD, ParmVarDecl *Param); /// FinalizeVarWithDestructor - Prepare for calling destructor on the /// constructed variable. void FinalizeVarWithDestructor(VarDecl *VD, const RecordType *DeclInitType); /// Helper class that collects exception specifications for /// implicitly-declared special member functions. class ImplicitExceptionSpecification { // Pointer to allow copying Sema *Self; // We order exception specifications thus: // noexcept is the most restrictive, but is only used in C++11. // throw() comes next. // Then a throw(collected exceptions) // Finally no specification, which is expressed as noexcept(false). // throw(...) is used instead if any called function uses it. ExceptionSpecificationType ComputedEST; llvm::SmallPtrSet ExceptionsSeen; SmallVector Exceptions; void ClearExceptions() { ExceptionsSeen.clear(); Exceptions.clear(); } public: explicit ImplicitExceptionSpecification(Sema &Self) : Self(&Self), ComputedEST(EST_BasicNoexcept) { if (!Self.getLangOpts().CPlusPlus11) ComputedEST = EST_DynamicNone; } /// Get the computed exception specification type. ExceptionSpecificationType getExceptionSpecType() const { assert(!isComputedNoexcept(ComputedEST) && "noexcept(expr) should not be a possible result"); return ComputedEST; } /// The number of exceptions in the exception specification. unsigned size() const { return Exceptions.size(); } /// The set of exceptions in the exception specification. const QualType *data() const { return Exceptions.data(); } /// Integrate another called method into the collected data. void CalledDecl(SourceLocation CallLoc, const CXXMethodDecl *Method); /// Integrate an invoked expression into the collected data. void CalledExpr(Expr *E) { CalledStmt(E); } /// Integrate an invoked statement into the collected data. void CalledStmt(Stmt *S); /// Overwrite an EPI's exception specification with this /// computed exception specification. FunctionProtoType::ExceptionSpecInfo getExceptionSpec() const { FunctionProtoType::ExceptionSpecInfo ESI; ESI.Type = getExceptionSpecType(); if (ESI.Type == EST_Dynamic) { ESI.Exceptions = Exceptions; } else if (ESI.Type == EST_None) { /// C++11 [except.spec]p14: /// The exception-specification is noexcept(false) if the set of /// potential exceptions of the special member function contains "any" ESI.Type = EST_NoexceptFalse; ESI.NoexceptExpr = Self->ActOnCXXBoolLiteral(SourceLocation(), tok::kw_false).get(); } return ESI; } }; /// Determine what sort of exception specification a defaulted /// copy constructor of a class will have. ImplicitExceptionSpecification ComputeDefaultedDefaultCtorExceptionSpec(SourceLocation Loc, CXXMethodDecl *MD); /// Determine what sort of exception specification a defaulted /// default constructor of a class will have, and whether the parameter /// will be const. ImplicitExceptionSpecification ComputeDefaultedCopyCtorExceptionSpec(CXXMethodDecl *MD); /// Determine what sort of exception specification a defaulted /// copy assignment operator of a class will have, and whether the /// parameter will be const. ImplicitExceptionSpecification ComputeDefaultedCopyAssignmentExceptionSpec(CXXMethodDecl *MD); /// Determine what sort of exception specification a defaulted move /// constructor of a class will have. ImplicitExceptionSpecification ComputeDefaultedMoveCtorExceptionSpec(CXXMethodDecl *MD); /// Determine what sort of exception specification a defaulted move /// assignment operator of a class will have. ImplicitExceptionSpecification ComputeDefaultedMoveAssignmentExceptionSpec(CXXMethodDecl *MD); /// Determine what sort of exception specification a defaulted /// destructor of a class will have. ImplicitExceptionSpecification ComputeDefaultedDtorExceptionSpec(CXXMethodDecl *MD); /// Determine what sort of exception specification an inheriting /// constructor of a class will have. ImplicitExceptionSpecification ComputeInheritingCtorExceptionSpec(SourceLocation Loc, CXXConstructorDecl *CD); /// Evaluate the implicit exception specification for a defaulted /// special member function. void EvaluateImplicitExceptionSpec(SourceLocation Loc, FunctionDecl *FD); /// Check the given noexcept-specifier, convert its expression, and compute /// the appropriate ExceptionSpecificationType. ExprResult ActOnNoexceptSpec(SourceLocation NoexceptLoc, Expr *NoexceptExpr, ExceptionSpecificationType &EST); /// Check the given exception-specification and update the /// exception specification information with the results. void checkExceptionSpecification(bool IsTopLevel, ExceptionSpecificationType EST, ArrayRef DynamicExceptions, ArrayRef DynamicExceptionRanges, Expr *NoexceptExpr, SmallVectorImpl &Exceptions, FunctionProtoType::ExceptionSpecInfo &ESI); /// Determine if we're in a case where we need to (incorrectly) eagerly /// parse an exception specification to work around a libstdc++ bug. bool isLibstdcxxEagerExceptionSpecHack(const Declarator &D); /// Add an exception-specification to the given member function /// (or member function template). The exception-specification was parsed /// after the method itself was declared. void actOnDelayedExceptionSpecification(Decl *Method, ExceptionSpecificationType EST, SourceRange SpecificationRange, ArrayRef DynamicExceptions, ArrayRef DynamicExceptionRanges, Expr *NoexceptExpr); class InheritedConstructorInfo; /// Determine if a special member function should have a deleted /// definition when it is defaulted. bool ShouldDeleteSpecialMember(CXXMethodDecl *MD, CXXSpecialMember CSM, InheritedConstructorInfo *ICI = nullptr, bool Diagnose = false); /// Produce notes explaining why a defaulted function was defined as deleted. void DiagnoseDeletedDefaultedFunction(FunctionDecl *FD); /// Declare the implicit default constructor for the given class. /// /// \param ClassDecl The class declaration into which the implicit /// default constructor will be added. /// /// \returns The implicitly-declared default constructor. CXXConstructorDecl *DeclareImplicitDefaultConstructor( CXXRecordDecl *ClassDecl); /// DefineImplicitDefaultConstructor - Checks for feasibility of /// defining this constructor as the default constructor. void DefineImplicitDefaultConstructor(SourceLocation CurrentLocation, CXXConstructorDecl *Constructor); /// Declare the implicit destructor for the given class. /// /// \param ClassDecl The class declaration into which the implicit /// destructor will be added. /// /// \returns The implicitly-declared destructor. CXXDestructorDecl *DeclareImplicitDestructor(CXXRecordDecl *ClassDecl); /// DefineImplicitDestructor - Checks for feasibility of /// defining this destructor as the default destructor. void DefineImplicitDestructor(SourceLocation CurrentLocation, CXXDestructorDecl *Destructor); /// Build an exception spec for destructors that don't have one. /// /// C++11 says that user-defined destructors with no exception spec get one /// that looks as if the destructor was implicitly declared. void AdjustDestructorExceptionSpec(CXXDestructorDecl *Destructor); /// Define the specified inheriting constructor. void DefineInheritingConstructor(SourceLocation UseLoc, CXXConstructorDecl *Constructor); /// Declare the implicit copy constructor for the given class. /// /// \param ClassDecl The class declaration into which the implicit /// copy constructor will be added. /// /// \returns The implicitly-declared copy constructor. CXXConstructorDecl *DeclareImplicitCopyConstructor(CXXRecordDecl *ClassDecl); /// DefineImplicitCopyConstructor - Checks for feasibility of /// defining this constructor as the copy constructor. void DefineImplicitCopyConstructor(SourceLocation CurrentLocation, CXXConstructorDecl *Constructor); /// Declare the implicit move constructor for the given class. /// /// \param ClassDecl The Class declaration into which the implicit /// move constructor will be added. /// /// \returns The implicitly-declared move constructor, or NULL if it wasn't /// declared. CXXConstructorDecl *DeclareImplicitMoveConstructor(CXXRecordDecl *ClassDecl); /// DefineImplicitMoveConstructor - Checks for feasibility of /// defining this constructor as the move constructor. void DefineImplicitMoveConstructor(SourceLocation CurrentLocation, CXXConstructorDecl *Constructor); /// Declare the implicit copy assignment operator for the given class. /// /// \param ClassDecl The class declaration into which the implicit /// copy assignment operator will be added. /// /// \returns The implicitly-declared copy assignment operator. CXXMethodDecl *DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl); /// Defines an implicitly-declared copy assignment operator. void DefineImplicitCopyAssignment(SourceLocation CurrentLocation, CXXMethodDecl *MethodDecl); /// Declare the implicit move assignment operator for the given class. /// /// \param ClassDecl The Class declaration into which the implicit /// move assignment operator will be added. /// /// \returns The implicitly-declared move assignment operator, or NULL if it /// wasn't declared. CXXMethodDecl *DeclareImplicitMoveAssignment(CXXRecordDecl *ClassDecl); /// Defines an implicitly-declared move assignment operator. void DefineImplicitMoveAssignment(SourceLocation CurrentLocation, CXXMethodDecl *MethodDecl); /// Force the declaration of any implicitly-declared members of this /// class. void ForceDeclarationOfImplicitMembers(CXXRecordDecl *Class); /// Check a completed declaration of an implicit special member. void CheckImplicitSpecialMemberDeclaration(Scope *S, FunctionDecl *FD); /// Determine whether the given function is an implicitly-deleted /// special member function. bool isImplicitlyDeleted(FunctionDecl *FD); /// Check whether 'this' shows up in the type of a static member /// function after the (naturally empty) cv-qualifier-seq would be. /// /// \returns true if an error occurred. bool checkThisInStaticMemberFunctionType(CXXMethodDecl *Method); /// Whether this' shows up in the exception specification of a static /// member function. bool checkThisInStaticMemberFunctionExceptionSpec(CXXMethodDecl *Method); /// Check whether 'this' shows up in the attributes of the given /// static member function. /// /// \returns true if an error occurred. bool checkThisInStaticMemberFunctionAttributes(CXXMethodDecl *Method); /// MaybeBindToTemporary - If the passed in expression has a record type with /// a non-trivial destructor, this will return CXXBindTemporaryExpr. Otherwise /// it simply returns the passed in expression. ExprResult MaybeBindToTemporary(Expr *E); bool CompleteConstructorCall(CXXConstructorDecl *Constructor, MultiExprArg ArgsPtr, SourceLocation Loc, SmallVectorImpl &ConvertedArgs, bool AllowExplicit = false, bool IsListInitialization = false); ParsedType getInheritingConstructorName(CXXScopeSpec &SS, SourceLocation NameLoc, IdentifierInfo &Name); ParsedType getConstructorName(IdentifierInfo &II, SourceLocation NameLoc, Scope *S, CXXScopeSpec &SS, bool EnteringContext); ParsedType getDestructorName(SourceLocation TildeLoc, IdentifierInfo &II, SourceLocation NameLoc, Scope *S, CXXScopeSpec &SS, ParsedType ObjectType, bool EnteringContext); ParsedType getDestructorTypeForDecltype(const DeclSpec &DS, ParsedType ObjectType); // Checks that reinterpret casts don't have undefined behavior. void CheckCompatibleReinterpretCast(QualType SrcType, QualType DestType, bool IsDereference, SourceRange Range); /// ActOnCXXNamedCast - Parse {dynamic,static,reinterpret,const}_cast's. ExprResult ActOnCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind, SourceLocation LAngleBracketLoc, Declarator &D, SourceLocation RAngleBracketLoc, SourceLocation LParenLoc, Expr *E, SourceLocation RParenLoc); ExprResult BuildCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind, TypeSourceInfo *Ty, Expr *E, SourceRange AngleBrackets, SourceRange Parens); ExprResult ActOnBuiltinBitCastExpr(SourceLocation KWLoc, Declarator &Dcl, ExprResult Operand, SourceLocation RParenLoc); ExprResult BuildBuiltinBitCastExpr(SourceLocation KWLoc, TypeSourceInfo *TSI, Expr *Operand, SourceLocation RParenLoc); ExprResult BuildCXXTypeId(QualType TypeInfoType, SourceLocation TypeidLoc, TypeSourceInfo *Operand, SourceLocation RParenLoc); ExprResult BuildCXXTypeId(QualType TypeInfoType, SourceLocation TypeidLoc, Expr *Operand, SourceLocation RParenLoc); /// ActOnCXXTypeid - Parse typeid( something ). ExprResult ActOnCXXTypeid(SourceLocation OpLoc, SourceLocation LParenLoc, bool isType, void *TyOrExpr, SourceLocation RParenLoc); ExprResult BuildCXXUuidof(QualType TypeInfoType, SourceLocation TypeidLoc, TypeSourceInfo *Operand, SourceLocation RParenLoc); ExprResult BuildCXXUuidof(QualType TypeInfoType, SourceLocation TypeidLoc, Expr *Operand, SourceLocation RParenLoc); /// ActOnCXXUuidof - Parse __uuidof( something ). ExprResult ActOnCXXUuidof(SourceLocation OpLoc, SourceLocation LParenLoc, bool isType, void *TyOrExpr, SourceLocation RParenLoc); /// Handle a C++1z fold-expression: ( expr op ... op expr ). ExprResult ActOnCXXFoldExpr(SourceLocation LParenLoc, Expr *LHS, tok::TokenKind Operator, SourceLocation EllipsisLoc, Expr *RHS, SourceLocation RParenLoc); ExprResult BuildCXXFoldExpr(SourceLocation LParenLoc, Expr *LHS, BinaryOperatorKind Operator, SourceLocation EllipsisLoc, Expr *RHS, SourceLocation RParenLoc, Optional NumExpansions); ExprResult BuildEmptyCXXFoldExpr(SourceLocation EllipsisLoc, BinaryOperatorKind Operator); //// ActOnCXXThis - Parse 'this' pointer. ExprResult ActOnCXXThis(SourceLocation loc); /// Build a CXXThisExpr and mark it referenced in the current context. Expr *BuildCXXThisExpr(SourceLocation Loc, QualType Type, bool IsImplicit); void MarkThisReferenced(CXXThisExpr *This); /// Try to retrieve the type of the 'this' pointer. /// /// \returns The type of 'this', if possible. Otherwise, returns a NULL type. QualType getCurrentThisType(); /// When non-NULL, the C++ 'this' expression is allowed despite the /// current context not being a non-static member function. In such cases, /// this provides the type used for 'this'. QualType CXXThisTypeOverride; /// RAII object used to temporarily allow the C++ 'this' expression /// to be used, with the given qualifiers on the current class type. class CXXThisScopeRAII { Sema &S; QualType OldCXXThisTypeOverride; bool Enabled; public: /// Introduce a new scope where 'this' may be allowed (when enabled), /// using the given declaration (which is either a class template or a /// class) along with the given qualifiers. /// along with the qualifiers placed on '*this'. CXXThisScopeRAII(Sema &S, Decl *ContextDecl, Qualifiers CXXThisTypeQuals, bool Enabled = true); ~CXXThisScopeRAII(); }; /// Make sure the value of 'this' is actually available in the current /// context, if it is a potentially evaluated context. /// /// \param Loc The location at which the capture of 'this' occurs. /// /// \param Explicit Whether 'this' is explicitly captured in a lambda /// capture list. /// /// \param FunctionScopeIndexToStopAt If non-null, it points to the index /// of the FunctionScopeInfo stack beyond which we do not attempt to capture. /// This is useful when enclosing lambdas must speculatively capture /// 'this' that may or may not be used in certain specializations of /// a nested generic lambda (depending on whether the name resolves to /// a non-static member function or a static function). /// \return returns 'true' if failed, 'false' if success. bool CheckCXXThisCapture(SourceLocation Loc, bool Explicit = false, bool BuildAndDiagnose = true, const unsigned *const FunctionScopeIndexToStopAt = nullptr, bool ByCopy = false); /// Determine whether the given type is the type of *this that is used /// outside of the body of a member function for a type that is currently /// being defined. bool isThisOutsideMemberFunctionBody(QualType BaseType); /// ActOnCXXBoolLiteral - Parse {true,false} literals. ExprResult ActOnCXXBoolLiteral(SourceLocation OpLoc, tok::TokenKind Kind); /// ActOnObjCBoolLiteral - Parse {__objc_yes,__objc_no} literals. ExprResult ActOnObjCBoolLiteral(SourceLocation OpLoc, tok::TokenKind Kind); ExprResult ActOnObjCAvailabilityCheckExpr(llvm::ArrayRef AvailSpecs, SourceLocation AtLoc, SourceLocation RParen); /// ActOnCXXNullPtrLiteral - Parse 'nullptr'. ExprResult ActOnCXXNullPtrLiteral(SourceLocation Loc); //// ActOnCXXThrow - Parse throw expressions. ExprResult ActOnCXXThrow(Scope *S, SourceLocation OpLoc, Expr *expr); ExprResult BuildCXXThrow(SourceLocation OpLoc, Expr *Ex, bool IsThrownVarInScope); bool CheckCXXThrowOperand(SourceLocation ThrowLoc, QualType ThrowTy, Expr *E); /// ActOnCXXTypeConstructExpr - Parse construction of a specified type. /// Can be interpreted either as function-style casting ("int(x)") /// or class type construction ("ClassType(x,y,z)") /// or creation of a value-initialized type ("int()"). ExprResult ActOnCXXTypeConstructExpr(ParsedType TypeRep, SourceLocation LParenOrBraceLoc, MultiExprArg Exprs, SourceLocation RParenOrBraceLoc, bool ListInitialization); ExprResult BuildCXXTypeConstructExpr(TypeSourceInfo *Type, SourceLocation LParenLoc, MultiExprArg Exprs, SourceLocation RParenLoc, bool ListInitialization); /// ActOnCXXNew - Parsed a C++ 'new' expression. ExprResult ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal, SourceLocation PlacementLParen, MultiExprArg PlacementArgs, SourceLocation PlacementRParen, SourceRange TypeIdParens, Declarator &D, Expr *Initializer); ExprResult BuildCXXNew(SourceRange Range, bool UseGlobal, SourceLocation PlacementLParen, MultiExprArg PlacementArgs, SourceLocation PlacementRParen, SourceRange TypeIdParens, QualType AllocType, TypeSourceInfo *AllocTypeInfo, Optional ArraySize, SourceRange DirectInitRange, Expr *Initializer); /// Determine whether \p FD is an aligned allocation or deallocation /// function that is unavailable. bool isUnavailableAlignedAllocationFunction(const FunctionDecl &FD) const; /// Produce diagnostics if \p FD is an aligned allocation or deallocation /// function that is unavailable. void diagnoseUnavailableAlignedAllocation(const FunctionDecl &FD, SourceLocation Loc); bool CheckAllocatedType(QualType AllocType, SourceLocation Loc, SourceRange R); /// The scope in which to find allocation functions. enum AllocationFunctionScope { /// Only look for allocation functions in the global scope. AFS_Global, /// Only look for allocation functions in the scope of the /// allocated class. AFS_Class, /// Look for allocation functions in both the global scope /// and in the scope of the allocated class. AFS_Both }; /// Finds the overloads of operator new and delete that are appropriate /// for the allocation. bool FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range, AllocationFunctionScope NewScope, AllocationFunctionScope DeleteScope, QualType AllocType, bool IsArray, bool &PassAlignment, MultiExprArg PlaceArgs, FunctionDecl *&OperatorNew, FunctionDecl *&OperatorDelete, bool Diagnose = true); void DeclareGlobalNewDelete(); void DeclareGlobalAllocationFunction(DeclarationName Name, QualType Return, ArrayRef Params); bool FindDeallocationFunction(SourceLocation StartLoc, CXXRecordDecl *RD, DeclarationName Name, FunctionDecl* &Operator, bool Diagnose = true); FunctionDecl *FindUsualDeallocationFunction(SourceLocation StartLoc, bool CanProvideSize, bool Overaligned, DeclarationName Name); FunctionDecl *FindDeallocationFunctionForDestructor(SourceLocation StartLoc, CXXRecordDecl *RD); /// ActOnCXXDelete - Parsed a C++ 'delete' expression ExprResult ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, bool ArrayForm, Expr *Operand); void CheckVirtualDtorCall(CXXDestructorDecl *dtor, SourceLocation Loc, bool IsDelete, bool CallCanBeVirtual, bool WarnOnNonAbstractTypes, SourceLocation DtorLoc); ExprResult ActOnNoexceptExpr(SourceLocation KeyLoc, SourceLocation LParen, Expr *Operand, SourceLocation RParen); ExprResult BuildCXXNoexceptExpr(SourceLocation KeyLoc, Expr *Operand, SourceLocation RParen); /// Parsed one of the type trait support pseudo-functions. ExprResult ActOnTypeTrait(TypeTrait Kind, SourceLocation KWLoc, ArrayRef Args, SourceLocation RParenLoc); ExprResult BuildTypeTrait(TypeTrait Kind, SourceLocation KWLoc, ArrayRef Args, SourceLocation RParenLoc); /// ActOnArrayTypeTrait - Parsed one of the binary type trait support /// pseudo-functions. ExprResult ActOnArrayTypeTrait(ArrayTypeTrait ATT, SourceLocation KWLoc, ParsedType LhsTy, Expr *DimExpr, SourceLocation RParen); ExprResult BuildArrayTypeTrait(ArrayTypeTrait ATT, SourceLocation KWLoc, TypeSourceInfo *TSInfo, Expr *DimExpr, SourceLocation RParen); /// ActOnExpressionTrait - Parsed one of the unary type trait support /// pseudo-functions. ExprResult ActOnExpressionTrait(ExpressionTrait OET, SourceLocation KWLoc, Expr *Queried, SourceLocation RParen); ExprResult BuildExpressionTrait(ExpressionTrait OET, SourceLocation KWLoc, Expr *Queried, SourceLocation RParen); ExprResult ActOnStartCXXMemberReference(Scope *S, Expr *Base, SourceLocation OpLoc, tok::TokenKind OpKind, ParsedType &ObjectType, bool &MayBePseudoDestructor); ExprResult BuildPseudoDestructorExpr(Expr *Base, SourceLocation OpLoc, tok::TokenKind OpKind, const CXXScopeSpec &SS, TypeSourceInfo *ScopeType, SourceLocation CCLoc, SourceLocation TildeLoc, PseudoDestructorTypeStorage DestroyedType); ExprResult ActOnPseudoDestructorExpr(Scope *S, Expr *Base, SourceLocation OpLoc, tok::TokenKind OpKind, CXXScopeSpec &SS, UnqualifiedId &FirstTypeName, SourceLocation CCLoc, SourceLocation TildeLoc, UnqualifiedId &SecondTypeName); ExprResult ActOnPseudoDestructorExpr(Scope *S, Expr *Base, SourceLocation OpLoc, tok::TokenKind OpKind, SourceLocation TildeLoc, const DeclSpec& DS); /// MaybeCreateExprWithCleanups - If the current full-expression /// requires any cleanups, surround it with a ExprWithCleanups node. /// Otherwise, just returns the passed-in expression. Expr *MaybeCreateExprWithCleanups(Expr *SubExpr); Stmt *MaybeCreateStmtWithCleanups(Stmt *SubStmt); ExprResult MaybeCreateExprWithCleanups(ExprResult SubExpr); MaterializeTemporaryExpr * CreateMaterializeTemporaryExpr(QualType T, Expr *Temporary, bool BoundToLvalueReference); ExprResult ActOnFinishFullExpr(Expr *Expr, bool DiscardedValue) { return ActOnFinishFullExpr( Expr, Expr ? Expr->getExprLoc() : SourceLocation(), DiscardedValue); } ExprResult ActOnFinishFullExpr(Expr *Expr, SourceLocation CC, bool DiscardedValue, bool IsConstexpr = false); StmtResult ActOnFinishFullStmt(Stmt *Stmt); // Marks SS invalid if it represents an incomplete type. bool RequireCompleteDeclContext(CXXScopeSpec &SS, DeclContext *DC); DeclContext *computeDeclContext(QualType T); DeclContext *computeDeclContext(const CXXScopeSpec &SS, bool EnteringContext = false); bool isDependentScopeSpecifier(const CXXScopeSpec &SS); CXXRecordDecl *getCurrentInstantiationOf(NestedNameSpecifier *NNS); /// The parser has parsed a global nested-name-specifier '::'. /// /// \param CCLoc The location of the '::'. /// /// \param SS The nested-name-specifier, which will be updated in-place /// to reflect the parsed nested-name-specifier. /// /// \returns true if an error occurred, false otherwise. bool ActOnCXXGlobalScopeSpecifier(SourceLocation CCLoc, CXXScopeSpec &SS); /// The parser has parsed a '__super' nested-name-specifier. /// /// \param SuperLoc The location of the '__super' keyword. /// /// \param ColonColonLoc The location of the '::'. /// /// \param SS The nested-name-specifier, which will be updated in-place /// to reflect the parsed nested-name-specifier. /// /// \returns true if an error occurred, false otherwise. bool ActOnSuperScopeSpecifier(SourceLocation SuperLoc, SourceLocation ColonColonLoc, CXXScopeSpec &SS); bool isAcceptableNestedNameSpecifier(const NamedDecl *SD, bool *CanCorrect = nullptr); NamedDecl *FindFirstQualifierInScope(Scope *S, NestedNameSpecifier *NNS); /// Keeps information about an identifier in a nested-name-spec. /// struct NestedNameSpecInfo { /// The type of the object, if we're parsing nested-name-specifier in /// a member access expression. ParsedType ObjectType; /// The identifier preceding the '::'. IdentifierInfo *Identifier; /// The location of the identifier. SourceLocation IdentifierLoc; /// The location of the '::'. SourceLocation CCLoc; /// Creates info object for the most typical case. NestedNameSpecInfo(IdentifierInfo *II, SourceLocation IdLoc, SourceLocation ColonColonLoc, ParsedType ObjectType = ParsedType()) : ObjectType(ObjectType), Identifier(II), IdentifierLoc(IdLoc), CCLoc(ColonColonLoc) { } NestedNameSpecInfo(IdentifierInfo *II, SourceLocation IdLoc, SourceLocation ColonColonLoc, QualType ObjectType) : ObjectType(ParsedType::make(ObjectType)), Identifier(II), IdentifierLoc(IdLoc), CCLoc(ColonColonLoc) { } }; bool isNonTypeNestedNameSpecifier(Scope *S, CXXScopeSpec &SS, NestedNameSpecInfo &IdInfo); bool BuildCXXNestedNameSpecifier(Scope *S, NestedNameSpecInfo &IdInfo, bool EnteringContext, CXXScopeSpec &SS, NamedDecl *ScopeLookupResult, bool ErrorRecoveryLookup, bool *IsCorrectedToColon = nullptr, bool OnlyNamespace = false); /// The parser has parsed a nested-name-specifier 'identifier::'. /// /// \param S The scope in which this nested-name-specifier occurs. /// /// \param IdInfo Parser information about an identifier in the /// nested-name-spec. /// /// \param EnteringContext Whether we're entering the context nominated by /// this nested-name-specifier. /// /// \param SS The nested-name-specifier, which is both an input /// parameter (the nested-name-specifier before this type) and an /// output parameter (containing the full nested-name-specifier, /// including this new type). /// /// \param ErrorRecoveryLookup If true, then this method is called to improve /// error recovery. In this case do not emit error message. /// /// \param IsCorrectedToColon If not null, suggestions to replace '::' -> ':' /// are allowed. The bool value pointed by this parameter is set to 'true' /// if the identifier is treated as if it was followed by ':', not '::'. /// /// \param OnlyNamespace If true, only considers namespaces in lookup. /// /// \returns true if an error occurred, false otherwise. bool ActOnCXXNestedNameSpecifier(Scope *S, NestedNameSpecInfo &IdInfo, bool EnteringContext, CXXScopeSpec &SS, bool ErrorRecoveryLookup = false, bool *IsCorrectedToColon = nullptr, bool OnlyNamespace = false); ExprResult ActOnDecltypeExpression(Expr *E); bool ActOnCXXNestedNameSpecifierDecltype(CXXScopeSpec &SS, const DeclSpec &DS, SourceLocation ColonColonLoc); bool IsInvalidUnlessNestedName(Scope *S, CXXScopeSpec &SS, NestedNameSpecInfo &IdInfo, bool EnteringContext); /// The parser has parsed a nested-name-specifier /// 'template[opt] template-name < template-args >::'. /// /// \param S The scope in which this nested-name-specifier occurs. /// /// \param SS The nested-name-specifier, which is both an input /// parameter (the nested-name-specifier before this type) and an /// output parameter (containing the full nested-name-specifier, /// including this new type). /// /// \param TemplateKWLoc the location of the 'template' keyword, if any. /// \param TemplateName the template name. /// \param TemplateNameLoc The location of the template name. /// \param LAngleLoc The location of the opening angle bracket ('<'). /// \param TemplateArgs The template arguments. /// \param RAngleLoc The location of the closing angle bracket ('>'). /// \param CCLoc The location of the '::'. /// /// \param EnteringContext Whether we're entering the context of the /// nested-name-specifier. /// /// /// \returns true if an error occurred, false otherwise. bool ActOnCXXNestedNameSpecifier(Scope *S, CXXScopeSpec &SS, SourceLocation TemplateKWLoc, TemplateTy TemplateName, SourceLocation TemplateNameLoc, SourceLocation LAngleLoc, ASTTemplateArgsPtr TemplateArgs, SourceLocation RAngleLoc, SourceLocation CCLoc, bool EnteringContext); /// Given a C++ nested-name-specifier, produce an annotation value /// that the parser can use later to reconstruct the given /// nested-name-specifier. /// /// \param SS A nested-name-specifier. /// /// \returns A pointer containing all of the information in the /// nested-name-specifier \p SS. void *SaveNestedNameSpecifierAnnotation(CXXScopeSpec &SS); /// Given an annotation pointer for a nested-name-specifier, restore /// the nested-name-specifier structure. /// /// \param Annotation The annotation pointer, produced by /// \c SaveNestedNameSpecifierAnnotation(). /// /// \param AnnotationRange The source range corresponding to the annotation. /// /// \param SS The nested-name-specifier that will be updated with the contents /// of the annotation pointer. void RestoreNestedNameSpecifierAnnotation(void *Annotation, SourceRange AnnotationRange, CXXScopeSpec &SS); bool ShouldEnterDeclaratorScope(Scope *S, const CXXScopeSpec &SS); /// ActOnCXXEnterDeclaratorScope - Called when a C++ scope specifier (global /// scope or nested-name-specifier) is parsed, part of a declarator-id. /// After this method is called, according to [C++ 3.4.3p3], names should be /// looked up in the declarator-id's scope, until the declarator is parsed and /// ActOnCXXExitDeclaratorScope is called. /// The 'SS' should be a non-empty valid CXXScopeSpec. bool ActOnCXXEnterDeclaratorScope(Scope *S, CXXScopeSpec &SS); /// ActOnCXXExitDeclaratorScope - Called when a declarator that previously /// invoked ActOnCXXEnterDeclaratorScope(), is finished. 'SS' is the same /// CXXScopeSpec that was passed to ActOnCXXEnterDeclaratorScope as well. /// Used to indicate that names should revert to being looked up in the /// defining scope. void ActOnCXXExitDeclaratorScope(Scope *S, const CXXScopeSpec &SS); /// ActOnCXXEnterDeclInitializer - Invoked when we are about to parse an /// initializer for the declaration 'Dcl'. /// After this method is called, according to [C++ 3.4.1p13], if 'Dcl' is a /// static data member of class X, names should be looked up in the scope of /// class X. void ActOnCXXEnterDeclInitializer(Scope *S, Decl *Dcl); /// ActOnCXXExitDeclInitializer - Invoked after we are finished parsing an /// initializer for the declaration 'Dcl'. void ActOnCXXExitDeclInitializer(Scope *S, Decl *Dcl); /// Create a new lambda closure type. CXXRecordDecl *createLambdaClosureType(SourceRange IntroducerRange, TypeSourceInfo *Info, bool KnownDependent, LambdaCaptureDefault CaptureDefault); /// Start the definition of a lambda expression. CXXMethodDecl *startLambdaDefinition(CXXRecordDecl *Class, SourceRange IntroducerRange, TypeSourceInfo *MethodType, SourceLocation EndLoc, ArrayRef Params, ConstexprSpecKind ConstexprKind, Expr *TrailingRequiresClause); /// Number lambda for linkage purposes if necessary. void handleLambdaNumbering( CXXRecordDecl *Class, CXXMethodDecl *Method, Optional> Mangling = None); /// Endow the lambda scope info with the relevant properties. void buildLambdaScope(sema::LambdaScopeInfo *LSI, CXXMethodDecl *CallOperator, SourceRange IntroducerRange, LambdaCaptureDefault CaptureDefault, SourceLocation CaptureDefaultLoc, bool ExplicitParams, bool ExplicitResultType, bool Mutable); /// Perform initialization analysis of the init-capture and perform /// any implicit conversions such as an lvalue-to-rvalue conversion if /// not being used to initialize a reference. ParsedType actOnLambdaInitCaptureInitialization( SourceLocation Loc, bool ByRef, SourceLocation EllipsisLoc, IdentifierInfo *Id, LambdaCaptureInitKind InitKind, Expr *&Init) { return ParsedType::make(buildLambdaInitCaptureInitialization( Loc, ByRef, EllipsisLoc, None, Id, InitKind != LambdaCaptureInitKind::CopyInit, Init)); } QualType buildLambdaInitCaptureInitialization( SourceLocation Loc, bool ByRef, SourceLocation EllipsisLoc, Optional NumExpansions, IdentifierInfo *Id, bool DirectInit, Expr *&Init); /// Create a dummy variable within the declcontext of the lambda's /// call operator, for name lookup purposes for a lambda init capture. /// /// CodeGen handles emission of lambda captures, ignoring these dummy /// variables appropriately. VarDecl *createLambdaInitCaptureVarDecl(SourceLocation Loc, QualType InitCaptureType, SourceLocation EllipsisLoc, IdentifierInfo *Id, unsigned InitStyle, Expr *Init); /// Add an init-capture to a lambda scope. void addInitCapture(sema::LambdaScopeInfo *LSI, VarDecl *Var); /// Note that we have finished the explicit captures for the /// given lambda. void finishLambdaExplicitCaptures(sema::LambdaScopeInfo *LSI); /// \brief This is called after parsing the explicit template parameter list /// on a lambda (if it exists) in C++2a. void ActOnLambdaExplicitTemplateParameterList(SourceLocation LAngleLoc, ArrayRef TParams, SourceLocation RAngleLoc); /// Introduce the lambda parameters into scope. void addLambdaParameters( ArrayRef Captures, CXXMethodDecl *CallOperator, Scope *CurScope); /// Deduce a block or lambda's return type based on the return /// statements present in the body. void deduceClosureReturnType(sema::CapturingScopeInfo &CSI); /// ActOnStartOfLambdaDefinition - This is called just before we start /// parsing the body of a lambda; it analyzes the explicit captures and /// arguments, and sets up various data-structures for the body of the /// lambda. void ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, Declarator &ParamInfo, Scope *CurScope); /// ActOnLambdaError - If there is an error parsing a lambda, this callback /// is invoked to pop the information about the lambda. void ActOnLambdaError(SourceLocation StartLoc, Scope *CurScope, bool IsInstantiation = false); /// ActOnLambdaExpr - This is called when the body of a lambda expression /// was successfully completed. ExprResult ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body, Scope *CurScope); /// Does copying/destroying the captured variable have side effects? bool CaptureHasSideEffects(const sema::Capture &From); /// Diagnose if an explicit lambda capture is unused. Returns true if a /// diagnostic is emitted. bool DiagnoseUnusedLambdaCapture(SourceRange CaptureRange, const sema::Capture &From); /// Build a FieldDecl suitable to hold the given capture. FieldDecl *BuildCaptureField(RecordDecl *RD, const sema::Capture &Capture); /// Initialize the given capture with a suitable expression. ExprResult BuildCaptureInit(const sema::Capture &Capture, SourceLocation ImplicitCaptureLoc, bool IsOpenMPMapping = false); /// Complete a lambda-expression having processed and attached the /// lambda body. ExprResult BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc, sema::LambdaScopeInfo *LSI); /// Get the return type to use for a lambda's conversion function(s) to /// function pointer type, given the type of the call operator. QualType getLambdaConversionFunctionResultType(const FunctionProtoType *CallOpType); /// Define the "body" of the conversion from a lambda object to a /// function pointer. /// /// This routine doesn't actually define a sensible body; rather, it fills /// in the initialization expression needed to copy the lambda object into /// the block, and IR generation actually generates the real body of the /// block pointer conversion. void DefineImplicitLambdaToFunctionPointerConversion( SourceLocation CurrentLoc, CXXConversionDecl *Conv); /// Define the "body" of the conversion from a lambda object to a /// block pointer. /// /// This routine doesn't actually define a sensible body; rather, it fills /// in the initialization expression needed to copy the lambda object into /// the block, and IR generation actually generates the real body of the /// block pointer conversion. void DefineImplicitLambdaToBlockPointerConversion(SourceLocation CurrentLoc, CXXConversionDecl *Conv); ExprResult BuildBlockForLambdaConversion(SourceLocation CurrentLocation, SourceLocation ConvLocation, CXXConversionDecl *Conv, Expr *Src); /// Check whether the given expression is a valid constraint expression. /// A diagnostic is emitted if it is not, false is returned, and /// PossibleNonPrimary will be set to true if the failure might be due to a /// non-primary expression being used as an atomic constraint. bool CheckConstraintExpression(Expr *CE, Token NextToken = Token(), bool *PossibleNonPrimary = nullptr, bool IsTrailingRequiresClause = false); /// Check whether the given type-dependent expression will be the name of a /// function or another callable function-like entity (e.g. a function // template or overload set) for any substitution. bool IsDependentFunctionNameExpr(Expr *E); private: /// Caches pairs of template-like decls whose associated constraints were /// checked for subsumption and whether or not the first's constraints did in /// fact subsume the second's. llvm::DenseMap, bool> SubsumptionCache; /// Caches the normalized associated constraints of declarations (concepts or /// constrained declarations). If an error occurred while normalizing the /// associated constraints of the template or concept, nullptr will be cached /// here. llvm::DenseMap NormalizationCache; llvm::ContextualFoldingSet SatisfactionCache; public: const NormalizedConstraint * getNormalizedAssociatedConstraints( NamedDecl *ConstrainedDecl, ArrayRef AssociatedConstraints); /// \brief Check whether the given declaration's associated constraints are /// at least as constrained than another declaration's according to the /// partial ordering of constraints. /// /// \param Result If no error occurred, receives the result of true if D1 is /// at least constrained than D2, and false otherwise. /// /// \returns true if an error occurred, false otherwise. bool IsAtLeastAsConstrained(NamedDecl *D1, ArrayRef AC1, NamedDecl *D2, ArrayRef AC2, bool &Result); /// If D1 was not at least as constrained as D2, but would've been if a pair /// of atomic constraints involved had been declared in a concept and not /// repeated in two separate places in code. /// \returns true if such a diagnostic was emitted, false otherwise. bool MaybeEmitAmbiguousAtomicConstraintsDiagnostic(NamedDecl *D1, ArrayRef AC1, NamedDecl *D2, ArrayRef AC2); /// \brief Check whether the given list of constraint expressions are /// satisfied (as if in a 'conjunction') given template arguments. /// \param Template the template-like entity that triggered the constraints /// check (either a concept or a constrained entity). /// \param ConstraintExprs a list of constraint expressions, treated as if /// they were 'AND'ed together. /// \param TemplateArgs the list of template arguments to substitute into the /// constraint expression. /// \param TemplateIDRange The source range of the template id that /// caused the constraints check. /// \param Satisfaction if true is returned, will contain details of the /// satisfaction, with enough information to diagnose an unsatisfied /// expression. /// \returns true if an error occurred and satisfaction could not be checked, /// false otherwise. bool CheckConstraintSatisfaction( const NamedDecl *Template, ArrayRef ConstraintExprs, ArrayRef TemplateArgs, SourceRange TemplateIDRange, ConstraintSatisfaction &Satisfaction); /// \brief Check whether the given non-dependent constraint expression is /// satisfied. Returns false and updates Satisfaction with the satisfaction /// verdict if successful, emits a diagnostic and returns true if an error /// occured and satisfaction could not be determined. /// /// \returns true if an error occurred, false otherwise. bool CheckConstraintSatisfaction(const Expr *ConstraintExpr, ConstraintSatisfaction &Satisfaction); /// Check whether the given function decl's trailing requires clause is /// satisfied, if any. Returns false and updates Satisfaction with the /// satisfaction verdict if successful, emits a diagnostic and returns true if /// an error occured and satisfaction could not be determined. /// /// \returns true if an error occurred, false otherwise. bool CheckFunctionConstraints(const FunctionDecl *FD, ConstraintSatisfaction &Satisfaction, SourceLocation UsageLoc = SourceLocation()); /// \brief Ensure that the given template arguments satisfy the constraints /// associated with the given template, emitting a diagnostic if they do not. /// /// \param Template The template to which the template arguments are being /// provided. /// /// \param TemplateArgs The converted, canonicalized template arguments. /// /// \param TemplateIDRange The source range of the template id that /// caused the constraints check. /// /// \returns true if the constrains are not satisfied or could not be checked /// for satisfaction, false if the constraints are satisfied. bool EnsureTemplateArgumentListConstraints(TemplateDecl *Template, ArrayRef TemplateArgs, SourceRange TemplateIDRange); /// \brief Emit diagnostics explaining why a constraint expression was deemed /// unsatisfied. /// \param First whether this is the first time an unsatisfied constraint is /// diagnosed for this error. void DiagnoseUnsatisfiedConstraint(const ConstraintSatisfaction &Satisfaction, bool First = true); /// \brief Emit diagnostics explaining why a constraint expression was deemed /// unsatisfied. void DiagnoseUnsatisfiedConstraint(const ASTConstraintSatisfaction &Satisfaction, bool First = true); /// \brief Emit diagnostics explaining why a constraint expression was deemed /// unsatisfied because it was ill-formed. void DiagnoseUnsatisfiedIllFormedConstraint(SourceLocation DiagnosticLocation, StringRef Diagnostic); void DiagnoseRedeclarationConstraintMismatch(SourceLocation Old, SourceLocation New); // ParseObjCStringLiteral - Parse Objective-C string literals. ExprResult ParseObjCStringLiteral(SourceLocation *AtLocs, ArrayRef Strings); ExprResult BuildObjCStringLiteral(SourceLocation AtLoc, StringLiteral *S); /// BuildObjCNumericLiteral - builds an ObjCBoxedExpr AST node for the /// numeric literal expression. Type of the expression will be "NSNumber *" /// or "id" if NSNumber is unavailable. ExprResult BuildObjCNumericLiteral(SourceLocation AtLoc, Expr *Number); ExprResult ActOnObjCBoolLiteral(SourceLocation AtLoc, SourceLocation ValueLoc, bool Value); ExprResult BuildObjCArrayLiteral(SourceRange SR, MultiExprArg Elements); /// BuildObjCBoxedExpr - builds an ObjCBoxedExpr AST node for the /// '@' prefixed parenthesized expression. The type of the expression will /// either be "NSNumber *", "NSString *" or "NSValue *" depending on the type /// of ValueType, which is allowed to be a built-in numeric type, "char *", /// "const char *" or C structure with attribute 'objc_boxable'. ExprResult BuildObjCBoxedExpr(SourceRange SR, Expr *ValueExpr); ExprResult BuildObjCSubscriptExpression(SourceLocation RB, Expr *BaseExpr, Expr *IndexExpr, ObjCMethodDecl *getterMethod, ObjCMethodDecl *setterMethod); ExprResult BuildObjCDictionaryLiteral(SourceRange SR, MutableArrayRef Elements); ExprResult BuildObjCEncodeExpression(SourceLocation AtLoc, TypeSourceInfo *EncodedTypeInfo, SourceLocation RParenLoc); ExprResult BuildCXXMemberCallExpr(Expr *Exp, NamedDecl *FoundDecl, CXXConversionDecl *Method, bool HadMultipleCandidates); ExprResult ParseObjCEncodeExpression(SourceLocation AtLoc, SourceLocation EncodeLoc, SourceLocation LParenLoc, ParsedType Ty, SourceLocation RParenLoc); /// ParseObjCSelectorExpression - Build selector expression for \@selector ExprResult ParseObjCSelectorExpression(Selector Sel, SourceLocation AtLoc, SourceLocation SelLoc, SourceLocation LParenLoc, SourceLocation RParenLoc, bool WarnMultipleSelectors); /// ParseObjCProtocolExpression - Build protocol expression for \@protocol ExprResult ParseObjCProtocolExpression(IdentifierInfo * ProtocolName, SourceLocation AtLoc, SourceLocation ProtoLoc, SourceLocation LParenLoc, SourceLocation ProtoIdLoc, SourceLocation RParenLoc); //===--------------------------------------------------------------------===// // C++ Declarations // Decl *ActOnStartLinkageSpecification(Scope *S, SourceLocation ExternLoc, Expr *LangStr, SourceLocation LBraceLoc); Decl *ActOnFinishLinkageSpecification(Scope *S, Decl *LinkageSpec, SourceLocation RBraceLoc); //===--------------------------------------------------------------------===// // C++ Classes // CXXRecordDecl *getCurrentClass(Scope *S, const CXXScopeSpec *SS); bool isCurrentClassName(const IdentifierInfo &II, Scope *S, const CXXScopeSpec *SS = nullptr); bool isCurrentClassNameTypo(IdentifierInfo *&II, const CXXScopeSpec *SS); bool ActOnAccessSpecifier(AccessSpecifier Access, SourceLocation ASLoc, SourceLocation ColonLoc, const ParsedAttributesView &Attrs); NamedDecl *ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, MultiTemplateParamsArg TemplateParameterLists, Expr *BitfieldWidth, const VirtSpecifiers &VS, InClassInitStyle InitStyle); void ActOnStartCXXInClassMemberInitializer(); void ActOnFinishCXXInClassMemberInitializer(Decl *VarDecl, SourceLocation EqualLoc, Expr *Init); MemInitResult ActOnMemInitializer(Decl *ConstructorD, Scope *S, CXXScopeSpec &SS, IdentifierInfo *MemberOrBase, ParsedType TemplateTypeTy, const DeclSpec &DS, SourceLocation IdLoc, SourceLocation LParenLoc, ArrayRef Args, SourceLocation RParenLoc, SourceLocation EllipsisLoc); MemInitResult ActOnMemInitializer(Decl *ConstructorD, Scope *S, CXXScopeSpec &SS, IdentifierInfo *MemberOrBase, ParsedType TemplateTypeTy, const DeclSpec &DS, SourceLocation IdLoc, Expr *InitList, SourceLocation EllipsisLoc); MemInitResult BuildMemInitializer(Decl *ConstructorD, Scope *S, CXXScopeSpec &SS, IdentifierInfo *MemberOrBase, ParsedType TemplateTypeTy, const DeclSpec &DS, SourceLocation IdLoc, Expr *Init, SourceLocation EllipsisLoc); MemInitResult BuildMemberInitializer(ValueDecl *Member, Expr *Init, SourceLocation IdLoc); MemInitResult BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo, Expr *Init, CXXRecordDecl *ClassDecl, SourceLocation EllipsisLoc); MemInitResult BuildDelegatingInitializer(TypeSourceInfo *TInfo, Expr *Init, CXXRecordDecl *ClassDecl); bool SetDelegatingInitializer(CXXConstructorDecl *Constructor, CXXCtorInitializer *Initializer); bool SetCtorInitializers(CXXConstructorDecl *Constructor, bool AnyErrors, ArrayRef Initializers = None); void SetIvarInitializers(ObjCImplementationDecl *ObjCImplementation); /// MarkBaseAndMemberDestructorsReferenced - Given a record decl, /// mark all the non-trivial destructors of its members and bases as /// referenced. void MarkBaseAndMemberDestructorsReferenced(SourceLocation Loc, CXXRecordDecl *Record); /// The list of classes whose vtables have been used within /// this translation unit, and the source locations at which the /// first use occurred. typedef std::pair VTableUse; /// The list of vtables that are required but have not yet been /// materialized. SmallVector VTableUses; /// The set of classes whose vtables have been used within /// this translation unit, and a bit that will be true if the vtable is /// required to be emitted (otherwise, it should be emitted only if needed /// by code generation). llvm::DenseMap VTablesUsed; /// Load any externally-stored vtable uses. void LoadExternalVTableUses(); /// Note that the vtable for the given class was used at the /// given location. void MarkVTableUsed(SourceLocation Loc, CXXRecordDecl *Class, bool DefinitionRequired = false); /// Mark the exception specifications of all virtual member functions /// in the given class as needed. void MarkVirtualMemberExceptionSpecsNeeded(SourceLocation Loc, const CXXRecordDecl *RD); /// MarkVirtualMembersReferenced - Will mark all members of the given /// CXXRecordDecl referenced. void MarkVirtualMembersReferenced(SourceLocation Loc, const CXXRecordDecl *RD, bool ConstexprOnly = false); /// Define all of the vtables that have been used in this /// translation unit and reference any virtual members used by those /// vtables. /// /// \returns true if any work was done, false otherwise. bool DefineUsedVTables(); void AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl); void ActOnMemInitializers(Decl *ConstructorDecl, SourceLocation ColonLoc, ArrayRef MemInits, bool AnyErrors); /// Check class-level dllimport/dllexport attribute. The caller must /// ensure that referenceDLLExportedClassMethods is called some point later /// when all outer classes of Class are complete. void checkClassLevelDLLAttribute(CXXRecordDecl *Class); void checkClassLevelCodeSegAttribute(CXXRecordDecl *Class); void referenceDLLExportedClassMethods(); void propagateDLLAttrToBaseClassTemplate( CXXRecordDecl *Class, Attr *ClassAttr, ClassTemplateSpecializationDecl *BaseTemplateSpec, SourceLocation BaseLoc); /// Add gsl::Pointer attribute to std::container::iterator /// \param ND The declaration that introduces the name /// std::container::iterator. \param UnderlyingRecord The record named by ND. void inferGslPointerAttribute(NamedDecl *ND, CXXRecordDecl *UnderlyingRecord); /// Add [[gsl::Owner]] and [[gsl::Pointer]] attributes for std:: types. void inferGslOwnerPointerAttribute(CXXRecordDecl *Record); /// Add [[gsl::Pointer]] attributes for std:: types. void inferGslPointerAttribute(TypedefNameDecl *TD); void CheckCompletedCXXClass(Scope *S, CXXRecordDecl *Record); /// Check that the C++ class annoated with "trivial_abi" satisfies all the /// conditions that are needed for the attribute to have an effect. void checkIllFormedTrivialABIStruct(CXXRecordDecl &RD); void ActOnFinishCXXMemberSpecification(Scope *S, SourceLocation RLoc, Decl *TagDecl, SourceLocation LBrac, SourceLocation RBrac, const ParsedAttributesView &AttrList); void ActOnFinishCXXMemberDecls(); void ActOnFinishCXXNonNestedClass(); void ActOnReenterCXXMethodParameter(Scope *S, ParmVarDecl *Param); unsigned ActOnReenterTemplateScope(Scope *S, Decl *Template); void ActOnStartDelayedMemberDeclarations(Scope *S, Decl *Record); void ActOnStartDelayedCXXMethodDeclaration(Scope *S, Decl *Method); void ActOnDelayedCXXMethodParameter(Scope *S, Decl *Param); void ActOnFinishDelayedMemberDeclarations(Scope *S, Decl *Record); void ActOnFinishDelayedCXXMethodDeclaration(Scope *S, Decl *Method); void ActOnFinishDelayedMemberInitializers(Decl *Record); void MarkAsLateParsedTemplate(FunctionDecl *FD, Decl *FnD, CachedTokens &Toks); void UnmarkAsLateParsedTemplate(FunctionDecl *FD); bool IsInsideALocalClassWithinATemplateFunction(); Decl *ActOnStaticAssertDeclaration(SourceLocation StaticAssertLoc, Expr *AssertExpr, Expr *AssertMessageExpr, SourceLocation RParenLoc); Decl *BuildStaticAssertDeclaration(SourceLocation StaticAssertLoc, Expr *AssertExpr, StringLiteral *AssertMessageExpr, SourceLocation RParenLoc, bool Failed); FriendDecl *CheckFriendTypeDecl(SourceLocation LocStart, SourceLocation FriendLoc, TypeSourceInfo *TSInfo); Decl *ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS, MultiTemplateParamsArg TemplateParams); NamedDecl *ActOnFriendFunctionDecl(Scope *S, Declarator &D, MultiTemplateParamsArg TemplateParams); QualType CheckConstructorDeclarator(Declarator &D, QualType R, StorageClass& SC); void CheckConstructor(CXXConstructorDecl *Constructor); QualType CheckDestructorDeclarator(Declarator &D, QualType R, StorageClass& SC); bool CheckDestructor(CXXDestructorDecl *Destructor); void CheckConversionDeclarator(Declarator &D, QualType &R, StorageClass& SC); Decl *ActOnConversionDeclarator(CXXConversionDecl *Conversion); void CheckDeductionGuideDeclarator(Declarator &D, QualType &R, StorageClass &SC); void CheckDeductionGuideTemplate(FunctionTemplateDecl *TD); void CheckExplicitlyDefaultedFunction(Scope *S, FunctionDecl *MD); bool CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD, CXXSpecialMember CSM); void CheckDelayedMemberExceptionSpecs(); bool CheckExplicitlyDefaultedComparison(Scope *S, FunctionDecl *MD, DefaultedComparisonKind DCK); void DeclareImplicitEqualityComparison(CXXRecordDecl *RD, FunctionDecl *Spaceship); void DefineDefaultedComparison(SourceLocation Loc, FunctionDecl *FD, DefaultedComparisonKind DCK); //===--------------------------------------------------------------------===// // C++ Derived Classes // /// ActOnBaseSpecifier - Parsed a base specifier CXXBaseSpecifier *CheckBaseSpecifier(CXXRecordDecl *Class, SourceRange SpecifierRange, bool Virtual, AccessSpecifier Access, TypeSourceInfo *TInfo, SourceLocation EllipsisLoc); BaseResult ActOnBaseSpecifier(Decl *classdecl, SourceRange SpecifierRange, ParsedAttributes &Attrs, bool Virtual, AccessSpecifier Access, ParsedType basetype, SourceLocation BaseLoc, SourceLocation EllipsisLoc); bool AttachBaseSpecifiers(CXXRecordDecl *Class, MutableArrayRef Bases); void ActOnBaseSpecifiers(Decl *ClassDecl, MutableArrayRef Bases); bool IsDerivedFrom(SourceLocation Loc, QualType Derived, QualType Base); bool IsDerivedFrom(SourceLocation Loc, QualType Derived, QualType Base, CXXBasePaths &Paths); // FIXME: I don't like this name. void BuildBasePathArray(const CXXBasePaths &Paths, CXXCastPath &BasePath); bool CheckDerivedToBaseConversion(QualType Derived, QualType Base, SourceLocation Loc, SourceRange Range, CXXCastPath *BasePath = nullptr, bool IgnoreAccess = false); bool CheckDerivedToBaseConversion(QualType Derived, QualType Base, unsigned InaccessibleBaseID, unsigned AmbigiousBaseConvID, SourceLocation Loc, SourceRange Range, DeclarationName Name, CXXCastPath *BasePath, bool IgnoreAccess = false); std::string getAmbiguousPathsDisplayString(CXXBasePaths &Paths); bool CheckOverridingFunctionAttributes(const CXXMethodDecl *New, const CXXMethodDecl *Old); /// CheckOverridingFunctionReturnType - Checks whether the return types are /// covariant, according to C++ [class.virtual]p5. bool CheckOverridingFunctionReturnType(const CXXMethodDecl *New, const CXXMethodDecl *Old); /// CheckOverridingFunctionExceptionSpec - Checks whether the exception /// spec is a subset of base spec. bool CheckOverridingFunctionExceptionSpec(const CXXMethodDecl *New, const CXXMethodDecl *Old); bool CheckPureMethod(CXXMethodDecl *Method, SourceRange InitRange); /// CheckOverrideControl - Check C++11 override control semantics. void CheckOverrideControl(NamedDecl *D); /// DiagnoseAbsenceOfOverrideControl - Diagnose if 'override' keyword was /// not used in the declaration of an overriding method. void DiagnoseAbsenceOfOverrideControl(NamedDecl *D); /// CheckForFunctionMarkedFinal - Checks whether a virtual member function /// overrides a virtual member function marked 'final', according to /// C++11 [class.virtual]p4. bool CheckIfOverriddenFunctionIsMarkedFinal(const CXXMethodDecl *New, const CXXMethodDecl *Old); //===--------------------------------------------------------------------===// // C++ Access Control // enum AccessResult { AR_accessible, AR_inaccessible, AR_dependent, AR_delayed }; bool SetMemberAccessSpecifier(NamedDecl *MemberDecl, NamedDecl *PrevMemberDecl, AccessSpecifier LexicalAS); AccessResult CheckUnresolvedMemberAccess(UnresolvedMemberExpr *E, DeclAccessPair FoundDecl); AccessResult CheckUnresolvedLookupAccess(UnresolvedLookupExpr *E, DeclAccessPair FoundDecl); AccessResult CheckAllocationAccess(SourceLocation OperatorLoc, SourceRange PlacementRange, CXXRecordDecl *NamingClass, DeclAccessPair FoundDecl, bool Diagnose = true); AccessResult CheckConstructorAccess(SourceLocation Loc, CXXConstructorDecl *D, DeclAccessPair FoundDecl, const InitializedEntity &Entity, bool IsCopyBindingRefToTemp = false); AccessResult CheckConstructorAccess(SourceLocation Loc, CXXConstructorDecl *D, DeclAccessPair FoundDecl, const InitializedEntity &Entity, const PartialDiagnostic &PDiag); AccessResult CheckDestructorAccess(SourceLocation Loc, CXXDestructorDecl *Dtor, const PartialDiagnostic &PDiag, QualType objectType = QualType()); AccessResult CheckFriendAccess(NamedDecl *D); AccessResult CheckMemberAccess(SourceLocation UseLoc, CXXRecordDecl *NamingClass, DeclAccessPair Found); AccessResult CheckStructuredBindingMemberAccess(SourceLocation UseLoc, CXXRecordDecl *DecomposedClass, DeclAccessPair Field); AccessResult CheckMemberOperatorAccess(SourceLocation Loc, Expr *ObjectExpr, Expr *ArgExpr, DeclAccessPair FoundDecl); AccessResult CheckAddressOfMemberAccess(Expr *OvlExpr, DeclAccessPair FoundDecl); AccessResult CheckBaseClassAccess(SourceLocation AccessLoc, QualType Base, QualType Derived, const CXXBasePath &Path, unsigned DiagID, bool ForceCheck = false, bool ForceUnprivileged = false); void CheckLookupAccess(const LookupResult &R); bool IsSimplyAccessible(NamedDecl *Decl, CXXRecordDecl *NamingClass, QualType BaseType); bool isMemberAccessibleForDeletion(CXXRecordDecl *NamingClass, DeclAccessPair Found, QualType ObjectType, SourceLocation Loc, const PartialDiagnostic &Diag); bool isMemberAccessibleForDeletion(CXXRecordDecl *NamingClass, DeclAccessPair Found, QualType ObjectType) { return isMemberAccessibleForDeletion(NamingClass, Found, ObjectType, SourceLocation(), PDiag()); } void HandleDependentAccessCheck(const DependentDiagnostic &DD, const MultiLevelTemplateArgumentList &TemplateArgs); void PerformDependentDiagnostics(const DeclContext *Pattern, const MultiLevelTemplateArgumentList &TemplateArgs); void HandleDelayedAccessCheck(sema::DelayedDiagnostic &DD, Decl *Ctx); /// When true, access checking violations are treated as SFINAE /// failures rather than hard errors. bool AccessCheckingSFINAE; enum AbstractDiagSelID { AbstractNone = -1, AbstractReturnType, AbstractParamType, AbstractVariableType, AbstractFieldType, AbstractIvarType, AbstractSynthesizedIvarType, AbstractArrayType }; bool isAbstractType(SourceLocation Loc, QualType T); bool RequireNonAbstractType(SourceLocation Loc, QualType T, TypeDiagnoser &Diagnoser); template bool RequireNonAbstractType(SourceLocation Loc, QualType T, unsigned DiagID, const Ts &...Args) { BoundTypeDiagnoser Diagnoser(DiagID, Args...); return RequireNonAbstractType(Loc, T, Diagnoser); } void DiagnoseAbstractType(const CXXRecordDecl *RD); //===--------------------------------------------------------------------===// // C++ Overloaded Operators [C++ 13.5] // bool CheckOverloadedOperatorDeclaration(FunctionDecl *FnDecl); bool CheckLiteralOperatorDeclaration(FunctionDecl *FnDecl); //===--------------------------------------------------------------------===// // C++ Templates [C++ 14] // void FilterAcceptableTemplateNames(LookupResult &R, bool AllowFunctionTemplates = true, bool AllowDependent = true); bool hasAnyAcceptableTemplateNames(LookupResult &R, bool AllowFunctionTemplates = true, bool AllowDependent = true, bool AllowNonTemplateFunctions = false); /// Try to interpret the lookup result D as a template-name. /// /// \param D A declaration found by name lookup. /// \param AllowFunctionTemplates Whether function templates should be /// considered valid results. /// \param AllowDependent Whether unresolved using declarations (that might /// name templates) should be considered valid results. NamedDecl *getAsTemplateNameDecl(NamedDecl *D, bool AllowFunctionTemplates = true, bool AllowDependent = true); enum class AssumedTemplateKind { /// This is not assumed to be a template name. None, /// This is assumed to be a template name because lookup found nothing. FoundNothing, /// This is assumed to be a template name because lookup found one or more /// functions (but no function templates). FoundFunctions, }; bool LookupTemplateName(LookupResult &R, Scope *S, CXXScopeSpec &SS, QualType ObjectType, bool EnteringContext, bool &MemberOfUnknownSpecialization, SourceLocation TemplateKWLoc = SourceLocation(), AssumedTemplateKind *ATK = nullptr); TemplateNameKind isTemplateName(Scope *S, CXXScopeSpec &SS, bool hasTemplateKeyword, const UnqualifiedId &Name, ParsedType ObjectType, bool EnteringContext, TemplateTy &Template, bool &MemberOfUnknownSpecialization); /// Try to resolve an undeclared template name as a type template. /// /// Sets II to the identifier corresponding to the template name, and updates /// Name to a corresponding (typo-corrected) type template name and TNK to /// the corresponding kind, if possible. void ActOnUndeclaredTypeTemplateName(Scope *S, TemplateTy &Name, TemplateNameKind &TNK, SourceLocation NameLoc, IdentifierInfo *&II); bool resolveAssumedTemplateNameAsType(Scope *S, TemplateName &Name, SourceLocation NameLoc, bool Diagnose = true); /// Determine whether a particular identifier might be the name in a C++1z /// deduction-guide declaration. bool isDeductionGuideName(Scope *S, const IdentifierInfo &Name, SourceLocation NameLoc, ParsedTemplateTy *Template = nullptr); bool DiagnoseUnknownTemplateName(const IdentifierInfo &II, SourceLocation IILoc, Scope *S, const CXXScopeSpec *SS, TemplateTy &SuggestedTemplate, TemplateNameKind &SuggestedKind); bool DiagnoseUninstantiableTemplate(SourceLocation PointOfInstantiation, NamedDecl *Instantiation, bool InstantiatedFromMember, const NamedDecl *Pattern, const NamedDecl *PatternDef, TemplateSpecializationKind TSK, bool Complain = true); void DiagnoseTemplateParameterShadow(SourceLocation Loc, Decl *PrevDecl); TemplateDecl *AdjustDeclIfTemplate(Decl *&Decl); NamedDecl *ActOnTypeParameter(Scope *S, bool Typename, SourceLocation EllipsisLoc, SourceLocation KeyLoc, IdentifierInfo *ParamName, SourceLocation ParamNameLoc, unsigned Depth, unsigned Position, SourceLocation EqualLoc, ParsedType DefaultArg, bool HasTypeConstraint); bool ActOnTypeConstraint(const CXXScopeSpec &SS, TemplateIdAnnotation *TypeConstraint, TemplateTypeParmDecl *ConstrainedParameter, SourceLocation EllipsisLoc); bool AttachTypeConstraint(NestedNameSpecifierLoc NS, DeclarationNameInfo NameInfo, ConceptDecl *NamedConcept, const TemplateArgumentListInfo *TemplateArgs, TemplateTypeParmDecl *ConstrainedParameter, SourceLocation EllipsisLoc); bool AttachTypeConstraint(AutoTypeLoc TL, NonTypeTemplateParmDecl *ConstrainedParameter, SourceLocation EllipsisLoc); QualType CheckNonTypeTemplateParameterType(TypeSourceInfo *&TSI, SourceLocation Loc); QualType CheckNonTypeTemplateParameterType(QualType T, SourceLocation Loc); NamedDecl *ActOnNonTypeTemplateParameter(Scope *S, Declarator &D, unsigned Depth, unsigned Position, SourceLocation EqualLoc, Expr *DefaultArg); NamedDecl *ActOnTemplateTemplateParameter(Scope *S, SourceLocation TmpLoc, TemplateParameterList *Params, SourceLocation EllipsisLoc, IdentifierInfo *ParamName, SourceLocation ParamNameLoc, unsigned Depth, unsigned Position, SourceLocation EqualLoc, ParsedTemplateArgument DefaultArg); TemplateParameterList * ActOnTemplateParameterList(unsigned Depth, SourceLocation ExportLoc, SourceLocation TemplateLoc, SourceLocation LAngleLoc, ArrayRef Params, SourceLocation RAngleLoc, Expr *RequiresClause); /// The context in which we are checking a template parameter list. enum TemplateParamListContext { TPC_ClassTemplate, TPC_VarTemplate, TPC_FunctionTemplate, TPC_ClassTemplateMember, TPC_FriendClassTemplate, TPC_FriendFunctionTemplate, TPC_FriendFunctionTemplateDefinition, TPC_TypeAliasTemplate }; bool CheckTemplateParameterList(TemplateParameterList *NewParams, TemplateParameterList *OldParams, TemplateParamListContext TPC, SkipBodyInfo *SkipBody = nullptr); TemplateParameterList *MatchTemplateParametersToScopeSpecifier( SourceLocation DeclStartLoc, SourceLocation DeclLoc, const CXXScopeSpec &SS, TemplateIdAnnotation *TemplateId, ArrayRef ParamLists, bool IsFriend, bool &IsMemberSpecialization, bool &Invalid, bool SuppressDiagnostic = false); DeclResult CheckClassTemplate( Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc, CXXScopeSpec &SS, IdentifierInfo *Name, SourceLocation NameLoc, const ParsedAttributesView &Attr, TemplateParameterList *TemplateParams, AccessSpecifier AS, SourceLocation ModulePrivateLoc, SourceLocation FriendLoc, unsigned NumOuterTemplateParamLists, TemplateParameterList **OuterTemplateParamLists, SkipBodyInfo *SkipBody = nullptr); TemplateArgumentLoc getTrivialTemplateArgumentLoc(const TemplateArgument &Arg, QualType NTTPType, SourceLocation Loc); /// Get a template argument mapping the given template parameter to itself, /// e.g. for X in \c template, this would return an expression template /// argument referencing X. TemplateArgumentLoc getIdentityTemplateArgumentLoc(NamedDecl *Param, SourceLocation Location); void translateTemplateArguments(const ASTTemplateArgsPtr &In, TemplateArgumentListInfo &Out); ParsedTemplateArgument ActOnTemplateTypeArgument(TypeResult ParsedType); void NoteAllFoundTemplates(TemplateName Name); QualType CheckTemplateIdType(TemplateName Template, SourceLocation TemplateLoc, TemplateArgumentListInfo &TemplateArgs); TypeResult ActOnTemplateIdType(Scope *S, CXXScopeSpec &SS, SourceLocation TemplateKWLoc, TemplateTy Template, IdentifierInfo *TemplateII, SourceLocation TemplateIILoc, SourceLocation LAngleLoc, ASTTemplateArgsPtr TemplateArgs, SourceLocation RAngleLoc, bool IsCtorOrDtorName = false, bool IsClassName = false); /// Parsed an elaborated-type-specifier that refers to a template-id, /// such as \c class T::template apply. TypeResult ActOnTagTemplateIdType(TagUseKind TUK, TypeSpecifierType TagSpec, SourceLocation TagLoc, CXXScopeSpec &SS, SourceLocation TemplateKWLoc, TemplateTy TemplateD, SourceLocation TemplateLoc, SourceLocation LAngleLoc, ASTTemplateArgsPtr TemplateArgsIn, SourceLocation RAngleLoc); DeclResult ActOnVarTemplateSpecialization( Scope *S, Declarator &D, TypeSourceInfo *DI, SourceLocation TemplateKWLoc, TemplateParameterList *TemplateParams, StorageClass SC, bool IsPartialSpecialization); DeclResult CheckVarTemplateId(VarTemplateDecl *Template, SourceLocation TemplateLoc, SourceLocation TemplateNameLoc, const TemplateArgumentListInfo &TemplateArgs); ExprResult CheckVarTemplateId(const CXXScopeSpec &SS, const DeclarationNameInfo &NameInfo, VarTemplateDecl *Template, SourceLocation TemplateLoc, const TemplateArgumentListInfo *TemplateArgs); ExprResult CheckConceptTemplateId(const CXXScopeSpec &SS, SourceLocation TemplateKWLoc, const DeclarationNameInfo &ConceptNameInfo, NamedDecl *FoundDecl, ConceptDecl *NamedConcept, const TemplateArgumentListInfo *TemplateArgs); void diagnoseMissingTemplateArguments(TemplateName Name, SourceLocation Loc); ExprResult BuildTemplateIdExpr(const CXXScopeSpec &SS, SourceLocation TemplateKWLoc, LookupResult &R, bool RequiresADL, const TemplateArgumentListInfo *TemplateArgs); ExprResult BuildQualifiedTemplateIdExpr(CXXScopeSpec &SS, SourceLocation TemplateKWLoc, const DeclarationNameInfo &NameInfo, const TemplateArgumentListInfo *TemplateArgs); TemplateNameKind ActOnDependentTemplateName( Scope *S, CXXScopeSpec &SS, SourceLocation TemplateKWLoc, const UnqualifiedId &Name, ParsedType ObjectType, bool EnteringContext, TemplateTy &Template, bool AllowInjectedClassName = false); DeclResult ActOnClassTemplateSpecialization( Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc, SourceLocation ModulePrivateLoc, CXXScopeSpec &SS, TemplateIdAnnotation &TemplateId, const ParsedAttributesView &Attr, MultiTemplateParamsArg TemplateParameterLists, SkipBodyInfo *SkipBody = nullptr); bool CheckTemplatePartialSpecializationArgs(SourceLocation Loc, TemplateDecl *PrimaryTemplate, unsigned NumExplicitArgs, ArrayRef Args); void CheckTemplatePartialSpecialization( ClassTemplatePartialSpecializationDecl *Partial); void CheckTemplatePartialSpecialization( VarTemplatePartialSpecializationDecl *Partial); Decl *ActOnTemplateDeclarator(Scope *S, MultiTemplateParamsArg TemplateParameterLists, Declarator &D); bool CheckSpecializationInstantiationRedecl(SourceLocation NewLoc, TemplateSpecializationKind NewTSK, NamedDecl *PrevDecl, TemplateSpecializationKind PrevTSK, SourceLocation PrevPtOfInstantiation, bool &SuppressNew); bool CheckDependentFunctionTemplateSpecialization(FunctionDecl *FD, const TemplateArgumentListInfo &ExplicitTemplateArgs, LookupResult &Previous); bool CheckFunctionTemplateSpecialization( FunctionDecl *FD, TemplateArgumentListInfo *ExplicitTemplateArgs, LookupResult &Previous, bool QualifiedFriend = false); bool CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous); void CompleteMemberSpecialization(NamedDecl *Member, LookupResult &Previous); DeclResult ActOnExplicitInstantiation( Scope *S, SourceLocation ExternLoc, SourceLocation TemplateLoc, unsigned TagSpec, SourceLocation KWLoc, const CXXScopeSpec &SS, TemplateTy Template, SourceLocation TemplateNameLoc, SourceLocation LAngleLoc, ASTTemplateArgsPtr TemplateArgs, SourceLocation RAngleLoc, const ParsedAttributesView &Attr); DeclResult ActOnExplicitInstantiation(Scope *S, SourceLocation ExternLoc, SourceLocation TemplateLoc, unsigned TagSpec, SourceLocation KWLoc, CXXScopeSpec &SS, IdentifierInfo *Name, SourceLocation NameLoc, const ParsedAttributesView &Attr); DeclResult ActOnExplicitInstantiation(Scope *S, SourceLocation ExternLoc, SourceLocation TemplateLoc, Declarator &D); TemplateArgumentLoc SubstDefaultTemplateArgumentIfAvailable(TemplateDecl *Template, SourceLocation TemplateLoc, SourceLocation RAngleLoc, Decl *Param, SmallVectorImpl &Converted, bool &HasDefaultArg); /// Specifies the context in which a particular template /// argument is being checked. enum CheckTemplateArgumentKind { /// The template argument was specified in the code or was /// instantiated with some deduced template arguments. CTAK_Specified, /// The template argument was deduced via template argument /// deduction. CTAK_Deduced, /// The template argument was deduced from an array bound /// via template argument deduction. CTAK_DeducedFromArrayBound }; bool CheckTemplateArgument(NamedDecl *Param, TemplateArgumentLoc &Arg, NamedDecl *Template, SourceLocation TemplateLoc, SourceLocation RAngleLoc, unsigned ArgumentPackIndex, SmallVectorImpl &Converted, CheckTemplateArgumentKind CTAK = CTAK_Specified); /// Check that the given template arguments can be be provided to /// the given template, converting the arguments along the way. /// /// \param Template The template to which the template arguments are being /// provided. /// /// \param TemplateLoc The location of the template name in the source. /// /// \param TemplateArgs The list of template arguments. If the template is /// a template template parameter, this function may extend the set of /// template arguments to also include substituted, defaulted template /// arguments. /// /// \param PartialTemplateArgs True if the list of template arguments is /// intentionally partial, e.g., because we're checking just the initial /// set of template arguments. /// /// \param Converted Will receive the converted, canonicalized template /// arguments. /// /// \param UpdateArgsWithConversions If \c true, update \p TemplateArgs to /// contain the converted forms of the template arguments as written. /// Otherwise, \p TemplateArgs will not be modified. /// /// \param ConstraintsNotSatisfied If provided, and an error occured, will /// receive true if the cause for the error is the associated constraints of /// the template not being satisfied by the template arguments. /// /// \returns true if an error occurred, false otherwise. bool CheckTemplateArgumentList(TemplateDecl *Template, SourceLocation TemplateLoc, TemplateArgumentListInfo &TemplateArgs, bool PartialTemplateArgs, SmallVectorImpl &Converted, bool UpdateArgsWithConversions = true, bool *ConstraintsNotSatisfied = nullptr); bool CheckTemplateTypeArgument(TemplateTypeParmDecl *Param, TemplateArgumentLoc &Arg, SmallVectorImpl &Converted); bool CheckTemplateArgument(TemplateTypeParmDecl *Param, TypeSourceInfo *Arg); ExprResult CheckTemplateArgument(NonTypeTemplateParmDecl *Param, QualType InstantiatedParamType, Expr *Arg, TemplateArgument &Converted, CheckTemplateArgumentKind CTAK = CTAK_Specified); bool CheckTemplateTemplateArgument(TemplateTemplateParmDecl *Param, TemplateParameterList *Params, TemplateArgumentLoc &Arg); ExprResult BuildExpressionFromDeclTemplateArgument(const TemplateArgument &Arg, QualType ParamType, SourceLocation Loc); ExprResult BuildExpressionFromIntegralTemplateArgument(const TemplateArgument &Arg, SourceLocation Loc); /// Enumeration describing how template parameter lists are compared /// for equality. enum TemplateParameterListEqualKind { /// We are matching the template parameter lists of two templates /// that might be redeclarations. /// /// \code /// template struct X; /// template struct X; /// \endcode TPL_TemplateMatch, /// We are matching the template parameter lists of two template /// template parameters as part of matching the template parameter lists /// of two templates that might be redeclarations. /// /// \code /// template class TT> struct X; /// template class Other> struct X; /// \endcode TPL_TemplateTemplateParmMatch, /// We are matching the template parameter lists of a template /// template argument against the template parameter lists of a template /// template parameter. /// /// \code /// template class Metafun> struct X; /// template struct integer_c; /// X xic; /// \endcode TPL_TemplateTemplateArgumentMatch }; bool TemplateParameterListsAreEqual(TemplateParameterList *New, TemplateParameterList *Old, bool Complain, TemplateParameterListEqualKind Kind, SourceLocation TemplateArgLoc = SourceLocation()); bool CheckTemplateDeclScope(Scope *S, TemplateParameterList *TemplateParams); /// Called when the parser has parsed a C++ typename /// specifier, e.g., "typename T::type". /// /// \param S The scope in which this typename type occurs. /// \param TypenameLoc the location of the 'typename' keyword /// \param SS the nested-name-specifier following the typename (e.g., 'T::'). /// \param II the identifier we're retrieving (e.g., 'type' in the example). /// \param IdLoc the location of the identifier. TypeResult ActOnTypenameType(Scope *S, SourceLocation TypenameLoc, const CXXScopeSpec &SS, const IdentifierInfo &II, SourceLocation IdLoc); /// Called when the parser has parsed a C++ typename /// specifier that ends in a template-id, e.g., /// "typename MetaFun::template apply". /// /// \param S The scope in which this typename type occurs. /// \param TypenameLoc the location of the 'typename' keyword /// \param SS the nested-name-specifier following the typename (e.g., 'T::'). /// \param TemplateLoc the location of the 'template' keyword, if any. /// \param TemplateName The template name. /// \param TemplateII The identifier used to name the template. /// \param TemplateIILoc The location of the template name. /// \param LAngleLoc The location of the opening angle bracket ('<'). /// \param TemplateArgs The template arguments. /// \param RAngleLoc The location of the closing angle bracket ('>'). TypeResult ActOnTypenameType(Scope *S, SourceLocation TypenameLoc, const CXXScopeSpec &SS, SourceLocation TemplateLoc, TemplateTy TemplateName, IdentifierInfo *TemplateII, SourceLocation TemplateIILoc, SourceLocation LAngleLoc, ASTTemplateArgsPtr TemplateArgs, SourceLocation RAngleLoc); QualType CheckTypenameType(ElaboratedTypeKeyword Keyword, SourceLocation KeywordLoc, NestedNameSpecifierLoc QualifierLoc, const IdentifierInfo &II, SourceLocation IILoc, TypeSourceInfo **TSI, bool DeducedTSTContext); QualType CheckTypenameType(ElaboratedTypeKeyword Keyword, SourceLocation KeywordLoc, NestedNameSpecifierLoc QualifierLoc, const IdentifierInfo &II, SourceLocation IILoc, bool DeducedTSTContext = true); TypeSourceInfo *RebuildTypeInCurrentInstantiation(TypeSourceInfo *T, SourceLocation Loc, DeclarationName Name); bool RebuildNestedNameSpecifierInCurrentInstantiation(CXXScopeSpec &SS); ExprResult RebuildExprInCurrentInstantiation(Expr *E); bool RebuildTemplateParamsInCurrentInstantiation( TemplateParameterList *Params); std::string getTemplateArgumentBindingsText(const TemplateParameterList *Params, const TemplateArgumentList &Args); std::string getTemplateArgumentBindingsText(const TemplateParameterList *Params, const TemplateArgument *Args, unsigned NumArgs); //===--------------------------------------------------------------------===// // C++ Concepts //===--------------------------------------------------------------------===// Decl *ActOnConceptDefinition( Scope *S, MultiTemplateParamsArg TemplateParameterLists, IdentifierInfo *Name, SourceLocation NameLoc, Expr *ConstraintExpr); RequiresExprBodyDecl * ActOnStartRequiresExpr(SourceLocation RequiresKWLoc, ArrayRef LocalParameters, Scope *BodyScope); void ActOnFinishRequiresExpr(); concepts::Requirement *ActOnSimpleRequirement(Expr *E); concepts::Requirement *ActOnTypeRequirement( SourceLocation TypenameKWLoc, CXXScopeSpec &SS, SourceLocation NameLoc, IdentifierInfo *TypeName, TemplateIdAnnotation *TemplateId); concepts::Requirement *ActOnCompoundRequirement(Expr *E, SourceLocation NoexceptLoc); concepts::Requirement * ActOnCompoundRequirement( Expr *E, SourceLocation NoexceptLoc, CXXScopeSpec &SS, TemplateIdAnnotation *TypeConstraint, unsigned Depth); concepts::Requirement *ActOnNestedRequirement(Expr *Constraint); concepts::ExprRequirement * BuildExprRequirement( Expr *E, bool IsSatisfied, SourceLocation NoexceptLoc, concepts::ExprRequirement::ReturnTypeRequirement ReturnTypeRequirement); concepts::ExprRequirement * BuildExprRequirement( concepts::Requirement::SubstitutionDiagnostic *ExprSubstDiag, bool IsSatisfied, SourceLocation NoexceptLoc, concepts::ExprRequirement::ReturnTypeRequirement ReturnTypeRequirement); concepts::TypeRequirement *BuildTypeRequirement(TypeSourceInfo *Type); concepts::TypeRequirement * BuildTypeRequirement( concepts::Requirement::SubstitutionDiagnostic *SubstDiag); concepts::NestedRequirement *BuildNestedRequirement(Expr *E); concepts::NestedRequirement * BuildNestedRequirement( concepts::Requirement::SubstitutionDiagnostic *SubstDiag); ExprResult ActOnRequiresExpr(SourceLocation RequiresKWLoc, RequiresExprBodyDecl *Body, ArrayRef LocalParameters, ArrayRef Requirements, SourceLocation ClosingBraceLoc); //===--------------------------------------------------------------------===// // C++ Variadic Templates (C++0x [temp.variadic]) //===--------------------------------------------------------------------===// /// Determine whether an unexpanded parameter pack might be permitted in this /// location. Useful for error recovery. bool isUnexpandedParameterPackPermitted(); /// The context in which an unexpanded parameter pack is /// being diagnosed. /// /// Note that the values of this enumeration line up with the first /// argument to the \c err_unexpanded_parameter_pack diagnostic. enum UnexpandedParameterPackContext { /// An arbitrary expression. UPPC_Expression = 0, /// The base type of a class type. UPPC_BaseType, /// The type of an arbitrary declaration. UPPC_DeclarationType, /// The type of a data member. UPPC_DataMemberType, /// The size of a bit-field. UPPC_BitFieldWidth, /// The expression in a static assertion. UPPC_StaticAssertExpression, /// The fixed underlying type of an enumeration. UPPC_FixedUnderlyingType, /// The enumerator value. UPPC_EnumeratorValue, /// A using declaration. UPPC_UsingDeclaration, /// A friend declaration. UPPC_FriendDeclaration, /// A declaration qualifier. UPPC_DeclarationQualifier, /// An initializer. UPPC_Initializer, /// A default argument. UPPC_DefaultArgument, /// The type of a non-type template parameter. UPPC_NonTypeTemplateParameterType, /// The type of an exception. UPPC_ExceptionType, /// Partial specialization. UPPC_PartialSpecialization, /// Microsoft __if_exists. UPPC_IfExists, /// Microsoft __if_not_exists. UPPC_IfNotExists, /// Lambda expression. UPPC_Lambda, /// Block expression, UPPC_Block, /// A type constraint, UPPC_TypeConstraint }; /// Diagnose unexpanded parameter packs. /// /// \param Loc The location at which we should emit the diagnostic. /// /// \param UPPC The context in which we are diagnosing unexpanded /// parameter packs. /// /// \param Unexpanded the set of unexpanded parameter packs. /// /// \returns true if an error occurred, false otherwise. bool DiagnoseUnexpandedParameterPacks(SourceLocation Loc, UnexpandedParameterPackContext UPPC, ArrayRef Unexpanded); /// If the given type contains an unexpanded parameter pack, /// diagnose the error. /// /// \param Loc The source location where a diagnostc should be emitted. /// /// \param T The type that is being checked for unexpanded parameter /// packs. /// /// \returns true if an error occurred, false otherwise. bool DiagnoseUnexpandedParameterPack(SourceLocation Loc, TypeSourceInfo *T, UnexpandedParameterPackContext UPPC); /// If the given expression contains an unexpanded parameter /// pack, diagnose the error. /// /// \param E The expression that is being checked for unexpanded /// parameter packs. /// /// \returns true if an error occurred, false otherwise. bool DiagnoseUnexpandedParameterPack(Expr *E, UnexpandedParameterPackContext UPPC = UPPC_Expression); /// If the given nested-name-specifier contains an unexpanded /// parameter pack, diagnose the error. /// /// \param SS The nested-name-specifier that is being checked for /// unexpanded parameter packs. /// /// \returns true if an error occurred, false otherwise. bool DiagnoseUnexpandedParameterPack(const CXXScopeSpec &SS, UnexpandedParameterPackContext UPPC); /// If the given name contains an unexpanded parameter pack, /// diagnose the error. /// /// \param NameInfo The name (with source location information) that /// is being checked for unexpanded parameter packs. /// /// \returns true if an error occurred, false otherwise. bool DiagnoseUnexpandedParameterPack(const DeclarationNameInfo &NameInfo, UnexpandedParameterPackContext UPPC); /// If the given template name contains an unexpanded parameter pack, /// diagnose the error. /// /// \param Loc The location of the template name. /// /// \param Template The template name that is being checked for unexpanded /// parameter packs. /// /// \returns true if an error occurred, false otherwise. bool DiagnoseUnexpandedParameterPack(SourceLocation Loc, TemplateName Template, UnexpandedParameterPackContext UPPC); /// If the given template argument contains an unexpanded parameter /// pack, diagnose the error. /// /// \param Arg The template argument that is being checked for unexpanded /// parameter packs. /// /// \returns true if an error occurred, false otherwise. bool DiagnoseUnexpandedParameterPack(TemplateArgumentLoc Arg, UnexpandedParameterPackContext UPPC); /// Collect the set of unexpanded parameter packs within the given /// template argument. /// /// \param Arg The template argument that will be traversed to find /// unexpanded parameter packs. void collectUnexpandedParameterPacks(TemplateArgument Arg, SmallVectorImpl &Unexpanded); /// Collect the set of unexpanded parameter packs within the given /// template argument. /// /// \param Arg The template argument that will be traversed to find /// unexpanded parameter packs. void collectUnexpandedParameterPacks(TemplateArgumentLoc Arg, SmallVectorImpl &Unexpanded); /// Collect the set of unexpanded parameter packs within the given /// type. /// /// \param T The type that will be traversed to find /// unexpanded parameter packs. void collectUnexpandedParameterPacks(QualType T, SmallVectorImpl &Unexpanded); /// Collect the set of unexpanded parameter packs within the given /// type. /// /// \param TL The type that will be traversed to find /// unexpanded parameter packs. void collectUnexpandedParameterPacks(TypeLoc TL, SmallVectorImpl &Unexpanded); /// Collect the set of unexpanded parameter packs within the given /// nested-name-specifier. /// /// \param NNS The nested-name-specifier that will be traversed to find /// unexpanded parameter packs. void collectUnexpandedParameterPacks(NestedNameSpecifierLoc NNS, SmallVectorImpl &Unexpanded); /// Collect the set of unexpanded parameter packs within the given /// name. /// /// \param NameInfo The name that will be traversed to find /// unexpanded parameter packs. void collectUnexpandedParameterPacks(const DeclarationNameInfo &NameInfo, SmallVectorImpl &Unexpanded); /// Invoked when parsing a template argument followed by an /// ellipsis, which creates a pack expansion. /// /// \param Arg The template argument preceding the ellipsis, which /// may already be invalid. /// /// \param EllipsisLoc The location of the ellipsis. ParsedTemplateArgument ActOnPackExpansion(const ParsedTemplateArgument &Arg, SourceLocation EllipsisLoc); /// Invoked when parsing a type followed by an ellipsis, which /// creates a pack expansion. /// /// \param Type The type preceding the ellipsis, which will become /// the pattern of the pack expansion. /// /// \param EllipsisLoc The location of the ellipsis. TypeResult ActOnPackExpansion(ParsedType Type, SourceLocation EllipsisLoc); /// Construct a pack expansion type from the pattern of the pack /// expansion. TypeSourceInfo *CheckPackExpansion(TypeSourceInfo *Pattern, SourceLocation EllipsisLoc, Optional NumExpansions); /// Construct a pack expansion type from the pattern of the pack /// expansion. QualType CheckPackExpansion(QualType Pattern, SourceRange PatternRange, SourceLocation EllipsisLoc, Optional NumExpansions); /// Invoked when parsing an expression followed by an ellipsis, which /// creates a pack expansion. /// /// \param Pattern The expression preceding the ellipsis, which will become /// the pattern of the pack expansion. /// /// \param EllipsisLoc The location of the ellipsis. ExprResult ActOnPackExpansion(Expr *Pattern, SourceLocation EllipsisLoc); /// Invoked when parsing an expression followed by an ellipsis, which /// creates a pack expansion. /// /// \param Pattern The expression preceding the ellipsis, which will become /// the pattern of the pack expansion. /// /// \param EllipsisLoc The location of the ellipsis. ExprResult CheckPackExpansion(Expr *Pattern, SourceLocation EllipsisLoc, Optional NumExpansions); /// Determine whether we could expand a pack expansion with the /// given set of parameter packs into separate arguments by repeatedly /// transforming the pattern. /// /// \param EllipsisLoc The location of the ellipsis that identifies the /// pack expansion. /// /// \param PatternRange The source range that covers the entire pattern of /// the pack expansion. /// /// \param Unexpanded The set of unexpanded parameter packs within the /// pattern. /// /// \param ShouldExpand Will be set to \c true if the transformer should /// expand the corresponding pack expansions into separate arguments. When /// set, \c NumExpansions must also be set. /// /// \param RetainExpansion Whether the caller should add an unexpanded /// pack expansion after all of the expanded arguments. This is used /// when extending explicitly-specified template argument packs per /// C++0x [temp.arg.explicit]p9. /// /// \param NumExpansions The number of separate arguments that will be in /// the expanded form of the corresponding pack expansion. This is both an /// input and an output parameter, which can be set by the caller if the /// number of expansions is known a priori (e.g., due to a prior substitution) /// and will be set by the callee when the number of expansions is known. /// The callee must set this value when \c ShouldExpand is \c true; it may /// set this value in other cases. /// /// \returns true if an error occurred (e.g., because the parameter packs /// are to be instantiated with arguments of different lengths), false /// otherwise. If false, \c ShouldExpand (and possibly \c NumExpansions) /// must be set. bool CheckParameterPacksForExpansion(SourceLocation EllipsisLoc, SourceRange PatternRange, ArrayRef Unexpanded, const MultiLevelTemplateArgumentList &TemplateArgs, bool &ShouldExpand, bool &RetainExpansion, Optional &NumExpansions); /// Determine the number of arguments in the given pack expansion /// type. /// /// This routine assumes that the number of arguments in the expansion is /// consistent across all of the unexpanded parameter packs in its pattern. /// /// Returns an empty Optional if the type can't be expanded. Optional getNumArgumentsInExpansion(QualType T, const MultiLevelTemplateArgumentList &TemplateArgs); /// Determine whether the given declarator contains any unexpanded /// parameter packs. /// /// This routine is used by the parser to disambiguate function declarators /// with an ellipsis prior to the ')', e.g., /// /// \code /// void f(T...); /// \endcode /// /// To determine whether we have an (unnamed) function parameter pack or /// a variadic function. /// /// \returns true if the declarator contains any unexpanded parameter packs, /// false otherwise. bool containsUnexpandedParameterPacks(Declarator &D); /// Returns the pattern of the pack expansion for a template argument. /// /// \param OrigLoc The template argument to expand. /// /// \param Ellipsis Will be set to the location of the ellipsis. /// /// \param NumExpansions Will be set to the number of expansions that will /// be generated from this pack expansion, if known a priori. TemplateArgumentLoc getTemplateArgumentPackExpansionPattern( TemplateArgumentLoc OrigLoc, SourceLocation &Ellipsis, Optional &NumExpansions) const; /// Given a template argument that contains an unexpanded parameter pack, but /// which has already been substituted, attempt to determine the number of /// elements that will be produced once this argument is fully-expanded. /// /// This is intended for use when transforming 'sizeof...(Arg)' in order to /// avoid actually expanding the pack where possible. Optional getFullyPackExpandedSize(TemplateArgument Arg); //===--------------------------------------------------------------------===// // C++ Template Argument Deduction (C++ [temp.deduct]) //===--------------------------------------------------------------------===// /// Adjust the type \p ArgFunctionType to match the calling convention, /// noreturn, and optionally the exception specification of \p FunctionType. /// Deduction often wants to ignore these properties when matching function /// types. QualType adjustCCAndNoReturn(QualType ArgFunctionType, QualType FunctionType, bool AdjustExceptionSpec = false); /// Describes the result of template argument deduction. /// /// The TemplateDeductionResult enumeration describes the result of /// template argument deduction, as returned from /// DeduceTemplateArguments(). The separate TemplateDeductionInfo /// structure provides additional information about the results of /// template argument deduction, e.g., the deduced template argument /// list (if successful) or the specific template parameters or /// deduced arguments that were involved in the failure. enum TemplateDeductionResult { /// Template argument deduction was successful. TDK_Success = 0, /// The declaration was invalid; do nothing. TDK_Invalid, /// Template argument deduction exceeded the maximum template /// instantiation depth (which has already been diagnosed). TDK_InstantiationDepth, /// Template argument deduction did not deduce a value /// for every template parameter. TDK_Incomplete, /// Template argument deduction did not deduce a value for every /// expansion of an expanded template parameter pack. TDK_IncompletePack, /// Template argument deduction produced inconsistent /// deduced values for the given template parameter. TDK_Inconsistent, /// Template argument deduction failed due to inconsistent /// cv-qualifiers on a template parameter type that would /// otherwise be deduced, e.g., we tried to deduce T in "const T" /// but were given a non-const "X". TDK_Underqualified, /// Substitution of the deduced template argument values /// resulted in an error. TDK_SubstitutionFailure, /// After substituting deduced template arguments, a dependent /// parameter type did not match the corresponding argument. TDK_DeducedMismatch, /// After substituting deduced template arguments, an element of /// a dependent parameter type did not match the corresponding element /// of the corresponding argument (when deducing from an initializer list). TDK_DeducedMismatchNested, /// A non-depnedent component of the parameter did not match the /// corresponding component of the argument. TDK_NonDeducedMismatch, /// When performing template argument deduction for a function /// template, there were too many call arguments. TDK_TooManyArguments, /// When performing template argument deduction for a function /// template, there were too few call arguments. TDK_TooFewArguments, /// The explicitly-specified template arguments were not valid /// template arguments for the given template. TDK_InvalidExplicitArguments, /// Checking non-dependent argument conversions failed. TDK_NonDependentConversionFailure, /// The deduced arguments did not satisfy the constraints associated /// with the template. TDK_ConstraintsNotSatisfied, /// Deduction failed; that's all we know. TDK_MiscellaneousDeductionFailure, /// CUDA Target attributes do not match. TDK_CUDATargetMismatch }; TemplateDeductionResult DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial, const TemplateArgumentList &TemplateArgs, sema::TemplateDeductionInfo &Info); TemplateDeductionResult DeduceTemplateArguments(VarTemplatePartialSpecializationDecl *Partial, const TemplateArgumentList &TemplateArgs, sema::TemplateDeductionInfo &Info); TemplateDeductionResult SubstituteExplicitTemplateArguments( FunctionTemplateDecl *FunctionTemplate, TemplateArgumentListInfo &ExplicitTemplateArgs, SmallVectorImpl &Deduced, SmallVectorImpl &ParamTypes, QualType *FunctionType, sema::TemplateDeductionInfo &Info); /// brief A function argument from which we performed template argument // deduction for a call. struct OriginalCallArg { OriginalCallArg(QualType OriginalParamType, bool DecomposedParam, unsigned ArgIdx, QualType OriginalArgType) : OriginalParamType(OriginalParamType), DecomposedParam(DecomposedParam), ArgIdx(ArgIdx), OriginalArgType(OriginalArgType) {} QualType OriginalParamType; bool DecomposedParam; unsigned ArgIdx; QualType OriginalArgType; }; TemplateDeductionResult FinishTemplateArgumentDeduction( FunctionTemplateDecl *FunctionTemplate, SmallVectorImpl &Deduced, unsigned NumExplicitlySpecified, FunctionDecl *&Specialization, sema::TemplateDeductionInfo &Info, SmallVectorImpl const *OriginalCallArgs = nullptr, bool PartialOverloading = false, llvm::function_ref CheckNonDependent = []{ return false; }); TemplateDeductionResult DeduceTemplateArguments( FunctionTemplateDecl *FunctionTemplate, TemplateArgumentListInfo *ExplicitTemplateArgs, ArrayRef Args, FunctionDecl *&Specialization, sema::TemplateDeductionInfo &Info, bool PartialOverloading, llvm::function_ref)> CheckNonDependent); TemplateDeductionResult DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, TemplateArgumentListInfo *ExplicitTemplateArgs, QualType ArgFunctionType, FunctionDecl *&Specialization, sema::TemplateDeductionInfo &Info, bool IsAddressOfFunction = false); TemplateDeductionResult DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, QualType ToType, CXXConversionDecl *&Specialization, sema::TemplateDeductionInfo &Info); TemplateDeductionResult DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, TemplateArgumentListInfo *ExplicitTemplateArgs, FunctionDecl *&Specialization, sema::TemplateDeductionInfo &Info, bool IsAddressOfFunction = false); /// Substitute Replacement for \p auto in \p TypeWithAuto QualType SubstAutoType(QualType TypeWithAuto, QualType Replacement); /// Substitute Replacement for auto in TypeWithAuto TypeSourceInfo* SubstAutoTypeSourceInfo(TypeSourceInfo *TypeWithAuto, QualType Replacement); /// Completely replace the \c auto in \p TypeWithAuto by /// \p Replacement. This does not retain any \c auto type sugar. QualType ReplaceAutoType(QualType TypeWithAuto, QualType Replacement); /// Result type of DeduceAutoType. enum DeduceAutoResult { DAR_Succeeded, DAR_Failed, DAR_FailedAlreadyDiagnosed }; DeduceAutoResult DeduceAutoType(TypeSourceInfo *AutoType, Expr *&Initializer, QualType &Result, Optional DependentDeductionDepth = None, bool IgnoreConstraints = false); DeduceAutoResult DeduceAutoType(TypeLoc AutoTypeLoc, Expr *&Initializer, QualType &Result, Optional DependentDeductionDepth = None, bool IgnoreConstraints = false); void DiagnoseAutoDeductionFailure(VarDecl *VDecl, Expr *Init); bool DeduceReturnType(FunctionDecl *FD, SourceLocation Loc, bool Diagnose = true); /// Declare implicit deduction guides for a class template if we've /// not already done so. void DeclareImplicitDeductionGuides(TemplateDecl *Template, SourceLocation Loc); QualType DeduceTemplateSpecializationFromInitializer( TypeSourceInfo *TInfo, const InitializedEntity &Entity, const InitializationKind &Kind, MultiExprArg Init); QualType deduceVarTypeFromInitializer(VarDecl *VDecl, DeclarationName Name, QualType Type, TypeSourceInfo *TSI, SourceRange Range, bool DirectInit, Expr *Init); TypeLoc getReturnTypeLoc(FunctionDecl *FD) const; bool DeduceFunctionTypeFromReturnExpr(FunctionDecl *FD, SourceLocation ReturnLoc, Expr *&RetExpr, AutoType *AT); FunctionTemplateDecl *getMoreSpecializedTemplate(FunctionTemplateDecl *FT1, FunctionTemplateDecl *FT2, SourceLocation Loc, TemplatePartialOrderingContext TPOC, unsigned NumCallArguments1, unsigned NumCallArguments2); UnresolvedSetIterator getMostSpecialized(UnresolvedSetIterator SBegin, UnresolvedSetIterator SEnd, TemplateSpecCandidateSet &FailedCandidates, SourceLocation Loc, const PartialDiagnostic &NoneDiag, const PartialDiagnostic &AmbigDiag, const PartialDiagnostic &CandidateDiag, bool Complain = true, QualType TargetType = QualType()); ClassTemplatePartialSpecializationDecl * getMoreSpecializedPartialSpecialization( ClassTemplatePartialSpecializationDecl *PS1, ClassTemplatePartialSpecializationDecl *PS2, SourceLocation Loc); bool isMoreSpecializedThanPrimary(ClassTemplatePartialSpecializationDecl *T, sema::TemplateDeductionInfo &Info); VarTemplatePartialSpecializationDecl *getMoreSpecializedPartialSpecialization( VarTemplatePartialSpecializationDecl *PS1, VarTemplatePartialSpecializationDecl *PS2, SourceLocation Loc); bool isMoreSpecializedThanPrimary(VarTemplatePartialSpecializationDecl *T, sema::TemplateDeductionInfo &Info); bool isTemplateTemplateParameterAtLeastAsSpecializedAs( TemplateParameterList *PParam, TemplateDecl *AArg, SourceLocation Loc); void MarkUsedTemplateParameters(const Expr *E, bool OnlyDeduced, unsigned Depth, llvm::SmallBitVector &Used); void MarkUsedTemplateParameters(const TemplateArgumentList &TemplateArgs, bool OnlyDeduced, unsigned Depth, llvm::SmallBitVector &Used); void MarkDeducedTemplateParameters( const FunctionTemplateDecl *FunctionTemplate, llvm::SmallBitVector &Deduced) { return MarkDeducedTemplateParameters(Context, FunctionTemplate, Deduced); } static void MarkDeducedTemplateParameters(ASTContext &Ctx, const FunctionTemplateDecl *FunctionTemplate, llvm::SmallBitVector &Deduced); //===--------------------------------------------------------------------===// // C++ Template Instantiation // MultiLevelTemplateArgumentList getTemplateInstantiationArgs(NamedDecl *D, const TemplateArgumentList *Innermost = nullptr, bool RelativeToPrimary = false, const FunctionDecl *Pattern = nullptr); /// A context in which code is being synthesized (where a source location /// alone is not sufficient to identify the context). This covers template /// instantiation and various forms of implicitly-generated functions. struct CodeSynthesisContext { /// The kind of template instantiation we are performing enum SynthesisKind { /// We are instantiating a template declaration. The entity is /// the declaration we're instantiating (e.g., a CXXRecordDecl). TemplateInstantiation, /// We are instantiating a default argument for a template /// parameter. The Entity is the template parameter whose argument is /// being instantiated, the Template is the template, and the /// TemplateArgs/NumTemplateArguments provide the template arguments as /// specified. DefaultTemplateArgumentInstantiation, /// We are instantiating a default argument for a function. /// The Entity is the ParmVarDecl, and TemplateArgs/NumTemplateArgs /// provides the template arguments as specified. DefaultFunctionArgumentInstantiation, /// We are substituting explicit template arguments provided for /// a function template. The entity is a FunctionTemplateDecl. ExplicitTemplateArgumentSubstitution, /// We are substituting template argument determined as part of /// template argument deduction for either a class template /// partial specialization or a function template. The /// Entity is either a {Class|Var}TemplatePartialSpecializationDecl or /// a TemplateDecl. DeducedTemplateArgumentSubstitution, /// We are substituting prior template arguments into a new /// template parameter. The template parameter itself is either a /// NonTypeTemplateParmDecl or a TemplateTemplateParmDecl. PriorTemplateArgumentSubstitution, /// We are checking the validity of a default template argument that /// has been used when naming a template-id. DefaultTemplateArgumentChecking, /// We are computing the exception specification for a defaulted special /// member function. ExceptionSpecEvaluation, /// We are instantiating the exception specification for a function /// template which was deferred until it was needed. ExceptionSpecInstantiation, /// We are instantiating a requirement of a requires expression. RequirementInstantiation, /// We are checking the satisfaction of a nested requirement of a requires /// expression. NestedRequirementConstraintsCheck, /// We are declaring an implicit special member function. DeclaringSpecialMember, /// We are declaring an implicit 'operator==' for a defaulted /// 'operator<=>'. DeclaringImplicitEqualityComparison, /// We are defining a synthesized function (such as a defaulted special /// member). DefiningSynthesizedFunction, // We are checking the constraints associated with a constrained entity or // the constraint expression of a concept. This includes the checks that // atomic constraints have the type 'bool' and that they can be constant // evaluated. ConstraintsCheck, // We are substituting template arguments into a constraint expression. ConstraintSubstitution, // We are normalizing a constraint expression. ConstraintNormalization, // We are substituting into the parameter mapping of an atomic constraint // during normalization. ParameterMappingSubstitution, /// We are rewriting a comparison operator in terms of an operator<=>. RewritingOperatorAsSpaceship, /// Added for Template instantiation observation. /// Memoization means we are _not_ instantiating a template because /// it is already instantiated (but we entered a context where we /// would have had to if it was not already instantiated). Memoization } Kind; /// Was the enclosing context a non-instantiation SFINAE context? bool SavedInNonInstantiationSFINAEContext; /// The point of instantiation or synthesis within the source code. SourceLocation PointOfInstantiation; /// The entity that is being synthesized. Decl *Entity; /// The template (or partial specialization) in which we are /// performing the instantiation, for substitutions of prior template /// arguments. NamedDecl *Template; /// The list of template arguments we are substituting, if they /// are not part of the entity. const TemplateArgument *TemplateArgs; // FIXME: Wrap this union around more members, or perhaps store the // kind-specific members in the RAII object owning the context. union { /// The number of template arguments in TemplateArgs. unsigned NumTemplateArgs; /// The special member being declared or defined. CXXSpecialMember SpecialMember; }; ArrayRef template_arguments() const { assert(Kind != DeclaringSpecialMember); return {TemplateArgs, NumTemplateArgs}; } /// The template deduction info object associated with the /// substitution or checking of explicit or deduced template arguments. sema::TemplateDeductionInfo *DeductionInfo; /// The source range that covers the construct that cause /// the instantiation, e.g., the template-id that causes a class /// template instantiation. SourceRange InstantiationRange; CodeSynthesisContext() : Kind(TemplateInstantiation), SavedInNonInstantiationSFINAEContext(false), Entity(nullptr), Template(nullptr), TemplateArgs(nullptr), NumTemplateArgs(0), DeductionInfo(nullptr) {} /// Determines whether this template is an actual instantiation /// that should be counted toward the maximum instantiation depth. bool isInstantiationRecord() const; }; /// List of active code synthesis contexts. /// /// This vector is treated as a stack. As synthesis of one entity requires /// synthesis of another, additional contexts are pushed onto the stack. SmallVector CodeSynthesisContexts; /// Specializations whose definitions are currently being instantiated. llvm::DenseSet> InstantiatingSpecializations; /// Non-dependent types used in templates that have already been instantiated /// by some template instantiation. llvm::DenseSet InstantiatedNonDependentTypes; /// Extra modules inspected when performing a lookup during a template /// instantiation. Computed lazily. SmallVector CodeSynthesisContextLookupModules; /// Cache of additional modules that should be used for name lookup /// within the current template instantiation. Computed lazily; use /// getLookupModules() to get a complete set. llvm::DenseSet LookupModulesCache; /// Get the set of additional modules that should be checked during /// name lookup. A module and its imports become visible when instanting a /// template defined within it. llvm::DenseSet &getLookupModules(); /// Map from the most recent declaration of a namespace to the most /// recent visible declaration of that namespace. llvm::DenseMap VisibleNamespaceCache; /// Whether we are in a SFINAE context that is not associated with /// template instantiation. /// /// This is used when setting up a SFINAE trap (\c see SFINAETrap) outside /// of a template instantiation or template argument deduction. bool InNonInstantiationSFINAEContext; /// The number of \p CodeSynthesisContexts that are not template /// instantiations and, therefore, should not be counted as part of the /// instantiation depth. /// /// When the instantiation depth reaches the user-configurable limit /// \p LangOptions::InstantiationDepth we will abort instantiation. // FIXME: Should we have a similar limit for other forms of synthesis? unsigned NonInstantiationEntries; /// The depth of the context stack at the point when the most recent /// error or warning was produced. /// /// This value is used to suppress printing of redundant context stacks /// when there are multiple errors or warnings in the same instantiation. // FIXME: Does this belong in Sema? It's tough to implement it anywhere else. unsigned LastEmittedCodeSynthesisContextDepth = 0; /// The template instantiation callbacks to trace or track /// instantiations (objects can be chained). /// /// This callbacks is used to print, trace or track template /// instantiations as they are being constructed. std::vector> TemplateInstCallbacks; /// The current index into pack expansion arguments that will be /// used for substitution of parameter packs. /// /// The pack expansion index will be -1 to indicate that parameter packs /// should be instantiated as themselves. Otherwise, the index specifies /// which argument within the parameter pack will be used for substitution. int ArgumentPackSubstitutionIndex; /// RAII object used to change the argument pack substitution index /// within a \c Sema object. /// /// See \c ArgumentPackSubstitutionIndex for more information. class ArgumentPackSubstitutionIndexRAII { Sema &Self; int OldSubstitutionIndex; public: ArgumentPackSubstitutionIndexRAII(Sema &Self, int NewSubstitutionIndex) : Self(Self), OldSubstitutionIndex(Self.ArgumentPackSubstitutionIndex) { Self.ArgumentPackSubstitutionIndex = NewSubstitutionIndex; } ~ArgumentPackSubstitutionIndexRAII() { Self.ArgumentPackSubstitutionIndex = OldSubstitutionIndex; } }; friend class ArgumentPackSubstitutionRAII; /// For each declaration that involved template argument deduction, the /// set of diagnostics that were suppressed during that template argument /// deduction. /// /// FIXME: Serialize this structure to the AST file. typedef llvm::DenseMap > SuppressedDiagnosticsMap; SuppressedDiagnosticsMap SuppressedDiagnostics; /// A stack object to be created when performing template /// instantiation. /// /// Construction of an object of type \c InstantiatingTemplate /// pushes the current instantiation onto the stack of active /// instantiations. If the size of this stack exceeds the maximum /// number of recursive template instantiations, construction /// produces an error and evaluates true. /// /// Destruction of this object will pop the named instantiation off /// the stack. struct InstantiatingTemplate { /// Note that we are instantiating a class template, /// function template, variable template, alias template, /// or a member thereof. InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, Decl *Entity, SourceRange InstantiationRange = SourceRange()); struct ExceptionSpecification {}; /// Note that we are instantiating an exception specification /// of a function template. InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, FunctionDecl *Entity, ExceptionSpecification, SourceRange InstantiationRange = SourceRange()); /// Note that we are instantiating a default argument in a /// template-id. InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, TemplateParameter Param, TemplateDecl *Template, ArrayRef TemplateArgs, SourceRange InstantiationRange = SourceRange()); /// Note that we are substituting either explicitly-specified or /// deduced template arguments during function template argument deduction. InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, FunctionTemplateDecl *FunctionTemplate, ArrayRef TemplateArgs, CodeSynthesisContext::SynthesisKind Kind, sema::TemplateDeductionInfo &DeductionInfo, SourceRange InstantiationRange = SourceRange()); /// Note that we are instantiating as part of template /// argument deduction for a class template declaration. InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, TemplateDecl *Template, ArrayRef TemplateArgs, sema::TemplateDeductionInfo &DeductionInfo, SourceRange InstantiationRange = SourceRange()); /// Note that we are instantiating as part of template /// argument deduction for a class template partial /// specialization. InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, ClassTemplatePartialSpecializationDecl *PartialSpec, ArrayRef TemplateArgs, sema::TemplateDeductionInfo &DeductionInfo, SourceRange InstantiationRange = SourceRange()); /// Note that we are instantiating as part of template /// argument deduction for a variable template partial /// specialization. InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, VarTemplatePartialSpecializationDecl *PartialSpec, ArrayRef TemplateArgs, sema::TemplateDeductionInfo &DeductionInfo, SourceRange InstantiationRange = SourceRange()); /// Note that we are instantiating a default argument for a function /// parameter. InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, ParmVarDecl *Param, ArrayRef TemplateArgs, SourceRange InstantiationRange = SourceRange()); /// Note that we are substituting prior template arguments into a /// non-type parameter. InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, NamedDecl *Template, NonTypeTemplateParmDecl *Param, ArrayRef TemplateArgs, SourceRange InstantiationRange); /// Note that we are substituting prior template arguments into a /// template template parameter. InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, NamedDecl *Template, TemplateTemplateParmDecl *Param, ArrayRef TemplateArgs, SourceRange InstantiationRange); /// Note that we are checking the default template argument /// against the template parameter for a given template-id. InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, TemplateDecl *Template, NamedDecl *Param, ArrayRef TemplateArgs, SourceRange InstantiationRange); struct ConstraintsCheck {}; /// \brief Note that we are checking the constraints associated with some /// constrained entity (a concept declaration or a template with associated /// constraints). InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, ConstraintsCheck, NamedDecl *Template, ArrayRef TemplateArgs, SourceRange InstantiationRange); struct ConstraintSubstitution {}; /// \brief Note that we are checking a constraint expression associated /// with a template declaration or as part of the satisfaction check of a /// concept. InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, ConstraintSubstitution, NamedDecl *Template, sema::TemplateDeductionInfo &DeductionInfo, SourceRange InstantiationRange); struct ConstraintNormalization {}; /// \brief Note that we are normalizing a constraint expression. InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, ConstraintNormalization, NamedDecl *Template, SourceRange InstantiationRange); struct ParameterMappingSubstitution {}; /// \brief Note that we are subtituting into the parameter mapping of an /// atomic constraint during constraint normalization. InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, ParameterMappingSubstitution, NamedDecl *Template, SourceRange InstantiationRange); /// \brief Note that we are substituting template arguments into a part of /// a requirement of a requires expression. InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, concepts::Requirement *Req, sema::TemplateDeductionInfo &DeductionInfo, SourceRange InstantiationRange = SourceRange()); /// \brief Note that we are checking the satisfaction of the constraint /// expression inside of a nested requirement. InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, concepts::NestedRequirement *Req, ConstraintsCheck, SourceRange InstantiationRange = SourceRange()); /// Note that we have finished instantiating this template. void Clear(); ~InstantiatingTemplate() { Clear(); } /// Determines whether we have exceeded the maximum /// recursive template instantiations. bool isInvalid() const { return Invalid; } /// Determine whether we are already instantiating this /// specialization in some surrounding active instantiation. bool isAlreadyInstantiating() const { return AlreadyInstantiating; } private: Sema &SemaRef; bool Invalid; bool AlreadyInstantiating; bool CheckInstantiationDepth(SourceLocation PointOfInstantiation, SourceRange InstantiationRange); InstantiatingTemplate( Sema &SemaRef, CodeSynthesisContext::SynthesisKind Kind, SourceLocation PointOfInstantiation, SourceRange InstantiationRange, Decl *Entity, NamedDecl *Template = nullptr, ArrayRef TemplateArgs = None, sema::TemplateDeductionInfo *DeductionInfo = nullptr); InstantiatingTemplate(const InstantiatingTemplate&) = delete; InstantiatingTemplate& operator=(const InstantiatingTemplate&) = delete; }; void pushCodeSynthesisContext(CodeSynthesisContext Ctx); void popCodeSynthesisContext(); /// Determine whether we are currently performing template instantiation. bool inTemplateInstantiation() const { return CodeSynthesisContexts.size() > NonInstantiationEntries; } void PrintContextStack() { if (!CodeSynthesisContexts.empty() && CodeSynthesisContexts.size() != LastEmittedCodeSynthesisContextDepth) { PrintInstantiationStack(); LastEmittedCodeSynthesisContextDepth = CodeSynthesisContexts.size(); } if (PragmaAttributeCurrentTargetDecl) PrintPragmaAttributeInstantiationPoint(); } void PrintInstantiationStack(); void PrintPragmaAttributeInstantiationPoint(); /// Determines whether we are currently in a context where /// template argument substitution failures are not considered /// errors. /// /// \returns An empty \c Optional if we're not in a SFINAE context. /// Otherwise, contains a pointer that, if non-NULL, contains the nearest /// template-deduction context object, which can be used to capture /// diagnostics that will be suppressed. Optional isSFINAEContext() const; /// Determines whether we are currently in a context that /// is not evaluated as per C++ [expr] p5. bool isUnevaluatedContext() const { assert(!ExprEvalContexts.empty() && "Must be in an expression evaluation context"); return ExprEvalContexts.back().isUnevaluated(); } /// RAII class used to determine whether SFINAE has /// trapped any errors that occur during template argument /// deduction. class SFINAETrap { Sema &SemaRef; unsigned PrevSFINAEErrors; bool PrevInNonInstantiationSFINAEContext; bool PrevAccessCheckingSFINAE; bool PrevLastDiagnosticIgnored; public: explicit SFINAETrap(Sema &SemaRef, bool AccessCheckingSFINAE = false) : SemaRef(SemaRef), PrevSFINAEErrors(SemaRef.NumSFINAEErrors), PrevInNonInstantiationSFINAEContext( SemaRef.InNonInstantiationSFINAEContext), PrevAccessCheckingSFINAE(SemaRef.AccessCheckingSFINAE), PrevLastDiagnosticIgnored( SemaRef.getDiagnostics().isLastDiagnosticIgnored()) { if (!SemaRef.isSFINAEContext()) SemaRef.InNonInstantiationSFINAEContext = true; SemaRef.AccessCheckingSFINAE = AccessCheckingSFINAE; } ~SFINAETrap() { SemaRef.NumSFINAEErrors = PrevSFINAEErrors; SemaRef.InNonInstantiationSFINAEContext = PrevInNonInstantiationSFINAEContext; SemaRef.AccessCheckingSFINAE = PrevAccessCheckingSFINAE; SemaRef.getDiagnostics().setLastDiagnosticIgnored( PrevLastDiagnosticIgnored); } /// Determine whether any SFINAE errors have been trapped. bool hasErrorOccurred() const { return SemaRef.NumSFINAEErrors > PrevSFINAEErrors; } }; /// RAII class used to indicate that we are performing provisional /// semantic analysis to determine the validity of a construct, so /// typo-correction and diagnostics in the immediate context (not within /// implicitly-instantiated templates) should be suppressed. class TentativeAnalysisScope { Sema &SemaRef; // FIXME: Using a SFINAETrap for this is a hack. SFINAETrap Trap; bool PrevDisableTypoCorrection; public: explicit TentativeAnalysisScope(Sema &SemaRef) : SemaRef(SemaRef), Trap(SemaRef, true), PrevDisableTypoCorrection(SemaRef.DisableTypoCorrection) { SemaRef.DisableTypoCorrection = true; } ~TentativeAnalysisScope() { SemaRef.DisableTypoCorrection = PrevDisableTypoCorrection; } }; /// The current instantiation scope used to store local /// variables. LocalInstantiationScope *CurrentInstantiationScope; /// Tracks whether we are in a context where typo correction is /// disabled. bool DisableTypoCorrection; /// The number of typos corrected by CorrectTypo. unsigned TyposCorrected; typedef llvm::SmallSet SrcLocSet; typedef llvm::DenseMap IdentifierSourceLocations; /// A cache containing identifiers for which typo correction failed and /// their locations, so that repeated attempts to correct an identifier in a /// given location are ignored if typo correction already failed for it. IdentifierSourceLocations TypoCorrectionFailures; /// Worker object for performing CFG-based warnings. sema::AnalysisBasedWarnings AnalysisWarnings; threadSafety::BeforeSet *ThreadSafetyDeclCache; /// An entity for which implicit template instantiation is required. /// /// The source location associated with the declaration is the first place in /// the source code where the declaration was "used". It is not necessarily /// the point of instantiation (which will be either before or after the /// namespace-scope declaration that triggered this implicit instantiation), /// However, it is the location that diagnostics should generally refer to, /// because users will need to know what code triggered the instantiation. typedef std::pair PendingImplicitInstantiation; /// The queue of implicit template instantiations that are required /// but have not yet been performed. std::deque PendingInstantiations; /// Queue of implicit template instantiations that cannot be performed /// eagerly. SmallVector LateParsedInstantiations; class GlobalEagerInstantiationScope { public: GlobalEagerInstantiationScope(Sema &S, bool Enabled) : S(S), Enabled(Enabled) { if (!Enabled) return; SavedPendingInstantiations.swap(S.PendingInstantiations); SavedVTableUses.swap(S.VTableUses); } void perform() { if (Enabled) { S.DefineUsedVTables(); S.PerformPendingInstantiations(); } } ~GlobalEagerInstantiationScope() { if (!Enabled) return; // Restore the set of pending vtables. assert(S.VTableUses.empty() && "VTableUses should be empty before it is discarded."); S.VTableUses.swap(SavedVTableUses); // Restore the set of pending implicit instantiations. assert(S.PendingInstantiations.empty() && "PendingInstantiations should be empty before it is discarded."); S.PendingInstantiations.swap(SavedPendingInstantiations); } private: Sema &S; SmallVector SavedVTableUses; std::deque SavedPendingInstantiations; bool Enabled; }; /// The queue of implicit template instantiations that are required /// and must be performed within the current local scope. /// /// This queue is only used for member functions of local classes in /// templates, which must be instantiated in the same scope as their /// enclosing function, so that they can reference function-local /// types, static variables, enumerators, etc. std::deque PendingLocalImplicitInstantiations; class LocalEagerInstantiationScope { public: LocalEagerInstantiationScope(Sema &S) : S(S) { SavedPendingLocalImplicitInstantiations.swap( S.PendingLocalImplicitInstantiations); } void perform() { S.PerformPendingInstantiations(/*LocalOnly=*/true); } ~LocalEagerInstantiationScope() { assert(S.PendingLocalImplicitInstantiations.empty() && "there shouldn't be any pending local implicit instantiations"); SavedPendingLocalImplicitInstantiations.swap( S.PendingLocalImplicitInstantiations); } private: Sema &S; std::deque SavedPendingLocalImplicitInstantiations; }; /// A helper class for building up ExtParameterInfos. class ExtParameterInfoBuilder { SmallVector Infos; bool HasInteresting = false; public: /// Set the ExtParameterInfo for the parameter at the given index, /// void set(unsigned index, FunctionProtoType::ExtParameterInfo info) { assert(Infos.size() <= index); Infos.resize(index); Infos.push_back(info); if (!HasInteresting) HasInteresting = (info != FunctionProtoType::ExtParameterInfo()); } /// Return a pointer (suitable for setting in an ExtProtoInfo) to the /// ExtParameterInfo array we've built up. const FunctionProtoType::ExtParameterInfo * getPointerOrNull(unsigned numParams) { if (!HasInteresting) return nullptr; Infos.resize(numParams); return Infos.data(); } }; void PerformPendingInstantiations(bool LocalOnly = false); TypeSourceInfo *SubstType(TypeSourceInfo *T, const MultiLevelTemplateArgumentList &TemplateArgs, SourceLocation Loc, DeclarationName Entity, bool AllowDeducedTST = false); QualType SubstType(QualType T, const MultiLevelTemplateArgumentList &TemplateArgs, SourceLocation Loc, DeclarationName Entity); TypeSourceInfo *SubstType(TypeLoc TL, const MultiLevelTemplateArgumentList &TemplateArgs, SourceLocation Loc, DeclarationName Entity); TypeSourceInfo *SubstFunctionDeclType(TypeSourceInfo *T, const MultiLevelTemplateArgumentList &TemplateArgs, SourceLocation Loc, DeclarationName Entity, CXXRecordDecl *ThisContext, Qualifiers ThisTypeQuals); void SubstExceptionSpec(FunctionDecl *New, const FunctionProtoType *Proto, const MultiLevelTemplateArgumentList &Args); bool SubstExceptionSpec(SourceLocation Loc, FunctionProtoType::ExceptionSpecInfo &ESI, SmallVectorImpl &ExceptionStorage, const MultiLevelTemplateArgumentList &Args); ParmVarDecl *SubstParmVarDecl(ParmVarDecl *D, const MultiLevelTemplateArgumentList &TemplateArgs, int indexAdjustment, Optional NumExpansions, bool ExpectParameterPack); bool SubstParmTypes(SourceLocation Loc, ArrayRef Params, const FunctionProtoType::ExtParameterInfo *ExtParamInfos, const MultiLevelTemplateArgumentList &TemplateArgs, SmallVectorImpl &ParamTypes, SmallVectorImpl *OutParams, ExtParameterInfoBuilder &ParamInfos); ExprResult SubstExpr(Expr *E, const MultiLevelTemplateArgumentList &TemplateArgs); /// Substitute the given template arguments into a list of /// expressions, expanding pack expansions if required. /// /// \param Exprs The list of expressions to substitute into. /// /// \param IsCall Whether this is some form of call, in which case /// default arguments will be dropped. /// /// \param TemplateArgs The set of template arguments to substitute. /// /// \param Outputs Will receive all of the substituted arguments. /// /// \returns true if an error occurred, false otherwise. bool SubstExprs(ArrayRef Exprs, bool IsCall, const MultiLevelTemplateArgumentList &TemplateArgs, SmallVectorImpl &Outputs); StmtResult SubstStmt(Stmt *S, const MultiLevelTemplateArgumentList &TemplateArgs); TemplateParameterList * SubstTemplateParams(TemplateParameterList *Params, DeclContext *Owner, const MultiLevelTemplateArgumentList &TemplateArgs); bool SubstTemplateArguments(ArrayRef Args, const MultiLevelTemplateArgumentList &TemplateArgs, TemplateArgumentListInfo &Outputs); Decl *SubstDecl(Decl *D, DeclContext *Owner, const MultiLevelTemplateArgumentList &TemplateArgs); /// Substitute the name and return type of a defaulted 'operator<=>' to form /// an implicit 'operator=='. FunctionDecl *SubstSpaceshipAsEqualEqual(CXXRecordDecl *RD, FunctionDecl *Spaceship); ExprResult SubstInitializer(Expr *E, const MultiLevelTemplateArgumentList &TemplateArgs, bool CXXDirectInit); bool SubstBaseSpecifiers(CXXRecordDecl *Instantiation, CXXRecordDecl *Pattern, const MultiLevelTemplateArgumentList &TemplateArgs); bool InstantiateClass(SourceLocation PointOfInstantiation, CXXRecordDecl *Instantiation, CXXRecordDecl *Pattern, const MultiLevelTemplateArgumentList &TemplateArgs, TemplateSpecializationKind TSK, bool Complain = true); bool InstantiateEnum(SourceLocation PointOfInstantiation, EnumDecl *Instantiation, EnumDecl *Pattern, const MultiLevelTemplateArgumentList &TemplateArgs, TemplateSpecializationKind TSK); bool InstantiateInClassInitializer( SourceLocation PointOfInstantiation, FieldDecl *Instantiation, FieldDecl *Pattern, const MultiLevelTemplateArgumentList &TemplateArgs); struct LateInstantiatedAttribute { const Attr *TmplAttr; LocalInstantiationScope *Scope; Decl *NewDecl; LateInstantiatedAttribute(const Attr *A, LocalInstantiationScope *S, Decl *D) : TmplAttr(A), Scope(S), NewDecl(D) { } }; typedef SmallVector LateInstantiatedAttrVec; void InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs, const Decl *Pattern, Decl *Inst, LateInstantiatedAttrVec *LateAttrs = nullptr, LocalInstantiationScope *OuterMostScope = nullptr); void InstantiateAttrsForDecl(const MultiLevelTemplateArgumentList &TemplateArgs, const Decl *Pattern, Decl *Inst, LateInstantiatedAttrVec *LateAttrs = nullptr, LocalInstantiationScope *OuterMostScope = nullptr); bool usesPartialOrExplicitSpecialization( SourceLocation Loc, ClassTemplateSpecializationDecl *ClassTemplateSpec); bool InstantiateClassTemplateSpecialization(SourceLocation PointOfInstantiation, ClassTemplateSpecializationDecl *ClassTemplateSpec, TemplateSpecializationKind TSK, bool Complain = true); void InstantiateClassMembers(SourceLocation PointOfInstantiation, CXXRecordDecl *Instantiation, const MultiLevelTemplateArgumentList &TemplateArgs, TemplateSpecializationKind TSK); void InstantiateClassTemplateSpecializationMembers( SourceLocation PointOfInstantiation, ClassTemplateSpecializationDecl *ClassTemplateSpec, TemplateSpecializationKind TSK); NestedNameSpecifierLoc SubstNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS, const MultiLevelTemplateArgumentList &TemplateArgs); DeclarationNameInfo SubstDeclarationNameInfo(const DeclarationNameInfo &NameInfo, const MultiLevelTemplateArgumentList &TemplateArgs); TemplateName SubstTemplateName(NestedNameSpecifierLoc QualifierLoc, TemplateName Name, SourceLocation Loc, const MultiLevelTemplateArgumentList &TemplateArgs); bool Subst(const TemplateArgumentLoc *Args, unsigned NumArgs, TemplateArgumentListInfo &Result, const MultiLevelTemplateArgumentList &TemplateArgs); void InstantiateExceptionSpec(SourceLocation PointOfInstantiation, FunctionDecl *Function); bool CheckInstantiatedFunctionTemplateConstraints( SourceLocation PointOfInstantiation, FunctionDecl *Decl, ArrayRef TemplateArgs, ConstraintSatisfaction &Satisfaction); FunctionDecl *InstantiateFunctionDeclaration(FunctionTemplateDecl *FTD, const TemplateArgumentList *Args, SourceLocation Loc); void InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, FunctionDecl *Function, bool Recursive = false, bool DefinitionRequired = false, bool AtEndOfTU = false); VarTemplateSpecializationDecl *BuildVarTemplateInstantiation( VarTemplateDecl *VarTemplate, VarDecl *FromVar, const TemplateArgumentList &TemplateArgList, const TemplateArgumentListInfo &TemplateArgsInfo, SmallVectorImpl &Converted, SourceLocation PointOfInstantiation, void *InsertPos, LateInstantiatedAttrVec *LateAttrs = nullptr, LocalInstantiationScope *StartingScope = nullptr); VarTemplateSpecializationDecl *CompleteVarTemplateSpecializationDecl( VarTemplateSpecializationDecl *VarSpec, VarDecl *PatternDecl, const MultiLevelTemplateArgumentList &TemplateArgs); void BuildVariableInstantiation(VarDecl *NewVar, VarDecl *OldVar, const MultiLevelTemplateArgumentList &TemplateArgs, LateInstantiatedAttrVec *LateAttrs, DeclContext *Owner, LocalInstantiationScope *StartingScope, bool InstantiatingVarTemplate = false, VarTemplateSpecializationDecl *PrevVTSD = nullptr); VarDecl *getVarTemplateSpecialization( VarTemplateDecl *VarTempl, const TemplateArgumentListInfo *TemplateArgs, const DeclarationNameInfo &MemberNameInfo, SourceLocation TemplateKWLoc); void InstantiateVariableInitializer( VarDecl *Var, VarDecl *OldVar, const MultiLevelTemplateArgumentList &TemplateArgs); void InstantiateVariableDefinition(SourceLocation PointOfInstantiation, VarDecl *Var, bool Recursive = false, bool DefinitionRequired = false, bool AtEndOfTU = false); void InstantiateMemInitializers(CXXConstructorDecl *New, const CXXConstructorDecl *Tmpl, const MultiLevelTemplateArgumentList &TemplateArgs); NamedDecl *FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D, const MultiLevelTemplateArgumentList &TemplateArgs, bool FindingInstantiatedContext = false); DeclContext *FindInstantiatedContext(SourceLocation Loc, DeclContext *DC, const MultiLevelTemplateArgumentList &TemplateArgs); // Objective-C declarations. enum ObjCContainerKind { OCK_None = -1, OCK_Interface = 0, OCK_Protocol, OCK_Category, OCK_ClassExtension, OCK_Implementation, OCK_CategoryImplementation }; ObjCContainerKind getObjCContainerKind() const; DeclResult actOnObjCTypeParam(Scope *S, ObjCTypeParamVariance variance, SourceLocation varianceLoc, unsigned index, IdentifierInfo *paramName, SourceLocation paramLoc, SourceLocation colonLoc, ParsedType typeBound); ObjCTypeParamList *actOnObjCTypeParamList(Scope *S, SourceLocation lAngleLoc, ArrayRef typeParams, SourceLocation rAngleLoc); void popObjCTypeParamList(Scope *S, ObjCTypeParamList *typeParamList); Decl *ActOnStartClassInterface( Scope *S, SourceLocation AtInterfaceLoc, IdentifierInfo *ClassName, SourceLocation ClassLoc, ObjCTypeParamList *typeParamList, IdentifierInfo *SuperName, SourceLocation SuperLoc, ArrayRef SuperTypeArgs, SourceRange SuperTypeArgsRange, Decl *const *ProtoRefs, unsigned NumProtoRefs, const SourceLocation *ProtoLocs, SourceLocation EndProtoLoc, const ParsedAttributesView &AttrList); void ActOnSuperClassOfClassInterface(Scope *S, SourceLocation AtInterfaceLoc, ObjCInterfaceDecl *IDecl, IdentifierInfo *ClassName, SourceLocation ClassLoc, IdentifierInfo *SuperName, SourceLocation SuperLoc, ArrayRef SuperTypeArgs, SourceRange SuperTypeArgsRange); void ActOnTypedefedProtocols(SmallVectorImpl &ProtocolRefs, SmallVectorImpl &ProtocolLocs, IdentifierInfo *SuperName, SourceLocation SuperLoc); Decl *ActOnCompatibilityAlias( SourceLocation AtCompatibilityAliasLoc, IdentifierInfo *AliasName, SourceLocation AliasLocation, IdentifierInfo *ClassName, SourceLocation ClassLocation); bool CheckForwardProtocolDeclarationForCircularDependency( IdentifierInfo *PName, SourceLocation &PLoc, SourceLocation PrevLoc, const ObjCList &PList); Decl *ActOnStartProtocolInterface( SourceLocation AtProtoInterfaceLoc, IdentifierInfo *ProtocolName, SourceLocation ProtocolLoc, Decl *const *ProtoRefNames, unsigned NumProtoRefs, const SourceLocation *ProtoLocs, SourceLocation EndProtoLoc, const ParsedAttributesView &AttrList); Decl *ActOnStartCategoryInterface( SourceLocation AtInterfaceLoc, IdentifierInfo *ClassName, SourceLocation ClassLoc, ObjCTypeParamList *typeParamList, IdentifierInfo *CategoryName, SourceLocation CategoryLoc, Decl *const *ProtoRefs, unsigned NumProtoRefs, const SourceLocation *ProtoLocs, SourceLocation EndProtoLoc, const ParsedAttributesView &AttrList); Decl *ActOnStartClassImplementation(SourceLocation AtClassImplLoc, IdentifierInfo *ClassName, SourceLocation ClassLoc, IdentifierInfo *SuperClassname, SourceLocation SuperClassLoc, const ParsedAttributesView &AttrList); Decl *ActOnStartCategoryImplementation(SourceLocation AtCatImplLoc, IdentifierInfo *ClassName, SourceLocation ClassLoc, IdentifierInfo *CatName, SourceLocation CatLoc, const ParsedAttributesView &AttrList); DeclGroupPtrTy ActOnFinishObjCImplementation(Decl *ObjCImpDecl, ArrayRef Decls); DeclGroupPtrTy ActOnForwardClassDeclaration(SourceLocation Loc, IdentifierInfo **IdentList, SourceLocation *IdentLocs, ArrayRef TypeParamLists, unsigned NumElts); DeclGroupPtrTy ActOnForwardProtocolDeclaration(SourceLocation AtProtoclLoc, ArrayRef IdentList, const ParsedAttributesView &attrList); void FindProtocolDeclaration(bool WarnOnDeclarations, bool ForObjCContainer, ArrayRef ProtocolId, SmallVectorImpl &Protocols); void DiagnoseTypeArgsAndProtocols(IdentifierInfo *ProtocolId, SourceLocation ProtocolLoc, IdentifierInfo *TypeArgId, SourceLocation TypeArgLoc, bool SelectProtocolFirst = false); /// Given a list of identifiers (and their locations), resolve the /// names to either Objective-C protocol qualifiers or type /// arguments, as appropriate. void actOnObjCTypeArgsOrProtocolQualifiers( Scope *S, ParsedType baseType, SourceLocation lAngleLoc, ArrayRef identifiers, ArrayRef identifierLocs, SourceLocation rAngleLoc, SourceLocation &typeArgsLAngleLoc, SmallVectorImpl &typeArgs, SourceLocation &typeArgsRAngleLoc, SourceLocation &protocolLAngleLoc, SmallVectorImpl &protocols, SourceLocation &protocolRAngleLoc, bool warnOnIncompleteProtocols); /// Build a an Objective-C protocol-qualified 'id' type where no /// base type was specified. TypeResult actOnObjCProtocolQualifierType( SourceLocation lAngleLoc, ArrayRef protocols, ArrayRef protocolLocs, SourceLocation rAngleLoc); /// Build a specialized and/or protocol-qualified Objective-C type. TypeResult actOnObjCTypeArgsAndProtocolQualifiers( Scope *S, SourceLocation Loc, ParsedType BaseType, SourceLocation TypeArgsLAngleLoc, ArrayRef TypeArgs, SourceLocation TypeArgsRAngleLoc, SourceLocation ProtocolLAngleLoc, ArrayRef Protocols, ArrayRef ProtocolLocs, SourceLocation ProtocolRAngleLoc); /// Build an Objective-C type parameter type. QualType BuildObjCTypeParamType(const ObjCTypeParamDecl *Decl, SourceLocation ProtocolLAngleLoc, ArrayRef Protocols, ArrayRef ProtocolLocs, SourceLocation ProtocolRAngleLoc, bool FailOnError = false); /// Build an Objective-C object pointer type. QualType BuildObjCObjectType(QualType BaseType, SourceLocation Loc, SourceLocation TypeArgsLAngleLoc, ArrayRef TypeArgs, SourceLocation TypeArgsRAngleLoc, SourceLocation ProtocolLAngleLoc, ArrayRef Protocols, ArrayRef ProtocolLocs, SourceLocation ProtocolRAngleLoc, bool FailOnError = false); /// Ensure attributes are consistent with type. /// \param [in, out] Attributes The attributes to check; they will /// be modified to be consistent with \p PropertyTy. void CheckObjCPropertyAttributes(Decl *PropertyPtrTy, SourceLocation Loc, unsigned &Attributes, bool propertyInPrimaryClass); /// Process the specified property declaration and create decls for the /// setters and getters as needed. /// \param property The property declaration being processed void ProcessPropertyDecl(ObjCPropertyDecl *property); void DiagnosePropertyMismatch(ObjCPropertyDecl *Property, ObjCPropertyDecl *SuperProperty, const IdentifierInfo *Name, bool OverridingProtocolProperty); void DiagnoseClassExtensionDupMethods(ObjCCategoryDecl *CAT, ObjCInterfaceDecl *ID); Decl *ActOnAtEnd(Scope *S, SourceRange AtEnd, ArrayRef allMethods = None, ArrayRef allTUVars = None); Decl *ActOnProperty(Scope *S, SourceLocation AtLoc, SourceLocation LParenLoc, FieldDeclarator &FD, ObjCDeclSpec &ODS, Selector GetterSel, Selector SetterSel, tok::ObjCKeywordKind MethodImplKind, DeclContext *lexicalDC = nullptr); Decl *ActOnPropertyImplDecl(Scope *S, SourceLocation AtLoc, SourceLocation PropertyLoc, bool ImplKind, IdentifierInfo *PropertyId, IdentifierInfo *PropertyIvar, SourceLocation PropertyIvarLoc, ObjCPropertyQueryKind QueryKind); enum ObjCSpecialMethodKind { OSMK_None, OSMK_Alloc, OSMK_New, OSMK_Copy, OSMK_RetainingInit, OSMK_NonRetainingInit }; struct ObjCArgInfo { IdentifierInfo *Name; SourceLocation NameLoc; // The Type is null if no type was specified, and the DeclSpec is invalid // in this case. ParsedType Type; ObjCDeclSpec DeclSpec; /// ArgAttrs - Attribute list for this argument. ParsedAttributesView ArgAttrs; }; Decl *ActOnMethodDeclaration( Scope *S, SourceLocation BeginLoc, // location of the + or -. SourceLocation EndLoc, // location of the ; or {. tok::TokenKind MethodType, ObjCDeclSpec &ReturnQT, ParsedType ReturnType, ArrayRef SelectorLocs, Selector Sel, // optional arguments. The number of types/arguments is obtained // from the Sel.getNumArgs(). ObjCArgInfo *ArgInfo, DeclaratorChunk::ParamInfo *CParamInfo, unsigned CNumArgs, // c-style args const ParsedAttributesView &AttrList, tok::ObjCKeywordKind MethodImplKind, bool isVariadic, bool MethodDefinition); ObjCMethodDecl *LookupMethodInQualifiedType(Selector Sel, const ObjCObjectPointerType *OPT, bool IsInstance); ObjCMethodDecl *LookupMethodInObjectType(Selector Sel, QualType Ty, bool IsInstance); bool CheckARCMethodDecl(ObjCMethodDecl *method); bool inferObjCARCLifetime(ValueDecl *decl); void deduceOpenCLAddressSpace(ValueDecl *decl); ExprResult HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT, Expr *BaseExpr, SourceLocation OpLoc, DeclarationName MemberName, SourceLocation MemberLoc, SourceLocation SuperLoc, QualType SuperType, bool Super); ExprResult ActOnClassPropertyRefExpr(IdentifierInfo &receiverName, IdentifierInfo &propertyName, SourceLocation receiverNameLoc, SourceLocation propertyNameLoc); ObjCMethodDecl *tryCaptureObjCSelf(SourceLocation Loc); /// Describes the kind of message expression indicated by a message /// send that starts with an identifier. enum ObjCMessageKind { /// The message is sent to 'super'. ObjCSuperMessage, /// The message is an instance message. ObjCInstanceMessage, /// The message is a class message, and the identifier is a type /// name. ObjCClassMessage }; ObjCMessageKind getObjCMessageKind(Scope *S, IdentifierInfo *Name, SourceLocation NameLoc, bool IsSuper, bool HasTrailingDot, ParsedType &ReceiverType); ExprResult ActOnSuperMessage(Scope *S, SourceLocation SuperLoc, Selector Sel, SourceLocation LBracLoc, ArrayRef SelectorLocs, SourceLocation RBracLoc, MultiExprArg Args); ExprResult BuildClassMessage(TypeSourceInfo *ReceiverTypeInfo, QualType ReceiverType, SourceLocation SuperLoc, Selector Sel, ObjCMethodDecl *Method, SourceLocation LBracLoc, ArrayRef SelectorLocs, SourceLocation RBracLoc, MultiExprArg Args, bool isImplicit = false); ExprResult BuildClassMessageImplicit(QualType ReceiverType, bool isSuperReceiver, SourceLocation Loc, Selector Sel, ObjCMethodDecl *Method, MultiExprArg Args); ExprResult ActOnClassMessage(Scope *S, ParsedType Receiver, Selector Sel, SourceLocation LBracLoc, ArrayRef SelectorLocs, SourceLocation RBracLoc, MultiExprArg Args); ExprResult BuildInstanceMessage(Expr *Receiver, QualType ReceiverType, SourceLocation SuperLoc, Selector Sel, ObjCMethodDecl *Method, SourceLocation LBracLoc, ArrayRef SelectorLocs, SourceLocation RBracLoc, MultiExprArg Args, bool isImplicit = false); ExprResult BuildInstanceMessageImplicit(Expr *Receiver, QualType ReceiverType, SourceLocation Loc, Selector Sel, ObjCMethodDecl *Method, MultiExprArg Args); ExprResult ActOnInstanceMessage(Scope *S, Expr *Receiver, Selector Sel, SourceLocation LBracLoc, ArrayRef SelectorLocs, SourceLocation RBracLoc, MultiExprArg Args); ExprResult BuildObjCBridgedCast(SourceLocation LParenLoc, ObjCBridgeCastKind Kind, SourceLocation BridgeKeywordLoc, TypeSourceInfo *TSInfo, Expr *SubExpr); ExprResult ActOnObjCBridgedCast(Scope *S, SourceLocation LParenLoc, ObjCBridgeCastKind Kind, SourceLocation BridgeKeywordLoc, ParsedType Type, SourceLocation RParenLoc, Expr *SubExpr); void CheckTollFreeBridgeCast(QualType castType, Expr *castExpr); void CheckObjCBridgeRelatedCast(QualType castType, Expr *castExpr); bool CheckTollFreeBridgeStaticCast(QualType castType, Expr *castExpr, CastKind &Kind); bool checkObjCBridgeRelatedComponents(SourceLocation Loc, QualType DestType, QualType SrcType, ObjCInterfaceDecl *&RelatedClass, ObjCMethodDecl *&ClassMethod, ObjCMethodDecl *&InstanceMethod, TypedefNameDecl *&TDNDecl, bool CfToNs, bool Diagnose = true); bool CheckObjCBridgeRelatedConversions(SourceLocation Loc, QualType DestType, QualType SrcType, Expr *&SrcExpr, bool Diagnose = true); bool ConversionToObjCStringLiteralCheck(QualType DstType, Expr *&SrcExpr, bool Diagnose = true); bool checkInitMethod(ObjCMethodDecl *method, QualType receiverTypeIfCall); /// Check whether the given new method is a valid override of the /// given overridden method, and set any properties that should be inherited. void CheckObjCMethodOverride(ObjCMethodDecl *NewMethod, const ObjCMethodDecl *Overridden); /// Describes the compatibility of a result type with its method. enum ResultTypeCompatibilityKind { RTC_Compatible, RTC_Incompatible, RTC_Unknown }; void CheckObjCMethodDirectOverrides(ObjCMethodDecl *method, ObjCMethodDecl *overridden); void CheckObjCMethodOverrides(ObjCMethodDecl *ObjCMethod, ObjCInterfaceDecl *CurrentClass, ResultTypeCompatibilityKind RTC); enum PragmaOptionsAlignKind { POAK_Native, // #pragma options align=native POAK_Natural, // #pragma options align=natural POAK_Packed, // #pragma options align=packed POAK_Power, // #pragma options align=power POAK_Mac68k, // #pragma options align=mac68k POAK_Reset // #pragma options align=reset }; /// ActOnPragmaClangSection - Called on well formed \#pragma clang section void ActOnPragmaClangSection(SourceLocation PragmaLoc, PragmaClangSectionAction Action, PragmaClangSectionKind SecKind, StringRef SecName); /// ActOnPragmaOptionsAlign - Called on well formed \#pragma options align. void ActOnPragmaOptionsAlign(PragmaOptionsAlignKind Kind, SourceLocation PragmaLoc); /// ActOnPragmaPack - Called on well formed \#pragma pack(...). void ActOnPragmaPack(SourceLocation PragmaLoc, PragmaMsStackAction Action, StringRef SlotLabel, Expr *Alignment); enum class PragmaPackDiagnoseKind { NonDefaultStateAtInclude, ChangedStateAtExit }; void DiagnoseNonDefaultPragmaPack(PragmaPackDiagnoseKind Kind, SourceLocation IncludeLoc); void DiagnoseUnterminatedPragmaPack(); /// ActOnPragmaMSStruct - Called on well formed \#pragma ms_struct [on|off]. void ActOnPragmaMSStruct(PragmaMSStructKind Kind); /// ActOnPragmaMSComment - Called on well formed /// \#pragma comment(kind, "arg"). void ActOnPragmaMSComment(SourceLocation CommentLoc, PragmaMSCommentKind Kind, StringRef Arg); /// ActOnPragmaMSPointersToMembers - called on well formed \#pragma /// pointers_to_members(representation method[, general purpose /// representation]). void ActOnPragmaMSPointersToMembers( LangOptions::PragmaMSPointersToMembersKind Kind, SourceLocation PragmaLoc); /// Called on well formed \#pragma vtordisp(). void ActOnPragmaMSVtorDisp(PragmaMsStackAction Action, SourceLocation PragmaLoc, MSVtorDispMode Value); enum PragmaSectionKind { PSK_DataSeg, PSK_BSSSeg, PSK_ConstSeg, PSK_CodeSeg, }; bool UnifySection(StringRef SectionName, int SectionFlags, DeclaratorDecl *TheDecl); bool UnifySection(StringRef SectionName, int SectionFlags, SourceLocation PragmaSectionLocation); /// Called on well formed \#pragma bss_seg/data_seg/const_seg/code_seg. void ActOnPragmaMSSeg(SourceLocation PragmaLocation, PragmaMsStackAction Action, llvm::StringRef StackSlotLabel, StringLiteral *SegmentName, llvm::StringRef PragmaName); /// Called on well formed \#pragma section(). void ActOnPragmaMSSection(SourceLocation PragmaLocation, int SectionFlags, StringLiteral *SegmentName); /// Called on well-formed \#pragma init_seg(). void ActOnPragmaMSInitSeg(SourceLocation PragmaLocation, StringLiteral *SegmentName); /// Called on #pragma clang __debug dump II void ActOnPragmaDump(Scope *S, SourceLocation Loc, IdentifierInfo *II); /// ActOnPragmaDetectMismatch - Call on well-formed \#pragma detect_mismatch void ActOnPragmaDetectMismatch(SourceLocation Loc, StringRef Name, StringRef Value); /// ActOnPragmaUnused - Called on well-formed '\#pragma unused'. void ActOnPragmaUnused(const Token &Identifier, Scope *curScope, SourceLocation PragmaLoc); /// ActOnPragmaVisibility - Called on well formed \#pragma GCC visibility... . void ActOnPragmaVisibility(const IdentifierInfo* VisType, SourceLocation PragmaLoc); NamedDecl *DeclClonePragmaWeak(NamedDecl *ND, IdentifierInfo *II, SourceLocation Loc); void DeclApplyPragmaWeak(Scope *S, NamedDecl *ND, WeakInfo &W); /// ActOnPragmaWeakID - Called on well formed \#pragma weak ident. void ActOnPragmaWeakID(IdentifierInfo* WeakName, SourceLocation PragmaLoc, SourceLocation WeakNameLoc); /// ActOnPragmaRedefineExtname - Called on well formed /// \#pragma redefine_extname oldname newname. void ActOnPragmaRedefineExtname(IdentifierInfo* WeakName, IdentifierInfo* AliasName, SourceLocation PragmaLoc, SourceLocation WeakNameLoc, SourceLocation AliasNameLoc); /// ActOnPragmaWeakAlias - Called on well formed \#pragma weak ident = ident. void ActOnPragmaWeakAlias(IdentifierInfo* WeakName, IdentifierInfo* AliasName, SourceLocation PragmaLoc, SourceLocation WeakNameLoc, SourceLocation AliasNameLoc); /// ActOnPragmaFPContract - Called on well formed /// \#pragma {STDC,OPENCL} FP_CONTRACT and /// \#pragma clang fp contract void ActOnPragmaFPContract(LangOptions::FPContractModeKind FPC); /// ActOnPragmaFenvAccess - Called on well formed /// \#pragma STDC FENV_ACCESS void ActOnPragmaFEnvAccess(LangOptions::FEnvAccessModeKind FPC); /// AddAlignmentAttributesForRecord - Adds any needed alignment attributes to /// a the record decl, to handle '\#pragma pack' and '\#pragma options align'. void AddAlignmentAttributesForRecord(RecordDecl *RD); /// AddMsStructLayoutForRecord - Adds ms_struct layout attribute to record. void AddMsStructLayoutForRecord(RecordDecl *RD); /// FreePackedContext - Deallocate and null out PackContext. void FreePackedContext(); /// PushNamespaceVisibilityAttr - Note that we've entered a /// namespace with a visibility attribute. void PushNamespaceVisibilityAttr(const VisibilityAttr *Attr, SourceLocation Loc); /// AddPushedVisibilityAttribute - If '\#pragma GCC visibility' was used, /// add an appropriate visibility attribute. void AddPushedVisibilityAttribute(Decl *RD); /// PopPragmaVisibility - Pop the top element of the visibility stack; used /// for '\#pragma GCC visibility' and visibility attributes on namespaces. void PopPragmaVisibility(bool IsNamespaceEnd, SourceLocation EndLoc); /// FreeVisContext - Deallocate and null out VisContext. void FreeVisContext(); /// AddCFAuditedAttribute - Check whether we're currently within /// '\#pragma clang arc_cf_code_audited' and, if so, consider adding /// the appropriate attribute. void AddCFAuditedAttribute(Decl *D); void ActOnPragmaAttributeAttribute(ParsedAttr &Attribute, SourceLocation PragmaLoc, attr::ParsedSubjectMatchRuleSet Rules); void ActOnPragmaAttributeEmptyPush(SourceLocation PragmaLoc, const IdentifierInfo *Namespace); /// Called on well-formed '\#pragma clang attribute pop'. void ActOnPragmaAttributePop(SourceLocation PragmaLoc, const IdentifierInfo *Namespace); /// Adds the attributes that have been specified using the /// '\#pragma clang attribute push' directives to the given declaration. void AddPragmaAttributes(Scope *S, Decl *D); void DiagnoseUnterminatedPragmaAttribute(); /// Called on well formed \#pragma clang optimize. void ActOnPragmaOptimize(bool On, SourceLocation PragmaLoc); /// Get the location for the currently active "\#pragma clang optimize /// off". If this location is invalid, then the state of the pragma is "on". SourceLocation getOptimizeOffPragmaLocation() const { return OptimizeOffPragmaLocation; } /// Only called on function definitions; if there is a pragma in scope /// with the effect of a range-based optnone, consider marking the function /// with attribute optnone. void AddRangeBasedOptnone(FunctionDecl *FD); /// Adds the 'optnone' attribute to the function declaration if there /// are no conflicts; Loc represents the location causing the 'optnone' /// attribute to be added (usually because of a pragma). void AddOptnoneAttributeIfNoConflicts(FunctionDecl *FD, SourceLocation Loc); /// AddAlignedAttr - Adds an aligned attribute to a particular declaration. void AddAlignedAttr(Decl *D, const AttributeCommonInfo &CI, Expr *E, bool IsPackExpansion); void AddAlignedAttr(Decl *D, const AttributeCommonInfo &CI, TypeSourceInfo *T, bool IsPackExpansion); /// AddAssumeAlignedAttr - Adds an assume_aligned attribute to a particular /// declaration. void AddAssumeAlignedAttr(Decl *D, const AttributeCommonInfo &CI, Expr *E, Expr *OE); /// AddAllocAlignAttr - Adds an alloc_align attribute to a particular /// declaration. void AddAllocAlignAttr(Decl *D, const AttributeCommonInfo &CI, Expr *ParamExpr); /// AddAlignValueAttr - Adds an align_value attribute to a particular /// declaration. void AddAlignValueAttr(Decl *D, const AttributeCommonInfo &CI, Expr *E); /// AddLaunchBoundsAttr - Adds a launch_bounds attribute to a particular /// declaration. void AddLaunchBoundsAttr(Decl *D, const AttributeCommonInfo &CI, Expr *MaxThreads, Expr *MinBlocks); /// AddModeAttr - Adds a mode attribute to a particular declaration. void AddModeAttr(Decl *D, const AttributeCommonInfo &CI, IdentifierInfo *Name, bool InInstantiation = false); void AddParameterABIAttr(Decl *D, const AttributeCommonInfo &CI, ParameterABI ABI); enum class RetainOwnershipKind {NS, CF, OS}; void AddXConsumedAttr(Decl *D, const AttributeCommonInfo &CI, RetainOwnershipKind K, bool IsTemplateInstantiation); /// addAMDGPUFlatWorkGroupSizeAttr - Adds an amdgpu_flat_work_group_size /// attribute to a particular declaration. void addAMDGPUFlatWorkGroupSizeAttr(Decl *D, const AttributeCommonInfo &CI, Expr *Min, Expr *Max); /// addAMDGPUWavePersEUAttr - Adds an amdgpu_waves_per_eu attribute to a /// particular declaration. void addAMDGPUWavesPerEUAttr(Decl *D, const AttributeCommonInfo &CI, Expr *Min, Expr *Max); bool checkNSReturnsRetainedReturnType(SourceLocation loc, QualType type); //===--------------------------------------------------------------------===// // C++ Coroutines TS // bool ActOnCoroutineBodyStart(Scope *S, SourceLocation KwLoc, StringRef Keyword); ExprResult ActOnCoawaitExpr(Scope *S, SourceLocation KwLoc, Expr *E); ExprResult ActOnCoyieldExpr(Scope *S, SourceLocation KwLoc, Expr *E); StmtResult ActOnCoreturnStmt(Scope *S, SourceLocation KwLoc, Expr *E); ExprResult BuildResolvedCoawaitExpr(SourceLocation KwLoc, Expr *E, bool IsImplicit = false); ExprResult BuildUnresolvedCoawaitExpr(SourceLocation KwLoc, Expr *E, UnresolvedLookupExpr* Lookup); ExprResult BuildCoyieldExpr(SourceLocation KwLoc, Expr *E); StmtResult BuildCoreturnStmt(SourceLocation KwLoc, Expr *E, bool IsImplicit = false); StmtResult BuildCoroutineBodyStmt(CoroutineBodyStmt::CtorArgs); bool buildCoroutineParameterMoves(SourceLocation Loc); VarDecl *buildCoroutinePromise(SourceLocation Loc); void CheckCompletedCoroutineBody(FunctionDecl *FD, Stmt *&Body); ClassTemplateDecl *lookupCoroutineTraits(SourceLocation KwLoc, SourceLocation FuncLoc); //===--------------------------------------------------------------------===// // OpenCL extensions. // private: std::string CurrOpenCLExtension; /// Extensions required by an OpenCL type. llvm::DenseMap> OpenCLTypeExtMap; /// Extensions required by an OpenCL declaration. llvm::DenseMap> OpenCLDeclExtMap; public: llvm::StringRef getCurrentOpenCLExtension() const { return CurrOpenCLExtension; } /// Check if a function declaration \p FD associates with any /// extensions present in OpenCLDeclExtMap and if so return the /// extension(s) name(s). std::string getOpenCLExtensionsFromDeclExtMap(FunctionDecl *FD); /// Check if a function type \p FT associates with any /// extensions present in OpenCLTypeExtMap and if so return the /// extension(s) name(s). std::string getOpenCLExtensionsFromTypeExtMap(FunctionType *FT); /// Find an extension in an appropriate extension map and return its name template std::string getOpenCLExtensionsFromExtMap(T* FT, MapT &Map); void setCurrentOpenCLExtension(llvm::StringRef Ext) { CurrOpenCLExtension = Ext; } /// Set OpenCL extensions for a type which can only be used when these /// OpenCL extensions are enabled. If \p Exts is empty, do nothing. /// \param Exts A space separated list of OpenCL extensions. void setOpenCLExtensionForType(QualType T, llvm::StringRef Exts); /// Set OpenCL extensions for a declaration which can only be /// used when these OpenCL extensions are enabled. If \p Exts is empty, do /// nothing. /// \param Exts A space separated list of OpenCL extensions. void setOpenCLExtensionForDecl(Decl *FD, llvm::StringRef Exts); /// Set current OpenCL extensions for a type which can only be used /// when these OpenCL extensions are enabled. If current OpenCL extension is /// empty, do nothing. void setCurrentOpenCLExtensionForType(QualType T); /// Set current OpenCL extensions for a declaration which /// can only be used when these OpenCL extensions are enabled. If current /// OpenCL extension is empty, do nothing. void setCurrentOpenCLExtensionForDecl(Decl *FD); bool isOpenCLDisabledDecl(Decl *FD); /// Check if type \p T corresponding to declaration specifier \p DS /// is disabled due to required OpenCL extensions being disabled. If so, /// emit diagnostics. /// \return true if type is disabled. bool checkOpenCLDisabledTypeDeclSpec(const DeclSpec &DS, QualType T); /// Check if declaration \p D used by expression \p E /// is disabled due to required OpenCL extensions being disabled. If so, /// emit diagnostics. /// \return true if type is disabled. bool checkOpenCLDisabledDecl(const NamedDecl &D, const Expr &E); //===--------------------------------------------------------------------===// // OpenMP directives and clauses. // private: void *VarDataSharingAttributesStack; /// Number of nested '#pragma omp declare target' directives. unsigned DeclareTargetNestingLevel = 0; /// Initialization of data-sharing attributes stack. void InitDataSharingAttributesStack(); void DestroyDataSharingAttributesStack(); ExprResult VerifyPositiveIntegerConstantInClause(Expr *Op, OpenMPClauseKind CKind, bool StrictlyPositive = true); /// Returns OpenMP nesting level for current directive. unsigned getOpenMPNestingLevel() const; /// Adjusts the function scopes index for the target-based regions. void adjustOpenMPTargetScopeIndex(unsigned &FunctionScopesIndex, unsigned Level) const; /// Returns the number of scopes associated with the construct on the given /// OpenMP level. int getNumberOfConstructScopes(unsigned Level) const; /// Push new OpenMP function region for non-capturing function. void pushOpenMPFunctionRegion(); /// Pop OpenMP function region for non-capturing function. void popOpenMPFunctionRegion(const sema::FunctionScopeInfo *OldFSI); /// Check whether we're allowed to call Callee from the current function. void checkOpenMPDeviceFunction(SourceLocation Loc, FunctionDecl *Callee, bool CheckForDelayedContext = true); /// Check whether we're allowed to call Callee from the current function. void checkOpenMPHostFunction(SourceLocation Loc, FunctionDecl *Callee, bool CheckCaller = true); /// Check if the expression is allowed to be used in expressions for the /// OpenMP devices. void checkOpenMPDeviceExpr(const Expr *E); /// Finishes analysis of the deferred functions calls that may be declared as /// host/nohost during device/host compilation. void finalizeOpenMPDelayedAnalysis(); /// Checks if a type or a declaration is disabled due to the owning extension /// being disabled, and emits diagnostic messages if it is disabled. /// \param D type or declaration to be checked. /// \param DiagLoc source location for the diagnostic message. /// \param DiagInfo information to be emitted for the diagnostic message. /// \param SrcRange source range of the declaration. /// \param Map maps type or declaration to the extensions. /// \param Selector selects diagnostic message: 0 for type and 1 for /// declaration. /// \return true if the type or declaration is disabled. template bool checkOpenCLDisabledTypeOrDecl(T D, DiagLocT DiagLoc, DiagInfoT DiagInfo, MapT &Map, unsigned Selector = 0, SourceRange SrcRange = SourceRange()); /// Marks all the functions that might be required for the currently active /// OpenMP context. void markOpenMPDeclareVariantFuncsReferenced(SourceLocation Loc, FunctionDecl *Func, bool MightBeOdrUse); public: /// Struct to store the context selectors info for declare variant directive. using OMPCtxStringType = SmallString<8>; using OMPCtxSelectorData = OpenMPCtxSelectorData, ExprResult>; /// Checks if the variant/multiversion functions are compatible. bool areMultiversionVariantFunctionsCompatible( const FunctionDecl *OldFD, const FunctionDecl *NewFD, const PartialDiagnostic &NoProtoDiagID, const PartialDiagnosticAt &NoteCausedDiagIDAt, const PartialDiagnosticAt &NoSupportDiagIDAt, const PartialDiagnosticAt &DiffDiagIDAt, bool TemplatesSupported, bool ConstexprSupported, bool CLinkageMayDiffer); /// Function tries to capture lambda's captured variables in the OpenMP region /// before the original lambda is captured. void tryCaptureOpenMPLambdas(ValueDecl *V); /// Return true if the provided declaration \a VD should be captured by /// reference. /// \param Level Relative level of nested OpenMP construct for that the check /// is performed. /// \param OpenMPCaptureLevel Capture level within an OpenMP construct. bool isOpenMPCapturedByRef(const ValueDecl *D, unsigned Level, unsigned OpenMPCaptureLevel) const; /// Check if the specified variable is used in one of the private /// clauses (private, firstprivate, lastprivate, reduction etc.) in OpenMP /// constructs. VarDecl *isOpenMPCapturedDecl(ValueDecl *D, bool CheckScopeInfo = false, unsigned StopAt = 0); ExprResult getOpenMPCapturedExpr(VarDecl *Capture, ExprValueKind VK, ExprObjectKind OK, SourceLocation Loc); /// If the current region is a loop-based region, mark the start of the loop /// construct. void startOpenMPLoop(); /// If the current region is a range loop-based region, mark the start of the /// loop construct. void startOpenMPCXXRangeFor(); /// Check if the specified variable is used in 'private' clause. /// \param Level Relative level of nested OpenMP construct for that the check /// is performed. bool isOpenMPPrivateDecl(const ValueDecl *D, unsigned Level) const; /// Sets OpenMP capture kind (OMPC_private, OMPC_firstprivate, OMPC_map etc.) /// for \p FD based on DSA for the provided corresponding captured declaration /// \p D. void setOpenMPCaptureKind(FieldDecl *FD, const ValueDecl *D, unsigned Level); /// Check if the specified variable is captured by 'target' directive. /// \param Level Relative level of nested OpenMP construct for that the check /// is performed. bool isOpenMPTargetCapturedDecl(const ValueDecl *D, unsigned Level) const; ExprResult PerformOpenMPImplicitIntegerConversion(SourceLocation OpLoc, Expr *Op); /// Called on start of new data sharing attribute block. void StartOpenMPDSABlock(OpenMPDirectiveKind K, const DeclarationNameInfo &DirName, Scope *CurScope, SourceLocation Loc); /// Start analysis of clauses. void StartOpenMPClause(OpenMPClauseKind K); /// End analysis of clauses. void EndOpenMPClause(); /// Called on end of data sharing attribute block. void EndOpenMPDSABlock(Stmt *CurDirective); /// Check if the current region is an OpenMP loop region and if it is, /// mark loop control variable, used in \p Init for loop initialization, as /// private by default. /// \param Init First part of the for loop. void ActOnOpenMPLoopInitialization(SourceLocation ForLoc, Stmt *Init); // OpenMP directives and clauses. /// Called on correct id-expression from the '#pragma omp /// threadprivate'. ExprResult ActOnOpenMPIdExpression(Scope *CurScope, CXXScopeSpec &ScopeSpec, const DeclarationNameInfo &Id, OpenMPDirectiveKind Kind); /// Called on well-formed '#pragma omp threadprivate'. DeclGroupPtrTy ActOnOpenMPThreadprivateDirective( SourceLocation Loc, ArrayRef VarList); /// Builds a new OpenMPThreadPrivateDecl and checks its correctness. OMPThreadPrivateDecl *CheckOMPThreadPrivateDecl(SourceLocation Loc, ArrayRef VarList); /// Called on well-formed '#pragma omp allocate'. DeclGroupPtrTy ActOnOpenMPAllocateDirective(SourceLocation Loc, ArrayRef VarList, ArrayRef Clauses, DeclContext *Owner = nullptr); /// Called on well-formed '#pragma omp requires'. DeclGroupPtrTy ActOnOpenMPRequiresDirective(SourceLocation Loc, ArrayRef ClauseList); /// Check restrictions on Requires directive OMPRequiresDecl *CheckOMPRequiresDecl(SourceLocation Loc, ArrayRef Clauses); /// Check if the specified type is allowed to be used in 'omp declare /// reduction' construct. QualType ActOnOpenMPDeclareReductionType(SourceLocation TyLoc, TypeResult ParsedType); /// Called on start of '#pragma omp declare reduction'. DeclGroupPtrTy ActOnOpenMPDeclareReductionDirectiveStart( Scope *S, DeclContext *DC, DeclarationName Name, ArrayRef> ReductionTypes, AccessSpecifier AS, Decl *PrevDeclInScope = nullptr); /// Initialize declare reduction construct initializer. void ActOnOpenMPDeclareReductionCombinerStart(Scope *S, Decl *D); /// Finish current declare reduction construct initializer. void ActOnOpenMPDeclareReductionCombinerEnd(Decl *D, Expr *Combiner); /// Initialize declare reduction construct initializer. /// \return omp_priv variable. VarDecl *ActOnOpenMPDeclareReductionInitializerStart(Scope *S, Decl *D); /// Finish current declare reduction construct initializer. void ActOnOpenMPDeclareReductionInitializerEnd(Decl *D, Expr *Initializer, VarDecl *OmpPrivParm); /// Called at the end of '#pragma omp declare reduction'. DeclGroupPtrTy ActOnOpenMPDeclareReductionDirectiveEnd( Scope *S, DeclGroupPtrTy DeclReductions, bool IsValid); /// Check variable declaration in 'omp declare mapper' construct. TypeResult ActOnOpenMPDeclareMapperVarDecl(Scope *S, Declarator &D); /// Check if the specified type is allowed to be used in 'omp declare /// mapper' construct. QualType ActOnOpenMPDeclareMapperType(SourceLocation TyLoc, TypeResult ParsedType); /// Called on start of '#pragma omp declare mapper'. OMPDeclareMapperDecl *ActOnOpenMPDeclareMapperDirectiveStart( Scope *S, DeclContext *DC, DeclarationName Name, QualType MapperType, SourceLocation StartLoc, DeclarationName VN, AccessSpecifier AS, Decl *PrevDeclInScope = nullptr); /// Build the mapper variable of '#pragma omp declare mapper'. void ActOnOpenMPDeclareMapperDirectiveVarDecl(OMPDeclareMapperDecl *DMD, Scope *S, QualType MapperType, SourceLocation StartLoc, DeclarationName VN); /// Called at the end of '#pragma omp declare mapper'. DeclGroupPtrTy ActOnOpenMPDeclareMapperDirectiveEnd(OMPDeclareMapperDecl *D, Scope *S, ArrayRef ClauseList); /// Called on the start of target region i.e. '#pragma omp declare target'. bool ActOnStartOpenMPDeclareTargetDirective(SourceLocation Loc); /// Called at the end of target region i.e. '#pragme omp end declare target'. void ActOnFinishOpenMPDeclareTargetDirective(); /// Searches for the provided declaration name for OpenMP declare target /// directive. NamedDecl * lookupOpenMPDeclareTargetName(Scope *CurScope, CXXScopeSpec &ScopeSpec, const DeclarationNameInfo &Id, NamedDeclSetType &SameDirectiveDecls); /// Called on correct id-expression from the '#pragma omp declare target'. void ActOnOpenMPDeclareTargetName(NamedDecl *ND, SourceLocation Loc, OMPDeclareTargetDeclAttr::MapTypeTy MT, OMPDeclareTargetDeclAttr::DevTypeTy DT); /// Check declaration inside target region. void checkDeclIsAllowedInOpenMPTarget(Expr *E, Decl *D, SourceLocation IdLoc = SourceLocation()); /// Return true inside OpenMP declare target region. bool isInOpenMPDeclareTargetContext() const { return DeclareTargetNestingLevel > 0; } /// Return true inside OpenMP target region. bool isInOpenMPTargetExecutionDirective() const; /// Return the number of captured regions created for an OpenMP directive. static int getOpenMPCaptureLevels(OpenMPDirectiveKind Kind); /// Initialization of captured region for OpenMP region. void ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope); /// End of OpenMP region. /// /// \param S Statement associated with the current OpenMP region. /// \param Clauses List of clauses for the current OpenMP region. /// /// \returns Statement for finished OpenMP region. StmtResult ActOnOpenMPRegionEnd(StmtResult S, ArrayRef Clauses); StmtResult ActOnOpenMPExecutableDirective( OpenMPDirectiveKind Kind, const DeclarationNameInfo &DirName, OpenMPDirectiveKind CancelRegion, ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc); /// Called on well-formed '\#pragma omp parallel' after parsing /// of the associated statement. StmtResult ActOnOpenMPParallelDirective(ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc); using VarsWithInheritedDSAType = llvm::SmallDenseMap; /// Called on well-formed '\#pragma omp simd' after parsing /// of the associated statement. StmtResult ActOnOpenMPSimdDirective(ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA); /// Called on well-formed '\#pragma omp for' after parsing /// of the associated statement. StmtResult ActOnOpenMPForDirective(ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA); /// Called on well-formed '\#pragma omp for simd' after parsing /// of the associated statement. StmtResult ActOnOpenMPForSimdDirective(ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA); /// Called on well-formed '\#pragma omp sections' after parsing /// of the associated statement. StmtResult ActOnOpenMPSectionsDirective(ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc); /// Called on well-formed '\#pragma omp section' after parsing of the /// associated statement. StmtResult ActOnOpenMPSectionDirective(Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc); /// Called on well-formed '\#pragma omp single' after parsing of the /// associated statement. StmtResult ActOnOpenMPSingleDirective(ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc); /// Called on well-formed '\#pragma omp master' after parsing of the /// associated statement. StmtResult ActOnOpenMPMasterDirective(Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc); /// Called on well-formed '\#pragma omp critical' after parsing of the /// associated statement. StmtResult ActOnOpenMPCriticalDirective(const DeclarationNameInfo &DirName, ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc); /// Called on well-formed '\#pragma omp parallel for' after parsing /// of the associated statement. StmtResult ActOnOpenMPParallelForDirective( ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA); /// Called on well-formed '\#pragma omp parallel for simd' after /// parsing of the associated statement. StmtResult ActOnOpenMPParallelForSimdDirective( ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA); /// Called on well-formed '\#pragma omp parallel master' after /// parsing of the associated statement. StmtResult ActOnOpenMPParallelMasterDirective(ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc); /// Called on well-formed '\#pragma omp parallel sections' after /// parsing of the associated statement. StmtResult ActOnOpenMPParallelSectionsDirective(ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc); /// Called on well-formed '\#pragma omp task' after parsing of the /// associated statement. StmtResult ActOnOpenMPTaskDirective(ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc); /// Called on well-formed '\#pragma omp taskyield'. StmtResult ActOnOpenMPTaskyieldDirective(SourceLocation StartLoc, SourceLocation EndLoc); /// Called on well-formed '\#pragma omp barrier'. StmtResult ActOnOpenMPBarrierDirective(SourceLocation StartLoc, SourceLocation EndLoc); /// Called on well-formed '\#pragma omp taskwait'. StmtResult ActOnOpenMPTaskwaitDirective(SourceLocation StartLoc, SourceLocation EndLoc); /// Called on well-formed '\#pragma omp taskgroup'. StmtResult ActOnOpenMPTaskgroupDirective(ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc); /// Called on well-formed '\#pragma omp flush'. StmtResult ActOnOpenMPFlushDirective(ArrayRef Clauses, SourceLocation StartLoc, SourceLocation EndLoc); /// Called on well-formed '\#pragma omp ordered' after parsing of the /// associated statement. StmtResult ActOnOpenMPOrderedDirective(ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc); /// Called on well-formed '\#pragma omp atomic' after parsing of the /// associated statement. StmtResult ActOnOpenMPAtomicDirective(ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc); /// Called on well-formed '\#pragma omp target' after parsing of the /// associated statement. StmtResult ActOnOpenMPTargetDirective(ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc); /// Called on well-formed '\#pragma omp target data' after parsing of /// the associated statement. StmtResult ActOnOpenMPTargetDataDirective(ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc); /// Called on well-formed '\#pragma omp target enter data' after /// parsing of the associated statement. StmtResult ActOnOpenMPTargetEnterDataDirective(ArrayRef Clauses, SourceLocation StartLoc, SourceLocation EndLoc, Stmt *AStmt); /// Called on well-formed '\#pragma omp target exit data' after /// parsing of the associated statement. StmtResult ActOnOpenMPTargetExitDataDirective(ArrayRef Clauses, SourceLocation StartLoc, SourceLocation EndLoc, Stmt *AStmt); /// Called on well-formed '\#pragma omp target parallel' after /// parsing of the associated statement. StmtResult ActOnOpenMPTargetParallelDirective(ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc); /// Called on well-formed '\#pragma omp target parallel for' after /// parsing of the associated statement. StmtResult ActOnOpenMPTargetParallelForDirective( ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA); /// Called on well-formed '\#pragma omp teams' after parsing of the /// associated statement. StmtResult ActOnOpenMPTeamsDirective(ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc); /// Called on well-formed '\#pragma omp cancellation point'. StmtResult ActOnOpenMPCancellationPointDirective(SourceLocation StartLoc, SourceLocation EndLoc, OpenMPDirectiveKind CancelRegion); /// Called on well-formed '\#pragma omp cancel'. StmtResult ActOnOpenMPCancelDirective(ArrayRef Clauses, SourceLocation StartLoc, SourceLocation EndLoc, OpenMPDirectiveKind CancelRegion); /// Called on well-formed '\#pragma omp taskloop' after parsing of the /// associated statement. StmtResult ActOnOpenMPTaskLoopDirective(ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA); /// Called on well-formed '\#pragma omp taskloop simd' after parsing of /// the associated statement. StmtResult ActOnOpenMPTaskLoopSimdDirective( ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA); /// Called on well-formed '\#pragma omp master taskloop' after parsing of the /// associated statement. StmtResult ActOnOpenMPMasterTaskLoopDirective( ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA); /// Called on well-formed '\#pragma omp master taskloop simd' after parsing of /// the associated statement. StmtResult ActOnOpenMPMasterTaskLoopSimdDirective( ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA); /// Called on well-formed '\#pragma omp parallel master taskloop' after /// parsing of the associated statement. StmtResult ActOnOpenMPParallelMasterTaskLoopDirective( ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA); /// Called on well-formed '\#pragma omp parallel master taskloop simd' after /// parsing of the associated statement. StmtResult ActOnOpenMPParallelMasterTaskLoopSimdDirective( ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA); /// Called on well-formed '\#pragma omp distribute' after parsing /// of the associated statement. StmtResult ActOnOpenMPDistributeDirective(ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA); /// Called on well-formed '\#pragma omp target update'. StmtResult ActOnOpenMPTargetUpdateDirective(ArrayRef Clauses, SourceLocation StartLoc, SourceLocation EndLoc, Stmt *AStmt); /// Called on well-formed '\#pragma omp distribute parallel for' after /// parsing of the associated statement. StmtResult ActOnOpenMPDistributeParallelForDirective( ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA); /// Called on well-formed '\#pragma omp distribute parallel for simd' /// after parsing of the associated statement. StmtResult ActOnOpenMPDistributeParallelForSimdDirective( ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA); /// Called on well-formed '\#pragma omp distribute simd' after /// parsing of the associated statement. StmtResult ActOnOpenMPDistributeSimdDirective( ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA); /// Called on well-formed '\#pragma omp target parallel for simd' after /// parsing of the associated statement. StmtResult ActOnOpenMPTargetParallelForSimdDirective( ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA); /// Called on well-formed '\#pragma omp target simd' after parsing of /// the associated statement. StmtResult ActOnOpenMPTargetSimdDirective(ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA); /// Called on well-formed '\#pragma omp teams distribute' after parsing of /// the associated statement. StmtResult ActOnOpenMPTeamsDistributeDirective( ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA); /// Called on well-formed '\#pragma omp teams distribute simd' after parsing /// of the associated statement. StmtResult ActOnOpenMPTeamsDistributeSimdDirective( ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA); /// Called on well-formed '\#pragma omp teams distribute parallel for simd' /// after parsing of the associated statement. StmtResult ActOnOpenMPTeamsDistributeParallelForSimdDirective( ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA); /// Called on well-formed '\#pragma omp teams distribute parallel for' /// after parsing of the associated statement. StmtResult ActOnOpenMPTeamsDistributeParallelForDirective( ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA); /// Called on well-formed '\#pragma omp target teams' after parsing of the /// associated statement. StmtResult ActOnOpenMPTargetTeamsDirective(ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc); /// Called on well-formed '\#pragma omp target teams distribute' after parsing /// of the associated statement. StmtResult ActOnOpenMPTargetTeamsDistributeDirective( ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA); /// Called on well-formed '\#pragma omp target teams distribute parallel for' /// after parsing of the associated statement. StmtResult ActOnOpenMPTargetTeamsDistributeParallelForDirective( ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA); /// Called on well-formed '\#pragma omp target teams distribute parallel for /// simd' after parsing of the associated statement. StmtResult ActOnOpenMPTargetTeamsDistributeParallelForSimdDirective( ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA); /// Called on well-formed '\#pragma omp target teams distribute simd' after /// parsing of the associated statement. StmtResult ActOnOpenMPTargetTeamsDistributeSimdDirective( ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA); /// Checks correctness of linear modifiers. bool CheckOpenMPLinearModifier(OpenMPLinearClauseKind LinKind, SourceLocation LinLoc); /// Checks that the specified declaration matches requirements for the linear /// decls. bool CheckOpenMPLinearDecl(const ValueDecl *D, SourceLocation ELoc, OpenMPLinearClauseKind LinKind, QualType Type); /// Called on well-formed '\#pragma omp declare simd' after parsing of /// the associated method/function. DeclGroupPtrTy ActOnOpenMPDeclareSimdDirective( DeclGroupPtrTy DG, OMPDeclareSimdDeclAttr::BranchStateTy BS, Expr *Simdlen, ArrayRef Uniforms, ArrayRef Aligneds, ArrayRef Alignments, ArrayRef Linears, ArrayRef LinModifiers, ArrayRef Steps, SourceRange SR); /// Checks '\#pragma omp declare variant' variant function and original /// functions after parsing of the associated method/function. /// \param DG Function declaration to which declare variant directive is /// applied to. /// \param VariantRef Expression that references the variant function, which /// must be used instead of the original one, specified in \p DG. /// \returns None, if the function/variant function are not compatible with /// the pragma, pair of original function/variant ref expression otherwise. Optional> checkOpenMPDeclareVariantFunction( DeclGroupPtrTy DG, Expr *VariantRef, SourceRange SR); /// Called on well-formed '\#pragma omp declare variant' after parsing of /// the associated method/function. /// \param FD Function declaration to which declare variant directive is /// applied to. /// \param VariantRef Expression that references the variant function, which /// must be used instead of the original one, specified in \p DG. /// \param Data Set of context-specific data for the specified context /// selector. void ActOnOpenMPDeclareVariantDirective(FunctionDecl *FD, Expr *VariantRef, SourceRange SR, ArrayRef Data); OMPClause *ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); /// Called on well-formed 'allocator' clause. OMPClause *ActOnOpenMPAllocatorClause(Expr *Allocator, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); /// Called on well-formed 'if' clause. OMPClause *ActOnOpenMPIfClause(OpenMPDirectiveKind NameModifier, Expr *Condition, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation NameModifierLoc, SourceLocation ColonLoc, SourceLocation EndLoc); /// Called on well-formed 'final' clause. OMPClause *ActOnOpenMPFinalClause(Expr *Condition, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); /// Called on well-formed 'num_threads' clause. OMPClause *ActOnOpenMPNumThreadsClause(Expr *NumThreads, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); /// Called on well-formed 'safelen' clause. OMPClause *ActOnOpenMPSafelenClause(Expr *Length, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); /// Called on well-formed 'simdlen' clause. OMPClause *ActOnOpenMPSimdlenClause(Expr *Length, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); /// Called on well-formed 'collapse' clause. OMPClause *ActOnOpenMPCollapseClause(Expr *NumForLoops, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); /// Called on well-formed 'ordered' clause. OMPClause * ActOnOpenMPOrderedClause(SourceLocation StartLoc, SourceLocation EndLoc, SourceLocation LParenLoc = SourceLocation(), Expr *NumForLoops = nullptr); /// Called on well-formed 'grainsize' clause. OMPClause *ActOnOpenMPGrainsizeClause(Expr *Size, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); /// Called on well-formed 'num_tasks' clause. OMPClause *ActOnOpenMPNumTasksClause(Expr *NumTasks, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); /// Called on well-formed 'hint' clause. OMPClause *ActOnOpenMPHintClause(Expr *Hint, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); OMPClause *ActOnOpenMPSimpleClause(OpenMPClauseKind Kind, unsigned Argument, SourceLocation ArgumentLoc, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); /// Called on well-formed 'default' clause. OMPClause *ActOnOpenMPDefaultClause(OpenMPDefaultClauseKind Kind, SourceLocation KindLoc, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); /// Called on well-formed 'proc_bind' clause. OMPClause *ActOnOpenMPProcBindClause(llvm::omp::ProcBindKind Kind, SourceLocation KindLoc, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); OMPClause *ActOnOpenMPSingleExprWithArgClause( OpenMPClauseKind Kind, ArrayRef Arguments, Expr *Expr, SourceLocation StartLoc, SourceLocation LParenLoc, ArrayRef ArgumentsLoc, SourceLocation DelimLoc, SourceLocation EndLoc); /// Called on well-formed 'schedule' clause. OMPClause *ActOnOpenMPScheduleClause( OpenMPScheduleClauseModifier M1, OpenMPScheduleClauseModifier M2, OpenMPScheduleClauseKind Kind, Expr *ChunkSize, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation M1Loc, SourceLocation M2Loc, SourceLocation KindLoc, SourceLocation CommaLoc, SourceLocation EndLoc); OMPClause *ActOnOpenMPClause(OpenMPClauseKind Kind, SourceLocation StartLoc, SourceLocation EndLoc); /// Called on well-formed 'nowait' clause. OMPClause *ActOnOpenMPNowaitClause(SourceLocation StartLoc, SourceLocation EndLoc); /// Called on well-formed 'untied' clause. OMPClause *ActOnOpenMPUntiedClause(SourceLocation StartLoc, SourceLocation EndLoc); /// Called on well-formed 'mergeable' clause. OMPClause *ActOnOpenMPMergeableClause(SourceLocation StartLoc, SourceLocation EndLoc); /// Called on well-formed 'read' clause. OMPClause *ActOnOpenMPReadClause(SourceLocation StartLoc, SourceLocation EndLoc); /// Called on well-formed 'write' clause. OMPClause *ActOnOpenMPWriteClause(SourceLocation StartLoc, SourceLocation EndLoc); /// Called on well-formed 'update' clause. OMPClause *ActOnOpenMPUpdateClause(SourceLocation StartLoc, SourceLocation EndLoc); /// Called on well-formed 'capture' clause. OMPClause *ActOnOpenMPCaptureClause(SourceLocation StartLoc, SourceLocation EndLoc); /// Called on well-formed 'seq_cst' clause. OMPClause *ActOnOpenMPSeqCstClause(SourceLocation StartLoc, SourceLocation EndLoc); /// Called on well-formed 'threads' clause. OMPClause *ActOnOpenMPThreadsClause(SourceLocation StartLoc, SourceLocation EndLoc); /// Called on well-formed 'simd' clause. OMPClause *ActOnOpenMPSIMDClause(SourceLocation StartLoc, SourceLocation EndLoc); /// Called on well-formed 'nogroup' clause. OMPClause *ActOnOpenMPNogroupClause(SourceLocation StartLoc, SourceLocation EndLoc); /// Called on well-formed 'unified_address' clause. OMPClause *ActOnOpenMPUnifiedAddressClause(SourceLocation StartLoc, SourceLocation EndLoc); /// Called on well-formed 'unified_address' clause. OMPClause *ActOnOpenMPUnifiedSharedMemoryClause(SourceLocation StartLoc, SourceLocation EndLoc); /// Called on well-formed 'reverse_offload' clause. OMPClause *ActOnOpenMPReverseOffloadClause(SourceLocation StartLoc, SourceLocation EndLoc); /// Called on well-formed 'dynamic_allocators' clause. OMPClause *ActOnOpenMPDynamicAllocatorsClause(SourceLocation StartLoc, SourceLocation EndLoc); /// Called on well-formed 'atomic_default_mem_order' clause. OMPClause *ActOnOpenMPAtomicDefaultMemOrderClause( OpenMPAtomicDefaultMemOrderClauseKind Kind, SourceLocation KindLoc, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); OMPClause *ActOnOpenMPVarListClause( OpenMPClauseKind Kind, ArrayRef Vars, Expr *TailExpr, const OMPVarListLocTy &Locs, SourceLocation ColonLoc, CXXScopeSpec &ReductionOrMapperIdScopeSpec, DeclarationNameInfo &ReductionOrMapperId, int ExtraModifier, ArrayRef MapTypeModifiers, ArrayRef MapTypeModifiersLoc, bool IsMapTypeImplicit, SourceLocation DepLinMapLastLoc); /// Called on well-formed 'allocate' clause. OMPClause * ActOnOpenMPAllocateClause(Expr *Allocator, ArrayRef VarList, SourceLocation StartLoc, SourceLocation ColonLoc, SourceLocation LParenLoc, SourceLocation EndLoc); /// Called on well-formed 'private' clause. OMPClause *ActOnOpenMPPrivateClause(ArrayRef VarList, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); /// Called on well-formed 'firstprivate' clause. OMPClause *ActOnOpenMPFirstprivateClause(ArrayRef VarList, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); /// Called on well-formed 'lastprivate' clause. OMPClause *ActOnOpenMPLastprivateClause( ArrayRef VarList, OpenMPLastprivateModifier LPKind, SourceLocation LPKindLoc, SourceLocation ColonLoc, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); /// Called on well-formed 'shared' clause. OMPClause *ActOnOpenMPSharedClause(ArrayRef VarList, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); /// Called on well-formed 'reduction' clause. OMPClause *ActOnOpenMPReductionClause( ArrayRef VarList, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation ColonLoc, SourceLocation EndLoc, CXXScopeSpec &ReductionIdScopeSpec, const DeclarationNameInfo &ReductionId, ArrayRef UnresolvedReductions = llvm::None); /// Called on well-formed 'task_reduction' clause. OMPClause *ActOnOpenMPTaskReductionClause( ArrayRef VarList, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation ColonLoc, SourceLocation EndLoc, CXXScopeSpec &ReductionIdScopeSpec, const DeclarationNameInfo &ReductionId, ArrayRef UnresolvedReductions = llvm::None); /// Called on well-formed 'in_reduction' clause. OMPClause *ActOnOpenMPInReductionClause( ArrayRef VarList, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation ColonLoc, SourceLocation EndLoc, CXXScopeSpec &ReductionIdScopeSpec, const DeclarationNameInfo &ReductionId, ArrayRef UnresolvedReductions = llvm::None); /// Called on well-formed 'linear' clause. OMPClause * ActOnOpenMPLinearClause(ArrayRef VarList, Expr *Step, SourceLocation StartLoc, SourceLocation LParenLoc, OpenMPLinearClauseKind LinKind, SourceLocation LinLoc, SourceLocation ColonLoc, SourceLocation EndLoc); /// Called on well-formed 'aligned' clause. OMPClause *ActOnOpenMPAlignedClause(ArrayRef VarList, Expr *Alignment, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation ColonLoc, SourceLocation EndLoc); /// Called on well-formed 'copyin' clause. OMPClause *ActOnOpenMPCopyinClause(ArrayRef VarList, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); /// Called on well-formed 'copyprivate' clause. OMPClause *ActOnOpenMPCopyprivateClause(ArrayRef VarList, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); /// Called on well-formed 'flush' pseudo clause. OMPClause *ActOnOpenMPFlushClause(ArrayRef VarList, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); /// Called on well-formed 'depend' clause. OMPClause * ActOnOpenMPDependClause(OpenMPDependClauseKind DepKind, SourceLocation DepLoc, SourceLocation ColonLoc, ArrayRef VarList, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); /// Called on well-formed 'device' clause. OMPClause *ActOnOpenMPDeviceClause(Expr *Device, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); /// Called on well-formed 'map' clause. OMPClause * ActOnOpenMPMapClause(ArrayRef MapTypeModifiers, ArrayRef MapTypeModifiersLoc, CXXScopeSpec &MapperIdScopeSpec, DeclarationNameInfo &MapperId, OpenMPMapClauseKind MapType, bool IsMapTypeImplicit, SourceLocation MapLoc, SourceLocation ColonLoc, ArrayRef VarList, const OMPVarListLocTy &Locs, ArrayRef UnresolvedMappers = llvm::None); /// Called on well-formed 'num_teams' clause. OMPClause *ActOnOpenMPNumTeamsClause(Expr *NumTeams, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); /// Called on well-formed 'thread_limit' clause. OMPClause *ActOnOpenMPThreadLimitClause(Expr *ThreadLimit, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); /// Called on well-formed 'priority' clause. OMPClause *ActOnOpenMPPriorityClause(Expr *Priority, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); /// Called on well-formed 'dist_schedule' clause. OMPClause *ActOnOpenMPDistScheduleClause( OpenMPDistScheduleClauseKind Kind, Expr *ChunkSize, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation KindLoc, SourceLocation CommaLoc, SourceLocation EndLoc); /// Called on well-formed 'defaultmap' clause. OMPClause *ActOnOpenMPDefaultmapClause( OpenMPDefaultmapClauseModifier M, OpenMPDefaultmapClauseKind Kind, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation MLoc, SourceLocation KindLoc, SourceLocation EndLoc); /// Called on well-formed 'to' clause. OMPClause * ActOnOpenMPToClause(ArrayRef VarList, CXXScopeSpec &MapperIdScopeSpec, DeclarationNameInfo &MapperId, const OMPVarListLocTy &Locs, ArrayRef UnresolvedMappers = llvm::None); /// Called on well-formed 'from' clause. OMPClause *ActOnOpenMPFromClause( ArrayRef VarList, CXXScopeSpec &MapperIdScopeSpec, DeclarationNameInfo &MapperId, const OMPVarListLocTy &Locs, ArrayRef UnresolvedMappers = llvm::None); /// Called on well-formed 'use_device_ptr' clause. OMPClause *ActOnOpenMPUseDevicePtrClause(ArrayRef VarList, const OMPVarListLocTy &Locs); /// Called on well-formed 'is_device_ptr' clause. OMPClause *ActOnOpenMPIsDevicePtrClause(ArrayRef VarList, const OMPVarListLocTy &Locs); /// Called on well-formed 'nontemporal' clause. OMPClause *ActOnOpenMPNontemporalClause(ArrayRef VarList, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); /// The kind of conversion being performed. enum CheckedConversionKind { /// An implicit conversion. CCK_ImplicitConversion, /// A C-style cast. CCK_CStyleCast, /// A functional-style cast. CCK_FunctionalCast, /// A cast other than a C-style cast. CCK_OtherCast, /// A conversion for an operand of a builtin overloaded operator. CCK_ForBuiltinOverloadedOp }; static bool isCast(CheckedConversionKind CCK) { return CCK == CCK_CStyleCast || CCK == CCK_FunctionalCast || CCK == CCK_OtherCast; } /// ImpCastExprToType - If Expr is not of type 'Type', insert an implicit /// cast. If there is already an implicit cast, merge into the existing one. /// If isLvalue, the result of the cast is an lvalue. ExprResult ImpCastExprToType(Expr *E, QualType Type, CastKind CK, ExprValueKind VK = VK_RValue, const CXXCastPath *BasePath = nullptr, CheckedConversionKind CCK = CCK_ImplicitConversion); /// ScalarTypeToBooleanCastKind - Returns the cast kind corresponding /// to the conversion from scalar type ScalarTy to the Boolean type. static CastKind ScalarTypeToBooleanCastKind(QualType ScalarTy); /// IgnoredValueConversions - Given that an expression's result is /// syntactically ignored, perform any conversions that are /// required. ExprResult IgnoredValueConversions(Expr *E); // UsualUnaryConversions - promotes integers (C99 6.3.1.1p2) and converts // functions and arrays to their respective pointers (C99 6.3.2.1). ExprResult UsualUnaryConversions(Expr *E); /// CallExprUnaryConversions - a special case of an unary conversion /// performed on a function designator of a call expression. ExprResult CallExprUnaryConversions(Expr *E); // DefaultFunctionArrayConversion - converts functions and arrays // to their respective pointers (C99 6.3.2.1). ExprResult DefaultFunctionArrayConversion(Expr *E, bool Diagnose = true); // DefaultFunctionArrayLvalueConversion - converts functions and // arrays to their respective pointers and performs the // lvalue-to-rvalue conversion. ExprResult DefaultFunctionArrayLvalueConversion(Expr *E, bool Diagnose = true); // DefaultLvalueConversion - performs lvalue-to-rvalue conversion on // the operand. This is DefaultFunctionArrayLvalueConversion, // except that it assumes the operand isn't of function or array // type. ExprResult DefaultLvalueConversion(Expr *E); // DefaultArgumentPromotion (C99 6.5.2.2p6). Used for function calls that // do not have a prototype. Integer promotions are performed on each // argument, and arguments that have type float are promoted to double. ExprResult DefaultArgumentPromotion(Expr *E); /// If \p E is a prvalue denoting an unmaterialized temporary, materialize /// it as an xvalue. In C++98, the result will still be a prvalue, because /// we don't have xvalues there. ExprResult TemporaryMaterializationConversion(Expr *E); // Used for emitting the right warning by DefaultVariadicArgumentPromotion enum VariadicCallType { VariadicFunction, VariadicBlock, VariadicMethod, VariadicConstructor, VariadicDoesNotApply }; VariadicCallType getVariadicCallType(FunctionDecl *FDecl, const FunctionProtoType *Proto, Expr *Fn); // Used for determining in which context a type is allowed to be passed to a // vararg function. enum VarArgKind { VAK_Valid, VAK_ValidInCXX11, VAK_Undefined, VAK_MSVCUndefined, VAK_Invalid }; // Determines which VarArgKind fits an expression. VarArgKind isValidVarArgType(const QualType &Ty); /// Check to see if the given expression is a valid argument to a variadic /// function, issuing a diagnostic if not. void checkVariadicArgument(const Expr *E, VariadicCallType CT); /// Check to see if a given expression could have '.c_str()' called on it. bool hasCStrMethod(const Expr *E); /// GatherArgumentsForCall - Collector argument expressions for various /// form of call prototypes. bool GatherArgumentsForCall(SourceLocation CallLoc, FunctionDecl *FDecl, const FunctionProtoType *Proto, unsigned FirstParam, ArrayRef Args, SmallVectorImpl &AllArgs, VariadicCallType CallType = VariadicDoesNotApply, bool AllowExplicit = false, bool IsListInitialization = false); // DefaultVariadicArgumentPromotion - Like DefaultArgumentPromotion, but // will create a runtime trap if the resulting type is not a POD type. ExprResult DefaultVariadicArgumentPromotion(Expr *E, VariadicCallType CT, FunctionDecl *FDecl); /// Context in which we're performing a usual arithmetic conversion. enum ArithConvKind { /// An arithmetic operation. ACK_Arithmetic, /// A bitwise operation. ACK_BitwiseOp, /// A comparison. ACK_Comparison, /// A conditional (?:) operator. ACK_Conditional, /// A compound assignment expression. ACK_CompAssign, }; // UsualArithmeticConversions - performs the UsualUnaryConversions on it's // operands and then handles various conversions that are common to binary // operators (C99 6.3.1.8). If both operands aren't arithmetic, this // routine returns the first non-arithmetic type found. The client is // responsible for emitting appropriate error diagnostics. QualType UsualArithmeticConversions(ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, ArithConvKind ACK); /// AssignConvertType - All of the 'assignment' semantic checks return this /// enum to indicate whether the assignment was allowed. These checks are /// done for simple assignments, as well as initialization, return from /// function, argument passing, etc. The query is phrased in terms of a /// source and destination type. enum AssignConvertType { /// Compatible - the types are compatible according to the standard. Compatible, /// PointerToInt - The assignment converts a pointer to an int, which we /// accept as an extension. PointerToInt, /// IntToPointer - The assignment converts an int to a pointer, which we /// accept as an extension. IntToPointer, /// FunctionVoidPointer - The assignment is between a function pointer and /// void*, which the standard doesn't allow, but we accept as an extension. FunctionVoidPointer, /// IncompatiblePointer - The assignment is between two pointers types that /// are not compatible, but we accept them as an extension. IncompatiblePointer, /// IncompatiblePointerSign - The assignment is between two pointers types /// which point to integers which have a different sign, but are otherwise /// identical. This is a subset of the above, but broken out because it's by /// far the most common case of incompatible pointers. IncompatiblePointerSign, /// CompatiblePointerDiscardsQualifiers - The assignment discards /// c/v/r qualifiers, which we accept as an extension. CompatiblePointerDiscardsQualifiers, /// IncompatiblePointerDiscardsQualifiers - The assignment /// discards qualifiers that we don't permit to be discarded, /// like address spaces. IncompatiblePointerDiscardsQualifiers, /// IncompatibleNestedPointerAddressSpaceMismatch - The assignment /// changes address spaces in nested pointer types which is not allowed. /// For instance, converting __private int ** to __generic int ** is /// illegal even though __private could be converted to __generic. IncompatibleNestedPointerAddressSpaceMismatch, /// IncompatibleNestedPointerQualifiers - The assignment is between two /// nested pointer types, and the qualifiers other than the first two /// levels differ e.g. char ** -> const char **, but we accept them as an /// extension. IncompatibleNestedPointerQualifiers, /// IncompatibleVectors - The assignment is between two vector types that /// have the same size, which we accept as an extension. IncompatibleVectors, /// IntToBlockPointer - The assignment converts an int to a block /// pointer. We disallow this. IntToBlockPointer, /// IncompatibleBlockPointer - The assignment is between two block /// pointers types that are not compatible. IncompatibleBlockPointer, /// IncompatibleObjCQualifiedId - The assignment is between a qualified /// id type and something else (that is incompatible with it). For example, /// "id " = "Foo *", where "Foo *" doesn't implement the XXX protocol. IncompatibleObjCQualifiedId, /// IncompatibleObjCWeakRef - Assigning a weak-unavailable object to an /// object with __weak qualifier. IncompatibleObjCWeakRef, /// Incompatible - We reject this conversion outright, it is invalid to /// represent it in the AST. Incompatible }; /// DiagnoseAssignmentResult - Emit a diagnostic, if required, for the /// assignment conversion type specified by ConvTy. This returns true if the /// conversion was invalid or false if the conversion was accepted. bool DiagnoseAssignmentResult(AssignConvertType ConvTy, SourceLocation Loc, QualType DstType, QualType SrcType, Expr *SrcExpr, AssignmentAction Action, bool *Complained = nullptr); /// IsValueInFlagEnum - Determine if a value is allowed as part of a flag /// enum. If AllowMask is true, then we also allow the complement of a valid /// value, to be used as a mask. bool IsValueInFlagEnum(const EnumDecl *ED, const llvm::APInt &Val, bool AllowMask) const; /// DiagnoseAssignmentEnum - Warn if assignment to enum is a constant /// integer not in the range of enum values. void DiagnoseAssignmentEnum(QualType DstType, QualType SrcType, Expr *SrcExpr); /// CheckAssignmentConstraints - Perform type checking for assignment, /// argument passing, variable initialization, and function return values. /// C99 6.5.16. AssignConvertType CheckAssignmentConstraints(SourceLocation Loc, QualType LHSType, QualType RHSType); /// Check assignment constraints and optionally prepare for a conversion of /// the RHS to the LHS type. The conversion is prepared for if ConvertRHS /// is true. AssignConvertType CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS, CastKind &Kind, bool ConvertRHS = true); /// Check assignment constraints for an assignment of RHS to LHSType. /// /// \param LHSType The destination type for the assignment. /// \param RHS The source expression for the assignment. /// \param Diagnose If \c true, diagnostics may be produced when checking /// for assignability. If a diagnostic is produced, \p RHS will be /// set to ExprError(). Note that this function may still return /// without producing a diagnostic, even for an invalid assignment. /// \param DiagnoseCFAudited If \c true, the target is a function parameter /// in an audited Core Foundation API and does not need to be checked /// for ARC retain issues. /// \param ConvertRHS If \c true, \p RHS will be updated to model the /// conversions necessary to perform the assignment. If \c false, /// \p Diagnose must also be \c false. AssignConvertType CheckSingleAssignmentConstraints( QualType LHSType, ExprResult &RHS, bool Diagnose = true, bool DiagnoseCFAudited = false, bool ConvertRHS = true); // If the lhs type is a transparent union, check whether we // can initialize the transparent union with the given expression. AssignConvertType CheckTransparentUnionArgumentConstraints(QualType ArgType, ExprResult &RHS); bool IsStringLiteralToNonConstPointerConversion(Expr *From, QualType ToType); bool CheckExceptionSpecCompatibility(Expr *From, QualType ToType); ExprResult PerformImplicitConversion(Expr *From, QualType ToType, AssignmentAction Action, bool AllowExplicit = false); ExprResult PerformImplicitConversion(Expr *From, QualType ToType, AssignmentAction Action, bool AllowExplicit, ImplicitConversionSequence& ICS); ExprResult PerformImplicitConversion(Expr *From, QualType ToType, const ImplicitConversionSequence& ICS, AssignmentAction Action, CheckedConversionKind CCK = CCK_ImplicitConversion); ExprResult PerformImplicitConversion(Expr *From, QualType ToType, const StandardConversionSequence& SCS, AssignmentAction Action, CheckedConversionKind CCK); ExprResult PerformQualificationConversion( Expr *E, QualType Ty, ExprValueKind VK = VK_RValue, CheckedConversionKind CCK = CCK_ImplicitConversion); /// the following "Check" methods will return a valid/converted QualType /// or a null QualType (indicating an error diagnostic was issued). /// type checking binary operators (subroutines of CreateBuiltinBinOp). QualType InvalidOperands(SourceLocation Loc, ExprResult &LHS, ExprResult &RHS); QualType InvalidLogicalVectorOperands(SourceLocation Loc, ExprResult &LHS, ExprResult &RHS); QualType CheckPointerToMemberOperands( // C++ 5.5 ExprResult &LHS, ExprResult &RHS, ExprValueKind &VK, SourceLocation OpLoc, bool isIndirect); QualType CheckMultiplyDivideOperands( // C99 6.5.5 ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, bool IsCompAssign, bool IsDivide); QualType CheckRemainderOperands( // C99 6.5.5 ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, bool IsCompAssign = false); QualType CheckAdditionOperands( // C99 6.5.6 ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, BinaryOperatorKind Opc, QualType* CompLHSTy = nullptr); QualType CheckSubtractionOperands( // C99 6.5.6 ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, QualType* CompLHSTy = nullptr); QualType CheckShiftOperands( // C99 6.5.7 ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, BinaryOperatorKind Opc, bool IsCompAssign = false); void CheckPtrComparisonWithNullChar(ExprResult &E, ExprResult &NullE); QualType CheckCompareOperands( // C99 6.5.8/9 ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, BinaryOperatorKind Opc); QualType CheckBitwiseOperands( // C99 6.5.[10...12] ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, BinaryOperatorKind Opc); QualType CheckLogicalOperands( // C99 6.5.[13,14] ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, BinaryOperatorKind Opc); // CheckAssignmentOperands is used for both simple and compound assignment. // For simple assignment, pass both expressions and a null converted type. // For compound assignment, pass both expressions and the converted type. QualType CheckAssignmentOperands( // C99 6.5.16.[1,2] Expr *LHSExpr, ExprResult &RHS, SourceLocation Loc, QualType CompoundType); ExprResult checkPseudoObjectIncDec(Scope *S, SourceLocation OpLoc, UnaryOperatorKind Opcode, Expr *Op); ExprResult checkPseudoObjectAssignment(Scope *S, SourceLocation OpLoc, BinaryOperatorKind Opcode, Expr *LHS, Expr *RHS); ExprResult checkPseudoObjectRValue(Expr *E); Expr *recreateSyntacticForm(PseudoObjectExpr *E); QualType CheckConditionalOperands( // C99 6.5.15 ExprResult &Cond, ExprResult &LHS, ExprResult &RHS, ExprValueKind &VK, ExprObjectKind &OK, SourceLocation QuestionLoc); QualType CXXCheckConditionalOperands( // C++ 5.16 ExprResult &cond, ExprResult &lhs, ExprResult &rhs, ExprValueKind &VK, ExprObjectKind &OK, SourceLocation questionLoc); QualType CheckGNUVectorConditionalTypes(ExprResult &Cond, ExprResult &LHS, ExprResult &RHS, SourceLocation QuestionLoc); QualType FindCompositePointerType(SourceLocation Loc, Expr *&E1, Expr *&E2, bool ConvertArgs = true); QualType FindCompositePointerType(SourceLocation Loc, ExprResult &E1, ExprResult &E2, bool ConvertArgs = true) { Expr *E1Tmp = E1.get(), *E2Tmp = E2.get(); QualType Composite = FindCompositePointerType(Loc, E1Tmp, E2Tmp, ConvertArgs); E1 = E1Tmp; E2 = E2Tmp; return Composite; } QualType FindCompositeObjCPointerType(ExprResult &LHS, ExprResult &RHS, SourceLocation QuestionLoc); bool DiagnoseConditionalForNull(Expr *LHSExpr, Expr *RHSExpr, SourceLocation QuestionLoc); void DiagnoseAlwaysNonNullPointer(Expr *E, Expr::NullPointerConstantKind NullType, bool IsEqual, SourceRange Range); /// type checking for vector binary operators. QualType CheckVectorOperands(ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, bool IsCompAssign, bool AllowBothBool, bool AllowBoolConversion); QualType GetSignedVectorType(QualType V); QualType CheckVectorCompareOperands(ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, BinaryOperatorKind Opc); QualType CheckVectorLogicalOperands(ExprResult &LHS, ExprResult &RHS, SourceLocation Loc); bool areLaxCompatibleVectorTypes(QualType srcType, QualType destType); bool isLaxVectorConversion(QualType srcType, QualType destType); /// type checking declaration initializers (C99 6.7.8) bool CheckForConstantInitializer(Expr *e, QualType t); // type checking C++ declaration initializers (C++ [dcl.init]). /// ReferenceCompareResult - Expresses the result of comparing two /// types (cv1 T1 and cv2 T2) to determine their compatibility for the /// purposes of initialization by reference (C++ [dcl.init.ref]p4). enum ReferenceCompareResult { /// Ref_Incompatible - The two types are incompatible, so direct /// reference binding is not possible. Ref_Incompatible = 0, /// Ref_Related - The two types are reference-related, which means /// that their unqualified forms (T1 and T2) are either the same /// or T1 is a base class of T2. Ref_Related, /// Ref_Compatible - The two types are reference-compatible. Ref_Compatible }; // Fake up a scoped enumeration that still contextually converts to bool. struct ReferenceConversionsScope { /// The conversions that would be performed on an lvalue of type T2 when /// binding a reference of type T1 to it, as determined when evaluating /// whether T1 is reference-compatible with T2. enum ReferenceConversions { Qualification = 0x1, NestedQualification = 0x2, Function = 0x4, DerivedToBase = 0x8, ObjC = 0x10, ObjCLifetime = 0x20, LLVM_MARK_AS_BITMASK_ENUM(/*LargestValue=*/ObjCLifetime) }; }; using ReferenceConversions = ReferenceConversionsScope::ReferenceConversions; ReferenceCompareResult CompareReferenceRelationship(SourceLocation Loc, QualType T1, QualType T2, ReferenceConversions *Conv = nullptr); ExprResult checkUnknownAnyCast(SourceRange TypeRange, QualType CastType, Expr *CastExpr, CastKind &CastKind, ExprValueKind &VK, CXXCastPath &Path); /// Force an expression with unknown-type to an expression of the /// given type. ExprResult forceUnknownAnyToType(Expr *E, QualType ToType); /// Type-check an expression that's being passed to an /// __unknown_anytype parameter. ExprResult checkUnknownAnyArg(SourceLocation callLoc, Expr *result, QualType ¶mType); // CheckVectorCast - check type constraints for vectors. // Since vectors are an extension, there are no C standard reference for this. // We allow casting between vectors and integer datatypes of the same size. // returns true if the cast is invalid bool CheckVectorCast(SourceRange R, QualType VectorTy, QualType Ty, CastKind &Kind); /// Prepare `SplattedExpr` for a vector splat operation, adding /// implicit casts if necessary. ExprResult prepareVectorSplat(QualType VectorTy, Expr *SplattedExpr); // CheckExtVectorCast - check type constraints for extended vectors. // Since vectors are an extension, there are no C standard reference for this. // We allow casting between vectors and integer datatypes of the same size, // or vectors and the element type of that vector. // returns the cast expr ExprResult CheckExtVectorCast(SourceRange R, QualType DestTy, Expr *CastExpr, CastKind &Kind); ExprResult BuildCXXFunctionalCastExpr(TypeSourceInfo *TInfo, QualType Type, SourceLocation LParenLoc, Expr *CastExpr, SourceLocation RParenLoc); enum ARCConversionResult { ACR_okay, ACR_unbridged, ACR_error }; /// Checks for invalid conversions and casts between /// retainable pointers and other pointer kinds for ARC and Weak. ARCConversionResult CheckObjCConversion(SourceRange castRange, QualType castType, Expr *&op, CheckedConversionKind CCK, bool Diagnose = true, bool DiagnoseCFAudited = false, BinaryOperatorKind Opc = BO_PtrMemD ); Expr *stripARCUnbridgedCast(Expr *e); void diagnoseARCUnbridgedCast(Expr *e); bool CheckObjCARCUnavailableWeakConversion(QualType castType, QualType ExprType); /// checkRetainCycles - Check whether an Objective-C message send /// might create an obvious retain cycle. void checkRetainCycles(ObjCMessageExpr *msg); void checkRetainCycles(Expr *receiver, Expr *argument); void checkRetainCycles(VarDecl *Var, Expr *Init); /// checkUnsafeAssigns - Check whether +1 expr is being assigned /// to weak/__unsafe_unretained type. bool checkUnsafeAssigns(SourceLocation Loc, QualType LHS, Expr *RHS); /// checkUnsafeExprAssigns - Check whether +1 expr is being assigned /// to weak/__unsafe_unretained expression. void checkUnsafeExprAssigns(SourceLocation Loc, Expr *LHS, Expr *RHS); /// CheckMessageArgumentTypes - Check types in an Obj-C message send. /// \param Method - May be null. /// \param [out] ReturnType - The return type of the send. /// \return true iff there were any incompatible types. bool CheckMessageArgumentTypes(const Expr *Receiver, QualType ReceiverType, MultiExprArg Args, Selector Sel, ArrayRef SelectorLocs, ObjCMethodDecl *Method, bool isClassMessage, bool isSuperMessage, SourceLocation lbrac, SourceLocation rbrac, SourceRange RecRange, QualType &ReturnType, ExprValueKind &VK); /// Determine the result of a message send expression based on /// the type of the receiver, the method expected to receive the message, /// and the form of the message send. QualType getMessageSendResultType(const Expr *Receiver, QualType ReceiverType, ObjCMethodDecl *Method, bool isClassMessage, bool isSuperMessage); /// If the given expression involves a message send to a method /// with a related result type, emit a note describing what happened. void EmitRelatedResultTypeNote(const Expr *E); /// Given that we had incompatible pointer types in a return /// statement, check whether we're in a method with a related result /// type, and if so, emit a note describing what happened. void EmitRelatedResultTypeNoteForReturn(QualType destType); class ConditionResult { Decl *ConditionVar; FullExprArg Condition; bool Invalid; bool HasKnownValue; bool KnownValue; friend class Sema; ConditionResult(Sema &S, Decl *ConditionVar, FullExprArg Condition, bool IsConstexpr) : ConditionVar(ConditionVar), Condition(Condition), Invalid(false), HasKnownValue(IsConstexpr && Condition.get() && !Condition.get()->isValueDependent()), KnownValue(HasKnownValue && !!Condition.get()->EvaluateKnownConstInt(S.Context)) {} explicit ConditionResult(bool Invalid) : ConditionVar(nullptr), Condition(nullptr), Invalid(Invalid), HasKnownValue(false), KnownValue(false) {} public: ConditionResult() : ConditionResult(false) {} bool isInvalid() const { return Invalid; } std::pair get() const { return std::make_pair(cast_or_null(ConditionVar), Condition.get()); } llvm::Optional getKnownValue() const { if (!HasKnownValue) return None; return KnownValue; } }; static ConditionResult ConditionError() { return ConditionResult(true); } enum class ConditionKind { Boolean, ///< A boolean condition, from 'if', 'while', 'for', or 'do'. ConstexprIf, ///< A constant boolean condition from 'if constexpr'. Switch ///< An integral condition for a 'switch' statement. }; ConditionResult ActOnCondition(Scope *S, SourceLocation Loc, Expr *SubExpr, ConditionKind CK); ConditionResult ActOnConditionVariable(Decl *ConditionVar, SourceLocation StmtLoc, ConditionKind CK); DeclResult ActOnCXXConditionDeclaration(Scope *S, Declarator &D); ExprResult CheckConditionVariable(VarDecl *ConditionVar, SourceLocation StmtLoc, ConditionKind CK); ExprResult CheckSwitchCondition(SourceLocation SwitchLoc, Expr *Cond); /// CheckBooleanCondition - Diagnose problems involving the use of /// the given expression as a boolean condition (e.g. in an if /// statement). Also performs the standard function and array /// decays, possibly changing the input variable. /// /// \param Loc - A location associated with the condition, e.g. the /// 'if' keyword. /// \return true iff there were any errors ExprResult CheckBooleanCondition(SourceLocation Loc, Expr *E, bool IsConstexpr = false); /// ActOnExplicitBoolSpecifier - Build an ExplicitSpecifier from an expression /// found in an explicit(bool) specifier. ExplicitSpecifier ActOnExplicitBoolSpecifier(Expr *E); /// tryResolveExplicitSpecifier - Attempt to resolve the explict specifier. /// Returns true if the explicit specifier is now resolved. bool tryResolveExplicitSpecifier(ExplicitSpecifier &ExplicitSpec); /// DiagnoseAssignmentAsCondition - Given that an expression is /// being used as a boolean condition, warn if it's an assignment. void DiagnoseAssignmentAsCondition(Expr *E); /// Redundant parentheses over an equality comparison can indicate /// that the user intended an assignment used as condition. void DiagnoseEqualityWithExtraParens(ParenExpr *ParenE); /// CheckCXXBooleanCondition - Returns true if conversion to bool is invalid. ExprResult CheckCXXBooleanCondition(Expr *CondExpr, bool IsConstexpr = false); /// ConvertIntegerToTypeWarnOnOverflow - Convert the specified APInt to have /// the specified width and sign. If an overflow occurs, detect it and emit /// the specified diagnostic. void ConvertIntegerToTypeWarnOnOverflow(llvm::APSInt &OldVal, unsigned NewWidth, bool NewSign, SourceLocation Loc, unsigned DiagID); /// Checks that the Objective-C declaration is declared in the global scope. /// Emits an error and marks the declaration as invalid if it's not declared /// in the global scope. bool CheckObjCDeclScope(Decl *D); /// Abstract base class used for diagnosing integer constant /// expression violations. class VerifyICEDiagnoser { public: bool Suppress; VerifyICEDiagnoser(bool Suppress = false) : Suppress(Suppress) { } virtual void diagnoseNotICE(Sema &S, SourceLocation Loc, SourceRange SR) =0; virtual void diagnoseFold(Sema &S, SourceLocation Loc, SourceRange SR); virtual ~VerifyICEDiagnoser() { } }; /// VerifyIntegerConstantExpression - Verifies that an expression is an ICE, /// and reports the appropriate diagnostics. Returns false on success. /// Can optionally return the value of the expression. ExprResult VerifyIntegerConstantExpression(Expr *E, llvm::APSInt *Result, VerifyICEDiagnoser &Diagnoser, bool AllowFold = true); ExprResult VerifyIntegerConstantExpression(Expr *E, llvm::APSInt *Result, unsigned DiagID, bool AllowFold = true); ExprResult VerifyIntegerConstantExpression(Expr *E, llvm::APSInt *Result = nullptr); /// VerifyBitField - verifies that a bit field expression is an ICE and has /// the correct width, and that the field type is valid. /// Returns false on success. /// Can optionally return whether the bit-field is of width 0 ExprResult VerifyBitField(SourceLocation FieldLoc, IdentifierInfo *FieldName, QualType FieldTy, bool IsMsStruct, Expr *BitWidth, bool *ZeroWidth = nullptr); private: unsigned ForceCUDAHostDeviceDepth = 0; public: /// Increments our count of the number of times we've seen a pragma forcing /// functions to be __host__ __device__. So long as this count is greater /// than zero, all functions encountered will be __host__ __device__. void PushForceCUDAHostDevice(); /// Decrements our count of the number of times we've seen a pragma forcing /// functions to be __host__ __device__. Returns false if the count is 0 /// before incrementing, so you can emit an error. bool PopForceCUDAHostDevice(); /// Diagnostics that are emitted only if we discover that the given function /// must be codegen'ed. Because handling these correctly adds overhead to /// compilation, this is currently only enabled for CUDA compilations. llvm::DenseMap, std::vector> DeviceDeferredDiags; /// A pair of a canonical FunctionDecl and a SourceLocation. When used as the /// key in a hashtable, both the FD and location are hashed. struct FunctionDeclAndLoc { CanonicalDeclPtr FD; SourceLocation Loc; }; /// FunctionDecls and SourceLocations for which CheckCUDACall has emitted a /// (maybe deferred) "bad call" diagnostic. We use this to avoid emitting the /// same deferred diag twice. llvm::DenseSet LocsWithCUDACallDiags; /// An inverse call graph, mapping known-emitted functions to one of their /// known-emitted callers (plus the location of the call). /// /// Functions that we can tell a priori must be emitted aren't added to this /// map. llvm::DenseMap, /* Caller = */ FunctionDeclAndLoc> DeviceKnownEmittedFns; /// A partial call graph maintained during CUDA/OpenMP device code compilation /// to support deferred diagnostics. /// /// Functions are only added here if, at the time they're considered, they are /// not known-emitted. As soon as we discover that a function is /// known-emitted, we remove it and everything it transitively calls from this /// set and add those functions to DeviceKnownEmittedFns. llvm::DenseMap, /* Callees = */ llvm::MapVector, SourceLocation>> DeviceCallGraph; /// Diagnostic builder for CUDA/OpenMP devices errors which may or may not be /// deferred. /// /// In CUDA, there exist constructs (e.g. variable-length arrays, try/catch) /// which are not allowed to appear inside __device__ functions and are /// allowed to appear in __host__ __device__ functions only if the host+device /// function is never codegen'ed. /// /// To handle this, we use the notion of "deferred diagnostics", where we /// attach a diagnostic to a FunctionDecl that's emitted iff it's codegen'ed. /// /// This class lets you emit either a regular diagnostic, a deferred /// diagnostic, or no diagnostic at all, according to an argument you pass to /// its constructor, thus simplifying the process of creating these "maybe /// deferred" diagnostics. class DeviceDiagBuilder { public: enum Kind { /// Emit no diagnostics. K_Nop, /// Emit the diagnostic immediately (i.e., behave like Sema::Diag()). K_Immediate, /// Emit the diagnostic immediately, and, if it's a warning or error, also /// emit a call stack showing how this function can be reached by an a /// priori known-emitted function. K_ImmediateWithCallStack, /// Create a deferred diagnostic, which is emitted only if the function /// it's attached to is codegen'ed. Also emit a call stack as with /// K_ImmediateWithCallStack. K_Deferred }; DeviceDiagBuilder(Kind K, SourceLocation Loc, unsigned DiagID, FunctionDecl *Fn, Sema &S); DeviceDiagBuilder(DeviceDiagBuilder &&D); DeviceDiagBuilder(const DeviceDiagBuilder &) = default; ~DeviceDiagBuilder(); /// Convertible to bool: True if we immediately emitted an error, false if /// we didn't emit an error or we created a deferred error. /// /// Example usage: /// /// if (DeviceDiagBuilder(...) << foo << bar) /// return ExprError(); /// /// But see CUDADiagIfDeviceCode() and CUDADiagIfHostCode() -- you probably /// want to use these instead of creating a DeviceDiagBuilder yourself. operator bool() const { return ImmediateDiag.hasValue(); } template friend const DeviceDiagBuilder &operator<<(const DeviceDiagBuilder &Diag, const T &Value) { if (Diag.ImmediateDiag.hasValue()) *Diag.ImmediateDiag << Value; else if (Diag.PartialDiagId.hasValue()) Diag.S.DeviceDeferredDiags[Diag.Fn][*Diag.PartialDiagId].second << Value; return Diag; } private: Sema &S; SourceLocation Loc; unsigned DiagID; FunctionDecl *Fn; bool ShowCallStack; // Invariant: At most one of these Optionals has a value. // FIXME: Switch these to a Variant once that exists. llvm::Optional ImmediateDiag; llvm::Optional PartialDiagId; }; /// Indicate that this function (and thus everything it transtively calls) /// will be codegen'ed, and emit any deferred diagnostics on this function and /// its (transitive) callees. void markKnownEmitted( Sema &S, FunctionDecl *OrigCaller, FunctionDecl *OrigCallee, SourceLocation OrigLoc, const llvm::function_ref IsKnownEmitted); /// Creates a DeviceDiagBuilder that emits the diagnostic if the current context /// is "used as device code". /// /// - If CurContext is a __host__ function, does not emit any diagnostics. /// - If CurContext is a __device__ or __global__ function, emits the /// diagnostics immediately. /// - If CurContext is a __host__ __device__ function and we are compiling for /// the device, creates a diagnostic which is emitted if and when we realize /// that the function will be codegen'ed. /// /// Example usage: /// /// // Variable-length arrays are not allowed in CUDA device code. /// if (CUDADiagIfDeviceCode(Loc, diag::err_cuda_vla) << CurrentCUDATarget()) /// return ExprError(); /// // Otherwise, continue parsing as normal. DeviceDiagBuilder CUDADiagIfDeviceCode(SourceLocation Loc, unsigned DiagID); /// Creates a DeviceDiagBuilder that emits the diagnostic if the current context /// is "used as host code". /// /// Same as CUDADiagIfDeviceCode, with "host" and "device" switched. DeviceDiagBuilder CUDADiagIfHostCode(SourceLocation Loc, unsigned DiagID); /// Creates a DeviceDiagBuilder that emits the diagnostic if the current /// context is "used as device code". /// /// - If CurContext is a `declare target` function or it is known that the /// function is emitted for the device, emits the diagnostics immediately. /// - If CurContext is a non-`declare target` function and we are compiling /// for the device, creates a diagnostic which is emitted if and when we /// realize that the function will be codegen'ed. /// /// Example usage: /// /// // Variable-length arrays are not allowed in NVPTX device code. /// if (diagIfOpenMPDeviceCode(Loc, diag::err_vla_unsupported)) /// return ExprError(); /// // Otherwise, continue parsing as normal. DeviceDiagBuilder diagIfOpenMPDeviceCode(SourceLocation Loc, unsigned DiagID); /// Creates a DeviceDiagBuilder that emits the diagnostic if the current /// context is "used as host code". /// /// - If CurContext is a `declare target` function or it is known that the /// function is emitted for the host, emits the diagnostics immediately. /// - If CurContext is a non-host function, just ignore it. /// /// Example usage: /// /// // Variable-length arrays are not allowed in NVPTX device code. /// if (diagIfOpenMPHostode(Loc, diag::err_vla_unsupported)) /// return ExprError(); /// // Otherwise, continue parsing as normal. DeviceDiagBuilder diagIfOpenMPHostCode(SourceLocation Loc, unsigned DiagID); DeviceDiagBuilder targetDiag(SourceLocation Loc, unsigned DiagID); enum CUDAFunctionTarget { CFT_Device, CFT_Global, CFT_Host, CFT_HostDevice, CFT_InvalidTarget }; /// Determines whether the given function is a CUDA device/host/kernel/etc. /// function. /// /// Use this rather than examining the function's attributes yourself -- you /// will get it wrong. Returns CFT_Host if D is null. CUDAFunctionTarget IdentifyCUDATarget(const FunctionDecl *D, bool IgnoreImplicitHDAttr = false); CUDAFunctionTarget IdentifyCUDATarget(const ParsedAttributesView &Attrs); /// Gets the CUDA target for the current context. CUDAFunctionTarget CurrentCUDATarget() { return IdentifyCUDATarget(dyn_cast(CurContext)); } // CUDA function call preference. Must be ordered numerically from // worst to best. enum CUDAFunctionPreference { CFP_Never, // Invalid caller/callee combination. CFP_WrongSide, // Calls from host-device to host or device // function that do not match current compilation // mode. CFP_HostDevice, // Any calls to host/device functions. CFP_SameSide, // Calls from host-device to host or device // function matching current compilation mode. CFP_Native, // host-to-host or device-to-device calls. }; /// Identifies relative preference of a given Caller/Callee /// combination, based on their host/device attributes. /// \param Caller function which needs address of \p Callee. /// nullptr in case of global context. /// \param Callee target function /// /// \returns preference value for particular Caller/Callee combination. CUDAFunctionPreference IdentifyCUDAPreference(const FunctionDecl *Caller, const FunctionDecl *Callee); /// Determines whether Caller may invoke Callee, based on their CUDA /// host/device attributes. Returns false if the call is not allowed. /// /// Note: Will return true for CFP_WrongSide calls. These may appear in /// semantically correct CUDA programs, but only if they're never codegen'ed. bool IsAllowedCUDACall(const FunctionDecl *Caller, const FunctionDecl *Callee) { return IdentifyCUDAPreference(Caller, Callee) != CFP_Never; } /// May add implicit CUDAHostAttr and CUDADeviceAttr attributes to FD, /// depending on FD and the current compilation settings. void maybeAddCUDAHostDeviceAttrs(FunctionDecl *FD, const LookupResult &Previous); public: /// Check whether we're allowed to call Callee from the current context. /// /// - If the call is never allowed in a semantically-correct program /// (CFP_Never), emits an error and returns false. /// /// - If the call is allowed in semantically-correct programs, but only if /// it's never codegen'ed (CFP_WrongSide), creates a deferred diagnostic to /// be emitted if and when the caller is codegen'ed, and returns true. /// /// Will only create deferred diagnostics for a given SourceLocation once, /// so you can safely call this multiple times without generating duplicate /// deferred errors. /// /// - Otherwise, returns true without emitting any diagnostics. bool CheckCUDACall(SourceLocation Loc, FunctionDecl *Callee); /// Set __device__ or __host__ __device__ attributes on the given lambda /// operator() method. /// /// CUDA lambdas declared inside __device__ or __global__ functions inherit /// the __device__ attribute. Similarly, lambdas inside __host__ __device__ /// functions become __host__ __device__ themselves. void CUDASetLambdaAttrs(CXXMethodDecl *Method); /// Finds a function in \p Matches with highest calling priority /// from \p Caller context and erases all functions with lower /// calling priority. void EraseUnwantedCUDAMatches( const FunctionDecl *Caller, SmallVectorImpl> &Matches); /// Given a implicit special member, infer its CUDA target from the /// calls it needs to make to underlying base/field special members. /// \param ClassDecl the class for which the member is being created. /// \param CSM the kind of special member. /// \param MemberDecl the special member itself. /// \param ConstRHS true if this is a copy operation with a const object on /// its RHS. /// \param Diagnose true if this call should emit diagnostics. /// \return true if there was an error inferring. /// The result of this call is implicit CUDA target attribute(s) attached to /// the member declaration. bool inferCUDATargetForImplicitSpecialMember(CXXRecordDecl *ClassDecl, CXXSpecialMember CSM, CXXMethodDecl *MemberDecl, bool ConstRHS, bool Diagnose); /// \return true if \p CD can be considered empty according to CUDA /// (E.2.3.1 in CUDA 7.5 Programming guide). bool isEmptyCudaConstructor(SourceLocation Loc, CXXConstructorDecl *CD); bool isEmptyCudaDestructor(SourceLocation Loc, CXXDestructorDecl *CD); // \brief Checks that initializers of \p Var satisfy CUDA restrictions. In // case of error emits appropriate diagnostic and invalidates \p Var. // // \details CUDA allows only empty constructors as initializers for global // variables (see E.2.3.1, CUDA 7.5). The same restriction also applies to all // __shared__ variables whether they are local or not (they all are implicitly // static in CUDA). One exception is that CUDA allows constant initializers // for __constant__ and __device__ variables. void checkAllowedCUDAInitializer(VarDecl *VD); /// Check whether NewFD is a valid overload for CUDA. Emits /// diagnostics and invalidates NewFD if not. void checkCUDATargetOverload(FunctionDecl *NewFD, const LookupResult &Previous); /// Copies target attributes from the template TD to the function FD. void inheritCUDATargetAttrs(FunctionDecl *FD, const FunctionTemplateDecl &TD); /// Returns the name of the launch configuration function. This is the name /// of the function that will be called to configure kernel call, with the /// parameters specified via <<<>>>. std::string getCudaConfigureFuncName() const; /// \name Code completion //@{ /// Describes the context in which code completion occurs. enum ParserCompletionContext { /// Code completion occurs at top-level or namespace context. PCC_Namespace, /// Code completion occurs within a class, struct, or union. PCC_Class, /// Code completion occurs within an Objective-C interface, protocol, /// or category. PCC_ObjCInterface, /// Code completion occurs within an Objective-C implementation or /// category implementation PCC_ObjCImplementation, /// Code completion occurs within the list of instance variables /// in an Objective-C interface, protocol, category, or implementation. PCC_ObjCInstanceVariableList, /// Code completion occurs following one or more template /// headers. PCC_Template, /// Code completion occurs following one or more template /// headers within a class. PCC_MemberTemplate, /// Code completion occurs within an expression. PCC_Expression, /// Code completion occurs within a statement, which may /// also be an expression or a declaration. PCC_Statement, /// Code completion occurs at the beginning of the /// initialization statement (or expression) in a for loop. PCC_ForInit, /// Code completion occurs within the condition of an if, /// while, switch, or for statement. PCC_Condition, /// Code completion occurs within the body of a function on a /// recovery path, where we do not have a specific handle on our position /// in the grammar. PCC_RecoveryInFunction, /// Code completion occurs where only a type is permitted. PCC_Type, /// Code completion occurs in a parenthesized expression, which /// might also be a type cast. PCC_ParenthesizedExpression, /// Code completion occurs within a sequence of declaration /// specifiers within a function, method, or block. PCC_LocalDeclarationSpecifiers }; void CodeCompleteModuleImport(SourceLocation ImportLoc, ModuleIdPath Path); void CodeCompleteOrdinaryName(Scope *S, ParserCompletionContext CompletionContext); void CodeCompleteDeclSpec(Scope *S, DeclSpec &DS, bool AllowNonIdentifiers, bool AllowNestedNameSpecifiers); struct CodeCompleteExpressionData; void CodeCompleteExpression(Scope *S, const CodeCompleteExpressionData &Data); void CodeCompleteExpression(Scope *S, QualType PreferredType, bool IsParenthesized = false); void CodeCompleteMemberReferenceExpr(Scope *S, Expr *Base, Expr *OtherOpBase, SourceLocation OpLoc, bool IsArrow, bool IsBaseExprStatement, QualType PreferredType); void CodeCompletePostfixExpression(Scope *S, ExprResult LHS, QualType PreferredType); void CodeCompleteTag(Scope *S, unsigned TagSpec); void CodeCompleteTypeQualifiers(DeclSpec &DS); void CodeCompleteFunctionQualifiers(DeclSpec &DS, Declarator &D, const VirtSpecifiers *VS = nullptr); void CodeCompleteBracketDeclarator(Scope *S); void CodeCompleteCase(Scope *S); /// Reports signatures for a call to CodeCompleteConsumer and returns the /// preferred type for the current argument. Returned type can be null. QualType ProduceCallSignatureHelp(Scope *S, Expr *Fn, ArrayRef Args, SourceLocation OpenParLoc); QualType ProduceConstructorSignatureHelp(Scope *S, QualType Type, SourceLocation Loc, ArrayRef Args, SourceLocation OpenParLoc); QualType ProduceCtorInitMemberSignatureHelp(Scope *S, Decl *ConstructorDecl, CXXScopeSpec SS, ParsedType TemplateTypeTy, ArrayRef ArgExprs, IdentifierInfo *II, SourceLocation OpenParLoc); void CodeCompleteInitializer(Scope *S, Decl *D); void CodeCompleteAfterIf(Scope *S); void CodeCompleteQualifiedId(Scope *S, CXXScopeSpec &SS, bool EnteringContext, bool IsUsingDeclaration, QualType BaseType, QualType PreferredType); void CodeCompleteUsing(Scope *S); void CodeCompleteUsingDirective(Scope *S); void CodeCompleteNamespaceDecl(Scope *S); void CodeCompleteNamespaceAliasDecl(Scope *S); void CodeCompleteOperatorName(Scope *S); void CodeCompleteConstructorInitializer( Decl *Constructor, ArrayRef Initializers); void CodeCompleteLambdaIntroducer(Scope *S, LambdaIntroducer &Intro, bool AfterAmpersand); void CodeCompleteObjCAtDirective(Scope *S); void CodeCompleteObjCAtVisibility(Scope *S); void CodeCompleteObjCAtStatement(Scope *S); void CodeCompleteObjCAtExpression(Scope *S); void CodeCompleteObjCPropertyFlags(Scope *S, ObjCDeclSpec &ODS); void CodeCompleteObjCPropertyGetter(Scope *S); void CodeCompleteObjCPropertySetter(Scope *S); void CodeCompleteObjCPassingType(Scope *S, ObjCDeclSpec &DS, bool IsParameter); void CodeCompleteObjCMessageReceiver(Scope *S); void CodeCompleteObjCSuperMessage(Scope *S, SourceLocation SuperLoc, ArrayRef SelIdents, bool AtArgumentExpression); void CodeCompleteObjCClassMessage(Scope *S, ParsedType Receiver, ArrayRef SelIdents, bool AtArgumentExpression, bool IsSuper = false); void CodeCompleteObjCInstanceMessage(Scope *S, Expr *Receiver, ArrayRef SelIdents, bool AtArgumentExpression, ObjCInterfaceDecl *Super = nullptr); void CodeCompleteObjCForCollection(Scope *S, DeclGroupPtrTy IterationVar); void CodeCompleteObjCSelector(Scope *S, ArrayRef SelIdents); void CodeCompleteObjCProtocolReferences( ArrayRef Protocols); void CodeCompleteObjCProtocolDecl(Scope *S); void CodeCompleteObjCInterfaceDecl(Scope *S); void CodeCompleteObjCSuperclass(Scope *S, IdentifierInfo *ClassName, SourceLocation ClassNameLoc); void CodeCompleteObjCImplementationDecl(Scope *S); void CodeCompleteObjCInterfaceCategory(Scope *S, IdentifierInfo *ClassName, SourceLocation ClassNameLoc); void CodeCompleteObjCImplementationCategory(Scope *S, IdentifierInfo *ClassName, SourceLocation ClassNameLoc); void CodeCompleteObjCPropertyDefinition(Scope *S); void CodeCompleteObjCPropertySynthesizeIvar(Scope *S, IdentifierInfo *PropertyName); void CodeCompleteObjCMethodDecl(Scope *S, Optional IsInstanceMethod, ParsedType ReturnType); void CodeCompleteObjCMethodDeclSelector(Scope *S, bool IsInstanceMethod, bool AtParameterName, ParsedType ReturnType, ArrayRef SelIdents); void CodeCompleteObjCClassPropertyRefExpr(Scope *S, IdentifierInfo &ClassName, SourceLocation ClassNameLoc, bool IsBaseExprStatement); void CodeCompletePreprocessorDirective(bool InConditional); void CodeCompleteInPreprocessorConditionalExclusion(Scope *S); void CodeCompletePreprocessorMacroName(bool IsDefinition); void CodeCompletePreprocessorExpression(); void CodeCompletePreprocessorMacroArgument(Scope *S, IdentifierInfo *Macro, MacroInfo *MacroInfo, unsigned Argument); void CodeCompleteIncludedFile(llvm::StringRef Dir, bool IsAngled); void CodeCompleteNaturalLanguage(); void CodeCompleteAvailabilityPlatformName(); void GatherGlobalCodeCompletions(CodeCompletionAllocator &Allocator, CodeCompletionTUInfo &CCTUInfo, SmallVectorImpl &Results); //@} //===--------------------------------------------------------------------===// // Extra semantic analysis beyond the C type system public: SourceLocation getLocationOfStringLiteralByte(const StringLiteral *SL, unsigned ByteNo) const; private: void CheckArrayAccess(const Expr *BaseExpr, const Expr *IndexExpr, const ArraySubscriptExpr *ASE=nullptr, bool AllowOnePastEnd=true, bool IndexNegated=false); void CheckArrayAccess(const Expr *E); // Used to grab the relevant information from a FormatAttr and a // FunctionDeclaration. struct FormatStringInfo { unsigned FormatIdx; unsigned FirstDataArg; bool HasVAListArg; }; static bool getFormatStringInfo(const FormatAttr *Format, bool IsCXXMember, FormatStringInfo *FSI); bool CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall, const FunctionProtoType *Proto); bool CheckObjCMethodCall(ObjCMethodDecl *Method, SourceLocation loc, ArrayRef Args); bool CheckPointerCall(NamedDecl *NDecl, CallExpr *TheCall, const FunctionProtoType *Proto); bool CheckOtherCall(CallExpr *TheCall, const FunctionProtoType *Proto); void CheckConstructorCall(FunctionDecl *FDecl, ArrayRef Args, const FunctionProtoType *Proto, SourceLocation Loc); void checkCall(NamedDecl *FDecl, const FunctionProtoType *Proto, const Expr *ThisArg, ArrayRef Args, bool IsMemberFunction, SourceLocation Loc, SourceRange Range, VariadicCallType CallType); bool CheckObjCString(Expr *Arg); ExprResult CheckOSLogFormatStringArg(Expr *Arg); ExprResult CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, CallExpr *TheCall); void checkFortifiedBuiltinMemoryFunction(FunctionDecl *FD, CallExpr *TheCall); bool CheckARMBuiltinExclusiveCall(unsigned BuiltinID, CallExpr *TheCall, unsigned MaxWidth); bool CheckNeonBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall); bool CheckMVEBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall); bool CheckARMBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall); bool CheckAArch64BuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall); bool CheckBPFBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall); bool CheckHexagonBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall); bool CheckHexagonBuiltinCpu(unsigned BuiltinID, CallExpr *TheCall); bool CheckHexagonBuiltinArgument(unsigned BuiltinID, CallExpr *TheCall); bool CheckMipsBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall); bool CheckMipsBuiltinCpu(unsigned BuiltinID, CallExpr *TheCall); bool CheckMipsBuiltinArgument(unsigned BuiltinID, CallExpr *TheCall); bool CheckSystemZBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall); bool CheckX86BuiltinRoundingOrSAE(unsigned BuiltinID, CallExpr *TheCall); bool CheckX86BuiltinGatherScatterScale(unsigned BuiltinID, CallExpr *TheCall); bool CheckX86BuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall); bool CheckPPCBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall); bool SemaBuiltinVAStart(unsigned BuiltinID, CallExpr *TheCall); bool SemaBuiltinVAStartARMMicrosoft(CallExpr *Call); bool SemaBuiltinUnorderedCompare(CallExpr *TheCall); bool SemaBuiltinFPClassification(CallExpr *TheCall, unsigned NumArgs); bool SemaBuiltinVSX(CallExpr *TheCall); bool SemaBuiltinOSLogFormat(CallExpr *TheCall); public: // Used by C++ template instantiation. ExprResult SemaBuiltinShuffleVector(CallExpr *TheCall); ExprResult SemaConvertVectorExpr(Expr *E, TypeSourceInfo *TInfo, SourceLocation BuiltinLoc, SourceLocation RParenLoc); private: bool SemaBuiltinPrefetch(CallExpr *TheCall); bool SemaBuiltinAllocaWithAlign(CallExpr *TheCall); bool SemaBuiltinAssume(CallExpr *TheCall); bool SemaBuiltinAssumeAligned(CallExpr *TheCall); bool SemaBuiltinLongjmp(CallExpr *TheCall); bool SemaBuiltinSetjmp(CallExpr *TheCall); ExprResult SemaBuiltinAtomicOverloaded(ExprResult TheCallResult); ExprResult SemaBuiltinNontemporalOverloaded(ExprResult TheCallResult); ExprResult SemaAtomicOpsOverloaded(ExprResult TheCallResult, AtomicExpr::AtomicOp Op); ExprResult SemaBuiltinOperatorNewDeleteOverloaded(ExprResult TheCallResult, bool IsDelete); bool SemaBuiltinConstantArg(CallExpr *TheCall, int ArgNum, llvm::APSInt &Result); bool SemaBuiltinConstantArgRange(CallExpr *TheCall, int ArgNum, int Low, int High, bool RangeIsError = true); bool SemaBuiltinConstantArgMultiple(CallExpr *TheCall, int ArgNum, unsigned Multiple); bool SemaBuiltinConstantArgPower2(CallExpr *TheCall, int ArgNum); bool SemaBuiltinConstantArgShiftedByte(CallExpr *TheCall, int ArgNum); bool SemaBuiltinConstantArgShiftedByteOrXXFF(CallExpr *TheCall, int ArgNum); bool SemaBuiltinARMSpecialReg(unsigned BuiltinID, CallExpr *TheCall, int ArgNum, unsigned ExpectedFieldNum, bool AllowName); bool SemaBuiltinARMMemoryTaggingCall(unsigned BuiltinID, CallExpr *TheCall); public: enum FormatStringType { FST_Scanf, FST_Printf, FST_NSString, FST_Strftime, FST_Strfmon, FST_Kprintf, FST_FreeBSDKPrintf, FST_OSTrace, FST_OSLog, FST_Unknown }; static FormatStringType GetFormatStringType(const FormatAttr *Format); bool FormatStringHasSArg(const StringLiteral *FExpr); static bool GetFormatNSStringIdx(const FormatAttr *Format, unsigned &Idx); private: bool CheckFormatArguments(const FormatAttr *Format, ArrayRef Args, bool IsCXXMember, VariadicCallType CallType, SourceLocation Loc, SourceRange Range, llvm::SmallBitVector &CheckedVarArgs); bool CheckFormatArguments(ArrayRef Args, bool HasVAListArg, unsigned format_idx, unsigned firstDataArg, FormatStringType Type, VariadicCallType CallType, SourceLocation Loc, SourceRange range, llvm::SmallBitVector &CheckedVarArgs); void CheckAbsoluteValueFunction(const CallExpr *Call, const FunctionDecl *FDecl); void CheckMaxUnsignedZero(const CallExpr *Call, const FunctionDecl *FDecl); void CheckMemaccessArguments(const CallExpr *Call, unsigned BId, IdentifierInfo *FnName); void CheckStrlcpycatArguments(const CallExpr *Call, IdentifierInfo *FnName); void CheckStrncatArguments(const CallExpr *Call, IdentifierInfo *FnName); void CheckReturnValExpr(Expr *RetValExp, QualType lhsType, SourceLocation ReturnLoc, bool isObjCMethod = false, const AttrVec *Attrs = nullptr, const FunctionDecl *FD = nullptr); public: void CheckFloatComparison(SourceLocation Loc, Expr *LHS, Expr *RHS); private: void CheckImplicitConversions(Expr *E, SourceLocation CC = SourceLocation()); void CheckBoolLikeConversion(Expr *E, SourceLocation CC); void CheckForIntOverflow(Expr *E); void CheckUnsequencedOperations(const Expr *E); /// Perform semantic checks on a completed expression. This will either /// be a full-expression or a default argument expression. void CheckCompletedExpr(Expr *E, SourceLocation CheckLoc = SourceLocation(), bool IsConstexpr = false); void CheckBitFieldInitialization(SourceLocation InitLoc, FieldDecl *Field, Expr *Init); /// Check if there is a field shadowing. void CheckShadowInheritedFields(const SourceLocation &Loc, DeclarationName FieldName, const CXXRecordDecl *RD, bool DeclIsField = true); /// Check if the given expression contains 'break' or 'continue' /// statement that produces control flow different from GCC. void CheckBreakContinueBinding(Expr *E); /// Check whether receiver is mutable ObjC container which /// attempts to add itself into the container void CheckObjCCircularContainer(ObjCMessageExpr *Message); void AnalyzeDeleteExprMismatch(const CXXDeleteExpr *DE); void AnalyzeDeleteExprMismatch(FieldDecl *Field, SourceLocation DeleteLoc, bool DeleteWasArrayForm); public: /// Register a magic integral constant to be used as a type tag. void RegisterTypeTagForDatatype(const IdentifierInfo *ArgumentKind, uint64_t MagicValue, QualType Type, bool LayoutCompatible, bool MustBeNull); struct TypeTagData { TypeTagData() {} TypeTagData(QualType Type, bool LayoutCompatible, bool MustBeNull) : Type(Type), LayoutCompatible(LayoutCompatible), MustBeNull(MustBeNull) {} QualType Type; /// If true, \c Type should be compared with other expression's types for /// layout-compatibility. unsigned LayoutCompatible : 1; unsigned MustBeNull : 1; }; /// A pair of ArgumentKind identifier and magic value. This uniquely /// identifies the magic value. typedef std::pair TypeTagMagicValue; private: /// A map from magic value to type information. std::unique_ptr> TypeTagForDatatypeMagicValues; /// Peform checks on a call of a function with argument_with_type_tag /// or pointer_with_type_tag attributes. void CheckArgumentWithTypeTag(const ArgumentWithTypeTagAttr *Attr, const ArrayRef ExprArgs, SourceLocation CallSiteLoc); /// Check if we are taking the address of a packed field /// as this may be a problem if the pointer value is dereferenced. void CheckAddressOfPackedMember(Expr *rhs); /// The parser's current scope. /// /// The parser maintains this state here. Scope *CurScope; mutable IdentifierInfo *Ident_super; mutable IdentifierInfo *Ident___float128; /// Nullability type specifiers. IdentifierInfo *Ident__Nonnull = nullptr; IdentifierInfo *Ident__Nullable = nullptr; IdentifierInfo *Ident__Null_unspecified = nullptr; IdentifierInfo *Ident_NSError = nullptr; /// The handler for the FileChanged preprocessor events. /// /// Used for diagnostics that implement custom semantic analysis for #include /// directives, like -Wpragma-pack. sema::SemaPPCallbacks *SemaPPCallbackHandler; protected: friend class Parser; friend class InitializationSequence; friend class ASTReader; friend class ASTDeclReader; friend class ASTWriter; public: /// Retrieve the keyword associated IdentifierInfo *getNullabilityKeyword(NullabilityKind nullability); /// The struct behind the CFErrorRef pointer. RecordDecl *CFError = nullptr; /// Retrieve the identifier "NSError". IdentifierInfo *getNSErrorIdent(); /// Retrieve the parser's current scope. /// /// This routine must only be used when it is certain that semantic analysis /// and the parser are in precisely the same context, which is not the case /// when, e.g., we are performing any kind of template instantiation. /// Therefore, the only safe places to use this scope are in the parser /// itself and in routines directly invoked from the parser and *never* from /// template substitution or instantiation. Scope *getCurScope() const { return CurScope; } void incrementMSManglingNumber() const { return CurScope->incrementMSManglingNumber(); } IdentifierInfo *getSuperIdentifier() const; IdentifierInfo *getFloat128Identifier() const; Decl *getObjCDeclContext() const; DeclContext *getCurLexicalContext() const { return OriginalLexicalContext ? OriginalLexicalContext : CurContext; } const DeclContext *getCurObjCLexicalContext() const { const DeclContext *DC = getCurLexicalContext(); // A category implicitly has the attribute of the interface. if (const ObjCCategoryDecl *CatD = dyn_cast(DC)) DC = CatD->getClassInterface(); return DC; } + + /// Determine the number of levels of enclosing template parameters. This is + /// only usable while parsing. Note that this does not include dependent + /// contexts in which no template parameters have yet been declared, such as + /// in a terse function template or generic lambda before the first 'auto' is + /// encountered. + unsigned getTemplateDepth(Scope *S) const; /// To be used for checking whether the arguments being passed to /// function exceeds the number of parameters expected for it. static bool TooManyArguments(size_t NumParams, size_t NumArgs, bool PartialOverloading = false) { // We check whether we're just after a comma in code-completion. if (NumArgs > 0 && PartialOverloading) return NumArgs + 1 > NumParams; // If so, we view as an extra argument. return NumArgs > NumParams; } // Emitting members of dllexported classes is delayed until the class // (including field initializers) is fully parsed. SmallVector DelayedDllExportClasses; SmallVector DelayedDllExportMemberFunctions; private: int ParsingClassDepth = 0; class SavePendingParsedClassStateRAII { public: SavePendingParsedClassStateRAII(Sema &S) : S(S) { swapSavedState(); } ~SavePendingParsedClassStateRAII() { assert(S.DelayedOverridingExceptionSpecChecks.empty() && "there shouldn't be any pending delayed exception spec checks"); assert(S.DelayedEquivalentExceptionSpecChecks.empty() && "there shouldn't be any pending delayed exception spec checks"); swapSavedState(); } private: Sema &S; decltype(DelayedOverridingExceptionSpecChecks) SavedOverridingExceptionSpecChecks; decltype(DelayedEquivalentExceptionSpecChecks) SavedEquivalentExceptionSpecChecks; void swapSavedState() { SavedOverridingExceptionSpecChecks.swap( S.DelayedOverridingExceptionSpecChecks); SavedEquivalentExceptionSpecChecks.swap( S.DelayedEquivalentExceptionSpecChecks); } }; /// Helper class that collects misaligned member designations and /// their location info for delayed diagnostics. struct MisalignedMember { Expr *E; RecordDecl *RD; ValueDecl *MD; CharUnits Alignment; MisalignedMember() : E(), RD(), MD(), Alignment() {} MisalignedMember(Expr *E, RecordDecl *RD, ValueDecl *MD, CharUnits Alignment) : E(E), RD(RD), MD(MD), Alignment(Alignment) {} explicit MisalignedMember(Expr *E) : MisalignedMember(E, nullptr, nullptr, CharUnits()) {} bool operator==(const MisalignedMember &m) { return this->E == m.E; } }; /// Small set of gathered accesses to potentially misaligned members /// due to the packed attribute. SmallVector MisalignedMembers; /// Adds an expression to the set of gathered misaligned members. void AddPotentialMisalignedMembers(Expr *E, RecordDecl *RD, ValueDecl *MD, CharUnits Alignment); public: /// Diagnoses the current set of gathered accesses. This typically /// happens at full expression level. The set is cleared after emitting the /// diagnostics. void DiagnoseMisalignedMembers(); /// This function checks if the expression is in the sef of potentially /// misaligned members and it is converted to some pointer type T with lower /// or equal alignment requirements. If so it removes it. This is used when /// we do not want to diagnose such misaligned access (e.g. in conversions to /// void*). void DiscardMisalignedMemberAddress(const Type *T, Expr *E); /// This function calls Action when it determines that E designates a /// misaligned member due to the packed attribute. This is used to emit /// local diagnostics like in reference binding. void RefersToMemberWithReducedAlignment( Expr *E, llvm::function_ref Action); /// Describes the reason a calling convention specification was ignored, used /// for diagnostics. enum class CallingConventionIgnoredReason { ForThisTarget = 0, VariadicFunction, ConstructorDestructor, BuiltinFunction }; }; /// RAII object that enters a new expression evaluation context. class EnterExpressionEvaluationContext { Sema &Actions; bool Entered = true; public: EnterExpressionEvaluationContext( Sema &Actions, Sema::ExpressionEvaluationContext NewContext, Decl *LambdaContextDecl = nullptr, Sema::ExpressionEvaluationContextRecord::ExpressionKind ExprContext = Sema::ExpressionEvaluationContextRecord::EK_Other, bool ShouldEnter = true) : Actions(Actions), Entered(ShouldEnter) { if (Entered) Actions.PushExpressionEvaluationContext(NewContext, LambdaContextDecl, ExprContext); } EnterExpressionEvaluationContext( Sema &Actions, Sema::ExpressionEvaluationContext NewContext, Sema::ReuseLambdaContextDecl_t, Sema::ExpressionEvaluationContextRecord::ExpressionKind ExprContext = Sema::ExpressionEvaluationContextRecord::EK_Other) : Actions(Actions) { Actions.PushExpressionEvaluationContext( NewContext, Sema::ReuseLambdaContextDecl, ExprContext); } enum InitListTag { InitList }; EnterExpressionEvaluationContext(Sema &Actions, InitListTag, bool ShouldEnter = true) : Actions(Actions), Entered(false) { // In C++11 onwards, narrowing checks are performed on the contents of // braced-init-lists, even when they occur within unevaluated operands. // Therefore we still need to instantiate constexpr functions used in such // a context. if (ShouldEnter && Actions.isUnevaluatedContext() && Actions.getLangOpts().CPlusPlus11) { Actions.PushExpressionEvaluationContext( Sema::ExpressionEvaluationContext::UnevaluatedList); Entered = true; } } ~EnterExpressionEvaluationContext() { if (Entered) Actions.PopExpressionEvaluationContext(); } }; DeductionFailureInfo MakeDeductionFailureInfo(ASTContext &Context, Sema::TemplateDeductionResult TDK, sema::TemplateDeductionInfo &Info); /// Contains a late templated function. /// Will be parsed at the end of the translation unit, used by Sema & Parser. struct LateParsedTemplate { CachedTokens Toks; /// The template function declaration to be late parsed. Decl *D; }; } // end namespace clang namespace llvm { // Hash a FunctionDeclAndLoc by looking at both its FunctionDecl and its // SourceLocation. template <> struct DenseMapInfo { using FunctionDeclAndLoc = clang::Sema::FunctionDeclAndLoc; using FDBaseInfo = DenseMapInfo>; static FunctionDeclAndLoc getEmptyKey() { return {FDBaseInfo::getEmptyKey(), clang::SourceLocation()}; } static FunctionDeclAndLoc getTombstoneKey() { return {FDBaseInfo::getTombstoneKey(), clang::SourceLocation()}; } static unsigned getHashValue(const FunctionDeclAndLoc &FDL) { return hash_combine(FDBaseInfo::getHashValue(FDL.FD), FDL.Loc.getRawEncoding()); } static bool isEqual(const FunctionDeclAndLoc &LHS, const FunctionDeclAndLoc &RHS) { return LHS.FD == RHS.FD && LHS.Loc == RHS.Loc; } }; } // namespace llvm #endif Index: vendor/llvm-project/release-10.x/clang/include/clang/Sema/Template.h =================================================================== --- vendor/llvm-project/release-10.x/clang/include/clang/Sema/Template.h (revision 359078) +++ vendor/llvm-project/release-10.x/clang/include/clang/Sema/Template.h (revision 359079) @@ -1,581 +1,591 @@ //===- SemaTemplate.h - C++ Templates ---------------------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception //===----------------------------------------------------------------------===// // // This file provides types used in the semantic analysis of C++ templates. // //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_SEMA_TEMPLATE_H #define LLVM_CLANG_SEMA_TEMPLATE_H #include "clang/AST/DeclTemplate.h" #include "clang/AST/DeclVisitor.h" #include "clang/AST/TemplateBase.h" #include "clang/AST/Type.h" #include "clang/Basic/LLVM.h" #include "clang/Sema/Sema.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/PointerUnion.h" #include "llvm/ADT/SmallVector.h" #include #include namespace clang { class ASTContext; class BindingDecl; class CXXMethodDecl; class Decl; class DeclaratorDecl; class DeclContext; class EnumDecl; class FunctionDecl; class NamedDecl; class ParmVarDecl; class TagDecl; class TypedefNameDecl; class TypeSourceInfo; class VarDecl; /// Data structure that captures multiple levels of template argument /// lists for use in template instantiation. /// /// Multiple levels of template arguments occur when instantiating the /// definitions of member templates. For example: /// /// \code /// template /// struct X { /// template /// struct Y { /// void f(); /// }; /// }; /// \endcode /// /// When instantiating X::Y<17>::f, the multi-level template argument /// list will contain a template argument list (int) at depth 0 and a /// template argument list (17) at depth 1. class MultiLevelTemplateArgumentList { /// The template argument list at a certain template depth using ArgList = ArrayRef; /// The template argument lists, stored from the innermost template /// argument list (first) to the outermost template argument list (last). SmallVector TemplateArgumentLists; /// The number of outer levels of template arguments that are not /// being substituted. unsigned NumRetainedOuterLevels = 0; public: /// Construct an empty set of template argument lists. MultiLevelTemplateArgumentList() = default; /// Construct a single-level template argument list. explicit MultiLevelTemplateArgumentList(const TemplateArgumentList &TemplateArgs) { addOuterTemplateArguments(&TemplateArgs); } /// Determine the number of levels in this template argument /// list. unsigned getNumLevels() const { return TemplateArgumentLists.size() + NumRetainedOuterLevels; } /// Determine the number of substituted levels in this template /// argument list. unsigned getNumSubstitutedLevels() const { return TemplateArgumentLists.size(); } + /// Determine how many of the \p OldDepth outermost template parameter + /// lists would be removed by substituting these arguments. + unsigned getNewDepth(unsigned OldDepth) const { + if (OldDepth < NumRetainedOuterLevels) + return OldDepth; + if (OldDepth < getNumLevels()) + return NumRetainedOuterLevels; + return OldDepth - TemplateArgumentLists.size(); + } + /// Retrieve the template argument at a given depth and index. const TemplateArgument &operator()(unsigned Depth, unsigned Index) const { assert(NumRetainedOuterLevels <= Depth && Depth < getNumLevels()); assert(Index < TemplateArgumentLists[getNumLevels() - Depth - 1].size()); return TemplateArgumentLists[getNumLevels() - Depth - 1][Index]; } /// Determine whether there is a non-NULL template argument at the /// given depth and index. /// /// There must exist a template argument list at the given depth. bool hasTemplateArgument(unsigned Depth, unsigned Index) const { assert(Depth < getNumLevels()); if (Depth < NumRetainedOuterLevels) return false; if (Index >= TemplateArgumentLists[getNumLevels() - Depth - 1].size()) return false; return !(*this)(Depth, Index).isNull(); } /// Clear out a specific template argument. void setArgument(unsigned Depth, unsigned Index, TemplateArgument Arg) { assert(NumRetainedOuterLevels <= Depth && Depth < getNumLevels()); assert(Index < TemplateArgumentLists[getNumLevels() - Depth - 1].size()); const_cast( TemplateArgumentLists[getNumLevels() - Depth - 1][Index]) = Arg; } /// Add a new outermost level to the multi-level template argument /// list. void addOuterTemplateArguments(const TemplateArgumentList *TemplateArgs) { addOuterTemplateArguments(ArgList(TemplateArgs->data(), TemplateArgs->size())); } /// Add a new outmost level to the multi-level template argument /// list. void addOuterTemplateArguments(ArgList Args) { assert(!NumRetainedOuterLevels && "substituted args outside retained args?"); TemplateArgumentLists.push_back(Args); } /// Add an outermost level that we are not substituting. We have no /// arguments at this level, and do not remove it from the depth of inner /// template parameters that we instantiate. void addOuterRetainedLevel() { ++NumRetainedOuterLevels; } /// Retrieve the innermost template argument list. const ArgList &getInnermost() const { return TemplateArgumentLists.front(); } }; /// The context in which partial ordering of function templates occurs. enum TPOC { /// Partial ordering of function templates for a function call. TPOC_Call, /// Partial ordering of function templates for a call to a /// conversion function. TPOC_Conversion, /// Partial ordering of function templates in other contexts, e.g., /// taking the address of a function template or matching a function /// template specialization to a function template. TPOC_Other }; // This is lame but unavoidable in a world without forward // declarations of enums. The alternatives are to either pollute // Sema.h (by including this file) or sacrifice type safety (by // making Sema.h declare things as enums). class TemplatePartialOrderingContext { TPOC Value; public: TemplatePartialOrderingContext(TPOC Value) : Value(Value) {} operator TPOC() const { return Value; } }; /// Captures a template argument whose value has been deduced /// via c++ template argument deduction. class DeducedTemplateArgument : public TemplateArgument { /// For a non-type template argument, whether the value was /// deduced from an array bound. bool DeducedFromArrayBound = false; public: DeducedTemplateArgument() = default; DeducedTemplateArgument(const TemplateArgument &Arg, bool DeducedFromArrayBound = false) : TemplateArgument(Arg), DeducedFromArrayBound(DeducedFromArrayBound) {} /// Construct an integral non-type template argument that /// has been deduced, possibly from an array bound. DeducedTemplateArgument(ASTContext &Ctx, const llvm::APSInt &Value, QualType ValueType, bool DeducedFromArrayBound) : TemplateArgument(Ctx, Value, ValueType), DeducedFromArrayBound(DeducedFromArrayBound) {} /// For a non-type template argument, determine whether the /// template argument was deduced from an array bound. bool wasDeducedFromArrayBound() const { return DeducedFromArrayBound; } /// Specify whether the given non-type template argument /// was deduced from an array bound. void setDeducedFromArrayBound(bool Deduced) { DeducedFromArrayBound = Deduced; } }; /// A stack-allocated class that identifies which local /// variable declaration instantiations are present in this scope. /// /// A new instance of this class type will be created whenever we /// instantiate a new function declaration, which will have its own /// set of parameter declarations. class LocalInstantiationScope { public: /// A set of declarations. using DeclArgumentPack = SmallVector; private: /// Reference to the semantic analysis that is performing /// this template instantiation. Sema &SemaRef; using LocalDeclsMap = llvm::SmallDenseMap, 4>; /// A mapping from local declarations that occur /// within a template to their instantiations. /// /// This mapping is used during instantiation to keep track of, /// e.g., function parameter and variable declarations. For example, /// given: /// /// \code /// template T add(T x, T y) { return x + y; } /// \endcode /// /// when we instantiate add, we will introduce a mapping from /// the ParmVarDecl for 'x' that occurs in the template to the /// instantiated ParmVarDecl for 'x'. /// /// For a parameter pack, the local instantiation scope may contain a /// set of instantiated parameters. This is stored as a DeclArgumentPack /// pointer. LocalDeclsMap LocalDecls; /// The set of argument packs we've allocated. SmallVector ArgumentPacks; /// The outer scope, which contains local variable /// definitions from some other instantiation (that may not be /// relevant to this particular scope). LocalInstantiationScope *Outer; /// Whether we have already exited this scope. bool Exited = false; /// Whether to combine this scope with the outer scope, such that /// lookup will search our outer scope. bool CombineWithOuterScope; /// If non-NULL, the template parameter pack that has been /// partially substituted per C++0x [temp.arg.explicit]p9. NamedDecl *PartiallySubstitutedPack = nullptr; /// If \c PartiallySubstitutedPack is non-null, the set of /// explicitly-specified template arguments in that pack. const TemplateArgument *ArgsInPartiallySubstitutedPack; /// If \c PartiallySubstitutedPack, the number of /// explicitly-specified template arguments in /// ArgsInPartiallySubstitutedPack. unsigned NumArgsInPartiallySubstitutedPack; public: LocalInstantiationScope(Sema &SemaRef, bool CombineWithOuterScope = false) : SemaRef(SemaRef), Outer(SemaRef.CurrentInstantiationScope), CombineWithOuterScope(CombineWithOuterScope) { SemaRef.CurrentInstantiationScope = this; } LocalInstantiationScope(const LocalInstantiationScope &) = delete; LocalInstantiationScope & operator=(const LocalInstantiationScope &) = delete; ~LocalInstantiationScope() { Exit(); } const Sema &getSema() const { return SemaRef; } /// Exit this local instantiation scope early. void Exit() { if (Exited) return; for (unsigned I = 0, N = ArgumentPacks.size(); I != N; ++I) delete ArgumentPacks[I]; SemaRef.CurrentInstantiationScope = Outer; Exited = true; } /// Clone this scope, and all outer scopes, down to the given /// outermost scope. LocalInstantiationScope *cloneScopes(LocalInstantiationScope *Outermost) { if (this == Outermost) return this; // Save the current scope from SemaRef since the LocalInstantiationScope // will overwrite it on construction LocalInstantiationScope *oldScope = SemaRef.CurrentInstantiationScope; LocalInstantiationScope *newScope = new LocalInstantiationScope(SemaRef, CombineWithOuterScope); newScope->Outer = nullptr; if (Outer) newScope->Outer = Outer->cloneScopes(Outermost); newScope->PartiallySubstitutedPack = PartiallySubstitutedPack; newScope->ArgsInPartiallySubstitutedPack = ArgsInPartiallySubstitutedPack; newScope->NumArgsInPartiallySubstitutedPack = NumArgsInPartiallySubstitutedPack; for (LocalDeclsMap::iterator I = LocalDecls.begin(), E = LocalDecls.end(); I != E; ++I) { const Decl *D = I->first; llvm::PointerUnion &Stored = newScope->LocalDecls[D]; if (I->second.is()) { Stored = I->second.get(); } else { DeclArgumentPack *OldPack = I->second.get(); DeclArgumentPack *NewPack = new DeclArgumentPack(*OldPack); Stored = NewPack; newScope->ArgumentPacks.push_back(NewPack); } } // Restore the saved scope to SemaRef SemaRef.CurrentInstantiationScope = oldScope; return newScope; } /// deletes the given scope, and all otuer scopes, down to the /// given outermost scope. static void deleteScopes(LocalInstantiationScope *Scope, LocalInstantiationScope *Outermost) { while (Scope && Scope != Outermost) { LocalInstantiationScope *Out = Scope->Outer; delete Scope; Scope = Out; } } /// Find the instantiation of the declaration D within the current /// instantiation scope. /// /// \param D The declaration whose instantiation we are searching for. /// /// \returns A pointer to the declaration or argument pack of declarations /// to which the declaration \c D is instantiated, if found. Otherwise, /// returns NULL. llvm::PointerUnion * findInstantiationOf(const Decl *D); void InstantiatedLocal(const Decl *D, Decl *Inst); void InstantiatedLocalPackArg(const Decl *D, VarDecl *Inst); void MakeInstantiatedLocalArgPack(const Decl *D); /// Note that the given parameter pack has been partially substituted /// via explicit specification of template arguments /// (C++0x [temp.arg.explicit]p9). /// /// \param Pack The parameter pack, which will always be a template /// parameter pack. /// /// \param ExplicitArgs The explicitly-specified template arguments provided /// for this parameter pack. /// /// \param NumExplicitArgs The number of explicitly-specified template /// arguments provided for this parameter pack. void SetPartiallySubstitutedPack(NamedDecl *Pack, const TemplateArgument *ExplicitArgs, unsigned NumExplicitArgs); /// Reset the partially-substituted pack when it is no longer of /// interest. void ResetPartiallySubstitutedPack() { assert(PartiallySubstitutedPack && "No partially-substituted pack"); PartiallySubstitutedPack = nullptr; ArgsInPartiallySubstitutedPack = nullptr; NumArgsInPartiallySubstitutedPack = 0; } /// Retrieve the partially-substitued template parameter pack. /// /// If there is no partially-substituted parameter pack, returns NULL. NamedDecl * getPartiallySubstitutedPack(const TemplateArgument **ExplicitArgs = nullptr, unsigned *NumExplicitArgs = nullptr) const; }; class TemplateDeclInstantiator : public DeclVisitor { Sema &SemaRef; Sema::ArgumentPackSubstitutionIndexRAII SubstIndex; DeclContext *Owner; const MultiLevelTemplateArgumentList &TemplateArgs; Sema::LateInstantiatedAttrVec* LateAttrs = nullptr; LocalInstantiationScope *StartingScope = nullptr; /// A list of out-of-line class template partial /// specializations that will need to be instantiated after the /// enclosing class's instantiation is complete. SmallVector, 4> OutOfLinePartialSpecs; /// A list of out-of-line variable template partial /// specializations that will need to be instantiated after the /// enclosing variable's instantiation is complete. /// FIXME: Verify that this is needed. SmallVector< std::pair, 4> OutOfLineVarPartialSpecs; public: TemplateDeclInstantiator(Sema &SemaRef, DeclContext *Owner, const MultiLevelTemplateArgumentList &TemplateArgs) : SemaRef(SemaRef), SubstIndex(SemaRef, SemaRef.ArgumentPackSubstitutionIndex), Owner(Owner), TemplateArgs(TemplateArgs) {} // Define all the decl visitors using DeclNodes.inc #define DECL(DERIVED, BASE) \ Decl *Visit ## DERIVED ## Decl(DERIVED ## Decl *D); #define ABSTRACT_DECL(DECL) // Decls which never appear inside a class or function. #define OBJCCONTAINER(DERIVED, BASE) #define FILESCOPEASM(DERIVED, BASE) #define IMPORT(DERIVED, BASE) #define EXPORT(DERIVED, BASE) #define LINKAGESPEC(DERIVED, BASE) #define OBJCCOMPATIBLEALIAS(DERIVED, BASE) #define OBJCMETHOD(DERIVED, BASE) #define OBJCTYPEPARAM(DERIVED, BASE) #define OBJCIVAR(DERIVED, BASE) #define OBJCPROPERTY(DERIVED, BASE) #define OBJCPROPERTYIMPL(DERIVED, BASE) #define EMPTY(DERIVED, BASE) #define LIFETIMEEXTENDEDTEMPORARY(DERIVED, BASE) // Decls which use special-case instantiation code. #define BLOCK(DERIVED, BASE) #define CAPTURED(DERIVED, BASE) #define IMPLICITPARAM(DERIVED, BASE) #include "clang/AST/DeclNodes.inc" enum class RewriteKind { None, RewriteSpaceshipAsEqualEqual }; void adjustForRewrite(RewriteKind RK, FunctionDecl *Orig, QualType &T, TypeSourceInfo *&TInfo, DeclarationNameInfo &NameInfo); // A few supplemental visitor functions. Decl *VisitCXXMethodDecl(CXXMethodDecl *D, TemplateParameterList *TemplateParams, Optional ClassScopeSpecializationArgs = llvm::None, RewriteKind RK = RewriteKind::None); Decl *VisitFunctionDecl(FunctionDecl *D, TemplateParameterList *TemplateParams, RewriteKind RK = RewriteKind::None); Decl *VisitDecl(Decl *D); Decl *VisitVarDecl(VarDecl *D, bool InstantiatingVarTemplate, ArrayRef *Bindings = nullptr); // Enable late instantiation of attributes. Late instantiated attributes // will be stored in LA. void enableLateAttributeInstantiation(Sema::LateInstantiatedAttrVec *LA) { LateAttrs = LA; StartingScope = SemaRef.CurrentInstantiationScope; } // Disable late instantiation of attributes. void disableLateAttributeInstantiation() { LateAttrs = nullptr; StartingScope = nullptr; } LocalInstantiationScope *getStartingScope() const { return StartingScope; } using delayed_partial_spec_iterator = SmallVectorImpl>::iterator; using delayed_var_partial_spec_iterator = SmallVectorImpl>::iterator; /// Return an iterator to the beginning of the set of /// "delayed" partial specializations, which must be passed to /// InstantiateClassTemplatePartialSpecialization once the class /// definition has been completed. delayed_partial_spec_iterator delayed_partial_spec_begin() { return OutOfLinePartialSpecs.begin(); } delayed_var_partial_spec_iterator delayed_var_partial_spec_begin() { return OutOfLineVarPartialSpecs.begin(); } /// Return an iterator to the end of the set of /// "delayed" partial specializations, which must be passed to /// InstantiateClassTemplatePartialSpecialization once the class /// definition has been completed. delayed_partial_spec_iterator delayed_partial_spec_end() { return OutOfLinePartialSpecs.end(); } delayed_var_partial_spec_iterator delayed_var_partial_spec_end() { return OutOfLineVarPartialSpecs.end(); } // Helper functions for instantiating methods. TypeSourceInfo *SubstFunctionType(FunctionDecl *D, SmallVectorImpl &Params); bool InitFunctionInstantiation(FunctionDecl *New, FunctionDecl *Tmpl); bool InitMethodInstantiation(CXXMethodDecl *New, CXXMethodDecl *Tmpl); bool SubstDefaultedFunction(FunctionDecl *New, FunctionDecl *Tmpl); TemplateParameterList * SubstTemplateParams(TemplateParameterList *List); bool SubstQualifier(const DeclaratorDecl *OldDecl, DeclaratorDecl *NewDecl); bool SubstQualifier(const TagDecl *OldDecl, TagDecl *NewDecl); Decl *VisitVarTemplateSpecializationDecl( VarTemplateDecl *VarTemplate, VarDecl *FromVar, void *InsertPos, const TemplateArgumentListInfo &TemplateArgsInfo, ArrayRef Converted, VarTemplateSpecializationDecl *PrevDecl = nullptr); Decl *InstantiateTypedefNameDecl(TypedefNameDecl *D, bool IsTypeAlias); ClassTemplatePartialSpecializationDecl * InstantiateClassTemplatePartialSpecialization( ClassTemplateDecl *ClassTemplate, ClassTemplatePartialSpecializationDecl *PartialSpec); VarTemplatePartialSpecializationDecl * InstantiateVarTemplatePartialSpecialization( VarTemplateDecl *VarTemplate, VarTemplatePartialSpecializationDecl *PartialSpec); void InstantiateEnumDefinition(EnumDecl *Enum, EnumDecl *Pattern); private: template Decl *instantiateUnresolvedUsingDecl(T *D, bool InstantiatingPackElement = false); }; } // namespace clang #endif // LLVM_CLANG_SEMA_TEMPLATE_H Index: vendor/llvm-project/release-10.x/clang/lib/AST/ASTImporter.cpp =================================================================== --- vendor/llvm-project/release-10.x/clang/lib/AST/ASTImporter.cpp (revision 359078) +++ vendor/llvm-project/release-10.x/clang/lib/AST/ASTImporter.cpp (revision 359079) @@ -1,9051 +1,9051 @@ //===- ASTImporter.cpp - Importing ASTs from other Contexts ---------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This file defines the ASTImporter class which imports AST nodes from one // context into another context. // //===----------------------------------------------------------------------===// #include "clang/AST/ASTImporter.h" #include "clang/AST/ASTImporterSharedState.h" #include "clang/AST/ASTContext.h" #include "clang/AST/ASTDiagnostic.h" #include "clang/AST/ASTStructuralEquivalence.h" #include "clang/AST/Attr.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclAccessPair.h" #include "clang/AST/DeclBase.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclFriend.h" #include "clang/AST/DeclGroup.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/DeclVisitor.h" #include "clang/AST/DeclarationName.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/ExprObjC.h" #include "clang/AST/ExternalASTSource.h" #include "clang/AST/LambdaCapture.h" #include "clang/AST/NestedNameSpecifier.h" #include "clang/AST/OperationKinds.h" #include "clang/AST/Stmt.h" #include "clang/AST/StmtCXX.h" #include "clang/AST/StmtObjC.h" #include "clang/AST/StmtVisitor.h" #include "clang/AST/TemplateBase.h" #include "clang/AST/TemplateName.h" #include "clang/AST/Type.h" #include "clang/AST/TypeLoc.h" #include "clang/AST/TypeVisitor.h" #include "clang/AST/UnresolvedSet.h" #include "clang/Basic/Builtins.h" #include "clang/Basic/ExceptionSpecificationType.h" #include "clang/Basic/FileManager.h" #include "clang/Basic/IdentifierTable.h" #include "clang/Basic/LLVM.h" #include "clang/Basic/LangOptions.h" #include "clang/Basic/SourceLocation.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/Specifiers.h" #include "llvm/ADT/APSInt.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/None.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/ScopeExit.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallVector.h" #include "llvm/Support/Casting.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/MemoryBuffer.h" #include #include #include #include #include #include namespace clang { using llvm::make_error; using llvm::Error; using llvm::Expected; using ExpectedType = llvm::Expected; using ExpectedStmt = llvm::Expected; using ExpectedExpr = llvm::Expected; using ExpectedDecl = llvm::Expected; using ExpectedSLoc = llvm::Expected; using ExpectedName = llvm::Expected; std::string ImportError::toString() const { // FIXME: Improve error texts. switch (Error) { case NameConflict: return "NameConflict"; case UnsupportedConstruct: return "UnsupportedConstruct"; case Unknown: return "Unknown error"; } llvm_unreachable("Invalid error code."); return "Invalid error code."; } void ImportError::log(raw_ostream &OS) const { OS << toString(); } std::error_code ImportError::convertToErrorCode() const { llvm_unreachable("Function not implemented."); } char ImportError::ID; template SmallVector getCanonicalForwardRedeclChain(Redeclarable* D) { SmallVector Redecls; for (auto *R : D->getFirstDecl()->redecls()) { if (R != D->getFirstDecl()) Redecls.push_back(R); } Redecls.push_back(D->getFirstDecl()); std::reverse(Redecls.begin(), Redecls.end()); return Redecls; } SmallVector getCanonicalForwardRedeclChain(Decl* D) { if (auto *FD = dyn_cast(D)) return getCanonicalForwardRedeclChain(FD); if (auto *VD = dyn_cast(D)) return getCanonicalForwardRedeclChain(VD); if (auto *TD = dyn_cast(D)) return getCanonicalForwardRedeclChain(TD); llvm_unreachable("Bad declaration kind"); } void updateFlags(const Decl *From, Decl *To) { // Check if some flags or attrs are new in 'From' and copy into 'To'. // FIXME: Other flags or attrs? if (From->isUsed(false) && !To->isUsed(false)) To->setIsUsed(); } class ASTNodeImporter : public TypeVisitor, public DeclVisitor, public StmtVisitor { ASTImporter &Importer; // Use this instead of Importer.importInto . template LLVM_NODISCARD Error importInto(ImportT &To, const ImportT &From) { return Importer.importInto(To, From); } // Use this to import pointers of specific type. template LLVM_NODISCARD Error importInto(ImportT *&To, ImportT *From) { auto ToOrErr = Importer.Import(From); if (ToOrErr) To = cast_or_null(*ToOrErr); return ToOrErr.takeError(); } // Call the import function of ASTImporter for a baseclass of type `T` and // cast the return value to `T`. template Expected import(T *From) { auto ToOrErr = Importer.Import(From); if (!ToOrErr) return ToOrErr.takeError(); return cast_or_null(*ToOrErr); } template Expected import(const T *From) { return import(const_cast(From)); } // Call the import function of ASTImporter for type `T`. template Expected import(const T &From) { return Importer.Import(From); } // Import an Optional by importing the contained T, if any. template Expected> import(Optional From) { if (!From) return Optional(); return import(*From); } template Expected> importSeq(const T &From) { Expected ToOrErr = import(From); if (!ToOrErr) return ToOrErr.takeError(); return std::make_tuple(std::move(*ToOrErr)); } // Import multiple objects with a single function call. // This should work for every type for which a variant of `import` exists. // The arguments are processed from left to right and import is stopped on // first error. template Expected> importSeq(const THead &FromHead, const TTail &...FromTail) { Expected> ToHeadOrErr = importSeq(FromHead); if (!ToHeadOrErr) return ToHeadOrErr.takeError(); Expected> ToTailOrErr = importSeq(FromTail...); if (!ToTailOrErr) return ToTailOrErr.takeError(); return std::tuple_cat(*ToHeadOrErr, *ToTailOrErr); } // Wrapper for an overload set. template struct CallOverloadedCreateFun { template auto operator()(Args &&... args) -> decltype(ToDeclT::Create(std::forward(args)...)) { return ToDeclT::Create(std::forward(args)...); } }; // Always use these functions to create a Decl during import. There are // certain tasks which must be done after the Decl was created, e.g. we // must immediately register that as an imported Decl. The parameter `ToD` // will be set to the newly created Decl or if had been imported before // then to the already imported Decl. Returns a bool value set to true if // the `FromD` had been imported before. template LLVM_NODISCARD bool GetImportedOrCreateDecl(ToDeclT *&ToD, FromDeclT *FromD, Args &&... args) { // There may be several overloads of ToDeclT::Create. We must make sure // to call the one which would be chosen by the arguments, thus we use a // wrapper for the overload set. CallOverloadedCreateFun OC; return GetImportedOrCreateSpecialDecl(ToD, OC, FromD, std::forward(args)...); } // Use this overload if a special Type is needed to be created. E.g if we // want to create a `TypeAliasDecl` and assign that to a `TypedefNameDecl` // then: // TypedefNameDecl *ToTypedef; // GetImportedOrCreateDecl(ToTypedef, FromD, ...); template LLVM_NODISCARD bool GetImportedOrCreateDecl(ToDeclT *&ToD, FromDeclT *FromD, Args &&... args) { CallOverloadedCreateFun OC; return GetImportedOrCreateSpecialDecl(ToD, OC, FromD, std::forward(args)...); } // Use this version if a special create function must be // used, e.g. CXXRecordDecl::CreateLambda . template LLVM_NODISCARD bool GetImportedOrCreateSpecialDecl(ToDeclT *&ToD, CreateFunT CreateFun, FromDeclT *FromD, Args &&... args) { if (Importer.getImportDeclErrorIfAny(FromD)) { ToD = nullptr; return true; // Already imported but with error. } ToD = cast_or_null(Importer.GetAlreadyImportedOrNull(FromD)); if (ToD) return true; // Already imported. ToD = CreateFun(std::forward(args)...); // Keep track of imported Decls. Importer.RegisterImportedDecl(FromD, ToD); InitializeImportedDecl(FromD, ToD); return false; // A new Decl is created. } void InitializeImportedDecl(Decl *FromD, Decl *ToD) { ToD->IdentifierNamespace = FromD->IdentifierNamespace; if (FromD->hasAttrs()) for (const Attr *FromAttr : FromD->getAttrs()) { // FIXME: Return of the error here is not possible until store of // import errors is implemented. auto ToAttrOrErr = import(FromAttr); if (ToAttrOrErr) ToD->addAttr(*ToAttrOrErr); else llvm::consumeError(ToAttrOrErr.takeError()); } if (FromD->isUsed()) ToD->setIsUsed(); if (FromD->isImplicit()) ToD->setImplicit(); } // Check if we have found an existing definition. Returns with that // definition if yes, otherwise returns null. Decl *FindAndMapDefinition(FunctionDecl *D, FunctionDecl *FoundFunction) { const FunctionDecl *Definition = nullptr; if (D->doesThisDeclarationHaveABody() && FoundFunction->hasBody(Definition)) return Importer.MapImported(D, const_cast(Definition)); return nullptr; } void addDeclToContexts(Decl *FromD, Decl *ToD) { if (Importer.isMinimalImport()) { // In minimal import case the decl must be added even if it is not // contained in original context, for LLDB compatibility. // FIXME: Check if a better solution is possible. if (!FromD->getDescribedTemplate() && FromD->getFriendObjectKind() == Decl::FOK_None) ToD->getLexicalDeclContext()->addDeclInternal(ToD); return; } DeclContext *FromDC = FromD->getDeclContext(); DeclContext *FromLexicalDC = FromD->getLexicalDeclContext(); DeclContext *ToDC = ToD->getDeclContext(); DeclContext *ToLexicalDC = ToD->getLexicalDeclContext(); bool Visible = false; if (FromDC->containsDeclAndLoad(FromD)) { ToDC->addDeclInternal(ToD); Visible = true; } if (ToDC != ToLexicalDC && FromLexicalDC->containsDeclAndLoad(FromD)) { ToLexicalDC->addDeclInternal(ToD); Visible = true; } // If the Decl was added to any context, it was made already visible. // Otherwise it is still possible that it should be visible. if (!Visible) { if (auto *FromNamed = dyn_cast(FromD)) { auto *ToNamed = cast(ToD); DeclContextLookupResult FromLookup = FromDC->lookup(FromNamed->getDeclName()); for (NamedDecl *ND : FromLookup) if (ND == FromNamed) { ToDC->makeDeclVisibleInContext(ToNamed); break; } } } } public: explicit ASTNodeImporter(ASTImporter &Importer) : Importer(Importer) {} using TypeVisitor::Visit; using DeclVisitor::Visit; using StmtVisitor::Visit; // Importing types ExpectedType VisitType(const Type *T); ExpectedType VisitAtomicType(const AtomicType *T); ExpectedType VisitBuiltinType(const BuiltinType *T); ExpectedType VisitDecayedType(const DecayedType *T); ExpectedType VisitComplexType(const ComplexType *T); ExpectedType VisitPointerType(const PointerType *T); ExpectedType VisitBlockPointerType(const BlockPointerType *T); ExpectedType VisitLValueReferenceType(const LValueReferenceType *T); ExpectedType VisitRValueReferenceType(const RValueReferenceType *T); ExpectedType VisitMemberPointerType(const MemberPointerType *T); ExpectedType VisitConstantArrayType(const ConstantArrayType *T); ExpectedType VisitIncompleteArrayType(const IncompleteArrayType *T); ExpectedType VisitVariableArrayType(const VariableArrayType *T); ExpectedType VisitDependentSizedArrayType(const DependentSizedArrayType *T); // FIXME: DependentSizedExtVectorType ExpectedType VisitVectorType(const VectorType *T); ExpectedType VisitExtVectorType(const ExtVectorType *T); ExpectedType VisitFunctionNoProtoType(const FunctionNoProtoType *T); ExpectedType VisitFunctionProtoType(const FunctionProtoType *T); ExpectedType VisitUnresolvedUsingType(const UnresolvedUsingType *T); ExpectedType VisitParenType(const ParenType *T); ExpectedType VisitTypedefType(const TypedefType *T); ExpectedType VisitTypeOfExprType(const TypeOfExprType *T); // FIXME: DependentTypeOfExprType ExpectedType VisitTypeOfType(const TypeOfType *T); ExpectedType VisitDecltypeType(const DecltypeType *T); ExpectedType VisitUnaryTransformType(const UnaryTransformType *T); ExpectedType VisitAutoType(const AutoType *T); ExpectedType VisitInjectedClassNameType(const InjectedClassNameType *T); // FIXME: DependentDecltypeType ExpectedType VisitRecordType(const RecordType *T); ExpectedType VisitEnumType(const EnumType *T); ExpectedType VisitAttributedType(const AttributedType *T); ExpectedType VisitTemplateTypeParmType(const TemplateTypeParmType *T); ExpectedType VisitSubstTemplateTypeParmType( const SubstTemplateTypeParmType *T); ExpectedType VisitTemplateSpecializationType( const TemplateSpecializationType *T); ExpectedType VisitElaboratedType(const ElaboratedType *T); ExpectedType VisitDependentNameType(const DependentNameType *T); ExpectedType VisitPackExpansionType(const PackExpansionType *T); ExpectedType VisitDependentTemplateSpecializationType( const DependentTemplateSpecializationType *T); ExpectedType VisitObjCInterfaceType(const ObjCInterfaceType *T); ExpectedType VisitObjCObjectType(const ObjCObjectType *T); ExpectedType VisitObjCObjectPointerType(const ObjCObjectPointerType *T); // Importing declarations Error ImportDeclParts( NamedDecl *D, DeclContext *&DC, DeclContext *&LexicalDC, DeclarationName &Name, NamedDecl *&ToD, SourceLocation &Loc); Error ImportDefinitionIfNeeded(Decl *FromD, Decl *ToD = nullptr); Error ImportDeclarationNameLoc( const DeclarationNameInfo &From, DeclarationNameInfo &To); Error ImportDeclContext(DeclContext *FromDC, bool ForceImport = false); Error ImportDeclContext( Decl *From, DeclContext *&ToDC, DeclContext *&ToLexicalDC); Error ImportImplicitMethods(const CXXRecordDecl *From, CXXRecordDecl *To); Expected ImportCastPath(CastExpr *E); using Designator = DesignatedInitExpr::Designator; /// What we should import from the definition. enum ImportDefinitionKind { /// Import the default subset of the definition, which might be /// nothing (if minimal import is set) or might be everything (if minimal /// import is not set). IDK_Default, /// Import everything. IDK_Everything, /// Import only the bare bones needed to establish a valid /// DeclContext. IDK_Basic }; bool shouldForceImportDeclContext(ImportDefinitionKind IDK) { return IDK == IDK_Everything || (IDK == IDK_Default && !Importer.isMinimalImport()); } Error ImportInitializer(VarDecl *From, VarDecl *To); Error ImportDefinition( RecordDecl *From, RecordDecl *To, ImportDefinitionKind Kind = IDK_Default); Error ImportDefinition( EnumDecl *From, EnumDecl *To, ImportDefinitionKind Kind = IDK_Default); Error ImportDefinition( ObjCInterfaceDecl *From, ObjCInterfaceDecl *To, ImportDefinitionKind Kind = IDK_Default); Error ImportDefinition( ObjCProtocolDecl *From, ObjCProtocolDecl *To, ImportDefinitionKind Kind = IDK_Default); Error ImportTemplateArguments( const TemplateArgument *FromArgs, unsigned NumFromArgs, SmallVectorImpl &ToArgs); Expected ImportTemplateArgument(const TemplateArgument &From); template Error ImportTemplateArgumentListInfo( const InContainerTy &Container, TemplateArgumentListInfo &ToTAInfo); template Error ImportTemplateArgumentListInfo( SourceLocation FromLAngleLoc, SourceLocation FromRAngleLoc, const InContainerTy &Container, TemplateArgumentListInfo &Result); using TemplateArgsTy = SmallVector; using FunctionTemplateAndArgsTy = std::tuple; Expected ImportFunctionTemplateWithTemplateArgsFromSpecialization( FunctionDecl *FromFD); Error ImportTemplateParameterLists(const DeclaratorDecl *FromD, DeclaratorDecl *ToD); Error ImportTemplateInformation(FunctionDecl *FromFD, FunctionDecl *ToFD); Error ImportFunctionDeclBody(FunctionDecl *FromFD, FunctionDecl *ToFD); Error ImportDefaultArgOfParmVarDecl(const ParmVarDecl *FromParam, ParmVarDecl *ToParam); template bool hasSameVisibilityContext(T *Found, T *From); bool IsStructuralMatch(Decl *From, Decl *To, bool Complain); bool IsStructuralMatch(RecordDecl *FromRecord, RecordDecl *ToRecord, bool Complain = true); bool IsStructuralMatch(VarDecl *FromVar, VarDecl *ToVar, bool Complain = true); bool IsStructuralMatch(EnumDecl *FromEnum, EnumDecl *ToRecord); bool IsStructuralMatch(EnumConstantDecl *FromEC, EnumConstantDecl *ToEC); bool IsStructuralMatch(FunctionTemplateDecl *From, FunctionTemplateDecl *To); bool IsStructuralMatch(FunctionDecl *From, FunctionDecl *To); bool IsStructuralMatch(ClassTemplateDecl *From, ClassTemplateDecl *To); bool IsStructuralMatch(VarTemplateDecl *From, VarTemplateDecl *To); ExpectedDecl VisitDecl(Decl *D); ExpectedDecl VisitImportDecl(ImportDecl *D); ExpectedDecl VisitEmptyDecl(EmptyDecl *D); ExpectedDecl VisitAccessSpecDecl(AccessSpecDecl *D); ExpectedDecl VisitStaticAssertDecl(StaticAssertDecl *D); ExpectedDecl VisitTranslationUnitDecl(TranslationUnitDecl *D); ExpectedDecl VisitNamespaceDecl(NamespaceDecl *D); ExpectedDecl VisitNamespaceAliasDecl(NamespaceAliasDecl *D); ExpectedDecl VisitTypedefNameDecl(TypedefNameDecl *D, bool IsAlias); ExpectedDecl VisitTypedefDecl(TypedefDecl *D); ExpectedDecl VisitTypeAliasDecl(TypeAliasDecl *D); ExpectedDecl VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D); ExpectedDecl VisitLabelDecl(LabelDecl *D); ExpectedDecl VisitEnumDecl(EnumDecl *D); ExpectedDecl VisitRecordDecl(RecordDecl *D); ExpectedDecl VisitEnumConstantDecl(EnumConstantDecl *D); ExpectedDecl VisitFunctionDecl(FunctionDecl *D); ExpectedDecl VisitCXXMethodDecl(CXXMethodDecl *D); ExpectedDecl VisitCXXConstructorDecl(CXXConstructorDecl *D); ExpectedDecl VisitCXXDestructorDecl(CXXDestructorDecl *D); ExpectedDecl VisitCXXConversionDecl(CXXConversionDecl *D); ExpectedDecl VisitFieldDecl(FieldDecl *D); ExpectedDecl VisitIndirectFieldDecl(IndirectFieldDecl *D); ExpectedDecl VisitFriendDecl(FriendDecl *D); ExpectedDecl VisitObjCIvarDecl(ObjCIvarDecl *D); ExpectedDecl VisitVarDecl(VarDecl *D); ExpectedDecl VisitImplicitParamDecl(ImplicitParamDecl *D); ExpectedDecl VisitParmVarDecl(ParmVarDecl *D); ExpectedDecl VisitObjCMethodDecl(ObjCMethodDecl *D); ExpectedDecl VisitObjCTypeParamDecl(ObjCTypeParamDecl *D); ExpectedDecl VisitObjCCategoryDecl(ObjCCategoryDecl *D); ExpectedDecl VisitObjCProtocolDecl(ObjCProtocolDecl *D); ExpectedDecl VisitLinkageSpecDecl(LinkageSpecDecl *D); ExpectedDecl VisitUsingDecl(UsingDecl *D); ExpectedDecl VisitUsingShadowDecl(UsingShadowDecl *D); ExpectedDecl VisitUsingDirectiveDecl(UsingDirectiveDecl *D); ExpectedDecl VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D); ExpectedDecl VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D); ExpectedDecl VisitBuiltinTemplateDecl(BuiltinTemplateDecl *D); ExpectedDecl VisitLifetimeExtendedTemporaryDecl(LifetimeExtendedTemporaryDecl *D); Expected ImportObjCTypeParamList(ObjCTypeParamList *list); ExpectedDecl VisitObjCInterfaceDecl(ObjCInterfaceDecl *D); ExpectedDecl VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D); ExpectedDecl VisitObjCImplementationDecl(ObjCImplementationDecl *D); ExpectedDecl VisitObjCPropertyDecl(ObjCPropertyDecl *D); ExpectedDecl VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D); ExpectedDecl VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D); ExpectedDecl VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D); ExpectedDecl VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D); ExpectedDecl VisitClassTemplateDecl(ClassTemplateDecl *D); ExpectedDecl VisitClassTemplateSpecializationDecl( ClassTemplateSpecializationDecl *D); ExpectedDecl VisitVarTemplateDecl(VarTemplateDecl *D); ExpectedDecl VisitVarTemplateSpecializationDecl(VarTemplateSpecializationDecl *D); ExpectedDecl VisitFunctionTemplateDecl(FunctionTemplateDecl *D); // Importing statements ExpectedStmt VisitStmt(Stmt *S); ExpectedStmt VisitGCCAsmStmt(GCCAsmStmt *S); ExpectedStmt VisitDeclStmt(DeclStmt *S); ExpectedStmt VisitNullStmt(NullStmt *S); ExpectedStmt VisitCompoundStmt(CompoundStmt *S); ExpectedStmt VisitCaseStmt(CaseStmt *S); ExpectedStmt VisitDefaultStmt(DefaultStmt *S); ExpectedStmt VisitLabelStmt(LabelStmt *S); ExpectedStmt VisitAttributedStmt(AttributedStmt *S); ExpectedStmt VisitIfStmt(IfStmt *S); ExpectedStmt VisitSwitchStmt(SwitchStmt *S); ExpectedStmt VisitWhileStmt(WhileStmt *S); ExpectedStmt VisitDoStmt(DoStmt *S); ExpectedStmt VisitForStmt(ForStmt *S); ExpectedStmt VisitGotoStmt(GotoStmt *S); ExpectedStmt VisitIndirectGotoStmt(IndirectGotoStmt *S); ExpectedStmt VisitContinueStmt(ContinueStmt *S); ExpectedStmt VisitBreakStmt(BreakStmt *S); ExpectedStmt VisitReturnStmt(ReturnStmt *S); // FIXME: MSAsmStmt // FIXME: SEHExceptStmt // FIXME: SEHFinallyStmt // FIXME: SEHTryStmt // FIXME: SEHLeaveStmt // FIXME: CapturedStmt ExpectedStmt VisitCXXCatchStmt(CXXCatchStmt *S); ExpectedStmt VisitCXXTryStmt(CXXTryStmt *S); ExpectedStmt VisitCXXForRangeStmt(CXXForRangeStmt *S); // FIXME: MSDependentExistsStmt ExpectedStmt VisitObjCForCollectionStmt(ObjCForCollectionStmt *S); ExpectedStmt VisitObjCAtCatchStmt(ObjCAtCatchStmt *S); ExpectedStmt VisitObjCAtFinallyStmt(ObjCAtFinallyStmt *S); ExpectedStmt VisitObjCAtTryStmt(ObjCAtTryStmt *S); ExpectedStmt VisitObjCAtSynchronizedStmt(ObjCAtSynchronizedStmt *S); ExpectedStmt VisitObjCAtThrowStmt(ObjCAtThrowStmt *S); ExpectedStmt VisitObjCAutoreleasePoolStmt(ObjCAutoreleasePoolStmt *S); // Importing expressions ExpectedStmt VisitExpr(Expr *E); ExpectedStmt VisitVAArgExpr(VAArgExpr *E); ExpectedStmt VisitChooseExpr(ChooseExpr *E); ExpectedStmt VisitGNUNullExpr(GNUNullExpr *E); ExpectedStmt VisitPredefinedExpr(PredefinedExpr *E); ExpectedStmt VisitDeclRefExpr(DeclRefExpr *E); ExpectedStmt VisitImplicitValueInitExpr(ImplicitValueInitExpr *E); ExpectedStmt VisitDesignatedInitExpr(DesignatedInitExpr *E); ExpectedStmt VisitCXXNullPtrLiteralExpr(CXXNullPtrLiteralExpr *E); ExpectedStmt VisitIntegerLiteral(IntegerLiteral *E); ExpectedStmt VisitFloatingLiteral(FloatingLiteral *E); ExpectedStmt VisitImaginaryLiteral(ImaginaryLiteral *E); ExpectedStmt VisitCharacterLiteral(CharacterLiteral *E); ExpectedStmt VisitStringLiteral(StringLiteral *E); ExpectedStmt VisitCompoundLiteralExpr(CompoundLiteralExpr *E); ExpectedStmt VisitAtomicExpr(AtomicExpr *E); ExpectedStmt VisitAddrLabelExpr(AddrLabelExpr *E); ExpectedStmt VisitConstantExpr(ConstantExpr *E); ExpectedStmt VisitParenExpr(ParenExpr *E); ExpectedStmt VisitParenListExpr(ParenListExpr *E); ExpectedStmt VisitStmtExpr(StmtExpr *E); ExpectedStmt VisitUnaryOperator(UnaryOperator *E); ExpectedStmt VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E); ExpectedStmt VisitBinaryOperator(BinaryOperator *E); ExpectedStmt VisitConditionalOperator(ConditionalOperator *E); ExpectedStmt VisitBinaryConditionalOperator(BinaryConditionalOperator *E); ExpectedStmt VisitOpaqueValueExpr(OpaqueValueExpr *E); ExpectedStmt VisitArrayTypeTraitExpr(ArrayTypeTraitExpr *E); ExpectedStmt VisitExpressionTraitExpr(ExpressionTraitExpr *E); ExpectedStmt VisitArraySubscriptExpr(ArraySubscriptExpr *E); ExpectedStmt VisitCompoundAssignOperator(CompoundAssignOperator *E); ExpectedStmt VisitImplicitCastExpr(ImplicitCastExpr *E); ExpectedStmt VisitExplicitCastExpr(ExplicitCastExpr *E); ExpectedStmt VisitOffsetOfExpr(OffsetOfExpr *OE); ExpectedStmt VisitCXXThrowExpr(CXXThrowExpr *E); ExpectedStmt VisitCXXNoexceptExpr(CXXNoexceptExpr *E); ExpectedStmt VisitCXXDefaultArgExpr(CXXDefaultArgExpr *E); ExpectedStmt VisitCXXScalarValueInitExpr(CXXScalarValueInitExpr *E); ExpectedStmt VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E); ExpectedStmt VisitCXXTemporaryObjectExpr(CXXTemporaryObjectExpr *E); ExpectedStmt VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *E); ExpectedStmt VisitPackExpansionExpr(PackExpansionExpr *E); ExpectedStmt VisitSizeOfPackExpr(SizeOfPackExpr *E); ExpectedStmt VisitCXXNewExpr(CXXNewExpr *E); ExpectedStmt VisitCXXDeleteExpr(CXXDeleteExpr *E); ExpectedStmt VisitCXXConstructExpr(CXXConstructExpr *E); ExpectedStmt VisitCXXMemberCallExpr(CXXMemberCallExpr *E); ExpectedStmt VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr *E); ExpectedStmt VisitDependentScopeDeclRefExpr(DependentScopeDeclRefExpr *E); ExpectedStmt VisitCXXUnresolvedConstructExpr(CXXUnresolvedConstructExpr *E); ExpectedStmt VisitUnresolvedLookupExpr(UnresolvedLookupExpr *E); ExpectedStmt VisitUnresolvedMemberExpr(UnresolvedMemberExpr *E); ExpectedStmt VisitExprWithCleanups(ExprWithCleanups *E); ExpectedStmt VisitCXXThisExpr(CXXThisExpr *E); ExpectedStmt VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *E); ExpectedStmt VisitCXXPseudoDestructorExpr(CXXPseudoDestructorExpr *E); ExpectedStmt VisitMemberExpr(MemberExpr *E); ExpectedStmt VisitCallExpr(CallExpr *E); ExpectedStmt VisitLambdaExpr(LambdaExpr *LE); ExpectedStmt VisitInitListExpr(InitListExpr *E); ExpectedStmt VisitCXXStdInitializerListExpr(CXXStdInitializerListExpr *E); ExpectedStmt VisitCXXInheritedCtorInitExpr(CXXInheritedCtorInitExpr *E); ExpectedStmt VisitArrayInitLoopExpr(ArrayInitLoopExpr *E); ExpectedStmt VisitArrayInitIndexExpr(ArrayInitIndexExpr *E); ExpectedStmt VisitCXXDefaultInitExpr(CXXDefaultInitExpr *E); ExpectedStmt VisitCXXNamedCastExpr(CXXNamedCastExpr *E); ExpectedStmt VisitSubstNonTypeTemplateParmExpr(SubstNonTypeTemplateParmExpr *E); ExpectedStmt VisitTypeTraitExpr(TypeTraitExpr *E); ExpectedStmt VisitCXXTypeidExpr(CXXTypeidExpr *E); template Error ImportArrayChecked(IIter Ibegin, IIter Iend, OIter Obegin) { using ItemT = typename std::remove_reference::type; for (; Ibegin != Iend; ++Ibegin, ++Obegin) { Expected ToOrErr = import(*Ibegin); if (!ToOrErr) return ToOrErr.takeError(); *Obegin = *ToOrErr; } return Error::success(); } // Import every item from a container structure into an output container. // If error occurs, stops at first error and returns the error. // The output container should have space for all needed elements (it is not // expanded, new items are put into from the beginning). template Error ImportContainerChecked( const InContainerTy &InContainer, OutContainerTy &OutContainer) { return ImportArrayChecked( InContainer.begin(), InContainer.end(), OutContainer.begin()); } template Error ImportArrayChecked(const InContainerTy &InContainer, OIter Obegin) { return ImportArrayChecked(InContainer.begin(), InContainer.end(), Obegin); } Error ImportOverriddenMethods(CXXMethodDecl *ToMethod, CXXMethodDecl *FromMethod); Expected FindFunctionTemplateSpecialization( FunctionDecl *FromFD); // Returns true if the given function has a placeholder return type and // that type is declared inside the body of the function. // E.g. auto f() { struct X{}; return X(); } bool hasAutoReturnTypeDeclaredInside(FunctionDecl *D); }; template Error ASTNodeImporter::ImportTemplateArgumentListInfo( SourceLocation FromLAngleLoc, SourceLocation FromRAngleLoc, const InContainerTy &Container, TemplateArgumentListInfo &Result) { auto ToLAngleLocOrErr = import(FromLAngleLoc); if (!ToLAngleLocOrErr) return ToLAngleLocOrErr.takeError(); auto ToRAngleLocOrErr = import(FromRAngleLoc); if (!ToRAngleLocOrErr) return ToRAngleLocOrErr.takeError(); TemplateArgumentListInfo ToTAInfo(*ToLAngleLocOrErr, *ToRAngleLocOrErr); if (auto Err = ImportTemplateArgumentListInfo(Container, ToTAInfo)) return Err; Result = ToTAInfo; return Error::success(); } template <> Error ASTNodeImporter::ImportTemplateArgumentListInfo( const TemplateArgumentListInfo &From, TemplateArgumentListInfo &Result) { return ImportTemplateArgumentListInfo( From.getLAngleLoc(), From.getRAngleLoc(), From.arguments(), Result); } template <> Error ASTNodeImporter::ImportTemplateArgumentListInfo< ASTTemplateArgumentListInfo>( const ASTTemplateArgumentListInfo &From, TemplateArgumentListInfo &Result) { return ImportTemplateArgumentListInfo( From.LAngleLoc, From.RAngleLoc, From.arguments(), Result); } Expected ASTNodeImporter::ImportFunctionTemplateWithTemplateArgsFromSpecialization( FunctionDecl *FromFD) { assert(FromFD->getTemplatedKind() == FunctionDecl::TK_FunctionTemplateSpecialization); FunctionTemplateAndArgsTy Result; auto *FTSInfo = FromFD->getTemplateSpecializationInfo(); if (Error Err = importInto(std::get<0>(Result), FTSInfo->getTemplate())) return std::move(Err); // Import template arguments. auto TemplArgs = FTSInfo->TemplateArguments->asArray(); if (Error Err = ImportTemplateArguments(TemplArgs.data(), TemplArgs.size(), std::get<1>(Result))) return std::move(Err); return Result; } template <> Expected ASTNodeImporter::import(TemplateParameterList *From) { SmallVector To(From->size()); if (Error Err = ImportContainerChecked(*From, To)) return std::move(Err); ExpectedExpr ToRequiresClause = import(From->getRequiresClause()); if (!ToRequiresClause) return ToRequiresClause.takeError(); auto ToTemplateLocOrErr = import(From->getTemplateLoc()); if (!ToTemplateLocOrErr) return ToTemplateLocOrErr.takeError(); auto ToLAngleLocOrErr = import(From->getLAngleLoc()); if (!ToLAngleLocOrErr) return ToLAngleLocOrErr.takeError(); auto ToRAngleLocOrErr = import(From->getRAngleLoc()); if (!ToRAngleLocOrErr) return ToRAngleLocOrErr.takeError(); return TemplateParameterList::Create( Importer.getToContext(), *ToTemplateLocOrErr, *ToLAngleLocOrErr, To, *ToRAngleLocOrErr, *ToRequiresClause); } template <> Expected ASTNodeImporter::import(const TemplateArgument &From) { switch (From.getKind()) { case TemplateArgument::Null: return TemplateArgument(); case TemplateArgument::Type: { ExpectedType ToTypeOrErr = import(From.getAsType()); if (!ToTypeOrErr) return ToTypeOrErr.takeError(); return TemplateArgument(*ToTypeOrErr); } case TemplateArgument::Integral: { ExpectedType ToTypeOrErr = import(From.getIntegralType()); if (!ToTypeOrErr) return ToTypeOrErr.takeError(); return TemplateArgument(From, *ToTypeOrErr); } case TemplateArgument::Declaration: { Expected ToOrErr = import(From.getAsDecl()); if (!ToOrErr) return ToOrErr.takeError(); ExpectedType ToTypeOrErr = import(From.getParamTypeForDecl()); if (!ToTypeOrErr) return ToTypeOrErr.takeError(); return TemplateArgument(*ToOrErr, *ToTypeOrErr); } case TemplateArgument::NullPtr: { ExpectedType ToTypeOrErr = import(From.getNullPtrType()); if (!ToTypeOrErr) return ToTypeOrErr.takeError(); return TemplateArgument(*ToTypeOrErr, /*isNullPtr*/true); } case TemplateArgument::Template: { Expected ToTemplateOrErr = import(From.getAsTemplate()); if (!ToTemplateOrErr) return ToTemplateOrErr.takeError(); return TemplateArgument(*ToTemplateOrErr); } case TemplateArgument::TemplateExpansion: { Expected ToTemplateOrErr = import(From.getAsTemplateOrTemplatePattern()); if (!ToTemplateOrErr) return ToTemplateOrErr.takeError(); return TemplateArgument( *ToTemplateOrErr, From.getNumTemplateExpansions()); } case TemplateArgument::Expression: if (ExpectedExpr ToExpr = import(From.getAsExpr())) return TemplateArgument(*ToExpr); else return ToExpr.takeError(); case TemplateArgument::Pack: { SmallVector ToPack; ToPack.reserve(From.pack_size()); if (Error Err = ImportTemplateArguments( From.pack_begin(), From.pack_size(), ToPack)) return std::move(Err); return TemplateArgument( llvm::makeArrayRef(ToPack).copy(Importer.getToContext())); } } llvm_unreachable("Invalid template argument kind"); } template <> Expected ASTNodeImporter::import(const TemplateArgumentLoc &TALoc) { Expected ArgOrErr = import(TALoc.getArgument()); if (!ArgOrErr) return ArgOrErr.takeError(); TemplateArgument Arg = *ArgOrErr; TemplateArgumentLocInfo FromInfo = TALoc.getLocInfo(); TemplateArgumentLocInfo ToInfo; if (Arg.getKind() == TemplateArgument::Expression) { ExpectedExpr E = import(FromInfo.getAsExpr()); if (!E) return E.takeError(); ToInfo = TemplateArgumentLocInfo(*E); } else if (Arg.getKind() == TemplateArgument::Type) { if (auto TSIOrErr = import(FromInfo.getAsTypeSourceInfo())) ToInfo = TemplateArgumentLocInfo(*TSIOrErr); else return TSIOrErr.takeError(); } else { auto ToTemplateQualifierLocOrErr = import(FromInfo.getTemplateQualifierLoc()); if (!ToTemplateQualifierLocOrErr) return ToTemplateQualifierLocOrErr.takeError(); auto ToTemplateNameLocOrErr = import(FromInfo.getTemplateNameLoc()); if (!ToTemplateNameLocOrErr) return ToTemplateNameLocOrErr.takeError(); auto ToTemplateEllipsisLocOrErr = import(FromInfo.getTemplateEllipsisLoc()); if (!ToTemplateEllipsisLocOrErr) return ToTemplateEllipsisLocOrErr.takeError(); ToInfo = TemplateArgumentLocInfo( *ToTemplateQualifierLocOrErr, *ToTemplateNameLocOrErr, *ToTemplateEllipsisLocOrErr); } return TemplateArgumentLoc(Arg, ToInfo); } template <> Expected ASTNodeImporter::import(const DeclGroupRef &DG) { if (DG.isNull()) return DeclGroupRef::Create(Importer.getToContext(), nullptr, 0); size_t NumDecls = DG.end() - DG.begin(); SmallVector ToDecls; ToDecls.reserve(NumDecls); for (Decl *FromD : DG) { if (auto ToDOrErr = import(FromD)) ToDecls.push_back(*ToDOrErr); else return ToDOrErr.takeError(); } return DeclGroupRef::Create(Importer.getToContext(), ToDecls.begin(), NumDecls); } template <> Expected ASTNodeImporter::import(const Designator &D) { if (D.isFieldDesignator()) { IdentifierInfo *ToFieldName = Importer.Import(D.getFieldName()); ExpectedSLoc ToDotLocOrErr = import(D.getDotLoc()); if (!ToDotLocOrErr) return ToDotLocOrErr.takeError(); ExpectedSLoc ToFieldLocOrErr = import(D.getFieldLoc()); if (!ToFieldLocOrErr) return ToFieldLocOrErr.takeError(); return Designator(ToFieldName, *ToDotLocOrErr, *ToFieldLocOrErr); } ExpectedSLoc ToLBracketLocOrErr = import(D.getLBracketLoc()); if (!ToLBracketLocOrErr) return ToLBracketLocOrErr.takeError(); ExpectedSLoc ToRBracketLocOrErr = import(D.getRBracketLoc()); if (!ToRBracketLocOrErr) return ToRBracketLocOrErr.takeError(); if (D.isArrayDesignator()) return Designator(D.getFirstExprIndex(), *ToLBracketLocOrErr, *ToRBracketLocOrErr); ExpectedSLoc ToEllipsisLocOrErr = import(D.getEllipsisLoc()); if (!ToEllipsisLocOrErr) return ToEllipsisLocOrErr.takeError(); assert(D.isArrayRangeDesignator()); return Designator( D.getFirstExprIndex(), *ToLBracketLocOrErr, *ToEllipsisLocOrErr, *ToRBracketLocOrErr); } template <> Expected ASTNodeImporter::import(const LambdaCapture &From) { VarDecl *Var = nullptr; if (From.capturesVariable()) { if (auto VarOrErr = import(From.getCapturedVar())) Var = *VarOrErr; else return VarOrErr.takeError(); } auto LocationOrErr = import(From.getLocation()); if (!LocationOrErr) return LocationOrErr.takeError(); SourceLocation EllipsisLoc; if (From.isPackExpansion()) if (Error Err = importInto(EllipsisLoc, From.getEllipsisLoc())) return std::move(Err); return LambdaCapture( *LocationOrErr, From.isImplicit(), From.getCaptureKind(), Var, EllipsisLoc); } template bool ASTNodeImporter::hasSameVisibilityContext(T *Found, T *From) { if (From->hasExternalFormalLinkage()) return Found->hasExternalFormalLinkage(); if (Importer.GetFromTU(Found) != From->getTranslationUnitDecl()) return false; if (From->isInAnonymousNamespace()) return Found->isInAnonymousNamespace(); else return !Found->isInAnonymousNamespace() && !Found->hasExternalFormalLinkage(); } template <> bool ASTNodeImporter::hasSameVisibilityContext(TypedefNameDecl *Found, TypedefNameDecl *From) { if (From->isInAnonymousNamespace() && Found->isInAnonymousNamespace()) return Importer.GetFromTU(Found) == From->getTranslationUnitDecl(); return From->isInAnonymousNamespace() == Found->isInAnonymousNamespace(); } } // namespace clang //---------------------------------------------------------------------------- // Import Types //---------------------------------------------------------------------------- using namespace clang; ExpectedType ASTNodeImporter::VisitType(const Type *T) { Importer.FromDiag(SourceLocation(), diag::err_unsupported_ast_node) << T->getTypeClassName(); return make_error(ImportError::UnsupportedConstruct); } ExpectedType ASTNodeImporter::VisitAtomicType(const AtomicType *T){ ExpectedType UnderlyingTypeOrErr = import(T->getValueType()); if (!UnderlyingTypeOrErr) return UnderlyingTypeOrErr.takeError(); return Importer.getToContext().getAtomicType(*UnderlyingTypeOrErr); } ExpectedType ASTNodeImporter::VisitBuiltinType(const BuiltinType *T) { switch (T->getKind()) { #define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \ case BuiltinType::Id: \ return Importer.getToContext().SingletonId; #include "clang/Basic/OpenCLImageTypes.def" #define EXT_OPAQUE_TYPE(ExtType, Id, Ext) \ case BuiltinType::Id: \ return Importer.getToContext().Id##Ty; #include "clang/Basic/OpenCLExtensionTypes.def" #define SVE_TYPE(Name, Id, SingletonId) \ case BuiltinType::Id: \ return Importer.getToContext().SingletonId; #include "clang/Basic/AArch64SVEACLETypes.def" #define SHARED_SINGLETON_TYPE(Expansion) #define BUILTIN_TYPE(Id, SingletonId) \ case BuiltinType::Id: return Importer.getToContext().SingletonId; #include "clang/AST/BuiltinTypes.def" // FIXME: for Char16, Char32, and NullPtr, make sure that the "to" // context supports C++. // FIXME: for ObjCId, ObjCClass, and ObjCSel, make sure that the "to" // context supports ObjC. case BuiltinType::Char_U: // The context we're importing from has an unsigned 'char'. If we're // importing into a context with a signed 'char', translate to // 'unsigned char' instead. if (Importer.getToContext().getLangOpts().CharIsSigned) return Importer.getToContext().UnsignedCharTy; return Importer.getToContext().CharTy; case BuiltinType::Char_S: // The context we're importing from has an unsigned 'char'. If we're // importing into a context with a signed 'char', translate to // 'unsigned char' instead. if (!Importer.getToContext().getLangOpts().CharIsSigned) return Importer.getToContext().SignedCharTy; return Importer.getToContext().CharTy; case BuiltinType::WChar_S: case BuiltinType::WChar_U: // FIXME: If not in C++, shall we translate to the C equivalent of // wchar_t? return Importer.getToContext().WCharTy; } llvm_unreachable("Invalid BuiltinType Kind!"); } ExpectedType ASTNodeImporter::VisitDecayedType(const DecayedType *T) { ExpectedType ToOriginalTypeOrErr = import(T->getOriginalType()); if (!ToOriginalTypeOrErr) return ToOriginalTypeOrErr.takeError(); return Importer.getToContext().getDecayedType(*ToOriginalTypeOrErr); } ExpectedType ASTNodeImporter::VisitComplexType(const ComplexType *T) { ExpectedType ToElementTypeOrErr = import(T->getElementType()); if (!ToElementTypeOrErr) return ToElementTypeOrErr.takeError(); return Importer.getToContext().getComplexType(*ToElementTypeOrErr); } ExpectedType ASTNodeImporter::VisitPointerType(const PointerType *T) { ExpectedType ToPointeeTypeOrErr = import(T->getPointeeType()); if (!ToPointeeTypeOrErr) return ToPointeeTypeOrErr.takeError(); return Importer.getToContext().getPointerType(*ToPointeeTypeOrErr); } ExpectedType ASTNodeImporter::VisitBlockPointerType(const BlockPointerType *T) { // FIXME: Check for blocks support in "to" context. ExpectedType ToPointeeTypeOrErr = import(T->getPointeeType()); if (!ToPointeeTypeOrErr) return ToPointeeTypeOrErr.takeError(); return Importer.getToContext().getBlockPointerType(*ToPointeeTypeOrErr); } ExpectedType ASTNodeImporter::VisitLValueReferenceType(const LValueReferenceType *T) { // FIXME: Check for C++ support in "to" context. ExpectedType ToPointeeTypeOrErr = import(T->getPointeeTypeAsWritten()); if (!ToPointeeTypeOrErr) return ToPointeeTypeOrErr.takeError(); return Importer.getToContext().getLValueReferenceType(*ToPointeeTypeOrErr); } ExpectedType ASTNodeImporter::VisitRValueReferenceType(const RValueReferenceType *T) { // FIXME: Check for C++0x support in "to" context. ExpectedType ToPointeeTypeOrErr = import(T->getPointeeTypeAsWritten()); if (!ToPointeeTypeOrErr) return ToPointeeTypeOrErr.takeError(); return Importer.getToContext().getRValueReferenceType(*ToPointeeTypeOrErr); } ExpectedType ASTNodeImporter::VisitMemberPointerType(const MemberPointerType *T) { // FIXME: Check for C++ support in "to" context. ExpectedType ToPointeeTypeOrErr = import(T->getPointeeType()); if (!ToPointeeTypeOrErr) return ToPointeeTypeOrErr.takeError(); ExpectedType ClassTypeOrErr = import(QualType(T->getClass(), 0)); if (!ClassTypeOrErr) return ClassTypeOrErr.takeError(); return Importer.getToContext().getMemberPointerType( *ToPointeeTypeOrErr, (*ClassTypeOrErr).getTypePtr()); } ExpectedType ASTNodeImporter::VisitConstantArrayType(const ConstantArrayType *T) { QualType ToElementType; const Expr *ToSizeExpr; if (auto Imp = importSeq(T->getElementType(), T->getSizeExpr())) std::tie(ToElementType, ToSizeExpr) = *Imp; else return Imp.takeError(); return Importer.getToContext().getConstantArrayType( ToElementType, T->getSize(), ToSizeExpr, T->getSizeModifier(), T->getIndexTypeCVRQualifiers()); } ExpectedType ASTNodeImporter::VisitIncompleteArrayType(const IncompleteArrayType *T) { ExpectedType ToElementTypeOrErr = import(T->getElementType()); if (!ToElementTypeOrErr) return ToElementTypeOrErr.takeError(); return Importer.getToContext().getIncompleteArrayType(*ToElementTypeOrErr, T->getSizeModifier(), T->getIndexTypeCVRQualifiers()); } ExpectedType ASTNodeImporter::VisitVariableArrayType(const VariableArrayType *T) { QualType ToElementType; Expr *ToSizeExpr; SourceRange ToBracketsRange; if (auto Imp = importSeq( T->getElementType(), T->getSizeExpr(), T->getBracketsRange())) std::tie(ToElementType, ToSizeExpr, ToBracketsRange) = *Imp; else return Imp.takeError(); return Importer.getToContext().getVariableArrayType( ToElementType, ToSizeExpr, T->getSizeModifier(), T->getIndexTypeCVRQualifiers(), ToBracketsRange); } ExpectedType ASTNodeImporter::VisitDependentSizedArrayType( const DependentSizedArrayType *T) { QualType ToElementType; Expr *ToSizeExpr; SourceRange ToBracketsRange; if (auto Imp = importSeq( T->getElementType(), T->getSizeExpr(), T->getBracketsRange())) std::tie(ToElementType, ToSizeExpr, ToBracketsRange) = *Imp; else return Imp.takeError(); // SizeExpr may be null if size is not specified directly. // For example, 'int a[]'. return Importer.getToContext().getDependentSizedArrayType( ToElementType, ToSizeExpr, T->getSizeModifier(), T->getIndexTypeCVRQualifiers(), ToBracketsRange); } ExpectedType ASTNodeImporter::VisitVectorType(const VectorType *T) { ExpectedType ToElementTypeOrErr = import(T->getElementType()); if (!ToElementTypeOrErr) return ToElementTypeOrErr.takeError(); return Importer.getToContext().getVectorType(*ToElementTypeOrErr, T->getNumElements(), T->getVectorKind()); } ExpectedType ASTNodeImporter::VisitExtVectorType(const ExtVectorType *T) { ExpectedType ToElementTypeOrErr = import(T->getElementType()); if (!ToElementTypeOrErr) return ToElementTypeOrErr.takeError(); return Importer.getToContext().getExtVectorType(*ToElementTypeOrErr, T->getNumElements()); } ExpectedType ASTNodeImporter::VisitFunctionNoProtoType(const FunctionNoProtoType *T) { // FIXME: What happens if we're importing a function without a prototype // into C++? Should we make it variadic? ExpectedType ToReturnTypeOrErr = import(T->getReturnType()); if (!ToReturnTypeOrErr) return ToReturnTypeOrErr.takeError(); return Importer.getToContext().getFunctionNoProtoType(*ToReturnTypeOrErr, T->getExtInfo()); } ExpectedType ASTNodeImporter::VisitFunctionProtoType(const FunctionProtoType *T) { ExpectedType ToReturnTypeOrErr = import(T->getReturnType()); if (!ToReturnTypeOrErr) return ToReturnTypeOrErr.takeError(); // Import argument types SmallVector ArgTypes; for (const auto &A : T->param_types()) { ExpectedType TyOrErr = import(A); if (!TyOrErr) return TyOrErr.takeError(); ArgTypes.push_back(*TyOrErr); } // Import exception types SmallVector ExceptionTypes; for (const auto &E : T->exceptions()) { ExpectedType TyOrErr = import(E); if (!TyOrErr) return TyOrErr.takeError(); ExceptionTypes.push_back(*TyOrErr); } FunctionProtoType::ExtProtoInfo FromEPI = T->getExtProtoInfo(); FunctionProtoType::ExtProtoInfo ToEPI; auto Imp = importSeq( FromEPI.ExceptionSpec.NoexceptExpr, FromEPI.ExceptionSpec.SourceDecl, FromEPI.ExceptionSpec.SourceTemplate); if (!Imp) return Imp.takeError(); ToEPI.ExtInfo = FromEPI.ExtInfo; ToEPI.Variadic = FromEPI.Variadic; ToEPI.HasTrailingReturn = FromEPI.HasTrailingReturn; ToEPI.TypeQuals = FromEPI.TypeQuals; ToEPI.RefQualifier = FromEPI.RefQualifier; ToEPI.ExceptionSpec.Type = FromEPI.ExceptionSpec.Type; ToEPI.ExceptionSpec.Exceptions = ExceptionTypes; std::tie( ToEPI.ExceptionSpec.NoexceptExpr, ToEPI.ExceptionSpec.SourceDecl, ToEPI.ExceptionSpec.SourceTemplate) = *Imp; return Importer.getToContext().getFunctionType( *ToReturnTypeOrErr, ArgTypes, ToEPI); } ExpectedType ASTNodeImporter::VisitUnresolvedUsingType( const UnresolvedUsingType *T) { UnresolvedUsingTypenameDecl *ToD; Decl *ToPrevD; if (auto Imp = importSeq(T->getDecl(), T->getDecl()->getPreviousDecl())) std::tie(ToD, ToPrevD) = *Imp; else return Imp.takeError(); return Importer.getToContext().getTypeDeclType( ToD, cast_or_null(ToPrevD)); } ExpectedType ASTNodeImporter::VisitParenType(const ParenType *T) { ExpectedType ToInnerTypeOrErr = import(T->getInnerType()); if (!ToInnerTypeOrErr) return ToInnerTypeOrErr.takeError(); return Importer.getToContext().getParenType(*ToInnerTypeOrErr); } ExpectedType ASTNodeImporter::VisitTypedefType(const TypedefType *T) { Expected ToDeclOrErr = import(T->getDecl()); if (!ToDeclOrErr) return ToDeclOrErr.takeError(); return Importer.getToContext().getTypeDeclType(*ToDeclOrErr); } ExpectedType ASTNodeImporter::VisitTypeOfExprType(const TypeOfExprType *T) { ExpectedExpr ToExprOrErr = import(T->getUnderlyingExpr()); if (!ToExprOrErr) return ToExprOrErr.takeError(); return Importer.getToContext().getTypeOfExprType(*ToExprOrErr); } ExpectedType ASTNodeImporter::VisitTypeOfType(const TypeOfType *T) { ExpectedType ToUnderlyingTypeOrErr = import(T->getUnderlyingType()); if (!ToUnderlyingTypeOrErr) return ToUnderlyingTypeOrErr.takeError(); return Importer.getToContext().getTypeOfType(*ToUnderlyingTypeOrErr); } ExpectedType ASTNodeImporter::VisitDecltypeType(const DecltypeType *T) { // FIXME: Make sure that the "to" context supports C++0x! ExpectedExpr ToExprOrErr = import(T->getUnderlyingExpr()); if (!ToExprOrErr) return ToExprOrErr.takeError(); ExpectedType ToUnderlyingTypeOrErr = import(T->getUnderlyingType()); if (!ToUnderlyingTypeOrErr) return ToUnderlyingTypeOrErr.takeError(); return Importer.getToContext().getDecltypeType( *ToExprOrErr, *ToUnderlyingTypeOrErr); } ExpectedType ASTNodeImporter::VisitUnaryTransformType(const UnaryTransformType *T) { ExpectedType ToBaseTypeOrErr = import(T->getBaseType()); if (!ToBaseTypeOrErr) return ToBaseTypeOrErr.takeError(); ExpectedType ToUnderlyingTypeOrErr = import(T->getUnderlyingType()); if (!ToUnderlyingTypeOrErr) return ToUnderlyingTypeOrErr.takeError(); return Importer.getToContext().getUnaryTransformType( *ToBaseTypeOrErr, *ToUnderlyingTypeOrErr, T->getUTTKind()); } ExpectedType ASTNodeImporter::VisitAutoType(const AutoType *T) { // FIXME: Make sure that the "to" context supports C++11! ExpectedType ToDeducedTypeOrErr = import(T->getDeducedType()); if (!ToDeducedTypeOrErr) return ToDeducedTypeOrErr.takeError(); ExpectedDecl ToTypeConstraintConcept = import(T->getTypeConstraintConcept()); if (!ToTypeConstraintConcept) return ToTypeConstraintConcept.takeError(); SmallVector ToTemplateArgs; ArrayRef FromTemplateArgs = T->getTypeConstraintArguments(); if (Error Err = ImportTemplateArguments(FromTemplateArgs.data(), FromTemplateArgs.size(), ToTemplateArgs)) return std::move(Err); return Importer.getToContext().getAutoType( *ToDeducedTypeOrErr, T->getKeyword(), /*IsDependent*/false, /*IsPack=*/false, cast_or_null(*ToTypeConstraintConcept), ToTemplateArgs); } ExpectedType ASTNodeImporter::VisitInjectedClassNameType( const InjectedClassNameType *T) { Expected ToDeclOrErr = import(T->getDecl()); if (!ToDeclOrErr) return ToDeclOrErr.takeError(); ExpectedType ToInjTypeOrErr = import(T->getInjectedSpecializationType()); if (!ToInjTypeOrErr) return ToInjTypeOrErr.takeError(); // FIXME: ASTContext::getInjectedClassNameType is not suitable for AST reading // See comments in InjectedClassNameType definition for details // return Importer.getToContext().getInjectedClassNameType(D, InjType); enum { TypeAlignmentInBits = 4, TypeAlignment = 1 << TypeAlignmentInBits }; return QualType(new (Importer.getToContext(), TypeAlignment) InjectedClassNameType(*ToDeclOrErr, *ToInjTypeOrErr), 0); } ExpectedType ASTNodeImporter::VisitRecordType(const RecordType *T) { Expected ToDeclOrErr = import(T->getDecl()); if (!ToDeclOrErr) return ToDeclOrErr.takeError(); return Importer.getToContext().getTagDeclType(*ToDeclOrErr); } ExpectedType ASTNodeImporter::VisitEnumType(const EnumType *T) { Expected ToDeclOrErr = import(T->getDecl()); if (!ToDeclOrErr) return ToDeclOrErr.takeError(); return Importer.getToContext().getTagDeclType(*ToDeclOrErr); } ExpectedType ASTNodeImporter::VisitAttributedType(const AttributedType *T) { ExpectedType ToModifiedTypeOrErr = import(T->getModifiedType()); if (!ToModifiedTypeOrErr) return ToModifiedTypeOrErr.takeError(); ExpectedType ToEquivalentTypeOrErr = import(T->getEquivalentType()); if (!ToEquivalentTypeOrErr) return ToEquivalentTypeOrErr.takeError(); return Importer.getToContext().getAttributedType(T->getAttrKind(), *ToModifiedTypeOrErr, *ToEquivalentTypeOrErr); } ExpectedType ASTNodeImporter::VisitTemplateTypeParmType( const TemplateTypeParmType *T) { Expected ToDeclOrErr = import(T->getDecl()); if (!ToDeclOrErr) return ToDeclOrErr.takeError(); return Importer.getToContext().getTemplateTypeParmType( T->getDepth(), T->getIndex(), T->isParameterPack(), *ToDeclOrErr); } ExpectedType ASTNodeImporter::VisitSubstTemplateTypeParmType( const SubstTemplateTypeParmType *T) { ExpectedType ReplacedOrErr = import(QualType(T->getReplacedParameter(), 0)); if (!ReplacedOrErr) return ReplacedOrErr.takeError(); const TemplateTypeParmType *Replaced = cast((*ReplacedOrErr).getTypePtr()); ExpectedType ToReplacementTypeOrErr = import(T->getReplacementType()); if (!ToReplacementTypeOrErr) return ToReplacementTypeOrErr.takeError(); return Importer.getToContext().getSubstTemplateTypeParmType( Replaced, (*ToReplacementTypeOrErr).getCanonicalType()); } ExpectedType ASTNodeImporter::VisitTemplateSpecializationType( const TemplateSpecializationType *T) { auto ToTemplateOrErr = import(T->getTemplateName()); if (!ToTemplateOrErr) return ToTemplateOrErr.takeError(); SmallVector ToTemplateArgs; if (Error Err = ImportTemplateArguments( T->getArgs(), T->getNumArgs(), ToTemplateArgs)) return std::move(Err); QualType ToCanonType; if (!QualType(T, 0).isCanonical()) { QualType FromCanonType = Importer.getFromContext().getCanonicalType(QualType(T, 0)); if (ExpectedType TyOrErr = import(FromCanonType)) ToCanonType = *TyOrErr; else return TyOrErr.takeError(); } return Importer.getToContext().getTemplateSpecializationType(*ToTemplateOrErr, ToTemplateArgs, ToCanonType); } ExpectedType ASTNodeImporter::VisitElaboratedType(const ElaboratedType *T) { // Note: the qualifier in an ElaboratedType is optional. auto ToQualifierOrErr = import(T->getQualifier()); if (!ToQualifierOrErr) return ToQualifierOrErr.takeError(); ExpectedType ToNamedTypeOrErr = import(T->getNamedType()); if (!ToNamedTypeOrErr) return ToNamedTypeOrErr.takeError(); Expected ToOwnedTagDeclOrErr = import(T->getOwnedTagDecl()); if (!ToOwnedTagDeclOrErr) return ToOwnedTagDeclOrErr.takeError(); return Importer.getToContext().getElaboratedType(T->getKeyword(), *ToQualifierOrErr, *ToNamedTypeOrErr, *ToOwnedTagDeclOrErr); } ExpectedType ASTNodeImporter::VisitPackExpansionType(const PackExpansionType *T) { ExpectedType ToPatternOrErr = import(T->getPattern()); if (!ToPatternOrErr) return ToPatternOrErr.takeError(); return Importer.getToContext().getPackExpansionType(*ToPatternOrErr, T->getNumExpansions()); } ExpectedType ASTNodeImporter::VisitDependentTemplateSpecializationType( const DependentTemplateSpecializationType *T) { auto ToQualifierOrErr = import(T->getQualifier()); if (!ToQualifierOrErr) return ToQualifierOrErr.takeError(); IdentifierInfo *ToName = Importer.Import(T->getIdentifier()); SmallVector ToPack; ToPack.reserve(T->getNumArgs()); if (Error Err = ImportTemplateArguments( T->getArgs(), T->getNumArgs(), ToPack)) return std::move(Err); return Importer.getToContext().getDependentTemplateSpecializationType( T->getKeyword(), *ToQualifierOrErr, ToName, ToPack); } ExpectedType ASTNodeImporter::VisitDependentNameType(const DependentNameType *T) { auto ToQualifierOrErr = import(T->getQualifier()); if (!ToQualifierOrErr) return ToQualifierOrErr.takeError(); IdentifierInfo *Name = Importer.Import(T->getIdentifier()); QualType Canon; if (T != T->getCanonicalTypeInternal().getTypePtr()) { if (ExpectedType TyOrErr = import(T->getCanonicalTypeInternal())) Canon = (*TyOrErr).getCanonicalType(); else return TyOrErr.takeError(); } return Importer.getToContext().getDependentNameType(T->getKeyword(), *ToQualifierOrErr, Name, Canon); } ExpectedType ASTNodeImporter::VisitObjCInterfaceType(const ObjCInterfaceType *T) { Expected ToDeclOrErr = import(T->getDecl()); if (!ToDeclOrErr) return ToDeclOrErr.takeError(); return Importer.getToContext().getObjCInterfaceType(*ToDeclOrErr); } ExpectedType ASTNodeImporter::VisitObjCObjectType(const ObjCObjectType *T) { ExpectedType ToBaseTypeOrErr = import(T->getBaseType()); if (!ToBaseTypeOrErr) return ToBaseTypeOrErr.takeError(); SmallVector TypeArgs; for (auto TypeArg : T->getTypeArgsAsWritten()) { if (ExpectedType TyOrErr = import(TypeArg)) TypeArgs.push_back(*TyOrErr); else return TyOrErr.takeError(); } SmallVector Protocols; for (auto *P : T->quals()) { if (Expected ProtocolOrErr = import(P)) Protocols.push_back(*ProtocolOrErr); else return ProtocolOrErr.takeError(); } return Importer.getToContext().getObjCObjectType(*ToBaseTypeOrErr, TypeArgs, Protocols, T->isKindOfTypeAsWritten()); } ExpectedType ASTNodeImporter::VisitObjCObjectPointerType(const ObjCObjectPointerType *T) { ExpectedType ToPointeeTypeOrErr = import(T->getPointeeType()); if (!ToPointeeTypeOrErr) return ToPointeeTypeOrErr.takeError(); return Importer.getToContext().getObjCObjectPointerType(*ToPointeeTypeOrErr); } //---------------------------------------------------------------------------- // Import Declarations //---------------------------------------------------------------------------- Error ASTNodeImporter::ImportDeclParts( NamedDecl *D, DeclContext *&DC, DeclContext *&LexicalDC, DeclarationName &Name, NamedDecl *&ToD, SourceLocation &Loc) { // Check if RecordDecl is in FunctionDecl parameters to avoid infinite loop. // example: int struct_in_proto(struct data_t{int a;int b;} *d); // FIXME: We could support these constructs by importing a different type of // this parameter and by importing the original type of the parameter only // after the FunctionDecl is created. See // VisitFunctionDecl::UsedDifferentProtoType. DeclContext *OrigDC = D->getDeclContext(); FunctionDecl *FunDecl; if (isa(D) && (FunDecl = dyn_cast(OrigDC)) && FunDecl->hasBody()) { auto getLeafPointeeType = [](const Type *T) { while (T->isPointerType() || T->isArrayType()) { T = T->getPointeeOrArrayElementType(); } return T; }; for (const ParmVarDecl *P : FunDecl->parameters()) { const Type *LeafT = getLeafPointeeType(P->getType().getCanonicalType().getTypePtr()); auto *RT = dyn_cast(LeafT); if (RT && RT->getDecl() == D) { Importer.FromDiag(D->getLocation(), diag::err_unsupported_ast_node) << D->getDeclKindName(); return make_error(ImportError::UnsupportedConstruct); } } } // Import the context of this declaration. if (Error Err = ImportDeclContext(D, DC, LexicalDC)) return Err; // Import the name of this declaration. if (Error Err = importInto(Name, D->getDeclName())) return Err; // Import the location of this declaration. if (Error Err = importInto(Loc, D->getLocation())) return Err; ToD = cast_or_null(Importer.GetAlreadyImportedOrNull(D)); if (ToD) if (Error Err = ASTNodeImporter(*this).ImportDefinitionIfNeeded(D, ToD)) return Err; return Error::success(); } Error ASTNodeImporter::ImportDefinitionIfNeeded(Decl *FromD, Decl *ToD) { if (!FromD) return Error::success(); if (!ToD) if (Error Err = importInto(ToD, FromD)) return Err; if (RecordDecl *FromRecord = dyn_cast(FromD)) { if (RecordDecl *ToRecord = cast(ToD)) { if (FromRecord->getDefinition() && FromRecord->isCompleteDefinition() && !ToRecord->getDefinition()) { if (Error Err = ImportDefinition(FromRecord, ToRecord)) return Err; } } return Error::success(); } if (EnumDecl *FromEnum = dyn_cast(FromD)) { if (EnumDecl *ToEnum = cast(ToD)) { if (FromEnum->getDefinition() && !ToEnum->getDefinition()) { if (Error Err = ImportDefinition(FromEnum, ToEnum)) return Err; } } return Error::success(); } return Error::success(); } Error ASTNodeImporter::ImportDeclarationNameLoc( const DeclarationNameInfo &From, DeclarationNameInfo& To) { // NOTE: To.Name and To.Loc are already imported. // We only have to import To.LocInfo. switch (To.getName().getNameKind()) { case DeclarationName::Identifier: case DeclarationName::ObjCZeroArgSelector: case DeclarationName::ObjCOneArgSelector: case DeclarationName::ObjCMultiArgSelector: case DeclarationName::CXXUsingDirective: case DeclarationName::CXXDeductionGuideName: return Error::success(); case DeclarationName::CXXOperatorName: { if (auto ToRangeOrErr = import(From.getCXXOperatorNameRange())) To.setCXXOperatorNameRange(*ToRangeOrErr); else return ToRangeOrErr.takeError(); return Error::success(); } case DeclarationName::CXXLiteralOperatorName: { if (ExpectedSLoc LocOrErr = import(From.getCXXLiteralOperatorNameLoc())) To.setCXXLiteralOperatorNameLoc(*LocOrErr); else return LocOrErr.takeError(); return Error::success(); } case DeclarationName::CXXConstructorName: case DeclarationName::CXXDestructorName: case DeclarationName::CXXConversionFunctionName: { if (auto ToTInfoOrErr = import(From.getNamedTypeInfo())) To.setNamedTypeInfo(*ToTInfoOrErr); else return ToTInfoOrErr.takeError(); return Error::success(); } } llvm_unreachable("Unknown name kind."); } Error ASTNodeImporter::ImportDeclContext(DeclContext *FromDC, bool ForceImport) { if (Importer.isMinimalImport() && !ForceImport) { auto ToDCOrErr = Importer.ImportContext(FromDC); return ToDCOrErr.takeError(); } // We use strict error handling in case of records and enums, but not // with e.g. namespaces. // // FIXME Clients of the ASTImporter should be able to choose an // appropriate error handling strategy for their needs. For instance, // they may not want to mark an entire namespace as erroneous merely // because there is an ODR error with two typedefs. As another example, // the client may allow EnumConstantDecls with same names but with // different values in two distinct translation units. bool AccumulateChildErrors = isa(FromDC); Error ChildErrors = Error::success(); for (auto *From : FromDC->decls()) { ExpectedDecl ImportedOrErr = import(From); // If we are in the process of ImportDefinition(...) for a RecordDecl we // want to make sure that we are also completing each FieldDecl. There // are currently cases where this does not happen and this is correctness // fix since operations such as code generation will expect this to be so. if (ImportedOrErr) { FieldDecl *FieldFrom = dyn_cast_or_null(From); Decl *ImportedDecl = (Decl*)*ImportedOrErr; FieldDecl *FieldTo = dyn_cast_or_null(ImportedDecl); if (FieldFrom && FieldTo) { const RecordType *RecordFrom = FieldFrom->getType()->getAs(); const RecordType *RecordTo = FieldTo->getType()->getAs(); if (RecordFrom && RecordTo) { RecordDecl *FromRecordDecl = RecordFrom->getDecl(); RecordDecl *ToRecordDecl = RecordTo->getDecl(); if (FromRecordDecl->isCompleteDefinition() && !ToRecordDecl->isCompleteDefinition()) { Error Err = ImportDefinition(FromRecordDecl, ToRecordDecl); if (Err && AccumulateChildErrors) ChildErrors = joinErrors(std::move(ChildErrors), std::move(Err)); else consumeError(std::move(Err)); } } } } else { if (AccumulateChildErrors) ChildErrors = joinErrors(std::move(ChildErrors), ImportedOrErr.takeError()); else consumeError(ImportedOrErr.takeError()); } } // We reorder declarations in RecordDecls because they may have another order // in the "to" context than they have in the "from" context. This may happen // e.g when we import a class like this: // struct declToImport { // int a = c + b; // int b = 1; // int c = 2; // }; // During the import of `a` we import first the dependencies in sequence, // thus the order would be `c`, `b`, `a`. We will get the normal order by // first removing the already imported members and then adding them in the // order as they apper in the "from" context. // // Keeping field order is vital because it determines structure layout. // // Here and below, we cannot call field_begin() method and its callers on // ToDC if it has an external storage. Calling field_begin() will // automatically load all the fields by calling // LoadFieldsFromExternalStorage(). LoadFieldsFromExternalStorage() would // call ASTImporter::Import(). This is because the ExternalASTSource // interface in LLDB is implemented by the means of the ASTImporter. However, // calling an import at this point would result in an uncontrolled import, we // must avoid that. const auto *FromRD = dyn_cast(FromDC); if (!FromRD) return ChildErrors; auto ToDCOrErr = Importer.ImportContext(FromDC); if (!ToDCOrErr) { consumeError(std::move(ChildErrors)); return ToDCOrErr.takeError(); } DeclContext *ToDC = *ToDCOrErr; // Remove all declarations, which may be in wrong order in the // lexical DeclContext and then add them in the proper order. for (auto *D : FromRD->decls()) { if (isa(D) || isa(D) || isa(D)) { assert(D && "DC contains a null decl"); Decl *ToD = Importer.GetAlreadyImportedOrNull(D); // Remove only the decls which we successfully imported. if (ToD) { assert(ToDC == ToD->getLexicalDeclContext() && ToDC->containsDecl(ToD)); // Remove the decl from its wrong place in the linked list. ToDC->removeDecl(ToD); // Add the decl to the end of the linked list. // This time it will be at the proper place because the enclosing for // loop iterates in the original (good) order of the decls. ToDC->addDeclInternal(ToD); } } } return ChildErrors; } Error ASTNodeImporter::ImportDeclContext( Decl *FromD, DeclContext *&ToDC, DeclContext *&ToLexicalDC) { auto ToDCOrErr = Importer.ImportContext(FromD->getDeclContext()); if (!ToDCOrErr) return ToDCOrErr.takeError(); ToDC = *ToDCOrErr; if (FromD->getDeclContext() != FromD->getLexicalDeclContext()) { auto ToLexicalDCOrErr = Importer.ImportContext( FromD->getLexicalDeclContext()); if (!ToLexicalDCOrErr) return ToLexicalDCOrErr.takeError(); ToLexicalDC = *ToLexicalDCOrErr; } else ToLexicalDC = ToDC; return Error::success(); } Error ASTNodeImporter::ImportImplicitMethods( const CXXRecordDecl *From, CXXRecordDecl *To) { assert(From->isCompleteDefinition() && To->getDefinition() == To && "Import implicit methods to or from non-definition"); for (CXXMethodDecl *FromM : From->methods()) if (FromM->isImplicit()) { Expected ToMOrErr = import(FromM); if (!ToMOrErr) return ToMOrErr.takeError(); } return Error::success(); } static Error setTypedefNameForAnonDecl(TagDecl *From, TagDecl *To, ASTImporter &Importer) { if (TypedefNameDecl *FromTypedef = From->getTypedefNameForAnonDecl()) { if (ExpectedDecl ToTypedefOrErr = Importer.Import(FromTypedef)) To->setTypedefNameForAnonDecl(cast(*ToTypedefOrErr)); else return ToTypedefOrErr.takeError(); } return Error::success(); } Error ASTNodeImporter::ImportDefinition( RecordDecl *From, RecordDecl *To, ImportDefinitionKind Kind) { auto DefinitionCompleter = [To]() { // There are cases in LLDB when we first import a class without its // members. The class will have DefinitionData, but no members. Then, // importDefinition is called from LLDB, which tries to get the members, so // when we get here, the class already has the DefinitionData set, so we // must unset the CompleteDefinition here to be able to complete again the // definition. To->setCompleteDefinition(false); To->completeDefinition(); }; if (To->getDefinition() || To->isBeingDefined()) { if (Kind == IDK_Everything || // In case of lambdas, the class already has a definition ptr set, but // the contained decls are not imported yet. Also, isBeingDefined was // set in CXXRecordDecl::CreateLambda. We must import the contained // decls here and finish the definition. (To->isLambda() && shouldForceImportDeclContext(Kind))) { Error Result = ImportDeclContext(From, /*ForceImport=*/true); // Finish the definition of the lambda, set isBeingDefined to false. if (To->isLambda()) DefinitionCompleter(); return Result; } return Error::success(); } To->startDefinition(); // Complete the definition even if error is returned. // The RecordDecl may be already part of the AST so it is better to // have it in complete state even if something is wrong with it. auto DefinitionCompleterScopeExit = llvm::make_scope_exit(DefinitionCompleter); if (Error Err = setTypedefNameForAnonDecl(From, To, Importer)) return Err; // Add base classes. auto *ToCXX = dyn_cast(To); auto *FromCXX = dyn_cast(From); if (ToCXX && FromCXX && ToCXX->dataPtr() && FromCXX->dataPtr()) { struct CXXRecordDecl::DefinitionData &ToData = ToCXX->data(); struct CXXRecordDecl::DefinitionData &FromData = FromCXX->data(); #define FIELD(Name, Width, Merge) \ ToData.Name = FromData.Name; #include "clang/AST/CXXRecordDeclDefinitionBits.def" // Copy over the data stored in RecordDeclBits ToCXX->setArgPassingRestrictions(FromCXX->getArgPassingRestrictions()); SmallVector Bases; for (const auto &Base1 : FromCXX->bases()) { ExpectedType TyOrErr = import(Base1.getType()); if (!TyOrErr) return TyOrErr.takeError(); SourceLocation EllipsisLoc; if (Base1.isPackExpansion()) { if (ExpectedSLoc LocOrErr = import(Base1.getEllipsisLoc())) EllipsisLoc = *LocOrErr; else return LocOrErr.takeError(); } // Ensure that we have a definition for the base. if (Error Err = ImportDefinitionIfNeeded(Base1.getType()->getAsCXXRecordDecl())) return Err; auto RangeOrErr = import(Base1.getSourceRange()); if (!RangeOrErr) return RangeOrErr.takeError(); auto TSIOrErr = import(Base1.getTypeSourceInfo()); if (!TSIOrErr) return TSIOrErr.takeError(); Bases.push_back( new (Importer.getToContext()) CXXBaseSpecifier( *RangeOrErr, Base1.isVirtual(), Base1.isBaseOfClass(), Base1.getAccessSpecifierAsWritten(), *TSIOrErr, EllipsisLoc)); } if (!Bases.empty()) ToCXX->setBases(Bases.data(), Bases.size()); } if (shouldForceImportDeclContext(Kind)) if (Error Err = ImportDeclContext(From, /*ForceImport=*/true)) return Err; return Error::success(); } Error ASTNodeImporter::ImportInitializer(VarDecl *From, VarDecl *To) { if (To->getAnyInitializer()) return Error::success(); Expr *FromInit = From->getInit(); if (!FromInit) return Error::success(); ExpectedExpr ToInitOrErr = import(FromInit); if (!ToInitOrErr) return ToInitOrErr.takeError(); To->setInit(*ToInitOrErr); if (From->isInitKnownICE()) { EvaluatedStmt *Eval = To->ensureEvaluatedStmt(); Eval->CheckedICE = true; Eval->IsICE = From->isInitICE(); } // FIXME: Other bits to merge? return Error::success(); } Error ASTNodeImporter::ImportDefinition( EnumDecl *From, EnumDecl *To, ImportDefinitionKind Kind) { if (To->getDefinition() || To->isBeingDefined()) { if (Kind == IDK_Everything) return ImportDeclContext(From, /*ForceImport=*/true); return Error::success(); } To->startDefinition(); if (Error Err = setTypedefNameForAnonDecl(From, To, Importer)) return Err; ExpectedType ToTypeOrErr = import(Importer.getFromContext().getTypeDeclType(From)); if (!ToTypeOrErr) return ToTypeOrErr.takeError(); ExpectedType ToPromotionTypeOrErr = import(From->getPromotionType()); if (!ToPromotionTypeOrErr) return ToPromotionTypeOrErr.takeError(); if (shouldForceImportDeclContext(Kind)) if (Error Err = ImportDeclContext(From, /*ForceImport=*/true)) return Err; // FIXME: we might need to merge the number of positive or negative bits // if the enumerator lists don't match. To->completeDefinition(*ToTypeOrErr, *ToPromotionTypeOrErr, From->getNumPositiveBits(), From->getNumNegativeBits()); return Error::success(); } Error ASTNodeImporter::ImportTemplateArguments( const TemplateArgument *FromArgs, unsigned NumFromArgs, SmallVectorImpl &ToArgs) { for (unsigned I = 0; I != NumFromArgs; ++I) { if (auto ToOrErr = import(FromArgs[I])) ToArgs.push_back(*ToOrErr); else return ToOrErr.takeError(); } return Error::success(); } // FIXME: Do not forget to remove this and use only 'import'. Expected ASTNodeImporter::ImportTemplateArgument(const TemplateArgument &From) { return import(From); } template Error ASTNodeImporter::ImportTemplateArgumentListInfo( const InContainerTy &Container, TemplateArgumentListInfo &ToTAInfo) { for (const auto &FromLoc : Container) { if (auto ToLocOrErr = import(FromLoc)) ToTAInfo.addArgument(*ToLocOrErr); else return ToLocOrErr.takeError(); } return Error::success(); } static StructuralEquivalenceKind getStructuralEquivalenceKind(const ASTImporter &Importer) { return Importer.isMinimalImport() ? StructuralEquivalenceKind::Minimal : StructuralEquivalenceKind::Default; } bool ASTNodeImporter::IsStructuralMatch(Decl *From, Decl *To, bool Complain) { StructuralEquivalenceContext Ctx( Importer.getFromContext(), Importer.getToContext(), Importer.getNonEquivalentDecls(), getStructuralEquivalenceKind(Importer), false, Complain); return Ctx.IsEquivalent(From, To); } bool ASTNodeImporter::IsStructuralMatch(RecordDecl *FromRecord, RecordDecl *ToRecord, bool Complain) { // Eliminate a potential failure point where we attempt to re-import // something we're trying to import while completing ToRecord. Decl *ToOrigin = Importer.GetOriginalDecl(ToRecord); if (ToOrigin) { auto *ToOriginRecord = dyn_cast(ToOrigin); if (ToOriginRecord) ToRecord = ToOriginRecord; } StructuralEquivalenceContext Ctx(Importer.getFromContext(), ToRecord->getASTContext(), Importer.getNonEquivalentDecls(), getStructuralEquivalenceKind(Importer), false, Complain); return Ctx.IsEquivalent(FromRecord, ToRecord); } bool ASTNodeImporter::IsStructuralMatch(VarDecl *FromVar, VarDecl *ToVar, bool Complain) { StructuralEquivalenceContext Ctx( Importer.getFromContext(), Importer.getToContext(), Importer.getNonEquivalentDecls(), getStructuralEquivalenceKind(Importer), false, Complain); return Ctx.IsEquivalent(FromVar, ToVar); } bool ASTNodeImporter::IsStructuralMatch(EnumDecl *FromEnum, EnumDecl *ToEnum) { // Eliminate a potential failure point where we attempt to re-import // something we're trying to import while completing ToEnum. if (Decl *ToOrigin = Importer.GetOriginalDecl(ToEnum)) if (auto *ToOriginEnum = dyn_cast(ToOrigin)) ToEnum = ToOriginEnum; StructuralEquivalenceContext Ctx( Importer.getFromContext(), Importer.getToContext(), Importer.getNonEquivalentDecls(), getStructuralEquivalenceKind(Importer)); return Ctx.IsEquivalent(FromEnum, ToEnum); } bool ASTNodeImporter::IsStructuralMatch(FunctionTemplateDecl *From, FunctionTemplateDecl *To) { StructuralEquivalenceContext Ctx( Importer.getFromContext(), Importer.getToContext(), Importer.getNonEquivalentDecls(), getStructuralEquivalenceKind(Importer), false, false); return Ctx.IsEquivalent(From, To); } bool ASTNodeImporter::IsStructuralMatch(FunctionDecl *From, FunctionDecl *To) { StructuralEquivalenceContext Ctx( Importer.getFromContext(), Importer.getToContext(), Importer.getNonEquivalentDecls(), getStructuralEquivalenceKind(Importer), false, false); return Ctx.IsEquivalent(From, To); } bool ASTNodeImporter::IsStructuralMatch(EnumConstantDecl *FromEC, EnumConstantDecl *ToEC) { const llvm::APSInt &FromVal = FromEC->getInitVal(); const llvm::APSInt &ToVal = ToEC->getInitVal(); return FromVal.isSigned() == ToVal.isSigned() && FromVal.getBitWidth() == ToVal.getBitWidth() && FromVal == ToVal; } bool ASTNodeImporter::IsStructuralMatch(ClassTemplateDecl *From, ClassTemplateDecl *To) { StructuralEquivalenceContext Ctx(Importer.getFromContext(), Importer.getToContext(), Importer.getNonEquivalentDecls(), getStructuralEquivalenceKind(Importer)); return Ctx.IsEquivalent(From, To); } bool ASTNodeImporter::IsStructuralMatch(VarTemplateDecl *From, VarTemplateDecl *To) { StructuralEquivalenceContext Ctx(Importer.getFromContext(), Importer.getToContext(), Importer.getNonEquivalentDecls(), getStructuralEquivalenceKind(Importer)); return Ctx.IsEquivalent(From, To); } ExpectedDecl ASTNodeImporter::VisitDecl(Decl *D) { Importer.FromDiag(D->getLocation(), diag::err_unsupported_ast_node) << D->getDeclKindName(); return make_error(ImportError::UnsupportedConstruct); } ExpectedDecl ASTNodeImporter::VisitImportDecl(ImportDecl *D) { Importer.FromDiag(D->getLocation(), diag::err_unsupported_ast_node) << D->getDeclKindName(); return make_error(ImportError::UnsupportedConstruct); } ExpectedDecl ASTNodeImporter::VisitEmptyDecl(EmptyDecl *D) { // Import the context of this declaration. DeclContext *DC, *LexicalDC; if (Error Err = ImportDeclContext(D, DC, LexicalDC)) return std::move(Err); // Import the location of this declaration. ExpectedSLoc LocOrErr = import(D->getLocation()); if (!LocOrErr) return LocOrErr.takeError(); EmptyDecl *ToD; if (GetImportedOrCreateDecl(ToD, D, Importer.getToContext(), DC, *LocOrErr)) return ToD; ToD->setLexicalDeclContext(LexicalDC); LexicalDC->addDeclInternal(ToD); return ToD; } ExpectedDecl ASTNodeImporter::VisitTranslationUnitDecl(TranslationUnitDecl *D) { TranslationUnitDecl *ToD = Importer.getToContext().getTranslationUnitDecl(); Importer.MapImported(D, ToD); return ToD; } ExpectedDecl ASTNodeImporter::VisitAccessSpecDecl(AccessSpecDecl *D) { ExpectedSLoc LocOrErr = import(D->getLocation()); if (!LocOrErr) return LocOrErr.takeError(); auto ColonLocOrErr = import(D->getColonLoc()); if (!ColonLocOrErr) return ColonLocOrErr.takeError(); // Import the context of this declaration. auto DCOrErr = Importer.ImportContext(D->getDeclContext()); if (!DCOrErr) return DCOrErr.takeError(); DeclContext *DC = *DCOrErr; AccessSpecDecl *ToD; if (GetImportedOrCreateDecl(ToD, D, Importer.getToContext(), D->getAccess(), DC, *LocOrErr, *ColonLocOrErr)) return ToD; // Lexical DeclContext and Semantic DeclContext // is always the same for the accessSpec. ToD->setLexicalDeclContext(DC); DC->addDeclInternal(ToD); return ToD; } ExpectedDecl ASTNodeImporter::VisitStaticAssertDecl(StaticAssertDecl *D) { auto DCOrErr = Importer.ImportContext(D->getDeclContext()); if (!DCOrErr) return DCOrErr.takeError(); DeclContext *DC = *DCOrErr; DeclContext *LexicalDC = DC; SourceLocation ToLocation, ToRParenLoc; Expr *ToAssertExpr; StringLiteral *ToMessage; if (auto Imp = importSeq( D->getLocation(), D->getAssertExpr(), D->getMessage(), D->getRParenLoc())) std::tie(ToLocation, ToAssertExpr, ToMessage, ToRParenLoc) = *Imp; else return Imp.takeError(); StaticAssertDecl *ToD; if (GetImportedOrCreateDecl( ToD, D, Importer.getToContext(), DC, ToLocation, ToAssertExpr, ToMessage, ToRParenLoc, D->isFailed())) return ToD; ToD->setLexicalDeclContext(LexicalDC); LexicalDC->addDeclInternal(ToD); return ToD; } ExpectedDecl ASTNodeImporter::VisitNamespaceDecl(NamespaceDecl *D) { // Import the major distinguishing characteristics of this namespace. DeclContext *DC, *LexicalDC; DeclarationName Name; SourceLocation Loc; NamedDecl *ToD; if (Error Err = ImportDeclParts(D, DC, LexicalDC, Name, ToD, Loc)) return std::move(Err); if (ToD) return ToD; NamespaceDecl *MergeWithNamespace = nullptr; if (!Name) { // This is an anonymous namespace. Adopt an existing anonymous // namespace if we can. // FIXME: Not testable. if (auto *TU = dyn_cast(DC)) MergeWithNamespace = TU->getAnonymousNamespace(); else MergeWithNamespace = cast(DC)->getAnonymousNamespace(); } else { SmallVector ConflictingDecls; auto FoundDecls = Importer.findDeclsInToCtx(DC, Name); for (auto *FoundDecl : FoundDecls) { if (!FoundDecl->isInIdentifierNamespace(Decl::IDNS_Namespace)) continue; if (auto *FoundNS = dyn_cast(FoundDecl)) { MergeWithNamespace = FoundNS; ConflictingDecls.clear(); break; } ConflictingDecls.push_back(FoundDecl); } if (!ConflictingDecls.empty()) { ExpectedName NameOrErr = Importer.HandleNameConflict( Name, DC, Decl::IDNS_Namespace, ConflictingDecls.data(), ConflictingDecls.size()); if (NameOrErr) Name = NameOrErr.get(); else return NameOrErr.takeError(); } } ExpectedSLoc BeginLocOrErr = import(D->getBeginLoc()); if (!BeginLocOrErr) return BeginLocOrErr.takeError(); ExpectedSLoc RBraceLocOrErr = import(D->getRBraceLoc()); if (!RBraceLocOrErr) return RBraceLocOrErr.takeError(); // Create the "to" namespace, if needed. NamespaceDecl *ToNamespace = MergeWithNamespace; if (!ToNamespace) { if (GetImportedOrCreateDecl( ToNamespace, D, Importer.getToContext(), DC, D->isInline(), *BeginLocOrErr, Loc, Name.getAsIdentifierInfo(), /*PrevDecl=*/nullptr)) return ToNamespace; ToNamespace->setRBraceLoc(*RBraceLocOrErr); ToNamespace->setLexicalDeclContext(LexicalDC); LexicalDC->addDeclInternal(ToNamespace); // If this is an anonymous namespace, register it as the anonymous // namespace within its context. if (!Name) { if (auto *TU = dyn_cast(DC)) TU->setAnonymousNamespace(ToNamespace); else cast(DC)->setAnonymousNamespace(ToNamespace); } } Importer.MapImported(D, ToNamespace); if (Error Err = ImportDeclContext(D)) return std::move(Err); return ToNamespace; } ExpectedDecl ASTNodeImporter::VisitNamespaceAliasDecl(NamespaceAliasDecl *D) { // Import the major distinguishing characteristics of this namespace. DeclContext *DC, *LexicalDC; DeclarationName Name; SourceLocation Loc; NamedDecl *LookupD; if (Error Err = ImportDeclParts(D, DC, LexicalDC, Name, LookupD, Loc)) return std::move(Err); if (LookupD) return LookupD; // NOTE: No conflict resolution is done for namespace aliases now. SourceLocation ToNamespaceLoc, ToAliasLoc, ToTargetNameLoc; NestedNameSpecifierLoc ToQualifierLoc; NamespaceDecl *ToNamespace; if (auto Imp = importSeq( D->getNamespaceLoc(), D->getAliasLoc(), D->getQualifierLoc(), D->getTargetNameLoc(), D->getNamespace())) std::tie( ToNamespaceLoc, ToAliasLoc, ToQualifierLoc, ToTargetNameLoc, ToNamespace) = *Imp; else return Imp.takeError(); IdentifierInfo *ToIdentifier = Importer.Import(D->getIdentifier()); NamespaceAliasDecl *ToD; if (GetImportedOrCreateDecl( ToD, D, Importer.getToContext(), DC, ToNamespaceLoc, ToAliasLoc, ToIdentifier, ToQualifierLoc, ToTargetNameLoc, ToNamespace)) return ToD; ToD->setLexicalDeclContext(LexicalDC); LexicalDC->addDeclInternal(ToD); return ToD; } ExpectedDecl ASTNodeImporter::VisitTypedefNameDecl(TypedefNameDecl *D, bool IsAlias) { // Import the major distinguishing characteristics of this typedef. DeclContext *DC, *LexicalDC; DeclarationName Name; SourceLocation Loc; NamedDecl *ToD; if (Error Err = ImportDeclParts(D, DC, LexicalDC, Name, ToD, Loc)) return std::move(Err); if (ToD) return ToD; // If this typedef is not in block scope, determine whether we've // seen a typedef with the same name (that we can merge with) or any // other entity by that name (which name lookup could conflict with). // Note: Repeated typedefs are not valid in C99: // 'typedef int T; typedef int T;' is invalid // We do not care about this now. if (!DC->isFunctionOrMethod()) { SmallVector ConflictingDecls; unsigned IDNS = Decl::IDNS_Ordinary; auto FoundDecls = Importer.findDeclsInToCtx(DC, Name); for (auto *FoundDecl : FoundDecls) { if (!FoundDecl->isInIdentifierNamespace(IDNS)) continue; if (auto *FoundTypedef = dyn_cast(FoundDecl)) { if (!hasSameVisibilityContext(FoundTypedef, D)) continue; QualType FromUT = D->getUnderlyingType(); QualType FoundUT = FoundTypedef->getUnderlyingType(); if (Importer.IsStructurallyEquivalent(FromUT, FoundUT)) { // If the "From" context has a complete underlying type but we // already have a complete underlying type then return with that. if (!FromUT->isIncompleteType() && !FoundUT->isIncompleteType()) return Importer.MapImported(D, FoundTypedef); // FIXME Handle redecl chain. When you do that make consistent changes // in ASTImporterLookupTable too. } else { ConflictingDecls.push_back(FoundDecl); } } } if (!ConflictingDecls.empty()) { ExpectedName NameOrErr = Importer.HandleNameConflict( Name, DC, IDNS, ConflictingDecls.data(), ConflictingDecls.size()); if (NameOrErr) Name = NameOrErr.get(); else return NameOrErr.takeError(); } } QualType ToUnderlyingType; TypeSourceInfo *ToTypeSourceInfo; SourceLocation ToBeginLoc; if (auto Imp = importSeq( D->getUnderlyingType(), D->getTypeSourceInfo(), D->getBeginLoc())) std::tie(ToUnderlyingType, ToTypeSourceInfo, ToBeginLoc) = *Imp; else return Imp.takeError(); // Create the new typedef node. // FIXME: ToUnderlyingType is not used. TypedefNameDecl *ToTypedef; if (IsAlias) { if (GetImportedOrCreateDecl( ToTypedef, D, Importer.getToContext(), DC, ToBeginLoc, Loc, Name.getAsIdentifierInfo(), ToTypeSourceInfo)) return ToTypedef; } else if (GetImportedOrCreateDecl( ToTypedef, D, Importer.getToContext(), DC, ToBeginLoc, Loc, Name.getAsIdentifierInfo(), ToTypeSourceInfo)) return ToTypedef; ToTypedef->setAccess(D->getAccess()); ToTypedef->setLexicalDeclContext(LexicalDC); // Templated declarations should not appear in DeclContext. TypeAliasDecl *FromAlias = IsAlias ? cast(D) : nullptr; if (!FromAlias || !FromAlias->getDescribedAliasTemplate()) LexicalDC->addDeclInternal(ToTypedef); return ToTypedef; } ExpectedDecl ASTNodeImporter::VisitTypedefDecl(TypedefDecl *D) { return VisitTypedefNameDecl(D, /*IsAlias=*/false); } ExpectedDecl ASTNodeImporter::VisitTypeAliasDecl(TypeAliasDecl *D) { return VisitTypedefNameDecl(D, /*IsAlias=*/true); } ExpectedDecl ASTNodeImporter::VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D) { // Import the major distinguishing characteristics of this typedef. DeclContext *DC, *LexicalDC; DeclarationName Name; SourceLocation Loc; NamedDecl *FoundD; if (Error Err = ImportDeclParts(D, DC, LexicalDC, Name, FoundD, Loc)) return std::move(Err); if (FoundD) return FoundD; // If this typedef is not in block scope, determine whether we've // seen a typedef with the same name (that we can merge with) or any // other entity by that name (which name lookup could conflict with). if (!DC->isFunctionOrMethod()) { SmallVector ConflictingDecls; unsigned IDNS = Decl::IDNS_Ordinary; auto FoundDecls = Importer.findDeclsInToCtx(DC, Name); for (auto *FoundDecl : FoundDecls) { if (!FoundDecl->isInIdentifierNamespace(IDNS)) continue; if (auto *FoundAlias = dyn_cast(FoundDecl)) return Importer.MapImported(D, FoundAlias); ConflictingDecls.push_back(FoundDecl); } if (!ConflictingDecls.empty()) { ExpectedName NameOrErr = Importer.HandleNameConflict( Name, DC, IDNS, ConflictingDecls.data(), ConflictingDecls.size()); if (NameOrErr) Name = NameOrErr.get(); else return NameOrErr.takeError(); } } TemplateParameterList *ToTemplateParameters; TypeAliasDecl *ToTemplatedDecl; if (auto Imp = importSeq(D->getTemplateParameters(), D->getTemplatedDecl())) std::tie(ToTemplateParameters, ToTemplatedDecl) = *Imp; else return Imp.takeError(); TypeAliasTemplateDecl *ToAlias; if (GetImportedOrCreateDecl(ToAlias, D, Importer.getToContext(), DC, Loc, Name, ToTemplateParameters, ToTemplatedDecl)) return ToAlias; ToTemplatedDecl->setDescribedAliasTemplate(ToAlias); ToAlias->setAccess(D->getAccess()); ToAlias->setLexicalDeclContext(LexicalDC); LexicalDC->addDeclInternal(ToAlias); return ToAlias; } ExpectedDecl ASTNodeImporter::VisitLabelDecl(LabelDecl *D) { // Import the major distinguishing characteristics of this label. DeclContext *DC, *LexicalDC; DeclarationName Name; SourceLocation Loc; NamedDecl *ToD; if (Error Err = ImportDeclParts(D, DC, LexicalDC, Name, ToD, Loc)) return std::move(Err); if (ToD) return ToD; assert(LexicalDC->isFunctionOrMethod()); LabelDecl *ToLabel; if (D->isGnuLocal()) { ExpectedSLoc BeginLocOrErr = import(D->getBeginLoc()); if (!BeginLocOrErr) return BeginLocOrErr.takeError(); if (GetImportedOrCreateDecl(ToLabel, D, Importer.getToContext(), DC, Loc, Name.getAsIdentifierInfo(), *BeginLocOrErr)) return ToLabel; } else { if (GetImportedOrCreateDecl(ToLabel, D, Importer.getToContext(), DC, Loc, Name.getAsIdentifierInfo())) return ToLabel; } Expected ToStmtOrErr = import(D->getStmt()); if (!ToStmtOrErr) return ToStmtOrErr.takeError(); ToLabel->setStmt(*ToStmtOrErr); ToLabel->setLexicalDeclContext(LexicalDC); LexicalDC->addDeclInternal(ToLabel); return ToLabel; } ExpectedDecl ASTNodeImporter::VisitEnumDecl(EnumDecl *D) { // Import the major distinguishing characteristics of this enum. DeclContext *DC, *LexicalDC; DeclarationName Name; SourceLocation Loc; NamedDecl *ToD; if (Error Err = ImportDeclParts(D, DC, LexicalDC, Name, ToD, Loc)) return std::move(Err); if (ToD) return ToD; // Figure out what enum name we're looking for. unsigned IDNS = Decl::IDNS_Tag; DeclarationName SearchName = Name; if (!SearchName && D->getTypedefNameForAnonDecl()) { if (Error Err = importInto( SearchName, D->getTypedefNameForAnonDecl()->getDeclName())) return std::move(Err); IDNS = Decl::IDNS_Ordinary; } else if (Importer.getToContext().getLangOpts().CPlusPlus) IDNS |= Decl::IDNS_Ordinary; // We may already have an enum of the same name; try to find and match it. if (!DC->isFunctionOrMethod() && SearchName) { SmallVector ConflictingDecls; auto FoundDecls = Importer.findDeclsInToCtx(DC, SearchName); for (auto *FoundDecl : FoundDecls) { if (!FoundDecl->isInIdentifierNamespace(IDNS)) continue; if (auto *Typedef = dyn_cast(FoundDecl)) { if (const auto *Tag = Typedef->getUnderlyingType()->getAs()) FoundDecl = Tag->getDecl(); } if (auto *FoundEnum = dyn_cast(FoundDecl)) { if (!hasSameVisibilityContext(FoundEnum, D)) continue; if (IsStructuralMatch(D, FoundEnum)) return Importer.MapImported(D, FoundEnum); ConflictingDecls.push_back(FoundDecl); } } if (!ConflictingDecls.empty()) { ExpectedName NameOrErr = Importer.HandleNameConflict( SearchName, DC, IDNS, ConflictingDecls.data(), ConflictingDecls.size()); if (NameOrErr) Name = NameOrErr.get(); else return NameOrErr.takeError(); } } SourceLocation ToBeginLoc; NestedNameSpecifierLoc ToQualifierLoc; QualType ToIntegerType; SourceRange ToBraceRange; if (auto Imp = importSeq(D->getBeginLoc(), D->getQualifierLoc(), D->getIntegerType(), D->getBraceRange())) std::tie(ToBeginLoc, ToQualifierLoc, ToIntegerType, ToBraceRange) = *Imp; else return Imp.takeError(); // Create the enum declaration. EnumDecl *D2; if (GetImportedOrCreateDecl( D2, D, Importer.getToContext(), DC, ToBeginLoc, Loc, Name.getAsIdentifierInfo(), nullptr, D->isScoped(), D->isScopedUsingClassTag(), D->isFixed())) return D2; D2->setQualifierInfo(ToQualifierLoc); D2->setIntegerType(ToIntegerType); D2->setBraceRange(ToBraceRange); D2->setAccess(D->getAccess()); D2->setLexicalDeclContext(LexicalDC); LexicalDC->addDeclInternal(D2); // Import the definition if (D->isCompleteDefinition()) if (Error Err = ImportDefinition(D, D2)) return std::move(Err); return D2; } ExpectedDecl ASTNodeImporter::VisitRecordDecl(RecordDecl *D) { bool IsFriendTemplate = false; if (auto *DCXX = dyn_cast(D)) { IsFriendTemplate = DCXX->getDescribedClassTemplate() && DCXX->getDescribedClassTemplate()->getFriendObjectKind() != Decl::FOK_None; } // Import the major distinguishing characteristics of this record. DeclContext *DC = nullptr, *LexicalDC = nullptr; DeclarationName Name; SourceLocation Loc; NamedDecl *ToD = nullptr; if (Error Err = ImportDeclParts(D, DC, LexicalDC, Name, ToD, Loc)) return std::move(Err); if (ToD) return ToD; // Figure out what structure name we're looking for. unsigned IDNS = Decl::IDNS_Tag; DeclarationName SearchName = Name; if (!SearchName && D->getTypedefNameForAnonDecl()) { if (Error Err = importInto( SearchName, D->getTypedefNameForAnonDecl()->getDeclName())) return std::move(Err); IDNS = Decl::IDNS_Ordinary; } else if (Importer.getToContext().getLangOpts().CPlusPlus) IDNS |= Decl::IDNS_Ordinary | Decl::IDNS_TagFriend; // We may already have a record of the same name; try to find and match it. RecordDecl *PrevDecl = nullptr; if (!DC->isFunctionOrMethod() && !D->isLambda()) { SmallVector ConflictingDecls; auto FoundDecls = Importer.findDeclsInToCtx(DC, SearchName); if (!FoundDecls.empty()) { // We're going to have to compare D against potentially conflicting Decls, // so complete it. if (D->hasExternalLexicalStorage() && !D->isCompleteDefinition()) D->getASTContext().getExternalSource()->CompleteType(D); } for (auto *FoundDecl : FoundDecls) { if (!FoundDecl->isInIdentifierNamespace(IDNS)) continue; Decl *Found = FoundDecl; if (auto *Typedef = dyn_cast(Found)) { if (const auto *Tag = Typedef->getUnderlyingType()->getAs()) Found = Tag->getDecl(); } if (auto *FoundRecord = dyn_cast(Found)) { // Do not emit false positive diagnostic in case of unnamed // struct/union and in case of anonymous structs. Would be false // because there may be several anonymous/unnamed structs in a class. // E.g. these are both valid: // struct A { // unnamed structs // struct { struct A *next; } entry0; // struct { struct A *next; } entry1; // }; // struct X { struct { int a; }; struct { int b; }; }; // anon structs if (!SearchName) if (!IsStructuralMatch(D, FoundRecord, false)) continue; if (!hasSameVisibilityContext(FoundRecord, D)) continue; if (IsStructuralMatch(D, FoundRecord)) { RecordDecl *FoundDef = FoundRecord->getDefinition(); if (D->isThisDeclarationADefinition() && FoundDef) { // FIXME: Structural equivalence check should check for same // user-defined methods. Importer.MapImported(D, FoundDef); if (const auto *DCXX = dyn_cast(D)) { auto *FoundCXX = dyn_cast(FoundDef); assert(FoundCXX && "Record type mismatch"); if (!Importer.isMinimalImport()) // FoundDef may not have every implicit method that D has // because implicit methods are created only if they are used. if (Error Err = ImportImplicitMethods(DCXX, FoundCXX)) return std::move(Err); } } PrevDecl = FoundRecord->getMostRecentDecl(); break; } ConflictingDecls.push_back(FoundDecl); } // kind is RecordDecl } // for if (!ConflictingDecls.empty() && SearchName) { ExpectedName NameOrErr = Importer.HandleNameConflict( SearchName, DC, IDNS, ConflictingDecls.data(), ConflictingDecls.size()); if (NameOrErr) Name = NameOrErr.get(); else return NameOrErr.takeError(); } } ExpectedSLoc BeginLocOrErr = import(D->getBeginLoc()); if (!BeginLocOrErr) return BeginLocOrErr.takeError(); // Create the record declaration. RecordDecl *D2 = nullptr; CXXRecordDecl *D2CXX = nullptr; if (auto *DCXX = dyn_cast(D)) { if (DCXX->isLambda()) { auto TInfoOrErr = import(DCXX->getLambdaTypeInfo()); if (!TInfoOrErr) return TInfoOrErr.takeError(); if (GetImportedOrCreateSpecialDecl( D2CXX, CXXRecordDecl::CreateLambda, D, Importer.getToContext(), DC, *TInfoOrErr, Loc, DCXX->isDependentLambda(), DCXX->isGenericLambda(), DCXX->getLambdaCaptureDefault())) return D2CXX; ExpectedDecl CDeclOrErr = import(DCXX->getLambdaContextDecl()); if (!CDeclOrErr) return CDeclOrErr.takeError(); D2CXX->setLambdaMangling(DCXX->getLambdaManglingNumber(), *CDeclOrErr, DCXX->hasKnownLambdaInternalLinkage()); } else if (DCXX->isInjectedClassName()) { // We have to be careful to do a similar dance to the one in // Sema::ActOnStartCXXMemberDeclarations const bool DelayTypeCreation = true; if (GetImportedOrCreateDecl( D2CXX, D, Importer.getToContext(), D->getTagKind(), DC, *BeginLocOrErr, Loc, Name.getAsIdentifierInfo(), cast_or_null(PrevDecl), DelayTypeCreation)) return D2CXX; Importer.getToContext().getTypeDeclType( D2CXX, dyn_cast(DC)); } else { if (GetImportedOrCreateDecl(D2CXX, D, Importer.getToContext(), D->getTagKind(), DC, *BeginLocOrErr, Loc, Name.getAsIdentifierInfo(), cast_or_null(PrevDecl))) return D2CXX; } D2 = D2CXX; D2->setAccess(D->getAccess()); D2->setLexicalDeclContext(LexicalDC); addDeclToContexts(D, D2); if (ClassTemplateDecl *FromDescribed = DCXX->getDescribedClassTemplate()) { ClassTemplateDecl *ToDescribed; if (Error Err = importInto(ToDescribed, FromDescribed)) return std::move(Err); D2CXX->setDescribedClassTemplate(ToDescribed); if (!DCXX->isInjectedClassName() && !IsFriendTemplate) { // In a record describing a template the type should be an // InjectedClassNameType (see Sema::CheckClassTemplate). Update the // previously set type to the correct value here (ToDescribed is not // available at record create). // FIXME: The previous type is cleared but not removed from // ASTContext's internal storage. CXXRecordDecl *Injected = nullptr; for (NamedDecl *Found : D2CXX->noload_lookup(Name)) { auto *Record = dyn_cast(Found); if (Record && Record->isInjectedClassName()) { Injected = Record; break; } } // Create an injected type for the whole redecl chain. SmallVector Redecls = getCanonicalForwardRedeclChain(D2CXX); for (auto *R : Redecls) { auto *RI = cast(R); RI->setTypeForDecl(nullptr); // Below we create a new injected type and assign that to the // canonical decl, subsequent declarations in the chain will reuse // that type. Importer.getToContext().getInjectedClassNameType( RI, ToDescribed->getInjectedClassNameSpecialization()); } // Set the new type for the previous injected decl too. if (Injected) { Injected->setTypeForDecl(nullptr); Importer.getToContext().getTypeDeclType(Injected, D2CXX); } } } else if (MemberSpecializationInfo *MemberInfo = DCXX->getMemberSpecializationInfo()) { TemplateSpecializationKind SK = MemberInfo->getTemplateSpecializationKind(); CXXRecordDecl *FromInst = DCXX->getInstantiatedFromMemberClass(); if (Expected ToInstOrErr = import(FromInst)) D2CXX->setInstantiationOfMemberClass(*ToInstOrErr, SK); else return ToInstOrErr.takeError(); if (ExpectedSLoc POIOrErr = import(MemberInfo->getPointOfInstantiation())) D2CXX->getMemberSpecializationInfo()->setPointOfInstantiation( *POIOrErr); else return POIOrErr.takeError(); } } else { if (GetImportedOrCreateDecl(D2, D, Importer.getToContext(), D->getTagKind(), DC, *BeginLocOrErr, Loc, Name.getAsIdentifierInfo(), PrevDecl)) return D2; D2->setLexicalDeclContext(LexicalDC); addDeclToContexts(D, D2); } if (auto BraceRangeOrErr = import(D->getBraceRange())) D2->setBraceRange(*BraceRangeOrErr); else return BraceRangeOrErr.takeError(); if (auto QualifierLocOrErr = import(D->getQualifierLoc())) D2->setQualifierInfo(*QualifierLocOrErr); else return QualifierLocOrErr.takeError(); if (D->isAnonymousStructOrUnion()) D2->setAnonymousStructOrUnion(true); if (D->isCompleteDefinition()) if (Error Err = ImportDefinition(D, D2, IDK_Default)) return std::move(Err); return D2; } ExpectedDecl ASTNodeImporter::VisitEnumConstantDecl(EnumConstantDecl *D) { // Import the major distinguishing characteristics of this enumerator. DeclContext *DC, *LexicalDC; DeclarationName Name; SourceLocation Loc; NamedDecl *ToD; if (Error Err = ImportDeclParts(D, DC, LexicalDC, Name, ToD, Loc)) return std::move(Err); if (ToD) return ToD; // Determine whether there are any other declarations with the same name and // in the same context. if (!LexicalDC->isFunctionOrMethod()) { SmallVector ConflictingDecls; unsigned IDNS = Decl::IDNS_Ordinary; auto FoundDecls = Importer.findDeclsInToCtx(DC, Name); for (auto *FoundDecl : FoundDecls) { if (!FoundDecl->isInIdentifierNamespace(IDNS)) continue; if (auto *FoundEnumConstant = dyn_cast(FoundDecl)) { if (IsStructuralMatch(D, FoundEnumConstant)) return Importer.MapImported(D, FoundEnumConstant); ConflictingDecls.push_back(FoundDecl); } } if (!ConflictingDecls.empty()) { ExpectedName NameOrErr = Importer.HandleNameConflict( Name, DC, IDNS, ConflictingDecls.data(), ConflictingDecls.size()); if (NameOrErr) Name = NameOrErr.get(); else return NameOrErr.takeError(); } } ExpectedType TypeOrErr = import(D->getType()); if (!TypeOrErr) return TypeOrErr.takeError(); ExpectedExpr InitOrErr = import(D->getInitExpr()); if (!InitOrErr) return InitOrErr.takeError(); EnumConstantDecl *ToEnumerator; if (GetImportedOrCreateDecl( ToEnumerator, D, Importer.getToContext(), cast(DC), Loc, Name.getAsIdentifierInfo(), *TypeOrErr, *InitOrErr, D->getInitVal())) return ToEnumerator; ToEnumerator->setAccess(D->getAccess()); ToEnumerator->setLexicalDeclContext(LexicalDC); LexicalDC->addDeclInternal(ToEnumerator); return ToEnumerator; } Error ASTNodeImporter::ImportTemplateParameterLists(const DeclaratorDecl *FromD, DeclaratorDecl *ToD) { unsigned int Num = FromD->getNumTemplateParameterLists(); if (Num == 0) return Error::success(); SmallVector ToTPLists(Num); for (unsigned int I = 0; I < Num; ++I) if (Expected ToTPListOrErr = import(FromD->getTemplateParameterList(I))) ToTPLists[I] = *ToTPListOrErr; else return ToTPListOrErr.takeError(); ToD->setTemplateParameterListsInfo(Importer.ToContext, ToTPLists); return Error::success(); } Error ASTNodeImporter::ImportTemplateInformation( FunctionDecl *FromFD, FunctionDecl *ToFD) { switch (FromFD->getTemplatedKind()) { case FunctionDecl::TK_NonTemplate: case FunctionDecl::TK_FunctionTemplate: return Error::success(); case FunctionDecl::TK_MemberSpecialization: { TemplateSpecializationKind TSK = FromFD->getTemplateSpecializationKind(); if (Expected InstFDOrErr = import(FromFD->getInstantiatedFromMemberFunction())) ToFD->setInstantiationOfMemberFunction(*InstFDOrErr, TSK); else return InstFDOrErr.takeError(); if (ExpectedSLoc POIOrErr = import( FromFD->getMemberSpecializationInfo()->getPointOfInstantiation())) ToFD->getMemberSpecializationInfo()->setPointOfInstantiation(*POIOrErr); else return POIOrErr.takeError(); return Error::success(); } case FunctionDecl::TK_FunctionTemplateSpecialization: { auto FunctionAndArgsOrErr = ImportFunctionTemplateWithTemplateArgsFromSpecialization(FromFD); if (!FunctionAndArgsOrErr) return FunctionAndArgsOrErr.takeError(); TemplateArgumentList *ToTAList = TemplateArgumentList::CreateCopy( Importer.getToContext(), std::get<1>(*FunctionAndArgsOrErr)); auto *FTSInfo = FromFD->getTemplateSpecializationInfo(); TemplateArgumentListInfo ToTAInfo; const auto *FromTAArgsAsWritten = FTSInfo->TemplateArgumentsAsWritten; if (FromTAArgsAsWritten) if (Error Err = ImportTemplateArgumentListInfo( *FromTAArgsAsWritten, ToTAInfo)) return Err; ExpectedSLoc POIOrErr = import(FTSInfo->getPointOfInstantiation()); if (!POIOrErr) return POIOrErr.takeError(); if (Error Err = ImportTemplateParameterLists(FromFD, ToFD)) return Err; TemplateSpecializationKind TSK = FTSInfo->getTemplateSpecializationKind(); ToFD->setFunctionTemplateSpecialization( std::get<0>(*FunctionAndArgsOrErr), ToTAList, /* InsertPos= */ nullptr, TSK, FromTAArgsAsWritten ? &ToTAInfo : nullptr, *POIOrErr); return Error::success(); } case FunctionDecl::TK_DependentFunctionTemplateSpecialization: { auto *FromInfo = FromFD->getDependentSpecializationInfo(); UnresolvedSet<8> TemplDecls; unsigned NumTemplates = FromInfo->getNumTemplates(); for (unsigned I = 0; I < NumTemplates; I++) { if (Expected ToFTDOrErr = import(FromInfo->getTemplate(I))) TemplDecls.addDecl(*ToFTDOrErr); else return ToFTDOrErr.takeError(); } // Import TemplateArgumentListInfo. TemplateArgumentListInfo ToTAInfo; if (Error Err = ImportTemplateArgumentListInfo( FromInfo->getLAngleLoc(), FromInfo->getRAngleLoc(), llvm::makeArrayRef( FromInfo->getTemplateArgs(), FromInfo->getNumTemplateArgs()), ToTAInfo)) return Err; ToFD->setDependentTemplateSpecialization(Importer.getToContext(), TemplDecls, ToTAInfo); return Error::success(); } } llvm_unreachable("All cases should be covered!"); } Expected ASTNodeImporter::FindFunctionTemplateSpecialization(FunctionDecl *FromFD) { auto FunctionAndArgsOrErr = ImportFunctionTemplateWithTemplateArgsFromSpecialization(FromFD); if (!FunctionAndArgsOrErr) return FunctionAndArgsOrErr.takeError(); FunctionTemplateDecl *Template; TemplateArgsTy ToTemplArgs; std::tie(Template, ToTemplArgs) = *FunctionAndArgsOrErr; void *InsertPos = nullptr; auto *FoundSpec = Template->findSpecialization(ToTemplArgs, InsertPos); return FoundSpec; } Error ASTNodeImporter::ImportFunctionDeclBody(FunctionDecl *FromFD, FunctionDecl *ToFD) { if (Stmt *FromBody = FromFD->getBody()) { if (ExpectedStmt ToBodyOrErr = import(FromBody)) ToFD->setBody(*ToBodyOrErr); else return ToBodyOrErr.takeError(); } return Error::success(); } // Returns true if the given D has a DeclContext up to the TranslationUnitDecl // which is equal to the given DC. static bool isAncestorDeclContextOf(const DeclContext *DC, const Decl *D) { const DeclContext *DCi = D->getDeclContext(); while (DCi != D->getTranslationUnitDecl()) { if (DCi == DC) return true; DCi = DCi->getParent(); } return false; } bool ASTNodeImporter::hasAutoReturnTypeDeclaredInside(FunctionDecl *D) { QualType FromTy = D->getType(); const FunctionProtoType *FromFPT = FromTy->getAs(); assert(FromFPT && "Must be called on FunctionProtoType"); if (AutoType *AutoT = FromFPT->getReturnType()->getContainedAutoType()) { QualType DeducedT = AutoT->getDeducedType(); if (const RecordType *RecordT = DeducedT.isNull() ? nullptr : dyn_cast(DeducedT)) { RecordDecl *RD = RecordT->getDecl(); assert(RD); if (isAncestorDeclContextOf(D, RD)) { assert(RD->getLexicalDeclContext() == RD->getDeclContext()); return true; } } } if (const TypedefType *TypedefT = dyn_cast(FromFPT->getReturnType())) { TypedefNameDecl *TD = TypedefT->getDecl(); assert(TD); if (isAncestorDeclContextOf(D, TD)) { assert(TD->getLexicalDeclContext() == TD->getDeclContext()); return true; } } return false; } ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) { SmallVector Redecls = getCanonicalForwardRedeclChain(D); auto RedeclIt = Redecls.begin(); // Import the first part of the decl chain. I.e. import all previous // declarations starting from the canonical decl. for (; RedeclIt != Redecls.end() && *RedeclIt != D; ++RedeclIt) { ExpectedDecl ToRedeclOrErr = import(*RedeclIt); if (!ToRedeclOrErr) return ToRedeclOrErr.takeError(); } assert(*RedeclIt == D); // Import the major distinguishing characteristics of this function. DeclContext *DC, *LexicalDC; DeclarationName Name; SourceLocation Loc; NamedDecl *ToD; if (Error Err = ImportDeclParts(D, DC, LexicalDC, Name, ToD, Loc)) return std::move(Err); if (ToD) return ToD; FunctionDecl *FoundByLookup = nullptr; FunctionTemplateDecl *FromFT = D->getDescribedFunctionTemplate(); // If this is a function template specialization, then try to find the same // existing specialization in the "to" context. The lookup below will not // find any specialization, but would find the primary template; thus, we // have to skip normal lookup in case of specializations. // FIXME handle member function templates (TK_MemberSpecialization) similarly? if (D->getTemplatedKind() == FunctionDecl::TK_FunctionTemplateSpecialization) { auto FoundFunctionOrErr = FindFunctionTemplateSpecialization(D); if (!FoundFunctionOrErr) return FoundFunctionOrErr.takeError(); if (FunctionDecl *FoundFunction = *FoundFunctionOrErr) { if (Decl *Def = FindAndMapDefinition(D, FoundFunction)) return Def; FoundByLookup = FoundFunction; } } // Try to find a function in our own ("to") context with the same name, same // type, and in the same context as the function we're importing. else if (!LexicalDC->isFunctionOrMethod()) { SmallVector ConflictingDecls; unsigned IDNS = Decl::IDNS_Ordinary | Decl::IDNS_OrdinaryFriend; auto FoundDecls = Importer.findDeclsInToCtx(DC, Name); for (auto *FoundDecl : FoundDecls) { if (!FoundDecl->isInIdentifierNamespace(IDNS)) continue; if (auto *FoundFunction = dyn_cast(FoundDecl)) { if (!hasSameVisibilityContext(FoundFunction, D)) continue; if (IsStructuralMatch(D, FoundFunction)) { if (Decl *Def = FindAndMapDefinition(D, FoundFunction)) return Def; FoundByLookup = FoundFunction; break; } // FIXME: Check for overloading more carefully, e.g., by boosting // Sema::IsOverload out to the AST library. // Function overloading is okay in C++. if (Importer.getToContext().getLangOpts().CPlusPlus) continue; // Complain about inconsistent function types. Importer.ToDiag(Loc, diag::warn_odr_function_type_inconsistent) << Name << D->getType() << FoundFunction->getType(); Importer.ToDiag(FoundFunction->getLocation(), diag::note_odr_value_here) << FoundFunction->getType(); ConflictingDecls.push_back(FoundDecl); } } if (!ConflictingDecls.empty()) { ExpectedName NameOrErr = Importer.HandleNameConflict( Name, DC, IDNS, ConflictingDecls.data(), ConflictingDecls.size()); if (NameOrErr) Name = NameOrErr.get(); else return NameOrErr.takeError(); } } // We do not allow more than one in-class declaration of a function. This is // because AST clients like VTableBuilder asserts on this. VTableBuilder // assumes there is only one in-class declaration. Building a redecl // chain would result in more than one in-class declaration for // overrides (even if they are part of the same redecl chain inside the // derived class.) if (FoundByLookup) { if (isa(FoundByLookup)) { if (D->getLexicalDeclContext() == D->getDeclContext()) { if (!D->doesThisDeclarationHaveABody()) { if (FunctionTemplateDecl *DescribedD = D->getDescribedFunctionTemplate()) { // Handle a "templated" function together with its described // template. This avoids need for a similar check at import of the // described template. assert(FoundByLookup->getDescribedFunctionTemplate() && "Templated function mapped to non-templated?"); Importer.MapImported(DescribedD, FoundByLookup->getDescribedFunctionTemplate()); } return Importer.MapImported(D, FoundByLookup); } else { // Let's continue and build up the redecl chain in this case. // FIXME Merge the functions into one decl. } } } } DeclarationNameInfo NameInfo(Name, Loc); // Import additional name location/type info. if (Error Err = ImportDeclarationNameLoc(D->getNameInfo(), NameInfo)) return std::move(Err); QualType FromTy = D->getType(); // Set to true if we do not import the type of the function as is. There are // cases when the original type would result in an infinite recursion during // the import. To avoid an infinite recursion when importing, we create the // FunctionDecl with a simplified function type and update it only after the // relevant AST nodes are already imported. bool UsedDifferentProtoType = false; if (const auto *FromFPT = FromTy->getAs()) { QualType FromReturnTy = FromFPT->getReturnType(); // Functions with auto return type may define a struct inside their body // and the return type could refer to that struct. // E.g.: auto foo() { struct X{}; return X(); } // To avoid an infinite recursion when importing, create the FunctionDecl // with a simplified return type. if (hasAutoReturnTypeDeclaredInside(D)) { FromReturnTy = Importer.getFromContext().VoidTy; UsedDifferentProtoType = true; } FunctionProtoType::ExtProtoInfo FromEPI = FromFPT->getExtProtoInfo(); // FunctionProtoType::ExtProtoInfo's ExceptionSpecDecl can point to the // FunctionDecl that we are importing the FunctionProtoType for. // To avoid an infinite recursion when importing, create the FunctionDecl // with a simplified function type. if (FromEPI.ExceptionSpec.SourceDecl || FromEPI.ExceptionSpec.SourceTemplate || FromEPI.ExceptionSpec.NoexceptExpr) { FunctionProtoType::ExtProtoInfo DefaultEPI; FromEPI = DefaultEPI; UsedDifferentProtoType = true; } FromTy = Importer.getFromContext().getFunctionType( FromReturnTy, FromFPT->getParamTypes(), FromEPI); } QualType T; TypeSourceInfo *TInfo; SourceLocation ToInnerLocStart, ToEndLoc; NestedNameSpecifierLoc ToQualifierLoc; Expr *TrailingRequiresClause; if (auto Imp = importSeq( FromTy, D->getTypeSourceInfo(), D->getInnerLocStart(), D->getQualifierLoc(), D->getEndLoc(), D->getTrailingRequiresClause())) std::tie(T, TInfo, ToInnerLocStart, ToQualifierLoc, ToEndLoc, TrailingRequiresClause) = *Imp; else return Imp.takeError(); // Import the function parameters. SmallVector Parameters; for (auto P : D->parameters()) { if (Expected ToPOrErr = import(P)) Parameters.push_back(*ToPOrErr); else return ToPOrErr.takeError(); } // Create the imported function. FunctionDecl *ToFunction = nullptr; if (auto *FromConstructor = dyn_cast(D)) { Expr *ExplicitExpr = nullptr; if (FromConstructor->getExplicitSpecifier().getExpr()) { auto Imp = importSeq(FromConstructor->getExplicitSpecifier().getExpr()); if (!Imp) return Imp.takeError(); std::tie(ExplicitExpr) = *Imp; } if (GetImportedOrCreateDecl( ToFunction, D, Importer.getToContext(), cast(DC), ToInnerLocStart, NameInfo, T, TInfo, ExplicitSpecifier( ExplicitExpr, FromConstructor->getExplicitSpecifier().getKind()), D->isInlineSpecified(), D->isImplicit(), D->getConstexprKind(), InheritedConstructor(), // FIXME: Properly import inherited // constructor info TrailingRequiresClause)) return ToFunction; } else if (CXXDestructorDecl *FromDtor = dyn_cast(D)) { auto Imp = importSeq(const_cast(FromDtor->getOperatorDelete()), FromDtor->getOperatorDeleteThisArg()); if (!Imp) return Imp.takeError(); FunctionDecl *ToOperatorDelete; Expr *ToThisArg; std::tie(ToOperatorDelete, ToThisArg) = *Imp; if (GetImportedOrCreateDecl( ToFunction, D, Importer.getToContext(), cast(DC), ToInnerLocStart, NameInfo, T, TInfo, D->isInlineSpecified(), D->isImplicit(), D->getConstexprKind(), TrailingRequiresClause)) return ToFunction; CXXDestructorDecl *ToDtor = cast(ToFunction); ToDtor->setOperatorDelete(ToOperatorDelete, ToThisArg); } else if (CXXConversionDecl *FromConversion = dyn_cast(D)) { Expr *ExplicitExpr = nullptr; if (FromConversion->getExplicitSpecifier().getExpr()) { auto Imp = importSeq(FromConversion->getExplicitSpecifier().getExpr()); if (!Imp) return Imp.takeError(); std::tie(ExplicitExpr) = *Imp; } if (GetImportedOrCreateDecl( ToFunction, D, Importer.getToContext(), cast(DC), ToInnerLocStart, NameInfo, T, TInfo, D->isInlineSpecified(), ExplicitSpecifier(ExplicitExpr, FromConversion->getExplicitSpecifier().getKind()), D->getConstexprKind(), SourceLocation(), TrailingRequiresClause)) return ToFunction; } else if (auto *Method = dyn_cast(D)) { if (GetImportedOrCreateDecl( ToFunction, D, Importer.getToContext(), cast(DC), ToInnerLocStart, NameInfo, T, TInfo, Method->getStorageClass(), Method->isInlineSpecified(), D->getConstexprKind(), SourceLocation(), TrailingRequiresClause)) return ToFunction; } else { if (GetImportedOrCreateDecl( ToFunction, D, Importer.getToContext(), DC, ToInnerLocStart, NameInfo, T, TInfo, D->getStorageClass(), D->isInlineSpecified(), D->hasWrittenPrototype(), D->getConstexprKind(), TrailingRequiresClause)) return ToFunction; } // Connect the redecl chain. if (FoundByLookup) { auto *Recent = const_cast( FoundByLookup->getMostRecentDecl()); ToFunction->setPreviousDecl(Recent); // FIXME Probably we should merge exception specifications. E.g. In the // "To" context the existing function may have exception specification with // noexcept-unevaluated, while the newly imported function may have an // evaluated noexcept. A call to adjustExceptionSpec() on the imported // decl and its redeclarations may be required. } ToFunction->setQualifierInfo(ToQualifierLoc); ToFunction->setAccess(D->getAccess()); ToFunction->setLexicalDeclContext(LexicalDC); ToFunction->setVirtualAsWritten(D->isVirtualAsWritten()); ToFunction->setTrivial(D->isTrivial()); ToFunction->setPure(D->isPure()); ToFunction->setDefaulted(D->isDefaulted()); ToFunction->setExplicitlyDefaulted(D->isExplicitlyDefaulted()); ToFunction->setDeletedAsWritten(D->isDeletedAsWritten()); ToFunction->setRangeEnd(ToEndLoc); // Set the parameters. for (auto *Param : Parameters) { Param->setOwningFunction(ToFunction); ToFunction->addDeclInternal(Param); } ToFunction->setParams(Parameters); // We need to complete creation of FunctionProtoTypeLoc manually with setting // params it refers to. if (TInfo) { if (auto ProtoLoc = TInfo->getTypeLoc().IgnoreParens().getAs()) { for (unsigned I = 0, N = Parameters.size(); I != N; ++I) ProtoLoc.setParam(I, Parameters[I]); } } // Import the describing template function, if any. if (FromFT) { auto ToFTOrErr = import(FromFT); if (!ToFTOrErr) return ToFTOrErr.takeError(); } // Import Ctor initializers. if (auto *FromConstructor = dyn_cast(D)) { if (unsigned NumInitializers = FromConstructor->getNumCtorInitializers()) { SmallVector CtorInitializers(NumInitializers); // Import first, then allocate memory and copy if there was no error. if (Error Err = ImportContainerChecked( FromConstructor->inits(), CtorInitializers)) return std::move(Err); auto **Memory = new (Importer.getToContext()) CXXCtorInitializer *[NumInitializers]; std::copy(CtorInitializers.begin(), CtorInitializers.end(), Memory); auto *ToCtor = cast(ToFunction); ToCtor->setCtorInitializers(Memory); ToCtor->setNumCtorInitializers(NumInitializers); } } if (D->doesThisDeclarationHaveABody()) { Error Err = ImportFunctionDeclBody(D, ToFunction); if (Err) return std::move(Err); } // Import and set the original type in case we used another type. if (UsedDifferentProtoType) { if (ExpectedType TyOrErr = import(D->getType())) ToFunction->setType(*TyOrErr); else return TyOrErr.takeError(); } // FIXME: Other bits to merge? // If it is a template, import all related things. if (Error Err = ImportTemplateInformation(D, ToFunction)) return std::move(Err); addDeclToContexts(D, ToFunction); if (auto *FromCXXMethod = dyn_cast(D)) if (Error Err = ImportOverriddenMethods(cast(ToFunction), FromCXXMethod)) return std::move(Err); // Import the rest of the chain. I.e. import all subsequent declarations. for (++RedeclIt; RedeclIt != Redecls.end(); ++RedeclIt) { ExpectedDecl ToRedeclOrErr = import(*RedeclIt); if (!ToRedeclOrErr) return ToRedeclOrErr.takeError(); } return ToFunction; } ExpectedDecl ASTNodeImporter::VisitCXXMethodDecl(CXXMethodDecl *D) { return VisitFunctionDecl(D); } ExpectedDecl ASTNodeImporter::VisitCXXConstructorDecl(CXXConstructorDecl *D) { return VisitCXXMethodDecl(D); } ExpectedDecl ASTNodeImporter::VisitCXXDestructorDecl(CXXDestructorDecl *D) { return VisitCXXMethodDecl(D); } ExpectedDecl ASTNodeImporter::VisitCXXConversionDecl(CXXConversionDecl *D) { return VisitCXXMethodDecl(D); } ExpectedDecl ASTNodeImporter::VisitFieldDecl(FieldDecl *D) { // Import the major distinguishing characteristics of a variable. DeclContext *DC, *LexicalDC; DeclarationName Name; SourceLocation Loc; NamedDecl *ToD; if (Error Err = ImportDeclParts(D, DC, LexicalDC, Name, ToD, Loc)) return std::move(Err); if (ToD) return ToD; // Determine whether we've already imported this field. auto FoundDecls = Importer.findDeclsInToCtx(DC, Name); for (auto *FoundDecl : FoundDecls) { if (FieldDecl *FoundField = dyn_cast(FoundDecl)) { // For anonymous fields, match up by index. if (!Name && ASTImporter::getFieldIndex(D) != ASTImporter::getFieldIndex(FoundField)) continue; if (Importer.IsStructurallyEquivalent(D->getType(), FoundField->getType())) { Importer.MapImported(D, FoundField); // In case of a FieldDecl of a ClassTemplateSpecializationDecl, the // initializer of a FieldDecl might not had been instantiated in the // "To" context. However, the "From" context might instantiated that, // thus we have to merge that. if (Expr *FromInitializer = D->getInClassInitializer()) { // We don't have yet the initializer set. if (FoundField->hasInClassInitializer() && !FoundField->getInClassInitializer()) { if (ExpectedExpr ToInitializerOrErr = import(FromInitializer)) FoundField->setInClassInitializer(*ToInitializerOrErr); else { // We can't return error here, // since we already mapped D as imported. // FIXME: warning message? consumeError(ToInitializerOrErr.takeError()); return FoundField; } } } return FoundField; } // FIXME: Why is this case not handled with calling HandleNameConflict? Importer.ToDiag(Loc, diag::warn_odr_field_type_inconsistent) << Name << D->getType() << FoundField->getType(); Importer.ToDiag(FoundField->getLocation(), diag::note_odr_value_here) << FoundField->getType(); return make_error(ImportError::NameConflict); } } QualType ToType; TypeSourceInfo *ToTInfo; Expr *ToBitWidth; SourceLocation ToInnerLocStart; Expr *ToInitializer; if (auto Imp = importSeq( D->getType(), D->getTypeSourceInfo(), D->getBitWidth(), D->getInnerLocStart(), D->getInClassInitializer())) std::tie( ToType, ToTInfo, ToBitWidth, ToInnerLocStart, ToInitializer) = *Imp; else return Imp.takeError(); FieldDecl *ToField; if (GetImportedOrCreateDecl(ToField, D, Importer.getToContext(), DC, ToInnerLocStart, Loc, Name.getAsIdentifierInfo(), ToType, ToTInfo, ToBitWidth, D->isMutable(), D->getInClassInitStyle())) return ToField; ToField->setAccess(D->getAccess()); ToField->setLexicalDeclContext(LexicalDC); if (ToInitializer) ToField->setInClassInitializer(ToInitializer); ToField->setImplicit(D->isImplicit()); LexicalDC->addDeclInternal(ToField); return ToField; } ExpectedDecl ASTNodeImporter::VisitIndirectFieldDecl(IndirectFieldDecl *D) { // Import the major distinguishing characteristics of a variable. DeclContext *DC, *LexicalDC; DeclarationName Name; SourceLocation Loc; NamedDecl *ToD; if (Error Err = ImportDeclParts(D, DC, LexicalDC, Name, ToD, Loc)) return std::move(Err); if (ToD) return ToD; // Determine whether we've already imported this field. auto FoundDecls = Importer.findDeclsInToCtx(DC, Name); for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) { if (auto *FoundField = dyn_cast(FoundDecls[I])) { // For anonymous indirect fields, match up by index. if (!Name && ASTImporter::getFieldIndex(D) != ASTImporter::getFieldIndex(FoundField)) continue; if (Importer.IsStructurallyEquivalent(D->getType(), FoundField->getType(), !Name.isEmpty())) { Importer.MapImported(D, FoundField); return FoundField; } // If there are more anonymous fields to check, continue. if (!Name && I < N-1) continue; // FIXME: Why is this case not handled with calling HandleNameConflict? Importer.ToDiag(Loc, diag::warn_odr_field_type_inconsistent) << Name << D->getType() << FoundField->getType(); Importer.ToDiag(FoundField->getLocation(), diag::note_odr_value_here) << FoundField->getType(); return make_error(ImportError::NameConflict); } } // Import the type. auto TypeOrErr = import(D->getType()); if (!TypeOrErr) return TypeOrErr.takeError(); auto **NamedChain = new (Importer.getToContext()) NamedDecl*[D->getChainingSize()]; unsigned i = 0; for (auto *PI : D->chain()) if (Expected ToD = import(PI)) NamedChain[i++] = *ToD; else return ToD.takeError(); llvm::MutableArrayRef CH = {NamedChain, D->getChainingSize()}; IndirectFieldDecl *ToIndirectField; if (GetImportedOrCreateDecl(ToIndirectField, D, Importer.getToContext(), DC, Loc, Name.getAsIdentifierInfo(), *TypeOrErr, CH)) // FIXME here we leak `NamedChain` which is allocated before return ToIndirectField; ToIndirectField->setAccess(D->getAccess()); ToIndirectField->setLexicalDeclContext(LexicalDC); LexicalDC->addDeclInternal(ToIndirectField); return ToIndirectField; } ExpectedDecl ASTNodeImporter::VisitFriendDecl(FriendDecl *D) { // Import the major distinguishing characteristics of a declaration. DeclContext *DC, *LexicalDC; if (Error Err = ImportDeclContext(D, DC, LexicalDC)) return std::move(Err); // Determine whether we've already imported this decl. // FriendDecl is not a NamedDecl so we cannot use lookup. auto *RD = cast(DC); FriendDecl *ImportedFriend = RD->getFirstFriend(); while (ImportedFriend) { if (D->getFriendDecl() && ImportedFriend->getFriendDecl()) { if (IsStructuralMatch(D->getFriendDecl(), ImportedFriend->getFriendDecl(), /*Complain=*/false)) return Importer.MapImported(D, ImportedFriend); } else if (D->getFriendType() && ImportedFriend->getFriendType()) { if (Importer.IsStructurallyEquivalent( D->getFriendType()->getType(), ImportedFriend->getFriendType()->getType(), true)) return Importer.MapImported(D, ImportedFriend); } ImportedFriend = ImportedFriend->getNextFriend(); } // Not found. Create it. FriendDecl::FriendUnion ToFU; if (NamedDecl *FriendD = D->getFriendDecl()) { NamedDecl *ToFriendD; if (Error Err = importInto(ToFriendD, FriendD)) return std::move(Err); if (FriendD->getFriendObjectKind() != Decl::FOK_None && !(FriendD->isInIdentifierNamespace(Decl::IDNS_NonMemberOperator))) ToFriendD->setObjectOfFriendDecl(false); ToFU = ToFriendD; } else { // The friend is a type, not a decl. if (auto TSIOrErr = import(D->getFriendType())) ToFU = *TSIOrErr; else return TSIOrErr.takeError(); } SmallVector ToTPLists(D->NumTPLists); auto **FromTPLists = D->getTrailingObjects(); for (unsigned I = 0; I < D->NumTPLists; I++) { if (auto ListOrErr = import(FromTPLists[I])) ToTPLists[I] = *ListOrErr; else return ListOrErr.takeError(); } auto LocationOrErr = import(D->getLocation()); if (!LocationOrErr) return LocationOrErr.takeError(); auto FriendLocOrErr = import(D->getFriendLoc()); if (!FriendLocOrErr) return FriendLocOrErr.takeError(); FriendDecl *FrD; if (GetImportedOrCreateDecl(FrD, D, Importer.getToContext(), DC, *LocationOrErr, ToFU, *FriendLocOrErr, ToTPLists)) return FrD; FrD->setAccess(D->getAccess()); FrD->setLexicalDeclContext(LexicalDC); LexicalDC->addDeclInternal(FrD); return FrD; } ExpectedDecl ASTNodeImporter::VisitObjCIvarDecl(ObjCIvarDecl *D) { // Import the major distinguishing characteristics of an ivar. DeclContext *DC, *LexicalDC; DeclarationName Name; SourceLocation Loc; NamedDecl *ToD; if (Error Err = ImportDeclParts(D, DC, LexicalDC, Name, ToD, Loc)) return std::move(Err); if (ToD) return ToD; // Determine whether we've already imported this ivar auto FoundDecls = Importer.findDeclsInToCtx(DC, Name); for (auto *FoundDecl : FoundDecls) { if (ObjCIvarDecl *FoundIvar = dyn_cast(FoundDecl)) { if (Importer.IsStructurallyEquivalent(D->getType(), FoundIvar->getType())) { Importer.MapImported(D, FoundIvar); return FoundIvar; } Importer.ToDiag(Loc, diag::warn_odr_ivar_type_inconsistent) << Name << D->getType() << FoundIvar->getType(); Importer.ToDiag(FoundIvar->getLocation(), diag::note_odr_value_here) << FoundIvar->getType(); return make_error(ImportError::NameConflict); } } QualType ToType; TypeSourceInfo *ToTypeSourceInfo; Expr *ToBitWidth; SourceLocation ToInnerLocStart; if (auto Imp = importSeq( D->getType(), D->getTypeSourceInfo(), D->getBitWidth(), D->getInnerLocStart())) std::tie(ToType, ToTypeSourceInfo, ToBitWidth, ToInnerLocStart) = *Imp; else return Imp.takeError(); ObjCIvarDecl *ToIvar; if (GetImportedOrCreateDecl( ToIvar, D, Importer.getToContext(), cast(DC), ToInnerLocStart, Loc, Name.getAsIdentifierInfo(), ToType, ToTypeSourceInfo, D->getAccessControl(),ToBitWidth, D->getSynthesize())) return ToIvar; ToIvar->setLexicalDeclContext(LexicalDC); LexicalDC->addDeclInternal(ToIvar); return ToIvar; } ExpectedDecl ASTNodeImporter::VisitVarDecl(VarDecl *D) { SmallVector Redecls = getCanonicalForwardRedeclChain(D); auto RedeclIt = Redecls.begin(); // Import the first part of the decl chain. I.e. import all previous // declarations starting from the canonical decl. for (; RedeclIt != Redecls.end() && *RedeclIt != D; ++RedeclIt) { ExpectedDecl RedeclOrErr = import(*RedeclIt); if (!RedeclOrErr) return RedeclOrErr.takeError(); } assert(*RedeclIt == D); // Import the major distinguishing characteristics of a variable. DeclContext *DC, *LexicalDC; DeclarationName Name; SourceLocation Loc; NamedDecl *ToD; if (Error Err = ImportDeclParts(D, DC, LexicalDC, Name, ToD, Loc)) return std::move(Err); if (ToD) return ToD; // Try to find a variable in our own ("to") context with the same name and // in the same context as the variable we're importing. VarDecl *FoundByLookup = nullptr; if (D->isFileVarDecl()) { SmallVector ConflictingDecls; unsigned IDNS = Decl::IDNS_Ordinary; auto FoundDecls = Importer.findDeclsInToCtx(DC, Name); for (auto *FoundDecl : FoundDecls) { if (!FoundDecl->isInIdentifierNamespace(IDNS)) continue; if (auto *FoundVar = dyn_cast(FoundDecl)) { if (!hasSameVisibilityContext(FoundVar, D)) continue; if (Importer.IsStructurallyEquivalent(D->getType(), FoundVar->getType())) { // The VarDecl in the "From" context has a definition, but in the // "To" context we already have a definition. VarDecl *FoundDef = FoundVar->getDefinition(); if (D->isThisDeclarationADefinition() && FoundDef) // FIXME Check for ODR error if the two definitions have // different initializers? return Importer.MapImported(D, FoundDef); // The VarDecl in the "From" context has an initializer, but in the // "To" context we already have an initializer. const VarDecl *FoundDInit = nullptr; if (D->getInit() && FoundVar->getAnyInitializer(FoundDInit)) // FIXME Diagnose ODR error if the two initializers are different? return Importer.MapImported(D, const_cast(FoundDInit)); FoundByLookup = FoundVar; break; } const ArrayType *FoundArray = Importer.getToContext().getAsArrayType(FoundVar->getType()); const ArrayType *TArray = Importer.getToContext().getAsArrayType(D->getType()); if (FoundArray && TArray) { if (isa(FoundArray) && isa(TArray)) { // Import the type. if (auto TyOrErr = import(D->getType())) FoundVar->setType(*TyOrErr); else return TyOrErr.takeError(); FoundByLookup = FoundVar; break; } else if (isa(TArray) && isa(FoundArray)) { FoundByLookup = FoundVar; break; } } Importer.ToDiag(Loc, diag::warn_odr_variable_type_inconsistent) << Name << D->getType() << FoundVar->getType(); Importer.ToDiag(FoundVar->getLocation(), diag::note_odr_value_here) << FoundVar->getType(); ConflictingDecls.push_back(FoundDecl); } } if (!ConflictingDecls.empty()) { ExpectedName NameOrErr = Importer.HandleNameConflict( Name, DC, IDNS, ConflictingDecls.data(), ConflictingDecls.size()); if (NameOrErr) Name = NameOrErr.get(); else return NameOrErr.takeError(); } } QualType ToType; TypeSourceInfo *ToTypeSourceInfo; SourceLocation ToInnerLocStart; NestedNameSpecifierLoc ToQualifierLoc; if (auto Imp = importSeq( D->getType(), D->getTypeSourceInfo(), D->getInnerLocStart(), D->getQualifierLoc())) std::tie(ToType, ToTypeSourceInfo, ToInnerLocStart, ToQualifierLoc) = *Imp; else return Imp.takeError(); // Create the imported variable. VarDecl *ToVar; if (GetImportedOrCreateDecl(ToVar, D, Importer.getToContext(), DC, ToInnerLocStart, Loc, Name.getAsIdentifierInfo(), ToType, ToTypeSourceInfo, D->getStorageClass())) return ToVar; ToVar->setQualifierInfo(ToQualifierLoc); ToVar->setAccess(D->getAccess()); ToVar->setLexicalDeclContext(LexicalDC); if (FoundByLookup) { auto *Recent = const_cast(FoundByLookup->getMostRecentDecl()); ToVar->setPreviousDecl(Recent); } if (Error Err = ImportInitializer(D, ToVar)) return std::move(Err); if (D->isConstexpr()) ToVar->setConstexpr(true); addDeclToContexts(D, ToVar); // Import the rest of the chain. I.e. import all subsequent declarations. for (++RedeclIt; RedeclIt != Redecls.end(); ++RedeclIt) { ExpectedDecl RedeclOrErr = import(*RedeclIt); if (!RedeclOrErr) return RedeclOrErr.takeError(); } return ToVar; } ExpectedDecl ASTNodeImporter::VisitImplicitParamDecl(ImplicitParamDecl *D) { // Parameters are created in the translation unit's context, then moved // into the function declaration's context afterward. DeclContext *DC = Importer.getToContext().getTranslationUnitDecl(); DeclarationName ToDeclName; SourceLocation ToLocation; QualType ToType; if (auto Imp = importSeq(D->getDeclName(), D->getLocation(), D->getType())) std::tie(ToDeclName, ToLocation, ToType) = *Imp; else return Imp.takeError(); // Create the imported parameter. ImplicitParamDecl *ToParm = nullptr; if (GetImportedOrCreateDecl(ToParm, D, Importer.getToContext(), DC, ToLocation, ToDeclName.getAsIdentifierInfo(), ToType, D->getParameterKind())) return ToParm; return ToParm; } Error ASTNodeImporter::ImportDefaultArgOfParmVarDecl( const ParmVarDecl *FromParam, ParmVarDecl *ToParam) { ToParam->setHasInheritedDefaultArg(FromParam->hasInheritedDefaultArg()); ToParam->setKNRPromoted(FromParam->isKNRPromoted()); if (FromParam->hasUninstantiatedDefaultArg()) { if (auto ToDefArgOrErr = import(FromParam->getUninstantiatedDefaultArg())) ToParam->setUninstantiatedDefaultArg(*ToDefArgOrErr); else return ToDefArgOrErr.takeError(); } else if (FromParam->hasUnparsedDefaultArg()) { ToParam->setUnparsedDefaultArg(); } else if (FromParam->hasDefaultArg()) { if (auto ToDefArgOrErr = import(FromParam->getDefaultArg())) ToParam->setDefaultArg(*ToDefArgOrErr); else return ToDefArgOrErr.takeError(); } return Error::success(); } ExpectedDecl ASTNodeImporter::VisitParmVarDecl(ParmVarDecl *D) { // Parameters are created in the translation unit's context, then moved // into the function declaration's context afterward. DeclContext *DC = Importer.getToContext().getTranslationUnitDecl(); DeclarationName ToDeclName; SourceLocation ToLocation, ToInnerLocStart; QualType ToType; TypeSourceInfo *ToTypeSourceInfo; if (auto Imp = importSeq( D->getDeclName(), D->getLocation(), D->getType(), D->getInnerLocStart(), D->getTypeSourceInfo())) std::tie( ToDeclName, ToLocation, ToType, ToInnerLocStart, ToTypeSourceInfo) = *Imp; else return Imp.takeError(); ParmVarDecl *ToParm; if (GetImportedOrCreateDecl(ToParm, D, Importer.getToContext(), DC, ToInnerLocStart, ToLocation, ToDeclName.getAsIdentifierInfo(), ToType, ToTypeSourceInfo, D->getStorageClass(), /*DefaultArg*/ nullptr)) return ToParm; // Set the default argument. It should be no problem if it was already done. // Do not import the default expression before GetImportedOrCreateDecl call // to avoid possible infinite import loop because circular dependency. if (Error Err = ImportDefaultArgOfParmVarDecl(D, ToParm)) return std::move(Err); if (D->isObjCMethodParameter()) { ToParm->setObjCMethodScopeInfo(D->getFunctionScopeIndex()); ToParm->setObjCDeclQualifier(D->getObjCDeclQualifier()); } else { ToParm->setScopeInfo(D->getFunctionScopeDepth(), D->getFunctionScopeIndex()); } return ToParm; } ExpectedDecl ASTNodeImporter::VisitObjCMethodDecl(ObjCMethodDecl *D) { // Import the major distinguishing characteristics of a method. DeclContext *DC, *LexicalDC; DeclarationName Name; SourceLocation Loc; NamedDecl *ToD; if (Error Err = ImportDeclParts(D, DC, LexicalDC, Name, ToD, Loc)) return std::move(Err); if (ToD) return ToD; auto FoundDecls = Importer.findDeclsInToCtx(DC, Name); for (auto *FoundDecl : FoundDecls) { if (auto *FoundMethod = dyn_cast(FoundDecl)) { if (FoundMethod->isInstanceMethod() != D->isInstanceMethod()) continue; // Check return types. if (!Importer.IsStructurallyEquivalent(D->getReturnType(), FoundMethod->getReturnType())) { Importer.ToDiag(Loc, diag::warn_odr_objc_method_result_type_inconsistent) << D->isInstanceMethod() << Name << D->getReturnType() << FoundMethod->getReturnType(); Importer.ToDiag(FoundMethod->getLocation(), diag::note_odr_objc_method_here) << D->isInstanceMethod() << Name; return make_error(ImportError::NameConflict); } // Check the number of parameters. if (D->param_size() != FoundMethod->param_size()) { Importer.ToDiag(Loc, diag::warn_odr_objc_method_num_params_inconsistent) << D->isInstanceMethod() << Name << D->param_size() << FoundMethod->param_size(); Importer.ToDiag(FoundMethod->getLocation(), diag::note_odr_objc_method_here) << D->isInstanceMethod() << Name; return make_error(ImportError::NameConflict); } // Check parameter types. for (ObjCMethodDecl::param_iterator P = D->param_begin(), PEnd = D->param_end(), FoundP = FoundMethod->param_begin(); P != PEnd; ++P, ++FoundP) { if (!Importer.IsStructurallyEquivalent((*P)->getType(), (*FoundP)->getType())) { Importer.FromDiag((*P)->getLocation(), diag::warn_odr_objc_method_param_type_inconsistent) << D->isInstanceMethod() << Name << (*P)->getType() << (*FoundP)->getType(); Importer.ToDiag((*FoundP)->getLocation(), diag::note_odr_value_here) << (*FoundP)->getType(); return make_error(ImportError::NameConflict); } } // Check variadic/non-variadic. // Check the number of parameters. if (D->isVariadic() != FoundMethod->isVariadic()) { Importer.ToDiag(Loc, diag::warn_odr_objc_method_variadic_inconsistent) << D->isInstanceMethod() << Name; Importer.ToDiag(FoundMethod->getLocation(), diag::note_odr_objc_method_here) << D->isInstanceMethod() << Name; return make_error(ImportError::NameConflict); } // FIXME: Any other bits we need to merge? return Importer.MapImported(D, FoundMethod); } } SourceLocation ToEndLoc; QualType ToReturnType; TypeSourceInfo *ToReturnTypeSourceInfo; if (auto Imp = importSeq( D->getEndLoc(), D->getReturnType(), D->getReturnTypeSourceInfo())) std::tie(ToEndLoc, ToReturnType, ToReturnTypeSourceInfo) = *Imp; else return Imp.takeError(); ObjCMethodDecl *ToMethod; if (GetImportedOrCreateDecl( ToMethod, D, Importer.getToContext(), Loc, ToEndLoc, Name.getObjCSelector(), ToReturnType, ToReturnTypeSourceInfo, DC, D->isInstanceMethod(), D->isVariadic(), D->isPropertyAccessor(), D->isSynthesizedAccessorStub(), D->isImplicit(), D->isDefined(), D->getImplementationControl(), D->hasRelatedResultType())) return ToMethod; // FIXME: When we decide to merge method definitions, we'll need to // deal with implicit parameters. // Import the parameters SmallVector ToParams; for (auto *FromP : D->parameters()) { if (Expected ToPOrErr = import(FromP)) ToParams.push_back(*ToPOrErr); else return ToPOrErr.takeError(); } // Set the parameters. for (auto *ToParam : ToParams) { ToParam->setOwningFunction(ToMethod); ToMethod->addDeclInternal(ToParam); } SmallVector FromSelLocs; D->getSelectorLocs(FromSelLocs); SmallVector ToSelLocs(FromSelLocs.size()); if (Error Err = ImportContainerChecked(FromSelLocs, ToSelLocs)) return std::move(Err); ToMethod->setMethodParams(Importer.getToContext(), ToParams, ToSelLocs); ToMethod->setLexicalDeclContext(LexicalDC); LexicalDC->addDeclInternal(ToMethod); // Implicit params are declared when Sema encounters the definition but this // never happens when the method is imported. Manually declare the implicit // params now that the MethodDecl knows its class interface. if (D->getSelfDecl()) ToMethod->createImplicitParams(Importer.getToContext(), ToMethod->getClassInterface()); return ToMethod; } ExpectedDecl ASTNodeImporter::VisitObjCTypeParamDecl(ObjCTypeParamDecl *D) { // Import the major distinguishing characteristics of a category. DeclContext *DC, *LexicalDC; DeclarationName Name; SourceLocation Loc; NamedDecl *ToD; if (Error Err = ImportDeclParts(D, DC, LexicalDC, Name, ToD, Loc)) return std::move(Err); if (ToD) return ToD; SourceLocation ToVarianceLoc, ToLocation, ToColonLoc; TypeSourceInfo *ToTypeSourceInfo; if (auto Imp = importSeq( D->getVarianceLoc(), D->getLocation(), D->getColonLoc(), D->getTypeSourceInfo())) std::tie(ToVarianceLoc, ToLocation, ToColonLoc, ToTypeSourceInfo) = *Imp; else return Imp.takeError(); ObjCTypeParamDecl *Result; if (GetImportedOrCreateDecl( Result, D, Importer.getToContext(), DC, D->getVariance(), ToVarianceLoc, D->getIndex(), ToLocation, Name.getAsIdentifierInfo(), ToColonLoc, ToTypeSourceInfo)) return Result; Result->setLexicalDeclContext(LexicalDC); return Result; } ExpectedDecl ASTNodeImporter::VisitObjCCategoryDecl(ObjCCategoryDecl *D) { // Import the major distinguishing characteristics of a category. DeclContext *DC, *LexicalDC; DeclarationName Name; SourceLocation Loc; NamedDecl *ToD; if (Error Err = ImportDeclParts(D, DC, LexicalDC, Name, ToD, Loc)) return std::move(Err); if (ToD) return ToD; ObjCInterfaceDecl *ToInterface; if (Error Err = importInto(ToInterface, D->getClassInterface())) return std::move(Err); // Determine if we've already encountered this category. ObjCCategoryDecl *MergeWithCategory = ToInterface->FindCategoryDeclaration(Name.getAsIdentifierInfo()); ObjCCategoryDecl *ToCategory = MergeWithCategory; if (!ToCategory) { SourceLocation ToAtStartLoc, ToCategoryNameLoc; SourceLocation ToIvarLBraceLoc, ToIvarRBraceLoc; if (auto Imp = importSeq( D->getAtStartLoc(), D->getCategoryNameLoc(), D->getIvarLBraceLoc(), D->getIvarRBraceLoc())) std::tie( ToAtStartLoc, ToCategoryNameLoc, ToIvarLBraceLoc, ToIvarRBraceLoc) = *Imp; else return Imp.takeError(); if (GetImportedOrCreateDecl(ToCategory, D, Importer.getToContext(), DC, ToAtStartLoc, Loc, ToCategoryNameLoc, Name.getAsIdentifierInfo(), ToInterface, /*TypeParamList=*/nullptr, ToIvarLBraceLoc, ToIvarRBraceLoc)) return ToCategory; ToCategory->setLexicalDeclContext(LexicalDC); LexicalDC->addDeclInternal(ToCategory); // Import the type parameter list after MapImported, to avoid // loops when bringing in their DeclContext. if (auto PListOrErr = ImportObjCTypeParamList(D->getTypeParamList())) ToCategory->setTypeParamList(*PListOrErr); else return PListOrErr.takeError(); // Import protocols SmallVector Protocols; SmallVector ProtocolLocs; ObjCCategoryDecl::protocol_loc_iterator FromProtoLoc = D->protocol_loc_begin(); for (ObjCCategoryDecl::protocol_iterator FromProto = D->protocol_begin(), FromProtoEnd = D->protocol_end(); FromProto != FromProtoEnd; ++FromProto, ++FromProtoLoc) { if (Expected ToProtoOrErr = import(*FromProto)) Protocols.push_back(*ToProtoOrErr); else return ToProtoOrErr.takeError(); if (ExpectedSLoc ToProtoLocOrErr = import(*FromProtoLoc)) ProtocolLocs.push_back(*ToProtoLocOrErr); else return ToProtoLocOrErr.takeError(); } // FIXME: If we're merging, make sure that the protocol list is the same. ToCategory->setProtocolList(Protocols.data(), Protocols.size(), ProtocolLocs.data(), Importer.getToContext()); } else { Importer.MapImported(D, ToCategory); } // Import all of the members of this category. if (Error Err = ImportDeclContext(D)) return std::move(Err); // If we have an implementation, import it as well. if (D->getImplementation()) { if (Expected ToImplOrErr = import(D->getImplementation())) ToCategory->setImplementation(*ToImplOrErr); else return ToImplOrErr.takeError(); } return ToCategory; } Error ASTNodeImporter::ImportDefinition( ObjCProtocolDecl *From, ObjCProtocolDecl *To, ImportDefinitionKind Kind) { if (To->getDefinition()) { if (shouldForceImportDeclContext(Kind)) if (Error Err = ImportDeclContext(From)) return Err; return Error::success(); } // Start the protocol definition To->startDefinition(); // Import protocols SmallVector Protocols; SmallVector ProtocolLocs; ObjCProtocolDecl::protocol_loc_iterator FromProtoLoc = From->protocol_loc_begin(); for (ObjCProtocolDecl::protocol_iterator FromProto = From->protocol_begin(), FromProtoEnd = From->protocol_end(); FromProto != FromProtoEnd; ++FromProto, ++FromProtoLoc) { if (Expected ToProtoOrErr = import(*FromProto)) Protocols.push_back(*ToProtoOrErr); else return ToProtoOrErr.takeError(); if (ExpectedSLoc ToProtoLocOrErr = import(*FromProtoLoc)) ProtocolLocs.push_back(*ToProtoLocOrErr); else return ToProtoLocOrErr.takeError(); } // FIXME: If we're merging, make sure that the protocol list is the same. To->setProtocolList(Protocols.data(), Protocols.size(), ProtocolLocs.data(), Importer.getToContext()); if (shouldForceImportDeclContext(Kind)) { // Import all of the members of this protocol. if (Error Err = ImportDeclContext(From, /*ForceImport=*/true)) return Err; } return Error::success(); } ExpectedDecl ASTNodeImporter::VisitObjCProtocolDecl(ObjCProtocolDecl *D) { // If this protocol has a definition in the translation unit we're coming // from, but this particular declaration is not that definition, import the // definition and map to that. ObjCProtocolDecl *Definition = D->getDefinition(); if (Definition && Definition != D) { if (ExpectedDecl ImportedDefOrErr = import(Definition)) return Importer.MapImported(D, *ImportedDefOrErr); else return ImportedDefOrErr.takeError(); } // Import the major distinguishing characteristics of a protocol. DeclContext *DC, *LexicalDC; DeclarationName Name; SourceLocation Loc; NamedDecl *ToD; if (Error Err = ImportDeclParts(D, DC, LexicalDC, Name, ToD, Loc)) return std::move(Err); if (ToD) return ToD; ObjCProtocolDecl *MergeWithProtocol = nullptr; auto FoundDecls = Importer.findDeclsInToCtx(DC, Name); for (auto *FoundDecl : FoundDecls) { if (!FoundDecl->isInIdentifierNamespace(Decl::IDNS_ObjCProtocol)) continue; if ((MergeWithProtocol = dyn_cast(FoundDecl))) break; } ObjCProtocolDecl *ToProto = MergeWithProtocol; if (!ToProto) { auto ToAtBeginLocOrErr = import(D->getAtStartLoc()); if (!ToAtBeginLocOrErr) return ToAtBeginLocOrErr.takeError(); if (GetImportedOrCreateDecl(ToProto, D, Importer.getToContext(), DC, Name.getAsIdentifierInfo(), Loc, *ToAtBeginLocOrErr, /*PrevDecl=*/nullptr)) return ToProto; ToProto->setLexicalDeclContext(LexicalDC); LexicalDC->addDeclInternal(ToProto); } Importer.MapImported(D, ToProto); if (D->isThisDeclarationADefinition()) if (Error Err = ImportDefinition(D, ToProto)) return std::move(Err); return ToProto; } ExpectedDecl ASTNodeImporter::VisitLinkageSpecDecl(LinkageSpecDecl *D) { DeclContext *DC, *LexicalDC; if (Error Err = ImportDeclContext(D, DC, LexicalDC)) return std::move(Err); ExpectedSLoc ExternLocOrErr = import(D->getExternLoc()); if (!ExternLocOrErr) return ExternLocOrErr.takeError(); ExpectedSLoc LangLocOrErr = import(D->getLocation()); if (!LangLocOrErr) return LangLocOrErr.takeError(); bool HasBraces = D->hasBraces(); LinkageSpecDecl *ToLinkageSpec; if (GetImportedOrCreateDecl(ToLinkageSpec, D, Importer.getToContext(), DC, *ExternLocOrErr, *LangLocOrErr, D->getLanguage(), HasBraces)) return ToLinkageSpec; if (HasBraces) { ExpectedSLoc RBraceLocOrErr = import(D->getRBraceLoc()); if (!RBraceLocOrErr) return RBraceLocOrErr.takeError(); ToLinkageSpec->setRBraceLoc(*RBraceLocOrErr); } ToLinkageSpec->setLexicalDeclContext(LexicalDC); LexicalDC->addDeclInternal(ToLinkageSpec); return ToLinkageSpec; } ExpectedDecl ASTNodeImporter::VisitUsingDecl(UsingDecl *D) { DeclContext *DC, *LexicalDC; DeclarationName Name; SourceLocation Loc; NamedDecl *ToD = nullptr; if (Error Err = ImportDeclParts(D, DC, LexicalDC, Name, ToD, Loc)) return std::move(Err); if (ToD) return ToD; SourceLocation ToLoc, ToUsingLoc; NestedNameSpecifierLoc ToQualifierLoc; if (auto Imp = importSeq( D->getNameInfo().getLoc(), D->getUsingLoc(), D->getQualifierLoc())) std::tie(ToLoc, ToUsingLoc, ToQualifierLoc) = *Imp; else return Imp.takeError(); DeclarationNameInfo NameInfo(Name, ToLoc); if (Error Err = ImportDeclarationNameLoc(D->getNameInfo(), NameInfo)) return std::move(Err); UsingDecl *ToUsing; if (GetImportedOrCreateDecl(ToUsing, D, Importer.getToContext(), DC, ToUsingLoc, ToQualifierLoc, NameInfo, D->hasTypename())) return ToUsing; ToUsing->setLexicalDeclContext(LexicalDC); LexicalDC->addDeclInternal(ToUsing); if (NamedDecl *FromPattern = Importer.getFromContext().getInstantiatedFromUsingDecl(D)) { if (Expected ToPatternOrErr = import(FromPattern)) Importer.getToContext().setInstantiatedFromUsingDecl( ToUsing, *ToPatternOrErr); else return ToPatternOrErr.takeError(); } for (UsingShadowDecl *FromShadow : D->shadows()) { if (Expected ToShadowOrErr = import(FromShadow)) ToUsing->addShadowDecl(*ToShadowOrErr); else // FIXME: We return error here but the definition is already created // and available with lookups. How to fix this?.. return ToShadowOrErr.takeError(); } return ToUsing; } ExpectedDecl ASTNodeImporter::VisitUsingShadowDecl(UsingShadowDecl *D) { DeclContext *DC, *LexicalDC; DeclarationName Name; SourceLocation Loc; NamedDecl *ToD = nullptr; if (Error Err = ImportDeclParts(D, DC, LexicalDC, Name, ToD, Loc)) return std::move(Err); if (ToD) return ToD; Expected ToUsingOrErr = import(D->getUsingDecl()); if (!ToUsingOrErr) return ToUsingOrErr.takeError(); Expected ToTargetOrErr = import(D->getTargetDecl()); if (!ToTargetOrErr) return ToTargetOrErr.takeError(); UsingShadowDecl *ToShadow; if (GetImportedOrCreateDecl(ToShadow, D, Importer.getToContext(), DC, Loc, *ToUsingOrErr, *ToTargetOrErr)) return ToShadow; ToShadow->setLexicalDeclContext(LexicalDC); ToShadow->setAccess(D->getAccess()); if (UsingShadowDecl *FromPattern = Importer.getFromContext().getInstantiatedFromUsingShadowDecl(D)) { if (Expected ToPatternOrErr = import(FromPattern)) Importer.getToContext().setInstantiatedFromUsingShadowDecl( ToShadow, *ToPatternOrErr); else // FIXME: We return error here but the definition is already created // and available with lookups. How to fix this?.. return ToPatternOrErr.takeError(); } LexicalDC->addDeclInternal(ToShadow); return ToShadow; } ExpectedDecl ASTNodeImporter::VisitUsingDirectiveDecl(UsingDirectiveDecl *D) { DeclContext *DC, *LexicalDC; DeclarationName Name; SourceLocation Loc; NamedDecl *ToD = nullptr; if (Error Err = ImportDeclParts(D, DC, LexicalDC, Name, ToD, Loc)) return std::move(Err); if (ToD) return ToD; auto ToComAncestorOrErr = Importer.ImportContext(D->getCommonAncestor()); if (!ToComAncestorOrErr) return ToComAncestorOrErr.takeError(); NamespaceDecl *ToNominatedNamespace; SourceLocation ToUsingLoc, ToNamespaceKeyLocation, ToIdentLocation; NestedNameSpecifierLoc ToQualifierLoc; if (auto Imp = importSeq( D->getNominatedNamespace(), D->getUsingLoc(), D->getNamespaceKeyLocation(), D->getQualifierLoc(), D->getIdentLocation())) std::tie( ToNominatedNamespace, ToUsingLoc, ToNamespaceKeyLocation, ToQualifierLoc, ToIdentLocation) = *Imp; else return Imp.takeError(); UsingDirectiveDecl *ToUsingDir; if (GetImportedOrCreateDecl(ToUsingDir, D, Importer.getToContext(), DC, ToUsingLoc, ToNamespaceKeyLocation, ToQualifierLoc, ToIdentLocation, ToNominatedNamespace, *ToComAncestorOrErr)) return ToUsingDir; ToUsingDir->setLexicalDeclContext(LexicalDC); LexicalDC->addDeclInternal(ToUsingDir); return ToUsingDir; } ExpectedDecl ASTNodeImporter::VisitUnresolvedUsingValueDecl( UnresolvedUsingValueDecl *D) { DeclContext *DC, *LexicalDC; DeclarationName Name; SourceLocation Loc; NamedDecl *ToD = nullptr; if (Error Err = ImportDeclParts(D, DC, LexicalDC, Name, ToD, Loc)) return std::move(Err); if (ToD) return ToD; SourceLocation ToLoc, ToUsingLoc, ToEllipsisLoc; NestedNameSpecifierLoc ToQualifierLoc; if (auto Imp = importSeq( D->getNameInfo().getLoc(), D->getUsingLoc(), D->getQualifierLoc(), D->getEllipsisLoc())) std::tie(ToLoc, ToUsingLoc, ToQualifierLoc, ToEllipsisLoc) = *Imp; else return Imp.takeError(); DeclarationNameInfo NameInfo(Name, ToLoc); if (Error Err = ImportDeclarationNameLoc(D->getNameInfo(), NameInfo)) return std::move(Err); UnresolvedUsingValueDecl *ToUsingValue; if (GetImportedOrCreateDecl(ToUsingValue, D, Importer.getToContext(), DC, ToUsingLoc, ToQualifierLoc, NameInfo, ToEllipsisLoc)) return ToUsingValue; ToUsingValue->setAccess(D->getAccess()); ToUsingValue->setLexicalDeclContext(LexicalDC); LexicalDC->addDeclInternal(ToUsingValue); return ToUsingValue; } ExpectedDecl ASTNodeImporter::VisitUnresolvedUsingTypenameDecl( UnresolvedUsingTypenameDecl *D) { DeclContext *DC, *LexicalDC; DeclarationName Name; SourceLocation Loc; NamedDecl *ToD = nullptr; if (Error Err = ImportDeclParts(D, DC, LexicalDC, Name, ToD, Loc)) return std::move(Err); if (ToD) return ToD; SourceLocation ToUsingLoc, ToTypenameLoc, ToEllipsisLoc; NestedNameSpecifierLoc ToQualifierLoc; if (auto Imp = importSeq( D->getUsingLoc(), D->getTypenameLoc(), D->getQualifierLoc(), D->getEllipsisLoc())) std::tie(ToUsingLoc, ToTypenameLoc, ToQualifierLoc, ToEllipsisLoc) = *Imp; else return Imp.takeError(); UnresolvedUsingTypenameDecl *ToUsing; if (GetImportedOrCreateDecl(ToUsing, D, Importer.getToContext(), DC, ToUsingLoc, ToTypenameLoc, ToQualifierLoc, Loc, Name, ToEllipsisLoc)) return ToUsing; ToUsing->setAccess(D->getAccess()); ToUsing->setLexicalDeclContext(LexicalDC); LexicalDC->addDeclInternal(ToUsing); return ToUsing; } ExpectedDecl ASTNodeImporter::VisitBuiltinTemplateDecl(BuiltinTemplateDecl *D) { Decl* ToD = nullptr; switch (D->getBuiltinTemplateKind()) { case BuiltinTemplateKind::BTK__make_integer_seq: ToD = Importer.getToContext().getMakeIntegerSeqDecl(); break; case BuiltinTemplateKind::BTK__type_pack_element: ToD = Importer.getToContext().getTypePackElementDecl(); break; } assert(ToD && "BuiltinTemplateDecl of unsupported kind!"); Importer.MapImported(D, ToD); return ToD; } Error ASTNodeImporter::ImportDefinition( ObjCInterfaceDecl *From, ObjCInterfaceDecl *To, ImportDefinitionKind Kind) { if (To->getDefinition()) { // Check consistency of superclass. ObjCInterfaceDecl *FromSuper = From->getSuperClass(); if (FromSuper) { if (auto FromSuperOrErr = import(FromSuper)) FromSuper = *FromSuperOrErr; else return FromSuperOrErr.takeError(); } ObjCInterfaceDecl *ToSuper = To->getSuperClass(); if ((bool)FromSuper != (bool)ToSuper || (FromSuper && !declaresSameEntity(FromSuper, ToSuper))) { Importer.ToDiag(To->getLocation(), diag::warn_odr_objc_superclass_inconsistent) << To->getDeclName(); if (ToSuper) Importer.ToDiag(To->getSuperClassLoc(), diag::note_odr_objc_superclass) << To->getSuperClass()->getDeclName(); else Importer.ToDiag(To->getLocation(), diag::note_odr_objc_missing_superclass); if (From->getSuperClass()) Importer.FromDiag(From->getSuperClassLoc(), diag::note_odr_objc_superclass) << From->getSuperClass()->getDeclName(); else Importer.FromDiag(From->getLocation(), diag::note_odr_objc_missing_superclass); } if (shouldForceImportDeclContext(Kind)) if (Error Err = ImportDeclContext(From)) return Err; return Error::success(); } // Start the definition. To->startDefinition(); // If this class has a superclass, import it. if (From->getSuperClass()) { if (auto SuperTInfoOrErr = import(From->getSuperClassTInfo())) To->setSuperClass(*SuperTInfoOrErr); else return SuperTInfoOrErr.takeError(); } // Import protocols SmallVector Protocols; SmallVector ProtocolLocs; ObjCInterfaceDecl::protocol_loc_iterator FromProtoLoc = From->protocol_loc_begin(); for (ObjCInterfaceDecl::protocol_iterator FromProto = From->protocol_begin(), FromProtoEnd = From->protocol_end(); FromProto != FromProtoEnd; ++FromProto, ++FromProtoLoc) { if (Expected ToProtoOrErr = import(*FromProto)) Protocols.push_back(*ToProtoOrErr); else return ToProtoOrErr.takeError(); if (ExpectedSLoc ToProtoLocOrErr = import(*FromProtoLoc)) ProtocolLocs.push_back(*ToProtoLocOrErr); else return ToProtoLocOrErr.takeError(); } // FIXME: If we're merging, make sure that the protocol list is the same. To->setProtocolList(Protocols.data(), Protocols.size(), ProtocolLocs.data(), Importer.getToContext()); // Import categories. When the categories themselves are imported, they'll // hook themselves into this interface. for (auto *Cat : From->known_categories()) { auto ToCatOrErr = import(Cat); if (!ToCatOrErr) return ToCatOrErr.takeError(); } // If we have an @implementation, import it as well. if (From->getImplementation()) { if (Expected ToImplOrErr = import(From->getImplementation())) To->setImplementation(*ToImplOrErr); else return ToImplOrErr.takeError(); } if (shouldForceImportDeclContext(Kind)) { // Import all of the members of this class. if (Error Err = ImportDeclContext(From, /*ForceImport=*/true)) return Err; } return Error::success(); } Expected ASTNodeImporter::ImportObjCTypeParamList(ObjCTypeParamList *list) { if (!list) return nullptr; SmallVector toTypeParams; for (auto *fromTypeParam : *list) { if (auto toTypeParamOrErr = import(fromTypeParam)) toTypeParams.push_back(*toTypeParamOrErr); else return toTypeParamOrErr.takeError(); } auto LAngleLocOrErr = import(list->getLAngleLoc()); if (!LAngleLocOrErr) return LAngleLocOrErr.takeError(); auto RAngleLocOrErr = import(list->getRAngleLoc()); if (!RAngleLocOrErr) return RAngleLocOrErr.takeError(); return ObjCTypeParamList::create(Importer.getToContext(), *LAngleLocOrErr, toTypeParams, *RAngleLocOrErr); } ExpectedDecl ASTNodeImporter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) { // If this class has a definition in the translation unit we're coming from, // but this particular declaration is not that definition, import the // definition and map to that. ObjCInterfaceDecl *Definition = D->getDefinition(); if (Definition && Definition != D) { if (ExpectedDecl ImportedDefOrErr = import(Definition)) return Importer.MapImported(D, *ImportedDefOrErr); else return ImportedDefOrErr.takeError(); } // Import the major distinguishing characteristics of an @interface. DeclContext *DC, *LexicalDC; DeclarationName Name; SourceLocation Loc; NamedDecl *ToD; if (Error Err = ImportDeclParts(D, DC, LexicalDC, Name, ToD, Loc)) return std::move(Err); if (ToD) return ToD; // Look for an existing interface with the same name. ObjCInterfaceDecl *MergeWithIface = nullptr; auto FoundDecls = Importer.findDeclsInToCtx(DC, Name); for (auto *FoundDecl : FoundDecls) { if (!FoundDecl->isInIdentifierNamespace(Decl::IDNS_Ordinary)) continue; if ((MergeWithIface = dyn_cast(FoundDecl))) break; } // Create an interface declaration, if one does not already exist. ObjCInterfaceDecl *ToIface = MergeWithIface; if (!ToIface) { ExpectedSLoc AtBeginLocOrErr = import(D->getAtStartLoc()); if (!AtBeginLocOrErr) return AtBeginLocOrErr.takeError(); if (GetImportedOrCreateDecl( ToIface, D, Importer.getToContext(), DC, *AtBeginLocOrErr, Name.getAsIdentifierInfo(), /*TypeParamList=*/nullptr, /*PrevDecl=*/nullptr, Loc, D->isImplicitInterfaceDecl())) return ToIface; ToIface->setLexicalDeclContext(LexicalDC); LexicalDC->addDeclInternal(ToIface); } Importer.MapImported(D, ToIface); // Import the type parameter list after MapImported, to avoid // loops when bringing in their DeclContext. if (auto ToPListOrErr = ImportObjCTypeParamList(D->getTypeParamListAsWritten())) ToIface->setTypeParamList(*ToPListOrErr); else return ToPListOrErr.takeError(); if (D->isThisDeclarationADefinition()) if (Error Err = ImportDefinition(D, ToIface)) return std::move(Err); return ToIface; } ExpectedDecl ASTNodeImporter::VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D) { ObjCCategoryDecl *Category; if (Error Err = importInto(Category, D->getCategoryDecl())) return std::move(Err); ObjCCategoryImplDecl *ToImpl = Category->getImplementation(); if (!ToImpl) { DeclContext *DC, *LexicalDC; if (Error Err = ImportDeclContext(D, DC, LexicalDC)) return std::move(Err); SourceLocation ToLocation, ToAtStartLoc, ToCategoryNameLoc; if (auto Imp = importSeq( D->getLocation(), D->getAtStartLoc(), D->getCategoryNameLoc())) std::tie(ToLocation, ToAtStartLoc, ToCategoryNameLoc) = *Imp; else return Imp.takeError(); if (GetImportedOrCreateDecl( ToImpl, D, Importer.getToContext(), DC, Importer.Import(D->getIdentifier()), Category->getClassInterface(), ToLocation, ToAtStartLoc, ToCategoryNameLoc)) return ToImpl; ToImpl->setLexicalDeclContext(LexicalDC); LexicalDC->addDeclInternal(ToImpl); Category->setImplementation(ToImpl); } Importer.MapImported(D, ToImpl); if (Error Err = ImportDeclContext(D)) return std::move(Err); return ToImpl; } ExpectedDecl ASTNodeImporter::VisitObjCImplementationDecl(ObjCImplementationDecl *D) { // Find the corresponding interface. ObjCInterfaceDecl *Iface; if (Error Err = importInto(Iface, D->getClassInterface())) return std::move(Err); // Import the superclass, if any. ObjCInterfaceDecl *Super; if (Error Err = importInto(Super, D->getSuperClass())) return std::move(Err); ObjCImplementationDecl *Impl = Iface->getImplementation(); if (!Impl) { // We haven't imported an implementation yet. Create a new @implementation // now. DeclContext *DC, *LexicalDC; if (Error Err = ImportDeclContext(D, DC, LexicalDC)) return std::move(Err); SourceLocation ToLocation, ToAtStartLoc, ToSuperClassLoc; SourceLocation ToIvarLBraceLoc, ToIvarRBraceLoc; if (auto Imp = importSeq( D->getLocation(), D->getAtStartLoc(), D->getSuperClassLoc(), D->getIvarLBraceLoc(), D->getIvarRBraceLoc())) std::tie( ToLocation, ToAtStartLoc, ToSuperClassLoc, ToIvarLBraceLoc, ToIvarRBraceLoc) = *Imp; else return Imp.takeError(); if (GetImportedOrCreateDecl(Impl, D, Importer.getToContext(), DC, Iface, Super, ToLocation, ToAtStartLoc, ToSuperClassLoc, ToIvarLBraceLoc, ToIvarRBraceLoc)) return Impl; Impl->setLexicalDeclContext(LexicalDC); // Associate the implementation with the class it implements. Iface->setImplementation(Impl); Importer.MapImported(D, Iface->getImplementation()); } else { Importer.MapImported(D, Iface->getImplementation()); // Verify that the existing @implementation has the same superclass. if ((Super && !Impl->getSuperClass()) || (!Super && Impl->getSuperClass()) || (Super && Impl->getSuperClass() && !declaresSameEntity(Super->getCanonicalDecl(), Impl->getSuperClass()))) { Importer.ToDiag(Impl->getLocation(), diag::warn_odr_objc_superclass_inconsistent) << Iface->getDeclName(); // FIXME: It would be nice to have the location of the superclass // below. if (Impl->getSuperClass()) Importer.ToDiag(Impl->getLocation(), diag::note_odr_objc_superclass) << Impl->getSuperClass()->getDeclName(); else Importer.ToDiag(Impl->getLocation(), diag::note_odr_objc_missing_superclass); if (D->getSuperClass()) Importer.FromDiag(D->getLocation(), diag::note_odr_objc_superclass) << D->getSuperClass()->getDeclName(); else Importer.FromDiag(D->getLocation(), diag::note_odr_objc_missing_superclass); return make_error(ImportError::NameConflict); } } // Import all of the members of this @implementation. if (Error Err = ImportDeclContext(D)) return std::move(Err); return Impl; } ExpectedDecl ASTNodeImporter::VisitObjCPropertyDecl(ObjCPropertyDecl *D) { // Import the major distinguishing characteristics of an @property. DeclContext *DC, *LexicalDC; DeclarationName Name; SourceLocation Loc; NamedDecl *ToD; if (Error Err = ImportDeclParts(D, DC, LexicalDC, Name, ToD, Loc)) return std::move(Err); if (ToD) return ToD; // Check whether we have already imported this property. auto FoundDecls = Importer.findDeclsInToCtx(DC, Name); for (auto *FoundDecl : FoundDecls) { if (auto *FoundProp = dyn_cast(FoundDecl)) { // Check property types. if (!Importer.IsStructurallyEquivalent(D->getType(), FoundProp->getType())) { Importer.ToDiag(Loc, diag::warn_odr_objc_property_type_inconsistent) << Name << D->getType() << FoundProp->getType(); Importer.ToDiag(FoundProp->getLocation(), diag::note_odr_value_here) << FoundProp->getType(); return make_error(ImportError::NameConflict); } // FIXME: Check property attributes, getters, setters, etc.? // Consider these properties to be equivalent. Importer.MapImported(D, FoundProp); return FoundProp; } } QualType ToType; TypeSourceInfo *ToTypeSourceInfo; SourceLocation ToAtLoc, ToLParenLoc; if (auto Imp = importSeq( D->getType(), D->getTypeSourceInfo(), D->getAtLoc(), D->getLParenLoc())) std::tie(ToType, ToTypeSourceInfo, ToAtLoc, ToLParenLoc) = *Imp; else return Imp.takeError(); // Create the new property. ObjCPropertyDecl *ToProperty; if (GetImportedOrCreateDecl( ToProperty, D, Importer.getToContext(), DC, Loc, Name.getAsIdentifierInfo(), ToAtLoc, ToLParenLoc, ToType, ToTypeSourceInfo, D->getPropertyImplementation())) return ToProperty; Selector ToGetterName, ToSetterName; SourceLocation ToGetterNameLoc, ToSetterNameLoc; ObjCMethodDecl *ToGetterMethodDecl, *ToSetterMethodDecl; ObjCIvarDecl *ToPropertyIvarDecl; if (auto Imp = importSeq( D->getGetterName(), D->getSetterName(), D->getGetterNameLoc(), D->getSetterNameLoc(), D->getGetterMethodDecl(), D->getSetterMethodDecl(), D->getPropertyIvarDecl())) std::tie( ToGetterName, ToSetterName, ToGetterNameLoc, ToSetterNameLoc, ToGetterMethodDecl, ToSetterMethodDecl, ToPropertyIvarDecl) = *Imp; else return Imp.takeError(); ToProperty->setLexicalDeclContext(LexicalDC); LexicalDC->addDeclInternal(ToProperty); ToProperty->setPropertyAttributes(D->getPropertyAttributes()); ToProperty->setPropertyAttributesAsWritten( D->getPropertyAttributesAsWritten()); ToProperty->setGetterName(ToGetterName, ToGetterNameLoc); ToProperty->setSetterName(ToSetterName, ToSetterNameLoc); ToProperty->setGetterMethodDecl(ToGetterMethodDecl); ToProperty->setSetterMethodDecl(ToSetterMethodDecl); ToProperty->setPropertyIvarDecl(ToPropertyIvarDecl); return ToProperty; } ExpectedDecl ASTNodeImporter::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D) { ObjCPropertyDecl *Property; if (Error Err = importInto(Property, D->getPropertyDecl())) return std::move(Err); DeclContext *DC, *LexicalDC; if (Error Err = ImportDeclContext(D, DC, LexicalDC)) return std::move(Err); auto *InImpl = cast(LexicalDC); // Import the ivar (for an @synthesize). ObjCIvarDecl *Ivar = nullptr; if (Error Err = importInto(Ivar, D->getPropertyIvarDecl())) return std::move(Err); ObjCPropertyImplDecl *ToImpl = InImpl->FindPropertyImplDecl(Property->getIdentifier(), Property->getQueryKind()); if (!ToImpl) { SourceLocation ToBeginLoc, ToLocation, ToPropertyIvarDeclLoc; if (auto Imp = importSeq( D->getBeginLoc(), D->getLocation(), D->getPropertyIvarDeclLoc())) std::tie(ToBeginLoc, ToLocation, ToPropertyIvarDeclLoc) = *Imp; else return Imp.takeError(); if (GetImportedOrCreateDecl(ToImpl, D, Importer.getToContext(), DC, ToBeginLoc, ToLocation, Property, D->getPropertyImplementation(), Ivar, ToPropertyIvarDeclLoc)) return ToImpl; ToImpl->setLexicalDeclContext(LexicalDC); LexicalDC->addDeclInternal(ToImpl); } else { // Check that we have the same kind of property implementation (@synthesize // vs. @dynamic). if (D->getPropertyImplementation() != ToImpl->getPropertyImplementation()) { Importer.ToDiag(ToImpl->getLocation(), diag::warn_odr_objc_property_impl_kind_inconsistent) << Property->getDeclName() << (ToImpl->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic); Importer.FromDiag(D->getLocation(), diag::note_odr_objc_property_impl_kind) << D->getPropertyDecl()->getDeclName() << (D->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic); return make_error(ImportError::NameConflict); } // For @synthesize, check that we have the same if (D->getPropertyImplementation() == ObjCPropertyImplDecl::Synthesize && Ivar != ToImpl->getPropertyIvarDecl()) { Importer.ToDiag(ToImpl->getPropertyIvarDeclLoc(), diag::warn_odr_objc_synthesize_ivar_inconsistent) << Property->getDeclName() << ToImpl->getPropertyIvarDecl()->getDeclName() << Ivar->getDeclName(); Importer.FromDiag(D->getPropertyIvarDeclLoc(), diag::note_odr_objc_synthesize_ivar_here) << D->getPropertyIvarDecl()->getDeclName(); return make_error(ImportError::NameConflict); } // Merge the existing implementation with the new implementation. Importer.MapImported(D, ToImpl); } return ToImpl; } ExpectedDecl ASTNodeImporter::VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D) { // For template arguments, we adopt the translation unit as our declaration // context. This context will be fixed when the actual template declaration // is created. // FIXME: Import default argument and constraint expression. ExpectedSLoc BeginLocOrErr = import(D->getBeginLoc()); if (!BeginLocOrErr) return BeginLocOrErr.takeError(); ExpectedSLoc LocationOrErr = import(D->getLocation()); if (!LocationOrErr) return LocationOrErr.takeError(); TemplateTypeParmDecl *ToD = nullptr; if (GetImportedOrCreateDecl( ToD, D, Importer.getToContext(), Importer.getToContext().getTranslationUnitDecl(), *BeginLocOrErr, *LocationOrErr, D->getDepth(), D->getIndex(), Importer.Import(D->getIdentifier()), D->wasDeclaredWithTypename(), D->isParameterPack(), D->hasTypeConstraint())) return ToD; // Import the type-constraint if (const TypeConstraint *TC = D->getTypeConstraint()) { NestedNameSpecifierLoc ToNNS; DeclarationName ToName; SourceLocation ToNameLoc; NamedDecl *ToFoundDecl; ConceptDecl *ToNamedConcept; Expr *ToIDC; if (auto Imp = importSeq(TC->getNestedNameSpecifierLoc(), TC->getConceptNameInfo().getName(), TC->getConceptNameInfo().getLoc(), TC->getFoundDecl(), TC->getNamedConcept(), TC->getImmediatelyDeclaredConstraint())) std::tie(ToNNS, ToName, ToNameLoc, ToFoundDecl, ToNamedConcept, ToIDC) = *Imp; else return Imp.takeError(); TemplateArgumentListInfo ToTAInfo; const auto *ASTTemplateArgs = TC->getTemplateArgsAsWritten(); if (ASTTemplateArgs) if (Error Err = ImportTemplateArgumentListInfo(*ASTTemplateArgs, ToTAInfo)) return std::move(Err); ToD->setTypeConstraint(ToNNS, DeclarationNameInfo(ToName, ToNameLoc), ToFoundDecl, ToNamedConcept, ASTTemplateArgs ? ASTTemplateArgumentListInfo::Create(Importer.getToContext(), ToTAInfo) : nullptr, ToIDC); } return ToD; } ExpectedDecl ASTNodeImporter::VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) { DeclarationName ToDeclName; SourceLocation ToLocation, ToInnerLocStart; QualType ToType; TypeSourceInfo *ToTypeSourceInfo; if (auto Imp = importSeq( D->getDeclName(), D->getLocation(), D->getType(), D->getTypeSourceInfo(), D->getInnerLocStart())) std::tie( ToDeclName, ToLocation, ToType, ToTypeSourceInfo, ToInnerLocStart) = *Imp; else return Imp.takeError(); // FIXME: Import default argument. NonTypeTemplateParmDecl *ToD = nullptr; (void)GetImportedOrCreateDecl( ToD, D, Importer.getToContext(), Importer.getToContext().getTranslationUnitDecl(), ToInnerLocStart, ToLocation, D->getDepth(), D->getPosition(), ToDeclName.getAsIdentifierInfo(), ToType, D->isParameterPack(), ToTypeSourceInfo); return ToD; } ExpectedDecl ASTNodeImporter::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) { // Import the name of this declaration. auto NameOrErr = import(D->getDeclName()); if (!NameOrErr) return NameOrErr.takeError(); // Import the location of this declaration. ExpectedSLoc LocationOrErr = import(D->getLocation()); if (!LocationOrErr) return LocationOrErr.takeError(); // Import template parameters. auto TemplateParamsOrErr = import(D->getTemplateParameters()); if (!TemplateParamsOrErr) return TemplateParamsOrErr.takeError(); // FIXME: Import default argument. TemplateTemplateParmDecl *ToD = nullptr; (void)GetImportedOrCreateDecl( ToD, D, Importer.getToContext(), Importer.getToContext().getTranslationUnitDecl(), *LocationOrErr, D->getDepth(), D->getPosition(), D->isParameterPack(), (*NameOrErr).getAsIdentifierInfo(), *TemplateParamsOrErr); return ToD; } // Returns the definition for a (forward) declaration of a TemplateDecl, if // it has any definition in the redecl chain. template static auto getTemplateDefinition(T *D) -> T * { assert(D->getTemplatedDecl() && "Should be called on templates only"); auto *ToTemplatedDef = D->getTemplatedDecl()->getDefinition(); if (!ToTemplatedDef) return nullptr; auto *TemplateWithDef = ToTemplatedDef->getDescribedTemplate(); return cast_or_null(TemplateWithDef); } ExpectedDecl ASTNodeImporter::VisitClassTemplateDecl(ClassTemplateDecl *D) { // Import the major distinguishing characteristics of this class template. DeclContext *DC, *LexicalDC; DeclarationName Name; SourceLocation Loc; NamedDecl *ToD; if (Error Err = ImportDeclParts(D, DC, LexicalDC, Name, ToD, Loc)) return std::move(Err); if (ToD) return ToD; ClassTemplateDecl *FoundByLookup = nullptr; // We may already have a template of the same name; try to find and match it. if (!DC->isFunctionOrMethod()) { SmallVector ConflictingDecls; auto FoundDecls = Importer.findDeclsInToCtx(DC, Name); for (auto *FoundDecl : FoundDecls) { if (!FoundDecl->isInIdentifierNamespace(Decl::IDNS_Ordinary | Decl::IDNS_TagFriend)) continue; Decl *Found = FoundDecl; auto *FoundTemplate = dyn_cast(Found); if (FoundTemplate) { if (!hasSameVisibilityContext(FoundTemplate, D)) continue; if (IsStructuralMatch(D, FoundTemplate)) { ClassTemplateDecl *TemplateWithDef = getTemplateDefinition(FoundTemplate); if (D->isThisDeclarationADefinition() && TemplateWithDef) return Importer.MapImported(D, TemplateWithDef); if (!FoundByLookup) FoundByLookup = FoundTemplate; // Search in all matches because there may be multiple decl chains, // see ASTTests test ImportExistingFriendClassTemplateDef. continue; } ConflictingDecls.push_back(FoundDecl); } } if (!ConflictingDecls.empty()) { ExpectedName NameOrErr = Importer.HandleNameConflict( Name, DC, Decl::IDNS_Ordinary, ConflictingDecls.data(), ConflictingDecls.size()); if (NameOrErr) Name = NameOrErr.get(); else return NameOrErr.takeError(); } } CXXRecordDecl *FromTemplated = D->getTemplatedDecl(); // Create the declaration that is being templated. CXXRecordDecl *ToTemplated; if (Error Err = importInto(ToTemplated, FromTemplated)) return std::move(Err); // Create the class template declaration itself. auto TemplateParamsOrErr = import(D->getTemplateParameters()); if (!TemplateParamsOrErr) return TemplateParamsOrErr.takeError(); ClassTemplateDecl *D2; if (GetImportedOrCreateDecl(D2, D, Importer.getToContext(), DC, Loc, Name, *TemplateParamsOrErr, ToTemplated)) return D2; ToTemplated->setDescribedClassTemplate(D2); D2->setAccess(D->getAccess()); D2->setLexicalDeclContext(LexicalDC); addDeclToContexts(D, D2); if (FoundByLookup) { auto *Recent = const_cast(FoundByLookup->getMostRecentDecl()); // It is possible that during the import of the class template definition // we start the import of a fwd friend decl of the very same class template // and we add the fwd friend decl to the lookup table. But the ToTemplated // had been created earlier and by that time the lookup could not find // anything existing, so it has no previous decl. Later, (still during the // import of the fwd friend decl) we start to import the definition again // and this time the lookup finds the previous fwd friend class template. // In this case we must set up the previous decl for the templated decl. if (!ToTemplated->getPreviousDecl()) { assert(FoundByLookup->getTemplatedDecl() && "Found decl must have its templated decl set"); CXXRecordDecl *PrevTemplated = FoundByLookup->getTemplatedDecl()->getMostRecentDecl(); if (ToTemplated != PrevTemplated) ToTemplated->setPreviousDecl(PrevTemplated); } D2->setPreviousDecl(Recent); } if (FromTemplated->isCompleteDefinition() && !ToTemplated->isCompleteDefinition()) { // FIXME: Import definition! } return D2; } ExpectedDecl ASTNodeImporter::VisitClassTemplateSpecializationDecl( ClassTemplateSpecializationDecl *D) { ClassTemplateDecl *ClassTemplate; if (Error Err = importInto(ClassTemplate, D->getSpecializedTemplate())) return std::move(Err); // Import the context of this declaration. DeclContext *DC, *LexicalDC; if (Error Err = ImportDeclContext(D, DC, LexicalDC)) return std::move(Err); // Import template arguments. SmallVector TemplateArgs; if (Error Err = ImportTemplateArguments( D->getTemplateArgs().data(), D->getTemplateArgs().size(), TemplateArgs)) return std::move(Err); // Try to find an existing specialization with these template arguments and // template parameter list. void *InsertPos = nullptr; ClassTemplateSpecializationDecl *PrevDecl = nullptr; ClassTemplatePartialSpecializationDecl *PartialSpec = dyn_cast(D); // Import template parameters. TemplateParameterList *ToTPList = nullptr; if (PartialSpec) { auto ToTPListOrErr = import(PartialSpec->getTemplateParameters()); if (!ToTPListOrErr) return ToTPListOrErr.takeError(); ToTPList = *ToTPListOrErr; PrevDecl = ClassTemplate->findPartialSpecialization(TemplateArgs, *ToTPListOrErr, InsertPos); } else PrevDecl = ClassTemplate->findSpecialization(TemplateArgs, InsertPos); if (PrevDecl) { if (IsStructuralMatch(D, PrevDecl)) { if (D->isThisDeclarationADefinition() && PrevDecl->getDefinition()) { Importer.MapImported(D, PrevDecl->getDefinition()); // Import those default field initializers which have been // instantiated in the "From" context, but not in the "To" context. for (auto *FromField : D->fields()) { auto ToOrErr = import(FromField); if (!ToOrErr) return ToOrErr.takeError(); } // Import those methods which have been instantiated in the // "From" context, but not in the "To" context. for (CXXMethodDecl *FromM : D->methods()) { auto ToOrErr = import(FromM); if (!ToOrErr) return ToOrErr.takeError(); } // TODO Import instantiated default arguments. // TODO Import instantiated exception specifications. // // Generally, ASTCommon.h/DeclUpdateKind enum gives a very good hint // what else could be fused during an AST merge. return PrevDecl; } } else { // ODR violation. // FIXME HandleNameConflict return make_error(ImportError::NameConflict); } } // Import the location of this declaration. ExpectedSLoc BeginLocOrErr = import(D->getBeginLoc()); if (!BeginLocOrErr) return BeginLocOrErr.takeError(); ExpectedSLoc IdLocOrErr = import(D->getLocation()); if (!IdLocOrErr) return IdLocOrErr.takeError(); // Create the specialization. ClassTemplateSpecializationDecl *D2 = nullptr; if (PartialSpec) { // Import TemplateArgumentListInfo. TemplateArgumentListInfo ToTAInfo; const auto &ASTTemplateArgs = *PartialSpec->getTemplateArgsAsWritten(); if (Error Err = ImportTemplateArgumentListInfo(ASTTemplateArgs, ToTAInfo)) return std::move(Err); QualType CanonInjType; if (Error Err = importInto( CanonInjType, PartialSpec->getInjectedSpecializationType())) return std::move(Err); CanonInjType = CanonInjType.getCanonicalType(); if (GetImportedOrCreateDecl( D2, D, Importer.getToContext(), D->getTagKind(), DC, *BeginLocOrErr, *IdLocOrErr, ToTPList, ClassTemplate, llvm::makeArrayRef(TemplateArgs.data(), TemplateArgs.size()), ToTAInfo, CanonInjType, cast_or_null(PrevDecl))) return D2; // Update InsertPos, because preceding import calls may have invalidated // it by adding new specializations. auto *PartSpec2 = cast(D2); if (!ClassTemplate->findPartialSpecialization(TemplateArgs, ToTPList, InsertPos)) // Add this partial specialization to the class template. ClassTemplate->AddPartialSpecialization(PartSpec2, InsertPos); } else { // Not a partial specialization. if (GetImportedOrCreateDecl( D2, D, Importer.getToContext(), D->getTagKind(), DC, *BeginLocOrErr, *IdLocOrErr, ClassTemplate, TemplateArgs, PrevDecl)) return D2; // Update InsertPos, because preceding import calls may have invalidated // it by adding new specializations. if (!ClassTemplate->findSpecialization(TemplateArgs, InsertPos)) // Add this specialization to the class template. ClassTemplate->AddSpecialization(D2, InsertPos); } D2->setSpecializationKind(D->getSpecializationKind()); // Set the context of this specialization/instantiation. D2->setLexicalDeclContext(LexicalDC); // Add to the DC only if it was an explicit specialization/instantiation. if (D2->isExplicitInstantiationOrSpecialization()) { LexicalDC->addDeclInternal(D2); } if (auto BraceRangeOrErr = import(D->getBraceRange())) D2->setBraceRange(*BraceRangeOrErr); else return BraceRangeOrErr.takeError(); // Import the qualifier, if any. if (auto LocOrErr = import(D->getQualifierLoc())) D2->setQualifierInfo(*LocOrErr); else return LocOrErr.takeError(); if (auto *TSI = D->getTypeAsWritten()) { if (auto TInfoOrErr = import(TSI)) D2->setTypeAsWritten(*TInfoOrErr); else return TInfoOrErr.takeError(); if (auto LocOrErr = import(D->getTemplateKeywordLoc())) D2->setTemplateKeywordLoc(*LocOrErr); else return LocOrErr.takeError(); if (auto LocOrErr = import(D->getExternLoc())) D2->setExternLoc(*LocOrErr); else return LocOrErr.takeError(); } if (D->getPointOfInstantiation().isValid()) { if (auto POIOrErr = import(D->getPointOfInstantiation())) D2->setPointOfInstantiation(*POIOrErr); else return POIOrErr.takeError(); } D2->setTemplateSpecializationKind(D->getTemplateSpecializationKind()); if (D->isCompleteDefinition()) if (Error Err = ImportDefinition(D, D2)) return std::move(Err); return D2; } ExpectedDecl ASTNodeImporter::VisitVarTemplateDecl(VarTemplateDecl *D) { // If this variable has a definition in the translation unit we're coming // from, // but this particular declaration is not that definition, import the // definition and map to that. auto *Definition = cast_or_null(D->getTemplatedDecl()->getDefinition()); if (Definition && Definition != D->getTemplatedDecl()) { if (ExpectedDecl ImportedDefOrErr = import( Definition->getDescribedVarTemplate())) return Importer.MapImported(D, *ImportedDefOrErr); else return ImportedDefOrErr.takeError(); } // Import the major distinguishing characteristics of this variable template. DeclContext *DC, *LexicalDC; DeclarationName Name; SourceLocation Loc; NamedDecl *ToD; if (Error Err = ImportDeclParts(D, DC, LexicalDC, Name, ToD, Loc)) return std::move(Err); if (ToD) return ToD; // We may already have a template of the same name; try to find and match it. assert(!DC->isFunctionOrMethod() && "Variable templates cannot be declared at function scope"); SmallVector ConflictingDecls; auto FoundDecls = Importer.findDeclsInToCtx(DC, Name); for (auto *FoundDecl : FoundDecls) { if (!FoundDecl->isInIdentifierNamespace(Decl::IDNS_Ordinary)) continue; Decl *Found = FoundDecl; if (VarTemplateDecl *FoundTemplate = dyn_cast(Found)) { if (IsStructuralMatch(D, FoundTemplate)) { // The variable templates structurally match; call it the same template. Importer.MapImported(D->getTemplatedDecl(), FoundTemplate->getTemplatedDecl()); return Importer.MapImported(D, FoundTemplate); } ConflictingDecls.push_back(FoundDecl); } } if (!ConflictingDecls.empty()) { ExpectedName NameOrErr = Importer.HandleNameConflict( Name, DC, Decl::IDNS_Ordinary, ConflictingDecls.data(), ConflictingDecls.size()); if (NameOrErr) Name = NameOrErr.get(); else return NameOrErr.takeError(); } VarDecl *DTemplated = D->getTemplatedDecl(); // Import the type. // FIXME: Value not used? ExpectedType TypeOrErr = import(DTemplated->getType()); if (!TypeOrErr) return TypeOrErr.takeError(); // Create the declaration that is being templated. VarDecl *ToTemplated; if (Error Err = importInto(ToTemplated, DTemplated)) return std::move(Err); // Create the variable template declaration itself. auto TemplateParamsOrErr = import(D->getTemplateParameters()); if (!TemplateParamsOrErr) return TemplateParamsOrErr.takeError(); VarTemplateDecl *ToVarTD; if (GetImportedOrCreateDecl(ToVarTD, D, Importer.getToContext(), DC, Loc, Name, *TemplateParamsOrErr, ToTemplated)) return ToVarTD; ToTemplated->setDescribedVarTemplate(ToVarTD); ToVarTD->setAccess(D->getAccess()); ToVarTD->setLexicalDeclContext(LexicalDC); LexicalDC->addDeclInternal(ToVarTD); if (DTemplated->isThisDeclarationADefinition() && !ToTemplated->isThisDeclarationADefinition()) { // FIXME: Import definition! } return ToVarTD; } ExpectedDecl ASTNodeImporter::VisitVarTemplateSpecializationDecl( VarTemplateSpecializationDecl *D) { // If this record has a definition in the translation unit we're coming from, // but this particular declaration is not that definition, import the // definition and map to that. VarDecl *Definition = D->getDefinition(); if (Definition && Definition != D) { if (ExpectedDecl ImportedDefOrErr = import(Definition)) return Importer.MapImported(D, *ImportedDefOrErr); else return ImportedDefOrErr.takeError(); } VarTemplateDecl *VarTemplate = nullptr; if (Error Err = importInto(VarTemplate, D->getSpecializedTemplate())) return std::move(Err); // Import the context of this declaration. DeclContext *DC, *LexicalDC; if (Error Err = ImportDeclContext(D, DC, LexicalDC)) return std::move(Err); // Import the location of this declaration. ExpectedSLoc BeginLocOrErr = import(D->getBeginLoc()); if (!BeginLocOrErr) return BeginLocOrErr.takeError(); auto IdLocOrErr = import(D->getLocation()); if (!IdLocOrErr) return IdLocOrErr.takeError(); // Import template arguments. SmallVector TemplateArgs; if (Error Err = ImportTemplateArguments( D->getTemplateArgs().data(), D->getTemplateArgs().size(), TemplateArgs)) return std::move(Err); // Try to find an existing specialization with these template arguments. void *InsertPos = nullptr; VarTemplateSpecializationDecl *D2 = VarTemplate->findSpecialization( TemplateArgs, InsertPos); if (D2) { // We already have a variable template specialization with these template // arguments. // FIXME: Check for specialization vs. instantiation errors. if (VarDecl *FoundDef = D2->getDefinition()) { if (!D->isThisDeclarationADefinition() || IsStructuralMatch(D, FoundDef)) { // The record types structurally match, or the "from" translation // unit only had a forward declaration anyway; call it the same // variable. return Importer.MapImported(D, FoundDef); } } } else { // Import the type. QualType T; if (Error Err = importInto(T, D->getType())) return std::move(Err); auto TInfoOrErr = import(D->getTypeSourceInfo()); if (!TInfoOrErr) return TInfoOrErr.takeError(); TemplateArgumentListInfo ToTAInfo; if (Error Err = ImportTemplateArgumentListInfo( D->getTemplateArgsInfo(), ToTAInfo)) return std::move(Err); using PartVarSpecDecl = VarTemplatePartialSpecializationDecl; // Create a new specialization. if (auto *FromPartial = dyn_cast(D)) { // Import TemplateArgumentListInfo TemplateArgumentListInfo ArgInfos; const auto *FromTAArgsAsWritten = FromPartial->getTemplateArgsAsWritten(); // NOTE: FromTAArgsAsWritten and template parameter list are non-null. if (Error Err = ImportTemplateArgumentListInfo( *FromTAArgsAsWritten, ArgInfos)) return std::move(Err); auto ToTPListOrErr = import(FromPartial->getTemplateParameters()); if (!ToTPListOrErr) return ToTPListOrErr.takeError(); PartVarSpecDecl *ToPartial; if (GetImportedOrCreateDecl(ToPartial, D, Importer.getToContext(), DC, *BeginLocOrErr, *IdLocOrErr, *ToTPListOrErr, VarTemplate, T, *TInfoOrErr, D->getStorageClass(), TemplateArgs, ArgInfos)) return ToPartial; if (Expected ToInstOrErr = import( FromPartial->getInstantiatedFromMember())) ToPartial->setInstantiatedFromMember(*ToInstOrErr); else return ToInstOrErr.takeError(); if (FromPartial->isMemberSpecialization()) ToPartial->setMemberSpecialization(); D2 = ToPartial; } else { // Full specialization if (GetImportedOrCreateDecl(D2, D, Importer.getToContext(), DC, *BeginLocOrErr, *IdLocOrErr, VarTemplate, T, *TInfoOrErr, D->getStorageClass(), TemplateArgs)) return D2; } if (D->getPointOfInstantiation().isValid()) { if (ExpectedSLoc POIOrErr = import(D->getPointOfInstantiation())) D2->setPointOfInstantiation(*POIOrErr); else return POIOrErr.takeError(); } D2->setSpecializationKind(D->getSpecializationKind()); D2->setTemplateArgsInfo(ToTAInfo); // Add this specialization to the class template. VarTemplate->AddSpecialization(D2, InsertPos); // Import the qualifier, if any. if (auto LocOrErr = import(D->getQualifierLoc())) D2->setQualifierInfo(*LocOrErr); else return LocOrErr.takeError(); if (D->isConstexpr()) D2->setConstexpr(true); // Add the specialization to this context. D2->setLexicalDeclContext(LexicalDC); LexicalDC->addDeclInternal(D2); D2->setAccess(D->getAccess()); } if (Error Err = ImportInitializer(D, D2)) return std::move(Err); return D2; } ExpectedDecl ASTNodeImporter::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) { DeclContext *DC, *LexicalDC; DeclarationName Name; SourceLocation Loc; NamedDecl *ToD; if (Error Err = ImportDeclParts(D, DC, LexicalDC, Name, ToD, Loc)) return std::move(Err); if (ToD) return ToD; const FunctionTemplateDecl *FoundByLookup = nullptr; // Try to find a function in our own ("to") context with the same name, same // type, and in the same context as the function we're importing. // FIXME Split this into a separate function. if (!LexicalDC->isFunctionOrMethod()) { unsigned IDNS = Decl::IDNS_Ordinary | Decl::IDNS_OrdinaryFriend; auto FoundDecls = Importer.findDeclsInToCtx(DC, Name); for (auto *FoundDecl : FoundDecls) { if (!FoundDecl->isInIdentifierNamespace(IDNS)) continue; if (auto *FoundTemplate = dyn_cast(FoundDecl)) { if (!hasSameVisibilityContext(FoundTemplate, D)) continue; if (IsStructuralMatch(D, FoundTemplate)) { FunctionTemplateDecl *TemplateWithDef = getTemplateDefinition(FoundTemplate); if (D->isThisDeclarationADefinition() && TemplateWithDef) return Importer.MapImported(D, TemplateWithDef); FoundByLookup = FoundTemplate; break; // TODO: handle conflicting names } } } } auto ParamsOrErr = import(D->getTemplateParameters()); if (!ParamsOrErr) return ParamsOrErr.takeError(); FunctionDecl *TemplatedFD; if (Error Err = importInto(TemplatedFD, D->getTemplatedDecl())) return std::move(Err); FunctionTemplateDecl *ToFunc; if (GetImportedOrCreateDecl(ToFunc, D, Importer.getToContext(), DC, Loc, Name, *ParamsOrErr, TemplatedFD)) return ToFunc; TemplatedFD->setDescribedFunctionTemplate(ToFunc); ToFunc->setAccess(D->getAccess()); ToFunc->setLexicalDeclContext(LexicalDC); LexicalDC->addDeclInternal(ToFunc); if (FoundByLookup) { auto *Recent = const_cast(FoundByLookup->getMostRecentDecl()); if (!TemplatedFD->getPreviousDecl()) { assert(FoundByLookup->getTemplatedDecl() && "Found decl must have its templated decl set"); auto *PrevTemplated = FoundByLookup->getTemplatedDecl()->getMostRecentDecl(); if (TemplatedFD != PrevTemplated) TemplatedFD->setPreviousDecl(PrevTemplated); } ToFunc->setPreviousDecl(Recent); } return ToFunc; } //---------------------------------------------------------------------------- // Import Statements //---------------------------------------------------------------------------- ExpectedStmt ASTNodeImporter::VisitStmt(Stmt *S) { Importer.FromDiag(S->getBeginLoc(), diag::err_unsupported_ast_node) << S->getStmtClassName(); return make_error(ImportError::UnsupportedConstruct); } ExpectedStmt ASTNodeImporter::VisitGCCAsmStmt(GCCAsmStmt *S) { if (Importer.returnWithErrorInTest()) return make_error(ImportError::UnsupportedConstruct); SmallVector Names; for (unsigned I = 0, E = S->getNumOutputs(); I != E; I++) { IdentifierInfo *ToII = Importer.Import(S->getOutputIdentifier(I)); // ToII is nullptr when no symbolic name is given for output operand // see ParseStmtAsm::ParseAsmOperandsOpt Names.push_back(ToII); } for (unsigned I = 0, E = S->getNumInputs(); I != E; I++) { IdentifierInfo *ToII = Importer.Import(S->getInputIdentifier(I)); // ToII is nullptr when no symbolic name is given for input operand // see ParseStmtAsm::ParseAsmOperandsOpt Names.push_back(ToII); } SmallVector Clobbers; for (unsigned I = 0, E = S->getNumClobbers(); I != E; I++) { if (auto ClobberOrErr = import(S->getClobberStringLiteral(I))) Clobbers.push_back(*ClobberOrErr); else return ClobberOrErr.takeError(); } SmallVector Constraints; for (unsigned I = 0, E = S->getNumOutputs(); I != E; I++) { if (auto OutputOrErr = import(S->getOutputConstraintLiteral(I))) Constraints.push_back(*OutputOrErr); else return OutputOrErr.takeError(); } for (unsigned I = 0, E = S->getNumInputs(); I != E; I++) { if (auto InputOrErr = import(S->getInputConstraintLiteral(I))) Constraints.push_back(*InputOrErr); else return InputOrErr.takeError(); } SmallVector Exprs(S->getNumOutputs() + S->getNumInputs() + S->getNumLabels()); if (Error Err = ImportContainerChecked(S->outputs(), Exprs)) return std::move(Err); if (Error Err = ImportArrayChecked(S->inputs(), Exprs.begin() + S->getNumOutputs())) return std::move(Err); if (Error Err = ImportArrayChecked( S->labels(), Exprs.begin() + S->getNumOutputs() + S->getNumInputs())) return std::move(Err); ExpectedSLoc AsmLocOrErr = import(S->getAsmLoc()); if (!AsmLocOrErr) return AsmLocOrErr.takeError(); auto AsmStrOrErr = import(S->getAsmString()); if (!AsmStrOrErr) return AsmStrOrErr.takeError(); ExpectedSLoc RParenLocOrErr = import(S->getRParenLoc()); if (!RParenLocOrErr) return RParenLocOrErr.takeError(); return new (Importer.getToContext()) GCCAsmStmt( Importer.getToContext(), *AsmLocOrErr, S->isSimple(), S->isVolatile(), S->getNumOutputs(), S->getNumInputs(), Names.data(), Constraints.data(), Exprs.data(), *AsmStrOrErr, S->getNumClobbers(), Clobbers.data(), S->getNumLabels(), *RParenLocOrErr); } ExpectedStmt ASTNodeImporter::VisitDeclStmt(DeclStmt *S) { auto Imp = importSeq(S->getDeclGroup(), S->getBeginLoc(), S->getEndLoc()); if (!Imp) return Imp.takeError(); DeclGroupRef ToDG; SourceLocation ToBeginLoc, ToEndLoc; std::tie(ToDG, ToBeginLoc, ToEndLoc) = *Imp; return new (Importer.getToContext()) DeclStmt(ToDG, ToBeginLoc, ToEndLoc); } ExpectedStmt ASTNodeImporter::VisitNullStmt(NullStmt *S) { ExpectedSLoc ToSemiLocOrErr = import(S->getSemiLoc()); if (!ToSemiLocOrErr) return ToSemiLocOrErr.takeError(); return new (Importer.getToContext()) NullStmt( *ToSemiLocOrErr, S->hasLeadingEmptyMacro()); } ExpectedStmt ASTNodeImporter::VisitCompoundStmt(CompoundStmt *S) { SmallVector ToStmts(S->size()); if (Error Err = ImportContainerChecked(S->body(), ToStmts)) return std::move(Err); ExpectedSLoc ToLBracLocOrErr = import(S->getLBracLoc()); if (!ToLBracLocOrErr) return ToLBracLocOrErr.takeError(); ExpectedSLoc ToRBracLocOrErr = import(S->getRBracLoc()); if (!ToRBracLocOrErr) return ToRBracLocOrErr.takeError(); return CompoundStmt::Create( Importer.getToContext(), ToStmts, *ToLBracLocOrErr, *ToRBracLocOrErr); } ExpectedStmt ASTNodeImporter::VisitCaseStmt(CaseStmt *S) { auto Imp = importSeq( S->getLHS(), S->getRHS(), S->getSubStmt(), S->getCaseLoc(), S->getEllipsisLoc(), S->getColonLoc()); if (!Imp) return Imp.takeError(); Expr *ToLHS, *ToRHS; Stmt *ToSubStmt; SourceLocation ToCaseLoc, ToEllipsisLoc, ToColonLoc; std::tie(ToLHS, ToRHS, ToSubStmt, ToCaseLoc, ToEllipsisLoc, ToColonLoc) = *Imp; auto *ToStmt = CaseStmt::Create(Importer.getToContext(), ToLHS, ToRHS, ToCaseLoc, ToEllipsisLoc, ToColonLoc); ToStmt->setSubStmt(ToSubStmt); return ToStmt; } ExpectedStmt ASTNodeImporter::VisitDefaultStmt(DefaultStmt *S) { auto Imp = importSeq(S->getDefaultLoc(), S->getColonLoc(), S->getSubStmt()); if (!Imp) return Imp.takeError(); SourceLocation ToDefaultLoc, ToColonLoc; Stmt *ToSubStmt; std::tie(ToDefaultLoc, ToColonLoc, ToSubStmt) = *Imp; return new (Importer.getToContext()) DefaultStmt( ToDefaultLoc, ToColonLoc, ToSubStmt); } ExpectedStmt ASTNodeImporter::VisitLabelStmt(LabelStmt *S) { auto Imp = importSeq(S->getIdentLoc(), S->getDecl(), S->getSubStmt()); if (!Imp) return Imp.takeError(); SourceLocation ToIdentLoc; LabelDecl *ToLabelDecl; Stmt *ToSubStmt; std::tie(ToIdentLoc, ToLabelDecl, ToSubStmt) = *Imp; return new (Importer.getToContext()) LabelStmt( ToIdentLoc, ToLabelDecl, ToSubStmt); } ExpectedStmt ASTNodeImporter::VisitAttributedStmt(AttributedStmt *S) { ExpectedSLoc ToAttrLocOrErr = import(S->getAttrLoc()); if (!ToAttrLocOrErr) return ToAttrLocOrErr.takeError(); ArrayRef FromAttrs(S->getAttrs()); SmallVector ToAttrs(FromAttrs.size()); if (Error Err = ImportContainerChecked(FromAttrs, ToAttrs)) return std::move(Err); ExpectedStmt ToSubStmtOrErr = import(S->getSubStmt()); if (!ToSubStmtOrErr) return ToSubStmtOrErr.takeError(); return AttributedStmt::Create( Importer.getToContext(), *ToAttrLocOrErr, ToAttrs, *ToSubStmtOrErr); } ExpectedStmt ASTNodeImporter::VisitIfStmt(IfStmt *S) { auto Imp = importSeq( S->getIfLoc(), S->getInit(), S->getConditionVariable(), S->getCond(), S->getThen(), S->getElseLoc(), S->getElse()); if (!Imp) return Imp.takeError(); SourceLocation ToIfLoc, ToElseLoc; Stmt *ToInit, *ToThen, *ToElse; VarDecl *ToConditionVariable; Expr *ToCond; std::tie( ToIfLoc, ToInit, ToConditionVariable, ToCond, ToThen, ToElseLoc, ToElse) = *Imp; return IfStmt::Create(Importer.getToContext(), ToIfLoc, S->isConstexpr(), ToInit, ToConditionVariable, ToCond, ToThen, ToElseLoc, ToElse); } ExpectedStmt ASTNodeImporter::VisitSwitchStmt(SwitchStmt *S) { auto Imp = importSeq( S->getInit(), S->getConditionVariable(), S->getCond(), S->getBody(), S->getSwitchLoc()); if (!Imp) return Imp.takeError(); Stmt *ToInit, *ToBody; VarDecl *ToConditionVariable; Expr *ToCond; SourceLocation ToSwitchLoc; std::tie(ToInit, ToConditionVariable, ToCond, ToBody, ToSwitchLoc) = *Imp; auto *ToStmt = SwitchStmt::Create(Importer.getToContext(), ToInit, ToConditionVariable, ToCond); ToStmt->setBody(ToBody); ToStmt->setSwitchLoc(ToSwitchLoc); // Now we have to re-chain the cases. SwitchCase *LastChainedSwitchCase = nullptr; for (SwitchCase *SC = S->getSwitchCaseList(); SC != nullptr; SC = SC->getNextSwitchCase()) { Expected ToSCOrErr = import(SC); if (!ToSCOrErr) return ToSCOrErr.takeError(); if (LastChainedSwitchCase) LastChainedSwitchCase->setNextSwitchCase(*ToSCOrErr); else ToStmt->setSwitchCaseList(*ToSCOrErr); LastChainedSwitchCase = *ToSCOrErr; } return ToStmt; } ExpectedStmt ASTNodeImporter::VisitWhileStmt(WhileStmt *S) { auto Imp = importSeq( S->getConditionVariable(), S->getCond(), S->getBody(), S->getWhileLoc()); if (!Imp) return Imp.takeError(); VarDecl *ToConditionVariable; Expr *ToCond; Stmt *ToBody; SourceLocation ToWhileLoc; std::tie(ToConditionVariable, ToCond, ToBody, ToWhileLoc) = *Imp; return WhileStmt::Create(Importer.getToContext(), ToConditionVariable, ToCond, ToBody, ToWhileLoc); } ExpectedStmt ASTNodeImporter::VisitDoStmt(DoStmt *S) { auto Imp = importSeq( S->getBody(), S->getCond(), S->getDoLoc(), S->getWhileLoc(), S->getRParenLoc()); if (!Imp) return Imp.takeError(); Stmt *ToBody; Expr *ToCond; SourceLocation ToDoLoc, ToWhileLoc, ToRParenLoc; std::tie(ToBody, ToCond, ToDoLoc, ToWhileLoc, ToRParenLoc) = *Imp; return new (Importer.getToContext()) DoStmt( ToBody, ToCond, ToDoLoc, ToWhileLoc, ToRParenLoc); } ExpectedStmt ASTNodeImporter::VisitForStmt(ForStmt *S) { auto Imp = importSeq( S->getInit(), S->getCond(), S->getConditionVariable(), S->getInc(), S->getBody(), S->getForLoc(), S->getLParenLoc(), S->getRParenLoc()); if (!Imp) return Imp.takeError(); Stmt *ToInit; Expr *ToCond, *ToInc; VarDecl *ToConditionVariable; Stmt *ToBody; SourceLocation ToForLoc, ToLParenLoc, ToRParenLoc; std::tie( ToInit, ToCond, ToConditionVariable, ToInc, ToBody, ToForLoc, ToLParenLoc, ToRParenLoc) = *Imp; return new (Importer.getToContext()) ForStmt( Importer.getToContext(), ToInit, ToCond, ToConditionVariable, ToInc, ToBody, ToForLoc, ToLParenLoc, ToRParenLoc); } ExpectedStmt ASTNodeImporter::VisitGotoStmt(GotoStmt *S) { auto Imp = importSeq(S->getLabel(), S->getGotoLoc(), S->getLabelLoc()); if (!Imp) return Imp.takeError(); LabelDecl *ToLabel; SourceLocation ToGotoLoc, ToLabelLoc; std::tie(ToLabel, ToGotoLoc, ToLabelLoc) = *Imp; return new (Importer.getToContext()) GotoStmt( ToLabel, ToGotoLoc, ToLabelLoc); } ExpectedStmt ASTNodeImporter::VisitIndirectGotoStmt(IndirectGotoStmt *S) { auto Imp = importSeq(S->getGotoLoc(), S->getStarLoc(), S->getTarget()); if (!Imp) return Imp.takeError(); SourceLocation ToGotoLoc, ToStarLoc; Expr *ToTarget; std::tie(ToGotoLoc, ToStarLoc, ToTarget) = *Imp; return new (Importer.getToContext()) IndirectGotoStmt( ToGotoLoc, ToStarLoc, ToTarget); } ExpectedStmt ASTNodeImporter::VisitContinueStmt(ContinueStmt *S) { ExpectedSLoc ToContinueLocOrErr = import(S->getContinueLoc()); if (!ToContinueLocOrErr) return ToContinueLocOrErr.takeError(); return new (Importer.getToContext()) ContinueStmt(*ToContinueLocOrErr); } ExpectedStmt ASTNodeImporter::VisitBreakStmt(BreakStmt *S) { auto ToBreakLocOrErr = import(S->getBreakLoc()); if (!ToBreakLocOrErr) return ToBreakLocOrErr.takeError(); return new (Importer.getToContext()) BreakStmt(*ToBreakLocOrErr); } ExpectedStmt ASTNodeImporter::VisitReturnStmt(ReturnStmt *S) { auto Imp = importSeq( S->getReturnLoc(), S->getRetValue(), S->getNRVOCandidate()); if (!Imp) return Imp.takeError(); SourceLocation ToReturnLoc; Expr *ToRetValue; const VarDecl *ToNRVOCandidate; std::tie(ToReturnLoc, ToRetValue, ToNRVOCandidate) = *Imp; return ReturnStmt::Create(Importer.getToContext(), ToReturnLoc, ToRetValue, ToNRVOCandidate); } ExpectedStmt ASTNodeImporter::VisitCXXCatchStmt(CXXCatchStmt *S) { auto Imp = importSeq( S->getCatchLoc(), S->getExceptionDecl(), S->getHandlerBlock()); if (!Imp) return Imp.takeError(); SourceLocation ToCatchLoc; VarDecl *ToExceptionDecl; Stmt *ToHandlerBlock; std::tie(ToCatchLoc, ToExceptionDecl, ToHandlerBlock) = *Imp; return new (Importer.getToContext()) CXXCatchStmt ( ToCatchLoc, ToExceptionDecl, ToHandlerBlock); } ExpectedStmt ASTNodeImporter::VisitCXXTryStmt(CXXTryStmt *S) { ExpectedSLoc ToTryLocOrErr = import(S->getTryLoc()); if (!ToTryLocOrErr) return ToTryLocOrErr.takeError(); ExpectedStmt ToTryBlockOrErr = import(S->getTryBlock()); if (!ToTryBlockOrErr) return ToTryBlockOrErr.takeError(); SmallVector ToHandlers(S->getNumHandlers()); for (unsigned HI = 0, HE = S->getNumHandlers(); HI != HE; ++HI) { CXXCatchStmt *FromHandler = S->getHandler(HI); if (auto ToHandlerOrErr = import(FromHandler)) ToHandlers[HI] = *ToHandlerOrErr; else return ToHandlerOrErr.takeError(); } return CXXTryStmt::Create( Importer.getToContext(), *ToTryLocOrErr,*ToTryBlockOrErr, ToHandlers); } ExpectedStmt ASTNodeImporter::VisitCXXForRangeStmt(CXXForRangeStmt *S) { auto Imp1 = importSeq( S->getInit(), S->getRangeStmt(), S->getBeginStmt(), S->getEndStmt(), S->getCond(), S->getInc(), S->getLoopVarStmt(), S->getBody()); if (!Imp1) return Imp1.takeError(); auto Imp2 = importSeq( S->getForLoc(), S->getCoawaitLoc(), S->getColonLoc(), S->getRParenLoc()); if (!Imp2) return Imp2.takeError(); DeclStmt *ToRangeStmt, *ToBeginStmt, *ToEndStmt, *ToLoopVarStmt; Expr *ToCond, *ToInc; Stmt *ToInit, *ToBody; std::tie( ToInit, ToRangeStmt, ToBeginStmt, ToEndStmt, ToCond, ToInc, ToLoopVarStmt, ToBody) = *Imp1; SourceLocation ToForLoc, ToCoawaitLoc, ToColonLoc, ToRParenLoc; std::tie(ToForLoc, ToCoawaitLoc, ToColonLoc, ToRParenLoc) = *Imp2; return new (Importer.getToContext()) CXXForRangeStmt( ToInit, ToRangeStmt, ToBeginStmt, ToEndStmt, ToCond, ToInc, ToLoopVarStmt, ToBody, ToForLoc, ToCoawaitLoc, ToColonLoc, ToRParenLoc); } ExpectedStmt ASTNodeImporter::VisitObjCForCollectionStmt(ObjCForCollectionStmt *S) { auto Imp = importSeq( S->getElement(), S->getCollection(), S->getBody(), S->getForLoc(), S->getRParenLoc()); if (!Imp) return Imp.takeError(); Stmt *ToElement, *ToBody; Expr *ToCollection; SourceLocation ToForLoc, ToRParenLoc; std::tie(ToElement, ToCollection, ToBody, ToForLoc, ToRParenLoc) = *Imp; return new (Importer.getToContext()) ObjCForCollectionStmt(ToElement, ToCollection, ToBody, ToForLoc, ToRParenLoc); } ExpectedStmt ASTNodeImporter::VisitObjCAtCatchStmt(ObjCAtCatchStmt *S) { auto Imp = importSeq( S->getAtCatchLoc(), S->getRParenLoc(), S->getCatchParamDecl(), S->getCatchBody()); if (!Imp) return Imp.takeError(); SourceLocation ToAtCatchLoc, ToRParenLoc; VarDecl *ToCatchParamDecl; Stmt *ToCatchBody; std::tie(ToAtCatchLoc, ToRParenLoc, ToCatchParamDecl, ToCatchBody) = *Imp; return new (Importer.getToContext()) ObjCAtCatchStmt ( ToAtCatchLoc, ToRParenLoc, ToCatchParamDecl, ToCatchBody); } ExpectedStmt ASTNodeImporter::VisitObjCAtFinallyStmt(ObjCAtFinallyStmt *S) { ExpectedSLoc ToAtFinallyLocOrErr = import(S->getAtFinallyLoc()); if (!ToAtFinallyLocOrErr) return ToAtFinallyLocOrErr.takeError(); ExpectedStmt ToAtFinallyStmtOrErr = import(S->getFinallyBody()); if (!ToAtFinallyStmtOrErr) return ToAtFinallyStmtOrErr.takeError(); return new (Importer.getToContext()) ObjCAtFinallyStmt(*ToAtFinallyLocOrErr, *ToAtFinallyStmtOrErr); } ExpectedStmt ASTNodeImporter::VisitObjCAtTryStmt(ObjCAtTryStmt *S) { auto Imp = importSeq( S->getAtTryLoc(), S->getTryBody(), S->getFinallyStmt()); if (!Imp) return Imp.takeError(); SourceLocation ToAtTryLoc; Stmt *ToTryBody, *ToFinallyStmt; std::tie(ToAtTryLoc, ToTryBody, ToFinallyStmt) = *Imp; SmallVector ToCatchStmts(S->getNumCatchStmts()); for (unsigned CI = 0, CE = S->getNumCatchStmts(); CI != CE; ++CI) { ObjCAtCatchStmt *FromCatchStmt = S->getCatchStmt(CI); if (ExpectedStmt ToCatchStmtOrErr = import(FromCatchStmt)) ToCatchStmts[CI] = *ToCatchStmtOrErr; else return ToCatchStmtOrErr.takeError(); } return ObjCAtTryStmt::Create(Importer.getToContext(), ToAtTryLoc, ToTryBody, ToCatchStmts.begin(), ToCatchStmts.size(), ToFinallyStmt); } ExpectedStmt ASTNodeImporter::VisitObjCAtSynchronizedStmt (ObjCAtSynchronizedStmt *S) { auto Imp = importSeq( S->getAtSynchronizedLoc(), S->getSynchExpr(), S->getSynchBody()); if (!Imp) return Imp.takeError(); SourceLocation ToAtSynchronizedLoc; Expr *ToSynchExpr; Stmt *ToSynchBody; std::tie(ToAtSynchronizedLoc, ToSynchExpr, ToSynchBody) = *Imp; return new (Importer.getToContext()) ObjCAtSynchronizedStmt( ToAtSynchronizedLoc, ToSynchExpr, ToSynchBody); } ExpectedStmt ASTNodeImporter::VisitObjCAtThrowStmt(ObjCAtThrowStmt *S) { ExpectedSLoc ToThrowLocOrErr = import(S->getThrowLoc()); if (!ToThrowLocOrErr) return ToThrowLocOrErr.takeError(); ExpectedExpr ToThrowExprOrErr = import(S->getThrowExpr()); if (!ToThrowExprOrErr) return ToThrowExprOrErr.takeError(); return new (Importer.getToContext()) ObjCAtThrowStmt( *ToThrowLocOrErr, *ToThrowExprOrErr); } ExpectedStmt ASTNodeImporter::VisitObjCAutoreleasePoolStmt( ObjCAutoreleasePoolStmt *S) { ExpectedSLoc ToAtLocOrErr = import(S->getAtLoc()); if (!ToAtLocOrErr) return ToAtLocOrErr.takeError(); ExpectedStmt ToSubStmtOrErr = import(S->getSubStmt()); if (!ToSubStmtOrErr) return ToSubStmtOrErr.takeError(); return new (Importer.getToContext()) ObjCAutoreleasePoolStmt(*ToAtLocOrErr, *ToSubStmtOrErr); } //---------------------------------------------------------------------------- // Import Expressions //---------------------------------------------------------------------------- ExpectedStmt ASTNodeImporter::VisitExpr(Expr *E) { Importer.FromDiag(E->getBeginLoc(), diag::err_unsupported_ast_node) << E->getStmtClassName(); return make_error(ImportError::UnsupportedConstruct); } ExpectedStmt ASTNodeImporter::VisitVAArgExpr(VAArgExpr *E) { auto Imp = importSeq( E->getBuiltinLoc(), E->getSubExpr(), E->getWrittenTypeInfo(), E->getRParenLoc(), E->getType()); if (!Imp) return Imp.takeError(); SourceLocation ToBuiltinLoc, ToRParenLoc; Expr *ToSubExpr; TypeSourceInfo *ToWrittenTypeInfo; QualType ToType; std::tie(ToBuiltinLoc, ToSubExpr, ToWrittenTypeInfo, ToRParenLoc, ToType) = *Imp; return new (Importer.getToContext()) VAArgExpr( ToBuiltinLoc, ToSubExpr, ToWrittenTypeInfo, ToRParenLoc, ToType, E->isMicrosoftABI()); } ExpectedStmt ASTNodeImporter::VisitChooseExpr(ChooseExpr *E) { auto Imp = importSeq(E->getCond(), E->getLHS(), E->getRHS(), E->getBuiltinLoc(), E->getRParenLoc(), E->getType()); if (!Imp) return Imp.takeError(); Expr *ToCond; Expr *ToLHS; Expr *ToRHS; SourceLocation ToBuiltinLoc, ToRParenLoc; QualType ToType; std::tie(ToCond, ToLHS, ToRHS, ToBuiltinLoc, ToRParenLoc, ToType) = *Imp; ExprValueKind VK = E->getValueKind(); ExprObjectKind OK = E->getObjectKind(); bool TypeDependent = ToCond->isTypeDependent(); bool ValueDependent = ToCond->isValueDependent(); // The value of CondIsTrue only matters if the value is not // condition-dependent. bool CondIsTrue = !E->isConditionDependent() && E->isConditionTrue(); return new (Importer.getToContext()) ChooseExpr(ToBuiltinLoc, ToCond, ToLHS, ToRHS, ToType, VK, OK, ToRParenLoc, CondIsTrue, TypeDependent, ValueDependent); } ExpectedStmt ASTNodeImporter::VisitGNUNullExpr(GNUNullExpr *E) { ExpectedType TypeOrErr = import(E->getType()); if (!TypeOrErr) return TypeOrErr.takeError(); ExpectedSLoc BeginLocOrErr = import(E->getBeginLoc()); if (!BeginLocOrErr) return BeginLocOrErr.takeError(); return new (Importer.getToContext()) GNUNullExpr(*TypeOrErr, *BeginLocOrErr); } ExpectedStmt ASTNodeImporter::VisitPredefinedExpr(PredefinedExpr *E) { auto Imp = importSeq( E->getBeginLoc(), E->getType(), E->getFunctionName()); if (!Imp) return Imp.takeError(); SourceLocation ToBeginLoc; QualType ToType; StringLiteral *ToFunctionName; std::tie(ToBeginLoc, ToType, ToFunctionName) = *Imp; return PredefinedExpr::Create(Importer.getToContext(), ToBeginLoc, ToType, E->getIdentKind(), ToFunctionName); } ExpectedStmt ASTNodeImporter::VisitDeclRefExpr(DeclRefExpr *E) { auto Imp = importSeq( E->getQualifierLoc(), E->getTemplateKeywordLoc(), E->getDecl(), E->getLocation(), E->getType()); if (!Imp) return Imp.takeError(); NestedNameSpecifierLoc ToQualifierLoc; SourceLocation ToTemplateKeywordLoc, ToLocation; ValueDecl *ToDecl; QualType ToType; std::tie(ToQualifierLoc, ToTemplateKeywordLoc, ToDecl, ToLocation, ToType) = *Imp; NamedDecl *ToFoundD = nullptr; if (E->getDecl() != E->getFoundDecl()) { auto FoundDOrErr = import(E->getFoundDecl()); if (!FoundDOrErr) return FoundDOrErr.takeError(); ToFoundD = *FoundDOrErr; } TemplateArgumentListInfo ToTAInfo; TemplateArgumentListInfo *ToResInfo = nullptr; if (E->hasExplicitTemplateArgs()) { if (Error Err = ImportTemplateArgumentListInfo(E->getLAngleLoc(), E->getRAngleLoc(), E->template_arguments(), ToTAInfo)) return std::move(Err); ToResInfo = &ToTAInfo; } auto *ToE = DeclRefExpr::Create( Importer.getToContext(), ToQualifierLoc, ToTemplateKeywordLoc, ToDecl, E->refersToEnclosingVariableOrCapture(), ToLocation, ToType, E->getValueKind(), ToFoundD, ToResInfo, E->isNonOdrUse()); if (E->hadMultipleCandidates()) ToE->setHadMultipleCandidates(true); return ToE; } ExpectedStmt ASTNodeImporter::VisitImplicitValueInitExpr(ImplicitValueInitExpr *E) { ExpectedType TypeOrErr = import(E->getType()); if (!TypeOrErr) return TypeOrErr.takeError(); return new (Importer.getToContext()) ImplicitValueInitExpr(*TypeOrErr); } ExpectedStmt ASTNodeImporter::VisitDesignatedInitExpr(DesignatedInitExpr *E) { ExpectedExpr ToInitOrErr = import(E->getInit()); if (!ToInitOrErr) return ToInitOrErr.takeError(); ExpectedSLoc ToEqualOrColonLocOrErr = import(E->getEqualOrColonLoc()); if (!ToEqualOrColonLocOrErr) return ToEqualOrColonLocOrErr.takeError(); SmallVector ToIndexExprs(E->getNumSubExprs() - 1); // List elements from the second, the first is Init itself for (unsigned I = 1, N = E->getNumSubExprs(); I < N; I++) { if (ExpectedExpr ToArgOrErr = import(E->getSubExpr(I))) ToIndexExprs[I - 1] = *ToArgOrErr; else return ToArgOrErr.takeError(); } SmallVector ToDesignators(E->size()); if (Error Err = ImportContainerChecked(E->designators(), ToDesignators)) return std::move(Err); return DesignatedInitExpr::Create( Importer.getToContext(), ToDesignators, ToIndexExprs, *ToEqualOrColonLocOrErr, E->usesGNUSyntax(), *ToInitOrErr); } ExpectedStmt ASTNodeImporter::VisitCXXNullPtrLiteralExpr(CXXNullPtrLiteralExpr *E) { ExpectedType ToTypeOrErr = import(E->getType()); if (!ToTypeOrErr) return ToTypeOrErr.takeError(); ExpectedSLoc ToLocationOrErr = import(E->getLocation()); if (!ToLocationOrErr) return ToLocationOrErr.takeError(); return new (Importer.getToContext()) CXXNullPtrLiteralExpr( *ToTypeOrErr, *ToLocationOrErr); } ExpectedStmt ASTNodeImporter::VisitIntegerLiteral(IntegerLiteral *E) { ExpectedType ToTypeOrErr = import(E->getType()); if (!ToTypeOrErr) return ToTypeOrErr.takeError(); ExpectedSLoc ToLocationOrErr = import(E->getLocation()); if (!ToLocationOrErr) return ToLocationOrErr.takeError(); return IntegerLiteral::Create( Importer.getToContext(), E->getValue(), *ToTypeOrErr, *ToLocationOrErr); } ExpectedStmt ASTNodeImporter::VisitFloatingLiteral(FloatingLiteral *E) { ExpectedType ToTypeOrErr = import(E->getType()); if (!ToTypeOrErr) return ToTypeOrErr.takeError(); ExpectedSLoc ToLocationOrErr = import(E->getLocation()); if (!ToLocationOrErr) return ToLocationOrErr.takeError(); return FloatingLiteral::Create( Importer.getToContext(), E->getValue(), E->isExact(), *ToTypeOrErr, *ToLocationOrErr); } ExpectedStmt ASTNodeImporter::VisitImaginaryLiteral(ImaginaryLiteral *E) { auto ToTypeOrErr = import(E->getType()); if (!ToTypeOrErr) return ToTypeOrErr.takeError(); ExpectedExpr ToSubExprOrErr = import(E->getSubExpr()); if (!ToSubExprOrErr) return ToSubExprOrErr.takeError(); return new (Importer.getToContext()) ImaginaryLiteral( *ToSubExprOrErr, *ToTypeOrErr); } ExpectedStmt ASTNodeImporter::VisitCharacterLiteral(CharacterLiteral *E) { ExpectedType ToTypeOrErr = import(E->getType()); if (!ToTypeOrErr) return ToTypeOrErr.takeError(); ExpectedSLoc ToLocationOrErr = import(E->getLocation()); if (!ToLocationOrErr) return ToLocationOrErr.takeError(); return new (Importer.getToContext()) CharacterLiteral( E->getValue(), E->getKind(), *ToTypeOrErr, *ToLocationOrErr); } ExpectedStmt ASTNodeImporter::VisitStringLiteral(StringLiteral *E) { ExpectedType ToTypeOrErr = import(E->getType()); if (!ToTypeOrErr) return ToTypeOrErr.takeError(); SmallVector ToLocations(E->getNumConcatenated()); if (Error Err = ImportArrayChecked( E->tokloc_begin(), E->tokloc_end(), ToLocations.begin())) return std::move(Err); return StringLiteral::Create( Importer.getToContext(), E->getBytes(), E->getKind(), E->isPascal(), *ToTypeOrErr, ToLocations.data(), ToLocations.size()); } ExpectedStmt ASTNodeImporter::VisitCompoundLiteralExpr(CompoundLiteralExpr *E) { auto Imp = importSeq( E->getLParenLoc(), E->getTypeSourceInfo(), E->getType(), E->getInitializer()); if (!Imp) return Imp.takeError(); SourceLocation ToLParenLoc; TypeSourceInfo *ToTypeSourceInfo; QualType ToType; Expr *ToInitializer; std::tie(ToLParenLoc, ToTypeSourceInfo, ToType, ToInitializer) = *Imp; return new (Importer.getToContext()) CompoundLiteralExpr( ToLParenLoc, ToTypeSourceInfo, ToType, E->getValueKind(), ToInitializer, E->isFileScope()); } ExpectedStmt ASTNodeImporter::VisitAtomicExpr(AtomicExpr *E) { auto Imp = importSeq( E->getBuiltinLoc(), E->getType(), E->getRParenLoc()); if (!Imp) return Imp.takeError(); SourceLocation ToBuiltinLoc, ToRParenLoc; QualType ToType; std::tie(ToBuiltinLoc, ToType, ToRParenLoc) = *Imp; SmallVector ToExprs(E->getNumSubExprs()); if (Error Err = ImportArrayChecked( E->getSubExprs(), E->getSubExprs() + E->getNumSubExprs(), ToExprs.begin())) return std::move(Err); return new (Importer.getToContext()) AtomicExpr( ToBuiltinLoc, ToExprs, ToType, E->getOp(), ToRParenLoc); } ExpectedStmt ASTNodeImporter::VisitAddrLabelExpr(AddrLabelExpr *E) { auto Imp = importSeq( E->getAmpAmpLoc(), E->getLabelLoc(), E->getLabel(), E->getType()); if (!Imp) return Imp.takeError(); SourceLocation ToAmpAmpLoc, ToLabelLoc; LabelDecl *ToLabel; QualType ToType; std::tie(ToAmpAmpLoc, ToLabelLoc, ToLabel, ToType) = *Imp; return new (Importer.getToContext()) AddrLabelExpr( ToAmpAmpLoc, ToLabelLoc, ToLabel, ToType); } ExpectedStmt ASTNodeImporter::VisitConstantExpr(ConstantExpr *E) { auto Imp = importSeq(E->getSubExpr()); if (!Imp) return Imp.takeError(); Expr *ToSubExpr; std::tie(ToSubExpr) = *Imp; // TODO : Handle APValue::ValueKind that require importing. APValue::ValueKind Kind = E->getResultAPValueKind(); if (Kind == APValue::Int || Kind == APValue::Float || Kind == APValue::FixedPoint || Kind == APValue::ComplexFloat || Kind == APValue::ComplexInt) return ConstantExpr::Create(Importer.getToContext(), ToSubExpr, E->getAPValueResult()); return ConstantExpr::Create(Importer.getToContext(), ToSubExpr); } ExpectedStmt ASTNodeImporter::VisitParenExpr(ParenExpr *E) { auto Imp = importSeq(E->getLParen(), E->getRParen(), E->getSubExpr()); if (!Imp) return Imp.takeError(); SourceLocation ToLParen, ToRParen; Expr *ToSubExpr; std::tie(ToLParen, ToRParen, ToSubExpr) = *Imp; return new (Importer.getToContext()) ParenExpr(ToLParen, ToRParen, ToSubExpr); } ExpectedStmt ASTNodeImporter::VisitParenListExpr(ParenListExpr *E) { SmallVector ToExprs(E->getNumExprs()); if (Error Err = ImportContainerChecked(E->exprs(), ToExprs)) return std::move(Err); ExpectedSLoc ToLParenLocOrErr = import(E->getLParenLoc()); if (!ToLParenLocOrErr) return ToLParenLocOrErr.takeError(); ExpectedSLoc ToRParenLocOrErr = import(E->getRParenLoc()); if (!ToRParenLocOrErr) return ToRParenLocOrErr.takeError(); return ParenListExpr::Create(Importer.getToContext(), *ToLParenLocOrErr, ToExprs, *ToRParenLocOrErr); } ExpectedStmt ASTNodeImporter::VisitStmtExpr(StmtExpr *E) { auto Imp = importSeq( E->getSubStmt(), E->getType(), E->getLParenLoc(), E->getRParenLoc()); if (!Imp) return Imp.takeError(); CompoundStmt *ToSubStmt; QualType ToType; SourceLocation ToLParenLoc, ToRParenLoc; std::tie(ToSubStmt, ToType, ToLParenLoc, ToRParenLoc) = *Imp; return new (Importer.getToContext()) StmtExpr(ToSubStmt, ToType, ToLParenLoc, ToRParenLoc, - E->isInstantiationDependent()); + E->getTemplateDepth()); } ExpectedStmt ASTNodeImporter::VisitUnaryOperator(UnaryOperator *E) { auto Imp = importSeq( E->getSubExpr(), E->getType(), E->getOperatorLoc()); if (!Imp) return Imp.takeError(); Expr *ToSubExpr; QualType ToType; SourceLocation ToOperatorLoc; std::tie(ToSubExpr, ToType, ToOperatorLoc) = *Imp; return new (Importer.getToContext()) UnaryOperator( ToSubExpr, E->getOpcode(), ToType, E->getValueKind(), E->getObjectKind(), ToOperatorLoc, E->canOverflow()); } ExpectedStmt ASTNodeImporter::VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E) { auto Imp = importSeq(E->getType(), E->getOperatorLoc(), E->getRParenLoc()); if (!Imp) return Imp.takeError(); QualType ToType; SourceLocation ToOperatorLoc, ToRParenLoc; std::tie(ToType, ToOperatorLoc, ToRParenLoc) = *Imp; if (E->isArgumentType()) { Expected ToArgumentTypeInfoOrErr = import(E->getArgumentTypeInfo()); if (!ToArgumentTypeInfoOrErr) return ToArgumentTypeInfoOrErr.takeError(); return new (Importer.getToContext()) UnaryExprOrTypeTraitExpr( E->getKind(), *ToArgumentTypeInfoOrErr, ToType, ToOperatorLoc, ToRParenLoc); } ExpectedExpr ToArgumentExprOrErr = import(E->getArgumentExpr()); if (!ToArgumentExprOrErr) return ToArgumentExprOrErr.takeError(); return new (Importer.getToContext()) UnaryExprOrTypeTraitExpr( E->getKind(), *ToArgumentExprOrErr, ToType, ToOperatorLoc, ToRParenLoc); } ExpectedStmt ASTNodeImporter::VisitBinaryOperator(BinaryOperator *E) { auto Imp = importSeq( E->getLHS(), E->getRHS(), E->getType(), E->getOperatorLoc()); if (!Imp) return Imp.takeError(); Expr *ToLHS, *ToRHS; QualType ToType; SourceLocation ToOperatorLoc; std::tie(ToLHS, ToRHS, ToType, ToOperatorLoc) = *Imp; return new (Importer.getToContext()) BinaryOperator( ToLHS, ToRHS, E->getOpcode(), ToType, E->getValueKind(), E->getObjectKind(), ToOperatorLoc, E->getFPFeatures()); } ExpectedStmt ASTNodeImporter::VisitConditionalOperator(ConditionalOperator *E) { auto Imp = importSeq( E->getCond(), E->getQuestionLoc(), E->getLHS(), E->getColonLoc(), E->getRHS(), E->getType()); if (!Imp) return Imp.takeError(); Expr *ToCond, *ToLHS, *ToRHS; SourceLocation ToQuestionLoc, ToColonLoc; QualType ToType; std::tie(ToCond, ToQuestionLoc, ToLHS, ToColonLoc, ToRHS, ToType) = *Imp; return new (Importer.getToContext()) ConditionalOperator( ToCond, ToQuestionLoc, ToLHS, ToColonLoc, ToRHS, ToType, E->getValueKind(), E->getObjectKind()); } ExpectedStmt ASTNodeImporter::VisitBinaryConditionalOperator( BinaryConditionalOperator *E) { auto Imp = importSeq( E->getCommon(), E->getOpaqueValue(), E->getCond(), E->getTrueExpr(), E->getFalseExpr(), E->getQuestionLoc(), E->getColonLoc(), E->getType()); if (!Imp) return Imp.takeError(); Expr *ToCommon, *ToCond, *ToTrueExpr, *ToFalseExpr; OpaqueValueExpr *ToOpaqueValue; SourceLocation ToQuestionLoc, ToColonLoc; QualType ToType; std::tie( ToCommon, ToOpaqueValue, ToCond, ToTrueExpr, ToFalseExpr, ToQuestionLoc, ToColonLoc, ToType) = *Imp; return new (Importer.getToContext()) BinaryConditionalOperator( ToCommon, ToOpaqueValue, ToCond, ToTrueExpr, ToFalseExpr, ToQuestionLoc, ToColonLoc, ToType, E->getValueKind(), E->getObjectKind()); } ExpectedStmt ASTNodeImporter::VisitArrayTypeTraitExpr(ArrayTypeTraitExpr *E) { auto Imp = importSeq( E->getBeginLoc(), E->getQueriedTypeSourceInfo(), E->getDimensionExpression(), E->getEndLoc(), E->getType()); if (!Imp) return Imp.takeError(); SourceLocation ToBeginLoc, ToEndLoc; TypeSourceInfo *ToQueriedTypeSourceInfo; Expr *ToDimensionExpression; QualType ToType; std::tie( ToBeginLoc, ToQueriedTypeSourceInfo, ToDimensionExpression, ToEndLoc, ToType) = *Imp; return new (Importer.getToContext()) ArrayTypeTraitExpr( ToBeginLoc, E->getTrait(), ToQueriedTypeSourceInfo, E->getValue(), ToDimensionExpression, ToEndLoc, ToType); } ExpectedStmt ASTNodeImporter::VisitExpressionTraitExpr(ExpressionTraitExpr *E) { auto Imp = importSeq( E->getBeginLoc(), E->getQueriedExpression(), E->getEndLoc(), E->getType()); if (!Imp) return Imp.takeError(); SourceLocation ToBeginLoc, ToEndLoc; Expr *ToQueriedExpression; QualType ToType; std::tie(ToBeginLoc, ToQueriedExpression, ToEndLoc, ToType) = *Imp; return new (Importer.getToContext()) ExpressionTraitExpr( ToBeginLoc, E->getTrait(), ToQueriedExpression, E->getValue(), ToEndLoc, ToType); } ExpectedStmt ASTNodeImporter::VisitOpaqueValueExpr(OpaqueValueExpr *E) { auto Imp = importSeq( E->getLocation(), E->getType(), E->getSourceExpr()); if (!Imp) return Imp.takeError(); SourceLocation ToLocation; QualType ToType; Expr *ToSourceExpr; std::tie(ToLocation, ToType, ToSourceExpr) = *Imp; return new (Importer.getToContext()) OpaqueValueExpr( ToLocation, ToType, E->getValueKind(), E->getObjectKind(), ToSourceExpr); } ExpectedStmt ASTNodeImporter::VisitArraySubscriptExpr(ArraySubscriptExpr *E) { auto Imp = importSeq( E->getLHS(), E->getRHS(), E->getType(), E->getRBracketLoc()); if (!Imp) return Imp.takeError(); Expr *ToLHS, *ToRHS; SourceLocation ToRBracketLoc; QualType ToType; std::tie(ToLHS, ToRHS, ToType, ToRBracketLoc) = *Imp; return new (Importer.getToContext()) ArraySubscriptExpr( ToLHS, ToRHS, ToType, E->getValueKind(), E->getObjectKind(), ToRBracketLoc); } ExpectedStmt ASTNodeImporter::VisitCompoundAssignOperator(CompoundAssignOperator *E) { auto Imp = importSeq( E->getLHS(), E->getRHS(), E->getType(), E->getComputationLHSType(), E->getComputationResultType(), E->getOperatorLoc()); if (!Imp) return Imp.takeError(); Expr *ToLHS, *ToRHS; QualType ToType, ToComputationLHSType, ToComputationResultType; SourceLocation ToOperatorLoc; std::tie(ToLHS, ToRHS, ToType, ToComputationLHSType, ToComputationResultType, ToOperatorLoc) = *Imp; return new (Importer.getToContext()) CompoundAssignOperator( ToLHS, ToRHS, E->getOpcode(), ToType, E->getValueKind(), E->getObjectKind(), ToComputationLHSType, ToComputationResultType, ToOperatorLoc, E->getFPFeatures()); } Expected ASTNodeImporter::ImportCastPath(CastExpr *CE) { CXXCastPath Path; for (auto I = CE->path_begin(), E = CE->path_end(); I != E; ++I) { if (auto SpecOrErr = import(*I)) Path.push_back(*SpecOrErr); else return SpecOrErr.takeError(); } return Path; } ExpectedStmt ASTNodeImporter::VisitImplicitCastExpr(ImplicitCastExpr *E) { ExpectedType ToTypeOrErr = import(E->getType()); if (!ToTypeOrErr) return ToTypeOrErr.takeError(); ExpectedExpr ToSubExprOrErr = import(E->getSubExpr()); if (!ToSubExprOrErr) return ToSubExprOrErr.takeError(); Expected ToBasePathOrErr = ImportCastPath(E); if (!ToBasePathOrErr) return ToBasePathOrErr.takeError(); return ImplicitCastExpr::Create( Importer.getToContext(), *ToTypeOrErr, E->getCastKind(), *ToSubExprOrErr, &(*ToBasePathOrErr), E->getValueKind()); } ExpectedStmt ASTNodeImporter::VisitExplicitCastExpr(ExplicitCastExpr *E) { auto Imp1 = importSeq( E->getType(), E->getSubExpr(), E->getTypeInfoAsWritten()); if (!Imp1) return Imp1.takeError(); QualType ToType; Expr *ToSubExpr; TypeSourceInfo *ToTypeInfoAsWritten; std::tie(ToType, ToSubExpr, ToTypeInfoAsWritten) = *Imp1; Expected ToBasePathOrErr = ImportCastPath(E); if (!ToBasePathOrErr) return ToBasePathOrErr.takeError(); CXXCastPath *ToBasePath = &(*ToBasePathOrErr); switch (E->getStmtClass()) { case Stmt::CStyleCastExprClass: { auto *CCE = cast(E); ExpectedSLoc ToLParenLocOrErr = import(CCE->getLParenLoc()); if (!ToLParenLocOrErr) return ToLParenLocOrErr.takeError(); ExpectedSLoc ToRParenLocOrErr = import(CCE->getRParenLoc()); if (!ToRParenLocOrErr) return ToRParenLocOrErr.takeError(); return CStyleCastExpr::Create( Importer.getToContext(), ToType, E->getValueKind(), E->getCastKind(), ToSubExpr, ToBasePath, ToTypeInfoAsWritten, *ToLParenLocOrErr, *ToRParenLocOrErr); } case Stmt::CXXFunctionalCastExprClass: { auto *FCE = cast(E); ExpectedSLoc ToLParenLocOrErr = import(FCE->getLParenLoc()); if (!ToLParenLocOrErr) return ToLParenLocOrErr.takeError(); ExpectedSLoc ToRParenLocOrErr = import(FCE->getRParenLoc()); if (!ToRParenLocOrErr) return ToRParenLocOrErr.takeError(); return CXXFunctionalCastExpr::Create( Importer.getToContext(), ToType, E->getValueKind(), ToTypeInfoAsWritten, E->getCastKind(), ToSubExpr, ToBasePath, *ToLParenLocOrErr, *ToRParenLocOrErr); } case Stmt::ObjCBridgedCastExprClass: { auto *OCE = cast(E); ExpectedSLoc ToLParenLocOrErr = import(OCE->getLParenLoc()); if (!ToLParenLocOrErr) return ToLParenLocOrErr.takeError(); ExpectedSLoc ToBridgeKeywordLocOrErr = import(OCE->getBridgeKeywordLoc()); if (!ToBridgeKeywordLocOrErr) return ToBridgeKeywordLocOrErr.takeError(); return new (Importer.getToContext()) ObjCBridgedCastExpr( *ToLParenLocOrErr, OCE->getBridgeKind(), E->getCastKind(), *ToBridgeKeywordLocOrErr, ToTypeInfoAsWritten, ToSubExpr); } default: llvm_unreachable("Cast expression of unsupported type!"); return make_error(ImportError::UnsupportedConstruct); } } ExpectedStmt ASTNodeImporter::VisitOffsetOfExpr(OffsetOfExpr *E) { SmallVector ToNodes; for (int I = 0, N = E->getNumComponents(); I < N; ++I) { const OffsetOfNode &FromNode = E->getComponent(I); SourceLocation ToBeginLoc, ToEndLoc; if (FromNode.getKind() != OffsetOfNode::Base) { auto Imp = importSeq(FromNode.getBeginLoc(), FromNode.getEndLoc()); if (!Imp) return Imp.takeError(); std::tie(ToBeginLoc, ToEndLoc) = *Imp; } switch (FromNode.getKind()) { case OffsetOfNode::Array: ToNodes.push_back( OffsetOfNode(ToBeginLoc, FromNode.getArrayExprIndex(), ToEndLoc)); break; case OffsetOfNode::Base: { auto ToBSOrErr = import(FromNode.getBase()); if (!ToBSOrErr) return ToBSOrErr.takeError(); ToNodes.push_back(OffsetOfNode(*ToBSOrErr)); break; } case OffsetOfNode::Field: { auto ToFieldOrErr = import(FromNode.getField()); if (!ToFieldOrErr) return ToFieldOrErr.takeError(); ToNodes.push_back(OffsetOfNode(ToBeginLoc, *ToFieldOrErr, ToEndLoc)); break; } case OffsetOfNode::Identifier: { IdentifierInfo *ToII = Importer.Import(FromNode.getFieldName()); ToNodes.push_back(OffsetOfNode(ToBeginLoc, ToII, ToEndLoc)); break; } } } SmallVector ToExprs(E->getNumExpressions()); for (int I = 0, N = E->getNumExpressions(); I < N; ++I) { ExpectedExpr ToIndexExprOrErr = import(E->getIndexExpr(I)); if (!ToIndexExprOrErr) return ToIndexExprOrErr.takeError(); ToExprs[I] = *ToIndexExprOrErr; } auto Imp = importSeq( E->getType(), E->getTypeSourceInfo(), E->getOperatorLoc(), E->getRParenLoc()); if (!Imp) return Imp.takeError(); QualType ToType; TypeSourceInfo *ToTypeSourceInfo; SourceLocation ToOperatorLoc, ToRParenLoc; std::tie(ToType, ToTypeSourceInfo, ToOperatorLoc, ToRParenLoc) = *Imp; return OffsetOfExpr::Create( Importer.getToContext(), ToType, ToOperatorLoc, ToTypeSourceInfo, ToNodes, ToExprs, ToRParenLoc); } ExpectedStmt ASTNodeImporter::VisitCXXNoexceptExpr(CXXNoexceptExpr *E) { auto Imp = importSeq( E->getType(), E->getOperand(), E->getBeginLoc(), E->getEndLoc()); if (!Imp) return Imp.takeError(); QualType ToType; Expr *ToOperand; SourceLocation ToBeginLoc, ToEndLoc; std::tie(ToType, ToOperand, ToBeginLoc, ToEndLoc) = *Imp; CanThrowResult ToCanThrow; if (E->isValueDependent()) ToCanThrow = CT_Dependent; else ToCanThrow = E->getValue() ? CT_Can : CT_Cannot; return new (Importer.getToContext()) CXXNoexceptExpr( ToType, ToOperand, ToCanThrow, ToBeginLoc, ToEndLoc); } ExpectedStmt ASTNodeImporter::VisitCXXThrowExpr(CXXThrowExpr *E) { auto Imp = importSeq(E->getSubExpr(), E->getType(), E->getThrowLoc()); if (!Imp) return Imp.takeError(); Expr *ToSubExpr; QualType ToType; SourceLocation ToThrowLoc; std::tie(ToSubExpr, ToType, ToThrowLoc) = *Imp; return new (Importer.getToContext()) CXXThrowExpr( ToSubExpr, ToType, ToThrowLoc, E->isThrownVariableInScope()); } ExpectedStmt ASTNodeImporter::VisitCXXDefaultArgExpr(CXXDefaultArgExpr *E) { ExpectedSLoc ToUsedLocOrErr = import(E->getUsedLocation()); if (!ToUsedLocOrErr) return ToUsedLocOrErr.takeError(); auto ToParamOrErr = import(E->getParam()); if (!ToParamOrErr) return ToParamOrErr.takeError(); auto UsedContextOrErr = Importer.ImportContext(E->getUsedContext()); if (!UsedContextOrErr) return UsedContextOrErr.takeError(); // Import the default arg if it was not imported yet. // This is needed because it can happen that during the import of the // default expression (from VisitParmVarDecl) the same ParmVarDecl is // encountered here. The default argument for a ParmVarDecl is set in the // ParmVarDecl only after it is imported (set in VisitParmVarDecl if not here, // see VisitParmVarDecl). ParmVarDecl *ToParam = *ToParamOrErr; if (!ToParam->getDefaultArg()) { Optional FromParam = Importer.getImportedFromDecl(ToParam); assert(FromParam && "ParmVarDecl was not imported?"); if (Error Err = ImportDefaultArgOfParmVarDecl(*FromParam, ToParam)) return std::move(Err); } return CXXDefaultArgExpr::Create(Importer.getToContext(), *ToUsedLocOrErr, *ToParamOrErr, *UsedContextOrErr); } ExpectedStmt ASTNodeImporter::VisitCXXScalarValueInitExpr(CXXScalarValueInitExpr *E) { auto Imp = importSeq( E->getType(), E->getTypeSourceInfo(), E->getRParenLoc()); if (!Imp) return Imp.takeError(); QualType ToType; TypeSourceInfo *ToTypeSourceInfo; SourceLocation ToRParenLoc; std::tie(ToType, ToTypeSourceInfo, ToRParenLoc) = *Imp; return new (Importer.getToContext()) CXXScalarValueInitExpr( ToType, ToTypeSourceInfo, ToRParenLoc); } ExpectedStmt ASTNodeImporter::VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E) { ExpectedExpr ToSubExprOrErr = import(E->getSubExpr()); if (!ToSubExprOrErr) return ToSubExprOrErr.takeError(); auto ToDtorOrErr = import(E->getTemporary()->getDestructor()); if (!ToDtorOrErr) return ToDtorOrErr.takeError(); ASTContext &ToCtx = Importer.getToContext(); CXXTemporary *Temp = CXXTemporary::Create(ToCtx, *ToDtorOrErr); return CXXBindTemporaryExpr::Create(ToCtx, Temp, *ToSubExprOrErr); } ExpectedStmt ASTNodeImporter::VisitCXXTemporaryObjectExpr(CXXTemporaryObjectExpr *E) { auto Imp = importSeq( E->getConstructor(), E->getType(), E->getTypeSourceInfo(), E->getParenOrBraceRange()); if (!Imp) return Imp.takeError(); CXXConstructorDecl *ToConstructor; QualType ToType; TypeSourceInfo *ToTypeSourceInfo; SourceRange ToParenOrBraceRange; std::tie(ToConstructor, ToType, ToTypeSourceInfo, ToParenOrBraceRange) = *Imp; SmallVector ToArgs(E->getNumArgs()); if (Error Err = ImportContainerChecked(E->arguments(), ToArgs)) return std::move(Err); return CXXTemporaryObjectExpr::Create( Importer.getToContext(), ToConstructor, ToType, ToTypeSourceInfo, ToArgs, ToParenOrBraceRange, E->hadMultipleCandidates(), E->isListInitialization(), E->isStdInitListInitialization(), E->requiresZeroInitialization()); } ExpectedDecl ASTNodeImporter::VisitLifetimeExtendedTemporaryDecl( LifetimeExtendedTemporaryDecl *D) { DeclContext *DC, *LexicalDC; if (Error Err = ImportDeclContext(D, DC, LexicalDC)) return std::move(Err); auto Imp = importSeq(D->getTemporaryExpr(), D->getExtendingDecl()); // FIXME: the APValue should be imported as well if present. if (!Imp) return Imp.takeError(); Expr *Temporary; ValueDecl *ExtendingDecl; std::tie(Temporary, ExtendingDecl) = *Imp; // FIXME: Should ManglingNumber get numbers associated with 'to' context? LifetimeExtendedTemporaryDecl *To; if (GetImportedOrCreateDecl(To, D, Temporary, ExtendingDecl, D->getManglingNumber())) return To; To->setLexicalDeclContext(LexicalDC); LexicalDC->addDeclInternal(To); return To; } ExpectedStmt ASTNodeImporter::VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *E) { auto Imp = importSeq(E->getType(), E->getLifetimeExtendedTemporaryDecl() ? nullptr : E->getSubExpr(), E->getLifetimeExtendedTemporaryDecl()); if (!Imp) return Imp.takeError(); QualType ToType; Expr *ToTemporaryExpr; LifetimeExtendedTemporaryDecl *ToMaterializedDecl; std::tie(ToType, ToTemporaryExpr, ToMaterializedDecl) = *Imp; if (!ToTemporaryExpr) ToTemporaryExpr = cast(ToMaterializedDecl->getTemporaryExpr()); auto *ToMTE = new (Importer.getToContext()) MaterializeTemporaryExpr( ToType, ToTemporaryExpr, E->isBoundToLvalueReference(), ToMaterializedDecl); return ToMTE; } ExpectedStmt ASTNodeImporter::VisitPackExpansionExpr(PackExpansionExpr *E) { auto Imp = importSeq( E->getType(), E->getPattern(), E->getEllipsisLoc()); if (!Imp) return Imp.takeError(); QualType ToType; Expr *ToPattern; SourceLocation ToEllipsisLoc; std::tie(ToType, ToPattern, ToEllipsisLoc) = *Imp; return new (Importer.getToContext()) PackExpansionExpr( ToType, ToPattern, ToEllipsisLoc, E->getNumExpansions()); } ExpectedStmt ASTNodeImporter::VisitSizeOfPackExpr(SizeOfPackExpr *E) { auto Imp = importSeq( E->getOperatorLoc(), E->getPack(), E->getPackLoc(), E->getRParenLoc()); if (!Imp) return Imp.takeError(); SourceLocation ToOperatorLoc, ToPackLoc, ToRParenLoc; NamedDecl *ToPack; std::tie(ToOperatorLoc, ToPack, ToPackLoc, ToRParenLoc) = *Imp; Optional Length; if (!E->isValueDependent()) Length = E->getPackLength(); SmallVector ToPartialArguments; if (E->isPartiallySubstituted()) { if (Error Err = ImportTemplateArguments( E->getPartialArguments().data(), E->getPartialArguments().size(), ToPartialArguments)) return std::move(Err); } return SizeOfPackExpr::Create( Importer.getToContext(), ToOperatorLoc, ToPack, ToPackLoc, ToRParenLoc, Length, ToPartialArguments); } ExpectedStmt ASTNodeImporter::VisitCXXNewExpr(CXXNewExpr *E) { auto Imp = importSeq( E->getOperatorNew(), E->getOperatorDelete(), E->getTypeIdParens(), E->getArraySize(), E->getInitializer(), E->getType(), E->getAllocatedTypeSourceInfo(), E->getSourceRange(), E->getDirectInitRange()); if (!Imp) return Imp.takeError(); FunctionDecl *ToOperatorNew, *ToOperatorDelete; SourceRange ToTypeIdParens, ToSourceRange, ToDirectInitRange; Optional ToArraySize; Expr *ToInitializer; QualType ToType; TypeSourceInfo *ToAllocatedTypeSourceInfo; std::tie( ToOperatorNew, ToOperatorDelete, ToTypeIdParens, ToArraySize, ToInitializer, ToType, ToAllocatedTypeSourceInfo, ToSourceRange, ToDirectInitRange) = *Imp; SmallVector ToPlacementArgs(E->getNumPlacementArgs()); if (Error Err = ImportContainerChecked(E->placement_arguments(), ToPlacementArgs)) return std::move(Err); return CXXNewExpr::Create( Importer.getToContext(), E->isGlobalNew(), ToOperatorNew, ToOperatorDelete, E->passAlignment(), E->doesUsualArrayDeleteWantSize(), ToPlacementArgs, ToTypeIdParens, ToArraySize, E->getInitializationStyle(), ToInitializer, ToType, ToAllocatedTypeSourceInfo, ToSourceRange, ToDirectInitRange); } ExpectedStmt ASTNodeImporter::VisitCXXDeleteExpr(CXXDeleteExpr *E) { auto Imp = importSeq( E->getType(), E->getOperatorDelete(), E->getArgument(), E->getBeginLoc()); if (!Imp) return Imp.takeError(); QualType ToType; FunctionDecl *ToOperatorDelete; Expr *ToArgument; SourceLocation ToBeginLoc; std::tie(ToType, ToOperatorDelete, ToArgument, ToBeginLoc) = *Imp; return new (Importer.getToContext()) CXXDeleteExpr( ToType, E->isGlobalDelete(), E->isArrayForm(), E->isArrayFormAsWritten(), E->doesUsualArrayDeleteWantSize(), ToOperatorDelete, ToArgument, ToBeginLoc); } ExpectedStmt ASTNodeImporter::VisitCXXConstructExpr(CXXConstructExpr *E) { auto Imp = importSeq( E->getType(), E->getLocation(), E->getConstructor(), E->getParenOrBraceRange()); if (!Imp) return Imp.takeError(); QualType ToType; SourceLocation ToLocation; CXXConstructorDecl *ToConstructor; SourceRange ToParenOrBraceRange; std::tie(ToType, ToLocation, ToConstructor, ToParenOrBraceRange) = *Imp; SmallVector ToArgs(E->getNumArgs()); if (Error Err = ImportContainerChecked(E->arguments(), ToArgs)) return std::move(Err); return CXXConstructExpr::Create( Importer.getToContext(), ToType, ToLocation, ToConstructor, E->isElidable(), ToArgs, E->hadMultipleCandidates(), E->isListInitialization(), E->isStdInitListInitialization(), E->requiresZeroInitialization(), E->getConstructionKind(), ToParenOrBraceRange); } ExpectedStmt ASTNodeImporter::VisitExprWithCleanups(ExprWithCleanups *E) { ExpectedExpr ToSubExprOrErr = import(E->getSubExpr()); if (!ToSubExprOrErr) return ToSubExprOrErr.takeError(); SmallVector ToObjects(E->getNumObjects()); if (Error Err = ImportContainerChecked(E->getObjects(), ToObjects)) return std::move(Err); return ExprWithCleanups::Create( Importer.getToContext(), *ToSubExprOrErr, E->cleanupsHaveSideEffects(), ToObjects); } ExpectedStmt ASTNodeImporter::VisitCXXMemberCallExpr(CXXMemberCallExpr *E) { auto Imp = importSeq( E->getCallee(), E->getType(), E->getRParenLoc()); if (!Imp) return Imp.takeError(); Expr *ToCallee; QualType ToType; SourceLocation ToRParenLoc; std::tie(ToCallee, ToType, ToRParenLoc) = *Imp; SmallVector ToArgs(E->getNumArgs()); if (Error Err = ImportContainerChecked(E->arguments(), ToArgs)) return std::move(Err); return CXXMemberCallExpr::Create(Importer.getToContext(), ToCallee, ToArgs, ToType, E->getValueKind(), ToRParenLoc); } ExpectedStmt ASTNodeImporter::VisitCXXThisExpr(CXXThisExpr *E) { ExpectedType ToTypeOrErr = import(E->getType()); if (!ToTypeOrErr) return ToTypeOrErr.takeError(); ExpectedSLoc ToLocationOrErr = import(E->getLocation()); if (!ToLocationOrErr) return ToLocationOrErr.takeError(); return new (Importer.getToContext()) CXXThisExpr( *ToLocationOrErr, *ToTypeOrErr, E->isImplicit()); } ExpectedStmt ASTNodeImporter::VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *E) { ExpectedType ToTypeOrErr = import(E->getType()); if (!ToTypeOrErr) return ToTypeOrErr.takeError(); ExpectedSLoc ToLocationOrErr = import(E->getLocation()); if (!ToLocationOrErr) return ToLocationOrErr.takeError(); return new (Importer.getToContext()) CXXBoolLiteralExpr( E->getValue(), *ToTypeOrErr, *ToLocationOrErr); } ExpectedStmt ASTNodeImporter::VisitMemberExpr(MemberExpr *E) { auto Imp1 = importSeq( E->getBase(), E->getOperatorLoc(), E->getQualifierLoc(), E->getTemplateKeywordLoc(), E->getMemberDecl(), E->getType()); if (!Imp1) return Imp1.takeError(); Expr *ToBase; SourceLocation ToOperatorLoc, ToTemplateKeywordLoc; NestedNameSpecifierLoc ToQualifierLoc; ValueDecl *ToMemberDecl; QualType ToType; std::tie( ToBase, ToOperatorLoc, ToQualifierLoc, ToTemplateKeywordLoc, ToMemberDecl, ToType) = *Imp1; auto Imp2 = importSeq( E->getFoundDecl().getDecl(), E->getMemberNameInfo().getName(), E->getMemberNameInfo().getLoc(), E->getLAngleLoc(), E->getRAngleLoc()); if (!Imp2) return Imp2.takeError(); NamedDecl *ToDecl; DeclarationName ToName; SourceLocation ToLoc, ToLAngleLoc, ToRAngleLoc; std::tie(ToDecl, ToName, ToLoc, ToLAngleLoc, ToRAngleLoc) = *Imp2; DeclAccessPair ToFoundDecl = DeclAccessPair::make(ToDecl, E->getFoundDecl().getAccess()); DeclarationNameInfo ToMemberNameInfo(ToName, ToLoc); TemplateArgumentListInfo ToTAInfo, *ResInfo = nullptr; if (E->hasExplicitTemplateArgs()) { if (Error Err = ImportTemplateArgumentListInfo(E->getLAngleLoc(), E->getRAngleLoc(), E->template_arguments(), ToTAInfo)) return std::move(Err); ResInfo = &ToTAInfo; } return MemberExpr::Create(Importer.getToContext(), ToBase, E->isArrow(), ToOperatorLoc, ToQualifierLoc, ToTemplateKeywordLoc, ToMemberDecl, ToFoundDecl, ToMemberNameInfo, ResInfo, ToType, E->getValueKind(), E->getObjectKind(), E->isNonOdrUse()); } ExpectedStmt ASTNodeImporter::VisitCXXPseudoDestructorExpr(CXXPseudoDestructorExpr *E) { auto Imp = importSeq( E->getBase(), E->getOperatorLoc(), E->getQualifierLoc(), E->getScopeTypeInfo(), E->getColonColonLoc(), E->getTildeLoc()); if (!Imp) return Imp.takeError(); Expr *ToBase; SourceLocation ToOperatorLoc, ToColonColonLoc, ToTildeLoc; NestedNameSpecifierLoc ToQualifierLoc; TypeSourceInfo *ToScopeTypeInfo; std::tie( ToBase, ToOperatorLoc, ToQualifierLoc, ToScopeTypeInfo, ToColonColonLoc, ToTildeLoc) = *Imp; PseudoDestructorTypeStorage Storage; if (IdentifierInfo *FromII = E->getDestroyedTypeIdentifier()) { IdentifierInfo *ToII = Importer.Import(FromII); ExpectedSLoc ToDestroyedTypeLocOrErr = import(E->getDestroyedTypeLoc()); if (!ToDestroyedTypeLocOrErr) return ToDestroyedTypeLocOrErr.takeError(); Storage = PseudoDestructorTypeStorage(ToII, *ToDestroyedTypeLocOrErr); } else { if (auto ToTIOrErr = import(E->getDestroyedTypeInfo())) Storage = PseudoDestructorTypeStorage(*ToTIOrErr); else return ToTIOrErr.takeError(); } return new (Importer.getToContext()) CXXPseudoDestructorExpr( Importer.getToContext(), ToBase, E->isArrow(), ToOperatorLoc, ToQualifierLoc, ToScopeTypeInfo, ToColonColonLoc, ToTildeLoc, Storage); } ExpectedStmt ASTNodeImporter::VisitCXXDependentScopeMemberExpr( CXXDependentScopeMemberExpr *E) { auto Imp = importSeq( E->getType(), E->getOperatorLoc(), E->getQualifierLoc(), E->getTemplateKeywordLoc(), E->getFirstQualifierFoundInScope()); if (!Imp) return Imp.takeError(); QualType ToType; SourceLocation ToOperatorLoc, ToTemplateKeywordLoc; NestedNameSpecifierLoc ToQualifierLoc; NamedDecl *ToFirstQualifierFoundInScope; std::tie( ToType, ToOperatorLoc, ToQualifierLoc, ToTemplateKeywordLoc, ToFirstQualifierFoundInScope) = *Imp; Expr *ToBase = nullptr; if (!E->isImplicitAccess()) { if (ExpectedExpr ToBaseOrErr = import(E->getBase())) ToBase = *ToBaseOrErr; else return ToBaseOrErr.takeError(); } TemplateArgumentListInfo ToTAInfo, *ResInfo = nullptr; if (E->hasExplicitTemplateArgs()) { if (Error Err = ImportTemplateArgumentListInfo( E->getLAngleLoc(), E->getRAngleLoc(), E->template_arguments(), ToTAInfo)) return std::move(Err); ResInfo = &ToTAInfo; } auto ToMemberNameInfoOrErr = importSeq(E->getMember(), E->getMemberLoc()); if (!ToMemberNameInfoOrErr) return ToMemberNameInfoOrErr.takeError(); DeclarationNameInfo ToMemberNameInfo( std::get<0>(*ToMemberNameInfoOrErr), std::get<1>(*ToMemberNameInfoOrErr)); // Import additional name location/type info. if (Error Err = ImportDeclarationNameLoc( E->getMemberNameInfo(), ToMemberNameInfo)) return std::move(Err); return CXXDependentScopeMemberExpr::Create( Importer.getToContext(), ToBase, ToType, E->isArrow(), ToOperatorLoc, ToQualifierLoc, ToTemplateKeywordLoc, ToFirstQualifierFoundInScope, ToMemberNameInfo, ResInfo); } ExpectedStmt ASTNodeImporter::VisitDependentScopeDeclRefExpr(DependentScopeDeclRefExpr *E) { auto Imp = importSeq(E->getQualifierLoc(), E->getTemplateKeywordLoc(), E->getDeclName(), E->getNameInfo().getLoc(), E->getLAngleLoc(), E->getRAngleLoc()); if (!Imp) return Imp.takeError(); NestedNameSpecifierLoc ToQualifierLoc; SourceLocation ToTemplateKeywordLoc, ToNameLoc, ToLAngleLoc, ToRAngleLoc; DeclarationName ToDeclName; std::tie(ToQualifierLoc, ToTemplateKeywordLoc, ToDeclName, ToNameLoc, ToLAngleLoc, ToRAngleLoc) = *Imp; DeclarationNameInfo ToNameInfo(ToDeclName, ToNameLoc); if (Error Err = ImportDeclarationNameLoc(E->getNameInfo(), ToNameInfo)) return std::move(Err); TemplateArgumentListInfo ToTAInfo(ToLAngleLoc, ToRAngleLoc); TemplateArgumentListInfo *ResInfo = nullptr; if (E->hasExplicitTemplateArgs()) { if (Error Err = ImportTemplateArgumentListInfo(E->template_arguments(), ToTAInfo)) return std::move(Err); ResInfo = &ToTAInfo; } return DependentScopeDeclRefExpr::Create( Importer.getToContext(), ToQualifierLoc, ToTemplateKeywordLoc, ToNameInfo, ResInfo); } ExpectedStmt ASTNodeImporter::VisitCXXUnresolvedConstructExpr( CXXUnresolvedConstructExpr *E) { auto Imp = importSeq( E->getLParenLoc(), E->getRParenLoc(), E->getTypeSourceInfo()); if (!Imp) return Imp.takeError(); SourceLocation ToLParenLoc, ToRParenLoc; TypeSourceInfo *ToTypeSourceInfo; std::tie(ToLParenLoc, ToRParenLoc, ToTypeSourceInfo) = *Imp; SmallVector ToArgs(E->arg_size()); if (Error Err = ImportArrayChecked(E->arg_begin(), E->arg_end(), ToArgs.begin())) return std::move(Err); return CXXUnresolvedConstructExpr::Create( Importer.getToContext(), ToTypeSourceInfo, ToLParenLoc, llvm::makeArrayRef(ToArgs), ToRParenLoc); } ExpectedStmt ASTNodeImporter::VisitUnresolvedLookupExpr(UnresolvedLookupExpr *E) { Expected ToNamingClassOrErr = import(E->getNamingClass()); if (!ToNamingClassOrErr) return ToNamingClassOrErr.takeError(); auto ToQualifierLocOrErr = import(E->getQualifierLoc()); if (!ToQualifierLocOrErr) return ToQualifierLocOrErr.takeError(); auto ToNameInfoOrErr = importSeq(E->getName(), E->getNameLoc()); if (!ToNameInfoOrErr) return ToNameInfoOrErr.takeError(); DeclarationNameInfo ToNameInfo( std::get<0>(*ToNameInfoOrErr), std::get<1>(*ToNameInfoOrErr)); // Import additional name location/type info. if (Error Err = ImportDeclarationNameLoc(E->getNameInfo(), ToNameInfo)) return std::move(Err); UnresolvedSet<8> ToDecls; for (auto *D : E->decls()) if (auto ToDOrErr = import(D)) ToDecls.addDecl(cast(*ToDOrErr)); else return ToDOrErr.takeError(); if (E->hasExplicitTemplateArgs()) { TemplateArgumentListInfo ToTAInfo; if (Error Err = ImportTemplateArgumentListInfo( E->getLAngleLoc(), E->getRAngleLoc(), E->template_arguments(), ToTAInfo)) return std::move(Err); ExpectedSLoc ToTemplateKeywordLocOrErr = import(E->getTemplateKeywordLoc()); if (!ToTemplateKeywordLocOrErr) return ToTemplateKeywordLocOrErr.takeError(); return UnresolvedLookupExpr::Create( Importer.getToContext(), *ToNamingClassOrErr, *ToQualifierLocOrErr, *ToTemplateKeywordLocOrErr, ToNameInfo, E->requiresADL(), &ToTAInfo, ToDecls.begin(), ToDecls.end()); } return UnresolvedLookupExpr::Create( Importer.getToContext(), *ToNamingClassOrErr, *ToQualifierLocOrErr, ToNameInfo, E->requiresADL(), E->isOverloaded(), ToDecls.begin(), ToDecls.end()); } ExpectedStmt ASTNodeImporter::VisitUnresolvedMemberExpr(UnresolvedMemberExpr *E) { auto Imp1 = importSeq( E->getType(), E->getOperatorLoc(), E->getQualifierLoc(), E->getTemplateKeywordLoc()); if (!Imp1) return Imp1.takeError(); QualType ToType; SourceLocation ToOperatorLoc, ToTemplateKeywordLoc; NestedNameSpecifierLoc ToQualifierLoc; std::tie(ToType, ToOperatorLoc, ToQualifierLoc, ToTemplateKeywordLoc) = *Imp1; auto Imp2 = importSeq(E->getName(), E->getNameLoc()); if (!Imp2) return Imp2.takeError(); DeclarationNameInfo ToNameInfo(std::get<0>(*Imp2), std::get<1>(*Imp2)); // Import additional name location/type info. if (Error Err = ImportDeclarationNameLoc(E->getNameInfo(), ToNameInfo)) return std::move(Err); UnresolvedSet<8> ToDecls; for (Decl *D : E->decls()) if (auto ToDOrErr = import(D)) ToDecls.addDecl(cast(*ToDOrErr)); else return ToDOrErr.takeError(); TemplateArgumentListInfo ToTAInfo; TemplateArgumentListInfo *ResInfo = nullptr; if (E->hasExplicitTemplateArgs()) { TemplateArgumentListInfo FromTAInfo; E->copyTemplateArgumentsInto(FromTAInfo); if (Error Err = ImportTemplateArgumentListInfo(FromTAInfo, ToTAInfo)) return std::move(Err); ResInfo = &ToTAInfo; } Expr *ToBase = nullptr; if (!E->isImplicitAccess()) { if (ExpectedExpr ToBaseOrErr = import(E->getBase())) ToBase = *ToBaseOrErr; else return ToBaseOrErr.takeError(); } return UnresolvedMemberExpr::Create( Importer.getToContext(), E->hasUnresolvedUsing(), ToBase, ToType, E->isArrow(), ToOperatorLoc, ToQualifierLoc, ToTemplateKeywordLoc, ToNameInfo, ResInfo, ToDecls.begin(), ToDecls.end()); } ExpectedStmt ASTNodeImporter::VisitCallExpr(CallExpr *E) { auto Imp = importSeq(E->getCallee(), E->getType(), E->getRParenLoc()); if (!Imp) return Imp.takeError(); Expr *ToCallee; QualType ToType; SourceLocation ToRParenLoc; std::tie(ToCallee, ToType, ToRParenLoc) = *Imp; unsigned NumArgs = E->getNumArgs(); llvm::SmallVector ToArgs(NumArgs); if (Error Err = ImportContainerChecked(E->arguments(), ToArgs)) return std::move(Err); if (const auto *OCE = dyn_cast(E)) { return CXXOperatorCallExpr::Create( Importer.getToContext(), OCE->getOperator(), ToCallee, ToArgs, ToType, OCE->getValueKind(), ToRParenLoc, OCE->getFPFeatures(), OCE->getADLCallKind()); } return CallExpr::Create(Importer.getToContext(), ToCallee, ToArgs, ToType, E->getValueKind(), ToRParenLoc, /*MinNumArgs=*/0, E->getADLCallKind()); } ExpectedStmt ASTNodeImporter::VisitLambdaExpr(LambdaExpr *E) { CXXRecordDecl *FromClass = E->getLambdaClass(); auto ToClassOrErr = import(FromClass); if (!ToClassOrErr) return ToClassOrErr.takeError(); CXXRecordDecl *ToClass = *ToClassOrErr; auto ToCallOpOrErr = import(E->getCallOperator()); if (!ToCallOpOrErr) return ToCallOpOrErr.takeError(); SmallVector ToCaptures; ToCaptures.reserve(E->capture_size()); for (const auto &FromCapture : E->captures()) { if (auto ToCaptureOrErr = import(FromCapture)) ToCaptures.push_back(*ToCaptureOrErr); else return ToCaptureOrErr.takeError(); } SmallVector ToCaptureInits(E->capture_size()); if (Error Err = ImportContainerChecked(E->capture_inits(), ToCaptureInits)) return std::move(Err); auto Imp = importSeq( E->getIntroducerRange(), E->getCaptureDefaultLoc(), E->getEndLoc()); if (!Imp) return Imp.takeError(); SourceRange ToIntroducerRange; SourceLocation ToCaptureDefaultLoc, ToEndLoc; std::tie(ToIntroducerRange, ToCaptureDefaultLoc, ToEndLoc) = *Imp; return LambdaExpr::Create( Importer.getToContext(), ToClass, ToIntroducerRange, E->getCaptureDefault(), ToCaptureDefaultLoc, ToCaptures, E->hasExplicitParameters(), E->hasExplicitResultType(), ToCaptureInits, ToEndLoc, E->containsUnexpandedParameterPack()); } ExpectedStmt ASTNodeImporter::VisitInitListExpr(InitListExpr *E) { auto Imp = importSeq(E->getLBraceLoc(), E->getRBraceLoc(), E->getType()); if (!Imp) return Imp.takeError(); SourceLocation ToLBraceLoc, ToRBraceLoc; QualType ToType; std::tie(ToLBraceLoc, ToRBraceLoc, ToType) = *Imp; SmallVector ToExprs(E->getNumInits()); if (Error Err = ImportContainerChecked(E->inits(), ToExprs)) return std::move(Err); ASTContext &ToCtx = Importer.getToContext(); InitListExpr *To = new (ToCtx) InitListExpr( ToCtx, ToLBraceLoc, ToExprs, ToRBraceLoc); To->setType(ToType); if (E->hasArrayFiller()) { if (ExpectedExpr ToFillerOrErr = import(E->getArrayFiller())) To->setArrayFiller(*ToFillerOrErr); else return ToFillerOrErr.takeError(); } if (FieldDecl *FromFD = E->getInitializedFieldInUnion()) { if (auto ToFDOrErr = import(FromFD)) To->setInitializedFieldInUnion(*ToFDOrErr); else return ToFDOrErr.takeError(); } if (InitListExpr *SyntForm = E->getSyntacticForm()) { if (auto ToSyntFormOrErr = import(SyntForm)) To->setSyntacticForm(*ToSyntFormOrErr); else return ToSyntFormOrErr.takeError(); } // Copy InitListExprBitfields, which are not handled in the ctor of // InitListExpr. To->sawArrayRangeDesignator(E->hadArrayRangeDesignator()); return To; } ExpectedStmt ASTNodeImporter::VisitCXXStdInitializerListExpr( CXXStdInitializerListExpr *E) { ExpectedType ToTypeOrErr = import(E->getType()); if (!ToTypeOrErr) return ToTypeOrErr.takeError(); ExpectedExpr ToSubExprOrErr = import(E->getSubExpr()); if (!ToSubExprOrErr) return ToSubExprOrErr.takeError(); return new (Importer.getToContext()) CXXStdInitializerListExpr( *ToTypeOrErr, *ToSubExprOrErr); } ExpectedStmt ASTNodeImporter::VisitCXXInheritedCtorInitExpr( CXXInheritedCtorInitExpr *E) { auto Imp = importSeq(E->getLocation(), E->getType(), E->getConstructor()); if (!Imp) return Imp.takeError(); SourceLocation ToLocation; QualType ToType; CXXConstructorDecl *ToConstructor; std::tie(ToLocation, ToType, ToConstructor) = *Imp; return new (Importer.getToContext()) CXXInheritedCtorInitExpr( ToLocation, ToType, ToConstructor, E->constructsVBase(), E->inheritedFromVBase()); } ExpectedStmt ASTNodeImporter::VisitArrayInitLoopExpr(ArrayInitLoopExpr *E) { auto Imp = importSeq(E->getType(), E->getCommonExpr(), E->getSubExpr()); if (!Imp) return Imp.takeError(); QualType ToType; Expr *ToCommonExpr, *ToSubExpr; std::tie(ToType, ToCommonExpr, ToSubExpr) = *Imp; return new (Importer.getToContext()) ArrayInitLoopExpr( ToType, ToCommonExpr, ToSubExpr); } ExpectedStmt ASTNodeImporter::VisitArrayInitIndexExpr(ArrayInitIndexExpr *E) { ExpectedType ToTypeOrErr = import(E->getType()); if (!ToTypeOrErr) return ToTypeOrErr.takeError(); return new (Importer.getToContext()) ArrayInitIndexExpr(*ToTypeOrErr); } ExpectedStmt ASTNodeImporter::VisitCXXDefaultInitExpr(CXXDefaultInitExpr *E) { ExpectedSLoc ToBeginLocOrErr = import(E->getBeginLoc()); if (!ToBeginLocOrErr) return ToBeginLocOrErr.takeError(); auto ToFieldOrErr = import(E->getField()); if (!ToFieldOrErr) return ToFieldOrErr.takeError(); auto UsedContextOrErr = Importer.ImportContext(E->getUsedContext()); if (!UsedContextOrErr) return UsedContextOrErr.takeError(); return CXXDefaultInitExpr::Create( Importer.getToContext(), *ToBeginLocOrErr, *ToFieldOrErr, *UsedContextOrErr); } ExpectedStmt ASTNodeImporter::VisitCXXNamedCastExpr(CXXNamedCastExpr *E) { auto Imp = importSeq( E->getType(), E->getSubExpr(), E->getTypeInfoAsWritten(), E->getOperatorLoc(), E->getRParenLoc(), E->getAngleBrackets()); if (!Imp) return Imp.takeError(); QualType ToType; Expr *ToSubExpr; TypeSourceInfo *ToTypeInfoAsWritten; SourceLocation ToOperatorLoc, ToRParenLoc; SourceRange ToAngleBrackets; std::tie( ToType, ToSubExpr, ToTypeInfoAsWritten, ToOperatorLoc, ToRParenLoc, ToAngleBrackets) = *Imp; ExprValueKind VK = E->getValueKind(); CastKind CK = E->getCastKind(); auto ToBasePathOrErr = ImportCastPath(E); if (!ToBasePathOrErr) return ToBasePathOrErr.takeError(); if (isa(E)) { return CXXStaticCastExpr::Create( Importer.getToContext(), ToType, VK, CK, ToSubExpr, &(*ToBasePathOrErr), ToTypeInfoAsWritten, ToOperatorLoc, ToRParenLoc, ToAngleBrackets); } else if (isa(E)) { return CXXDynamicCastExpr::Create( Importer.getToContext(), ToType, VK, CK, ToSubExpr, &(*ToBasePathOrErr), ToTypeInfoAsWritten, ToOperatorLoc, ToRParenLoc, ToAngleBrackets); } else if (isa(E)) { return CXXReinterpretCastExpr::Create( Importer.getToContext(), ToType, VK, CK, ToSubExpr, &(*ToBasePathOrErr), ToTypeInfoAsWritten, ToOperatorLoc, ToRParenLoc, ToAngleBrackets); } else if (isa(E)) { return CXXConstCastExpr::Create( Importer.getToContext(), ToType, VK, ToSubExpr, ToTypeInfoAsWritten, ToOperatorLoc, ToRParenLoc, ToAngleBrackets); } else { llvm_unreachable("Unknown cast type"); return make_error(); } } ExpectedStmt ASTNodeImporter::VisitSubstNonTypeTemplateParmExpr( SubstNonTypeTemplateParmExpr *E) { auto Imp = importSeq( E->getType(), E->getExprLoc(), E->getParameter(), E->getReplacement()); if (!Imp) return Imp.takeError(); QualType ToType; SourceLocation ToExprLoc; NonTypeTemplateParmDecl *ToParameter; Expr *ToReplacement; std::tie(ToType, ToExprLoc, ToParameter, ToReplacement) = *Imp; return new (Importer.getToContext()) SubstNonTypeTemplateParmExpr( ToType, E->getValueKind(), ToExprLoc, ToParameter, ToReplacement); } ExpectedStmt ASTNodeImporter::VisitTypeTraitExpr(TypeTraitExpr *E) { auto Imp = importSeq( E->getType(), E->getBeginLoc(), E->getEndLoc()); if (!Imp) return Imp.takeError(); QualType ToType; SourceLocation ToBeginLoc, ToEndLoc; std::tie(ToType, ToBeginLoc, ToEndLoc) = *Imp; SmallVector ToArgs(E->getNumArgs()); if (Error Err = ImportContainerChecked(E->getArgs(), ToArgs)) return std::move(Err); // According to Sema::BuildTypeTrait(), if E is value-dependent, // Value is always false. bool ToValue = (E->isValueDependent() ? false : E->getValue()); return TypeTraitExpr::Create( Importer.getToContext(), ToType, ToBeginLoc, E->getTrait(), ToArgs, ToEndLoc, ToValue); } ExpectedStmt ASTNodeImporter::VisitCXXTypeidExpr(CXXTypeidExpr *E) { ExpectedType ToTypeOrErr = import(E->getType()); if (!ToTypeOrErr) return ToTypeOrErr.takeError(); auto ToSourceRangeOrErr = import(E->getSourceRange()); if (!ToSourceRangeOrErr) return ToSourceRangeOrErr.takeError(); if (E->isTypeOperand()) { if (auto ToTSIOrErr = import(E->getTypeOperandSourceInfo())) return new (Importer.getToContext()) CXXTypeidExpr( *ToTypeOrErr, *ToTSIOrErr, *ToSourceRangeOrErr); else return ToTSIOrErr.takeError(); } ExpectedExpr ToExprOperandOrErr = import(E->getExprOperand()); if (!ToExprOperandOrErr) return ToExprOperandOrErr.takeError(); return new (Importer.getToContext()) CXXTypeidExpr( *ToTypeOrErr, *ToExprOperandOrErr, *ToSourceRangeOrErr); } Error ASTNodeImporter::ImportOverriddenMethods(CXXMethodDecl *ToMethod, CXXMethodDecl *FromMethod) { Error ImportErrors = Error::success(); for (auto *FromOverriddenMethod : FromMethod->overridden_methods()) { if (auto ImportedOrErr = import(FromOverriddenMethod)) ToMethod->getCanonicalDecl()->addOverriddenMethod(cast( (*ImportedOrErr)->getCanonicalDecl())); else ImportErrors = joinErrors(std::move(ImportErrors), ImportedOrErr.takeError()); } return ImportErrors; } ASTImporter::ASTImporter(ASTContext &ToContext, FileManager &ToFileManager, ASTContext &FromContext, FileManager &FromFileManager, bool MinimalImport, std::shared_ptr SharedState) : SharedState(SharedState), ToContext(ToContext), FromContext(FromContext), ToFileManager(ToFileManager), FromFileManager(FromFileManager), Minimal(MinimalImport), ODRHandling(ODRHandlingType::Conservative) { // Create a default state without the lookup table: LLDB case. if (!SharedState) { this->SharedState = std::make_shared(); } ImportedDecls[FromContext.getTranslationUnitDecl()] = ToContext.getTranslationUnitDecl(); } ASTImporter::~ASTImporter() = default; Optional ASTImporter::getFieldIndex(Decl *F) { assert(F && (isa(*F) || isa(*F)) && "Try to get field index for non-field."); auto *Owner = dyn_cast(F->getDeclContext()); if (!Owner) return None; unsigned Index = 0; for (const auto *D : Owner->decls()) { if (D == F) return Index; if (isa(*D) || isa(*D)) ++Index; } llvm_unreachable("Field was not found in its parent context."); return None; } ASTImporter::FoundDeclsTy ASTImporter::findDeclsInToCtx(DeclContext *DC, DeclarationName Name) { // We search in the redecl context because of transparent contexts. // E.g. a simple C language enum is a transparent context: // enum E { A, B }; // Now if we had a global variable in the TU // int A; // then the enum constant 'A' and the variable 'A' violates ODR. // We can diagnose this only if we search in the redecl context. DeclContext *ReDC = DC->getRedeclContext(); if (SharedState->getLookupTable()) { ASTImporterLookupTable::LookupResult LookupResult = SharedState->getLookupTable()->lookup(ReDC, Name); return FoundDeclsTy(LookupResult.begin(), LookupResult.end()); } else { DeclContext::lookup_result NoloadLookupResult = ReDC->noload_lookup(Name); FoundDeclsTy Result(NoloadLookupResult.begin(), NoloadLookupResult.end()); // We must search by the slow case of localUncachedLookup because that is // working even if there is no LookupPtr for the DC. We could use // DC::buildLookup() to create the LookupPtr, but that would load external // decls again, we must avoid that case. // Also, even if we had the LookupPtr, we must find Decls which are not // in the LookupPtr, so we need the slow case. // These cases are handled in ASTImporterLookupTable, but we cannot use // that with LLDB since that traverses through the AST which initiates the // load of external decls again via DC::decls(). And again, we must avoid // loading external decls during the import. if (Result.empty()) ReDC->localUncachedLookup(Name, Result); return Result; } } void ASTImporter::AddToLookupTable(Decl *ToD) { SharedState->addDeclToLookup(ToD); } Expected ASTImporter::ImportImpl(Decl *FromD) { // Import the decl using ASTNodeImporter. ASTNodeImporter Importer(*this); return Importer.Visit(FromD); } void ASTImporter::RegisterImportedDecl(Decl *FromD, Decl *ToD) { MapImported(FromD, ToD); } Expected ASTImporter::Import(QualType FromT) { if (FromT.isNull()) return QualType{}; const Type *FromTy = FromT.getTypePtr(); // Check whether we've already imported this type. llvm::DenseMap::iterator Pos = ImportedTypes.find(FromTy); if (Pos != ImportedTypes.end()) return ToContext.getQualifiedType(Pos->second, FromT.getLocalQualifiers()); // Import the type ASTNodeImporter Importer(*this); ExpectedType ToTOrErr = Importer.Visit(FromTy); if (!ToTOrErr) return ToTOrErr.takeError(); // Record the imported type. ImportedTypes[FromTy] = (*ToTOrErr).getTypePtr(); return ToContext.getQualifiedType(*ToTOrErr, FromT.getLocalQualifiers()); } Expected ASTImporter::Import(TypeSourceInfo *FromTSI) { if (!FromTSI) return FromTSI; // FIXME: For now we just create a "trivial" type source info based // on the type and a single location. Implement a real version of this. ExpectedType TOrErr = Import(FromTSI->getType()); if (!TOrErr) return TOrErr.takeError(); ExpectedSLoc BeginLocOrErr = Import(FromTSI->getTypeLoc().getBeginLoc()); if (!BeginLocOrErr) return BeginLocOrErr.takeError(); return ToContext.getTrivialTypeSourceInfo(*TOrErr, *BeginLocOrErr); } Expected ASTImporter::Import(const Attr *FromAttr) { Attr *ToAttr = FromAttr->clone(ToContext); if (auto ToRangeOrErr = Import(FromAttr->getRange())) ToAttr->setRange(*ToRangeOrErr); else return ToRangeOrErr.takeError(); return ToAttr; } Decl *ASTImporter::GetAlreadyImportedOrNull(const Decl *FromD) const { auto Pos = ImportedDecls.find(FromD); if (Pos != ImportedDecls.end()) return Pos->second; else return nullptr; } TranslationUnitDecl *ASTImporter::GetFromTU(Decl *ToD) { auto FromDPos = ImportedFromDecls.find(ToD); if (FromDPos == ImportedFromDecls.end()) return nullptr; return FromDPos->second->getTranslationUnitDecl(); } Expected ASTImporter::Import(Decl *FromD) { if (!FromD) return nullptr; // Push FromD to the stack, and remove that when we return. ImportPath.push(FromD); auto ImportPathBuilder = llvm::make_scope_exit([this]() { ImportPath.pop(); }); // Check whether there was a previous failed import. // If yes return the existing error. if (auto Error = getImportDeclErrorIfAny(FromD)) return make_error(*Error); // Check whether we've already imported this declaration. Decl *ToD = GetAlreadyImportedOrNull(FromD); if (ToD) { // Already imported (possibly from another TU) and with an error. if (auto Error = SharedState->getImportDeclErrorIfAny(ToD)) { setImportDeclError(FromD, *Error); return make_error(*Error); } // If FromD has some updated flags after last import, apply it updateFlags(FromD, ToD); // If we encounter a cycle during an import then we save the relevant part // of the import path associated to the Decl. if (ImportPath.hasCycleAtBack()) SavedImportPaths[FromD].push_back(ImportPath.copyCycleAtBack()); return ToD; } // Import the declaration. ExpectedDecl ToDOrErr = ImportImpl(FromD); if (!ToDOrErr) { // Failed to import. auto Pos = ImportedDecls.find(FromD); if (Pos != ImportedDecls.end()) { // Import failed after the object was created. // Remove all references to it. auto *ToD = Pos->second; ImportedDecls.erase(Pos); // ImportedDecls and ImportedFromDecls are not symmetric. It may happen // (e.g. with namespaces) that several decls from the 'from' context are // mapped to the same decl in the 'to' context. If we removed entries // from the LookupTable here then we may end up removing them multiple // times. // The Lookuptable contains decls only which are in the 'to' context. // Remove from the Lookuptable only if it is *imported* into the 'to' // context (and do not remove it if it was added during the initial // traverse of the 'to' context). auto PosF = ImportedFromDecls.find(ToD); if (PosF != ImportedFromDecls.end()) { SharedState->removeDeclFromLookup(ToD); ImportedFromDecls.erase(PosF); } // FIXME: AST may contain remaining references to the failed object. // However, the ImportDeclErrors in the shared state contains all the // failed objects together with their error. } // Error encountered for the first time. // After takeError the error is not usable any more in ToDOrErr. // Get a copy of the error object (any more simple solution for this?). ImportError ErrOut; handleAllErrors(ToDOrErr.takeError(), [&ErrOut](const ImportError &E) { ErrOut = E; }); setImportDeclError(FromD, ErrOut); // Set the error for the mapped to Decl, which is in the "to" context. if (Pos != ImportedDecls.end()) SharedState->setImportDeclError(Pos->second, ErrOut); // Set the error for all nodes which have been created before we // recognized the error. for (const auto &Path : SavedImportPaths[FromD]) for (Decl *FromDi : Path) { setImportDeclError(FromDi, ErrOut); //FIXME Should we remove these Decls from ImportedDecls? // Set the error for the mapped to Decl, which is in the "to" context. auto Ii = ImportedDecls.find(FromDi); if (Ii != ImportedDecls.end()) SharedState->setImportDeclError(Ii->second, ErrOut); // FIXME Should we remove these Decls from the LookupTable, // and from ImportedFromDecls? } SavedImportPaths[FromD].clear(); // Do not return ToDOrErr, error was taken out of it. return make_error(ErrOut); } ToD = *ToDOrErr; // FIXME: Handle the "already imported with error" case. We can get here // nullptr only if GetImportedOrCreateDecl returned nullptr (after a // previously failed create was requested). // Later GetImportedOrCreateDecl can be updated to return the error. if (!ToD) { auto Err = getImportDeclErrorIfAny(FromD); assert(Err); return make_error(*Err); } // We could import from the current TU without error. But previously we // already had imported a Decl as `ToD` from another TU (with another // ASTImporter object) and with an error. if (auto Error = SharedState->getImportDeclErrorIfAny(ToD)) { setImportDeclError(FromD, *Error); return make_error(*Error); } // Make sure that ImportImpl registered the imported decl. assert(ImportedDecls.count(FromD) != 0 && "Missing call to MapImported?"); // Notify subclasses. Imported(FromD, ToD); updateFlags(FromD, ToD); SavedImportPaths[FromD].clear(); return ToDOrErr; } Expected ASTImporter::ImportContext(DeclContext *FromDC) { if (!FromDC) return FromDC; ExpectedDecl ToDCOrErr = Import(cast(FromDC)); if (!ToDCOrErr) return ToDCOrErr.takeError(); auto *ToDC = cast(*ToDCOrErr); // When we're using a record/enum/Objective-C class/protocol as a context, we // need it to have a definition. if (auto *ToRecord = dyn_cast(ToDC)) { auto *FromRecord = cast(FromDC); if (ToRecord->isCompleteDefinition()) { // Do nothing. } else if (FromRecord->isCompleteDefinition()) { if (Error Err = ASTNodeImporter(*this).ImportDefinition( FromRecord, ToRecord, ASTNodeImporter::IDK_Basic)) return std::move(Err); } else { CompleteDecl(ToRecord); } } else if (auto *ToEnum = dyn_cast(ToDC)) { auto *FromEnum = cast(FromDC); if (ToEnum->isCompleteDefinition()) { // Do nothing. } else if (FromEnum->isCompleteDefinition()) { if (Error Err = ASTNodeImporter(*this).ImportDefinition( FromEnum, ToEnum, ASTNodeImporter::IDK_Basic)) return std::move(Err); } else { CompleteDecl(ToEnum); } } else if (auto *ToClass = dyn_cast(ToDC)) { auto *FromClass = cast(FromDC); if (ToClass->getDefinition()) { // Do nothing. } else if (ObjCInterfaceDecl *FromDef = FromClass->getDefinition()) { if (Error Err = ASTNodeImporter(*this).ImportDefinition( FromDef, ToClass, ASTNodeImporter::IDK_Basic)) return std::move(Err); } else { CompleteDecl(ToClass); } } else if (auto *ToProto = dyn_cast(ToDC)) { auto *FromProto = cast(FromDC); if (ToProto->getDefinition()) { // Do nothing. } else if (ObjCProtocolDecl *FromDef = FromProto->getDefinition()) { if (Error Err = ASTNodeImporter(*this).ImportDefinition( FromDef, ToProto, ASTNodeImporter::IDK_Basic)) return std::move(Err); } else { CompleteDecl(ToProto); } } return ToDC; } Expected ASTImporter::Import(Expr *FromE) { if (ExpectedStmt ToSOrErr = Import(cast_or_null(FromE))) return cast_or_null(*ToSOrErr); else return ToSOrErr.takeError(); } Expected ASTImporter::Import(Stmt *FromS) { if (!FromS) return nullptr; // Check whether we've already imported this statement. llvm::DenseMap::iterator Pos = ImportedStmts.find(FromS); if (Pos != ImportedStmts.end()) return Pos->second; // Import the statement. ASTNodeImporter Importer(*this); ExpectedStmt ToSOrErr = Importer.Visit(FromS); if (!ToSOrErr) return ToSOrErr; if (auto *ToE = dyn_cast(*ToSOrErr)) { auto *FromE = cast(FromS); // Copy ExprBitfields, which may not be handled in Expr subclasses // constructors. ToE->setValueKind(FromE->getValueKind()); ToE->setObjectKind(FromE->getObjectKind()); ToE->setTypeDependent(FromE->isTypeDependent()); ToE->setValueDependent(FromE->isValueDependent()); ToE->setInstantiationDependent(FromE->isInstantiationDependent()); ToE->setContainsUnexpandedParameterPack( FromE->containsUnexpandedParameterPack()); } // Record the imported statement object. ImportedStmts[FromS] = *ToSOrErr; return ToSOrErr; } Expected ASTImporter::Import(NestedNameSpecifier *FromNNS) { if (!FromNNS) return nullptr; NestedNameSpecifier *Prefix = nullptr; if (Error Err = importInto(Prefix, FromNNS->getPrefix())) return std::move(Err); switch (FromNNS->getKind()) { case NestedNameSpecifier::Identifier: assert(FromNNS->getAsIdentifier() && "NNS should contain identifier."); return NestedNameSpecifier::Create(ToContext, Prefix, Import(FromNNS->getAsIdentifier())); case NestedNameSpecifier::Namespace: if (ExpectedDecl NSOrErr = Import(FromNNS->getAsNamespace())) { return NestedNameSpecifier::Create(ToContext, Prefix, cast(*NSOrErr)); } else return NSOrErr.takeError(); case NestedNameSpecifier::NamespaceAlias: if (ExpectedDecl NSADOrErr = Import(FromNNS->getAsNamespaceAlias())) return NestedNameSpecifier::Create(ToContext, Prefix, cast(*NSADOrErr)); else return NSADOrErr.takeError(); case NestedNameSpecifier::Global: return NestedNameSpecifier::GlobalSpecifier(ToContext); case NestedNameSpecifier::Super: if (ExpectedDecl RDOrErr = Import(FromNNS->getAsRecordDecl())) return NestedNameSpecifier::SuperSpecifier(ToContext, cast(*RDOrErr)); else return RDOrErr.takeError(); case NestedNameSpecifier::TypeSpec: case NestedNameSpecifier::TypeSpecWithTemplate: if (Expected TyOrErr = Import(QualType(FromNNS->getAsType(), 0u))) { bool TSTemplate = FromNNS->getKind() == NestedNameSpecifier::TypeSpecWithTemplate; return NestedNameSpecifier::Create(ToContext, Prefix, TSTemplate, TyOrErr->getTypePtr()); } else { return TyOrErr.takeError(); } } llvm_unreachable("Invalid nested name specifier kind"); } Expected ASTImporter::Import(NestedNameSpecifierLoc FromNNS) { // Copied from NestedNameSpecifier mostly. SmallVector NestedNames; NestedNameSpecifierLoc NNS = FromNNS; // Push each of the nested-name-specifiers's onto a stack for // serialization in reverse order. while (NNS) { NestedNames.push_back(NNS); NNS = NNS.getPrefix(); } NestedNameSpecifierLocBuilder Builder; while (!NestedNames.empty()) { NNS = NestedNames.pop_back_val(); NestedNameSpecifier *Spec = nullptr; if (Error Err = importInto(Spec, NNS.getNestedNameSpecifier())) return std::move(Err); NestedNameSpecifier::SpecifierKind Kind = Spec->getKind(); SourceLocation ToLocalBeginLoc, ToLocalEndLoc; if (Kind != NestedNameSpecifier::Super) { if (Error Err = importInto(ToLocalBeginLoc, NNS.getLocalBeginLoc())) return std::move(Err); if (Kind != NestedNameSpecifier::Global) if (Error Err = importInto(ToLocalEndLoc, NNS.getLocalEndLoc())) return std::move(Err); } switch (Kind) { case NestedNameSpecifier::Identifier: Builder.Extend(getToContext(), Spec->getAsIdentifier(), ToLocalBeginLoc, ToLocalEndLoc); break; case NestedNameSpecifier::Namespace: Builder.Extend(getToContext(), Spec->getAsNamespace(), ToLocalBeginLoc, ToLocalEndLoc); break; case NestedNameSpecifier::NamespaceAlias: Builder.Extend(getToContext(), Spec->getAsNamespaceAlias(), ToLocalBeginLoc, ToLocalEndLoc); break; case NestedNameSpecifier::TypeSpec: case NestedNameSpecifier::TypeSpecWithTemplate: { SourceLocation ToTLoc; if (Error Err = importInto(ToTLoc, NNS.getTypeLoc().getBeginLoc())) return std::move(Err); TypeSourceInfo *TSI = getToContext().getTrivialTypeSourceInfo( QualType(Spec->getAsType(), 0), ToTLoc); if (Kind == NestedNameSpecifier::TypeSpecWithTemplate) // ToLocalBeginLoc is here the location of the 'template' keyword. Builder.Extend(getToContext(), ToLocalBeginLoc, TSI->getTypeLoc(), ToLocalEndLoc); else // No location for 'template' keyword here. Builder.Extend(getToContext(), SourceLocation{}, TSI->getTypeLoc(), ToLocalEndLoc); break; } case NestedNameSpecifier::Global: Builder.MakeGlobal(getToContext(), ToLocalBeginLoc); break; case NestedNameSpecifier::Super: { auto ToSourceRangeOrErr = Import(NNS.getSourceRange()); if (!ToSourceRangeOrErr) return ToSourceRangeOrErr.takeError(); Builder.MakeSuper(getToContext(), Spec->getAsRecordDecl(), ToSourceRangeOrErr->getBegin(), ToSourceRangeOrErr->getEnd()); } } } return Builder.getWithLocInContext(getToContext()); } Expected ASTImporter::Import(TemplateName From) { switch (From.getKind()) { case TemplateName::Template: if (ExpectedDecl ToTemplateOrErr = Import(From.getAsTemplateDecl())) return TemplateName(cast(*ToTemplateOrErr)); else return ToTemplateOrErr.takeError(); case TemplateName::OverloadedTemplate: { OverloadedTemplateStorage *FromStorage = From.getAsOverloadedTemplate(); UnresolvedSet<2> ToTemplates; for (auto *I : *FromStorage) { if (auto ToOrErr = Import(I)) ToTemplates.addDecl(cast(*ToOrErr)); else return ToOrErr.takeError(); } return ToContext.getOverloadedTemplateName(ToTemplates.begin(), ToTemplates.end()); } case TemplateName::AssumedTemplate: { AssumedTemplateStorage *FromStorage = From.getAsAssumedTemplateName(); auto DeclNameOrErr = Import(FromStorage->getDeclName()); if (!DeclNameOrErr) return DeclNameOrErr.takeError(); return ToContext.getAssumedTemplateName(*DeclNameOrErr); } case TemplateName::QualifiedTemplate: { QualifiedTemplateName *QTN = From.getAsQualifiedTemplateName(); auto QualifierOrErr = Import(QTN->getQualifier()); if (!QualifierOrErr) return QualifierOrErr.takeError(); if (ExpectedDecl ToTemplateOrErr = Import(From.getAsTemplateDecl())) return ToContext.getQualifiedTemplateName( *QualifierOrErr, QTN->hasTemplateKeyword(), cast(*ToTemplateOrErr)); else return ToTemplateOrErr.takeError(); } case TemplateName::DependentTemplate: { DependentTemplateName *DTN = From.getAsDependentTemplateName(); auto QualifierOrErr = Import(DTN->getQualifier()); if (!QualifierOrErr) return QualifierOrErr.takeError(); if (DTN->isIdentifier()) { return ToContext.getDependentTemplateName(*QualifierOrErr, Import(DTN->getIdentifier())); } return ToContext.getDependentTemplateName(*QualifierOrErr, DTN->getOperator()); } case TemplateName::SubstTemplateTemplateParm: { SubstTemplateTemplateParmStorage *Subst = From.getAsSubstTemplateTemplateParm(); ExpectedDecl ParamOrErr = Import(Subst->getParameter()); if (!ParamOrErr) return ParamOrErr.takeError(); auto ReplacementOrErr = Import(Subst->getReplacement()); if (!ReplacementOrErr) return ReplacementOrErr.takeError(); return ToContext.getSubstTemplateTemplateParm( cast(*ParamOrErr), *ReplacementOrErr); } case TemplateName::SubstTemplateTemplateParmPack: { SubstTemplateTemplateParmPackStorage *SubstPack = From.getAsSubstTemplateTemplateParmPack(); ExpectedDecl ParamOrErr = Import(SubstPack->getParameterPack()); if (!ParamOrErr) return ParamOrErr.takeError(); ASTNodeImporter Importer(*this); auto ArgPackOrErr = Importer.ImportTemplateArgument(SubstPack->getArgumentPack()); if (!ArgPackOrErr) return ArgPackOrErr.takeError(); return ToContext.getSubstTemplateTemplateParmPack( cast(*ParamOrErr), *ArgPackOrErr); } } llvm_unreachable("Invalid template name kind"); } Expected ASTImporter::Import(SourceLocation FromLoc) { if (FromLoc.isInvalid()) return SourceLocation{}; SourceManager &FromSM = FromContext.getSourceManager(); bool IsBuiltin = FromSM.isWrittenInBuiltinFile(FromLoc); std::pair Decomposed = FromSM.getDecomposedLoc(FromLoc); Expected ToFileIDOrErr = Import(Decomposed.first, IsBuiltin); if (!ToFileIDOrErr) return ToFileIDOrErr.takeError(); SourceManager &ToSM = ToContext.getSourceManager(); return ToSM.getComposedLoc(*ToFileIDOrErr, Decomposed.second); } Expected ASTImporter::Import(SourceRange FromRange) { SourceLocation ToBegin, ToEnd; if (Error Err = importInto(ToBegin, FromRange.getBegin())) return std::move(Err); if (Error Err = importInto(ToEnd, FromRange.getEnd())) return std::move(Err); return SourceRange(ToBegin, ToEnd); } Expected ASTImporter::Import(FileID FromID, bool IsBuiltin) { llvm::DenseMap::iterator Pos = ImportedFileIDs.find(FromID); if (Pos != ImportedFileIDs.end()) return Pos->second; SourceManager &FromSM = FromContext.getSourceManager(); SourceManager &ToSM = ToContext.getSourceManager(); const SrcMgr::SLocEntry &FromSLoc = FromSM.getSLocEntry(FromID); // Map the FromID to the "to" source manager. FileID ToID; if (FromSLoc.isExpansion()) { const SrcMgr::ExpansionInfo &FromEx = FromSLoc.getExpansion(); ExpectedSLoc ToSpLoc = Import(FromEx.getSpellingLoc()); if (!ToSpLoc) return ToSpLoc.takeError(); ExpectedSLoc ToExLocS = Import(FromEx.getExpansionLocStart()); if (!ToExLocS) return ToExLocS.takeError(); unsigned TokenLen = FromSM.getFileIDSize(FromID); SourceLocation MLoc; if (FromEx.isMacroArgExpansion()) { MLoc = ToSM.createMacroArgExpansionLoc(*ToSpLoc, *ToExLocS, TokenLen); } else { if (ExpectedSLoc ToExLocE = Import(FromEx.getExpansionLocEnd())) MLoc = ToSM.createExpansionLoc(*ToSpLoc, *ToExLocS, *ToExLocE, TokenLen, FromEx.isExpansionTokenRange()); else return ToExLocE.takeError(); } ToID = ToSM.getFileID(MLoc); } else { const SrcMgr::ContentCache *Cache = FromSLoc.getFile().getContentCache(); if (!IsBuiltin) { // Include location of this file. ExpectedSLoc ToIncludeLoc = Import(FromSLoc.getFile().getIncludeLoc()); if (!ToIncludeLoc) return ToIncludeLoc.takeError(); if (Cache->OrigEntry && Cache->OrigEntry->getDir()) { // FIXME: We probably want to use getVirtualFile(), so we don't hit the // disk again // FIXME: We definitely want to re-use the existing MemoryBuffer, rather // than mmap the files several times. auto Entry = ToFileManager.getFile(Cache->OrigEntry->getName()); // FIXME: The filename may be a virtual name that does probably not // point to a valid file and we get no Entry here. In this case try with // the memory buffer below. if (Entry) ToID = ToSM.createFileID(*Entry, *ToIncludeLoc, FromSLoc.getFile().getFileCharacteristic()); } } if (ToID.isInvalid() || IsBuiltin) { // FIXME: We want to re-use the existing MemoryBuffer! bool Invalid = true; const llvm::MemoryBuffer *FromBuf = Cache->getBuffer(FromContext.getDiagnostics(), FromSM.getFileManager(), SourceLocation{}, &Invalid); if (!FromBuf || Invalid) // FIXME: Use a new error kind? return llvm::make_error(ImportError::Unknown); std::unique_ptr ToBuf = llvm::MemoryBuffer::getMemBufferCopy(FromBuf->getBuffer(), FromBuf->getBufferIdentifier()); ToID = ToSM.createFileID(std::move(ToBuf), FromSLoc.getFile().getFileCharacteristic()); } } assert(ToID.isValid() && "Unexpected invalid fileID was created."); ImportedFileIDs[FromID] = ToID; if (FileIDImportHandler) FileIDImportHandler(ToID, FromID); return ToID; } Expected ASTImporter::Import(CXXCtorInitializer *From) { ExpectedExpr ToExprOrErr = Import(From->getInit()); if (!ToExprOrErr) return ToExprOrErr.takeError(); auto LParenLocOrErr = Import(From->getLParenLoc()); if (!LParenLocOrErr) return LParenLocOrErr.takeError(); auto RParenLocOrErr = Import(From->getRParenLoc()); if (!RParenLocOrErr) return RParenLocOrErr.takeError(); if (From->isBaseInitializer()) { auto ToTInfoOrErr = Import(From->getTypeSourceInfo()); if (!ToTInfoOrErr) return ToTInfoOrErr.takeError(); SourceLocation EllipsisLoc; if (From->isPackExpansion()) if (Error Err = importInto(EllipsisLoc, From->getEllipsisLoc())) return std::move(Err); return new (ToContext) CXXCtorInitializer( ToContext, *ToTInfoOrErr, From->isBaseVirtual(), *LParenLocOrErr, *ToExprOrErr, *RParenLocOrErr, EllipsisLoc); } else if (From->isMemberInitializer()) { ExpectedDecl ToFieldOrErr = Import(From->getMember()); if (!ToFieldOrErr) return ToFieldOrErr.takeError(); auto MemberLocOrErr = Import(From->getMemberLocation()); if (!MemberLocOrErr) return MemberLocOrErr.takeError(); return new (ToContext) CXXCtorInitializer( ToContext, cast_or_null(*ToFieldOrErr), *MemberLocOrErr, *LParenLocOrErr, *ToExprOrErr, *RParenLocOrErr); } else if (From->isIndirectMemberInitializer()) { ExpectedDecl ToIFieldOrErr = Import(From->getIndirectMember()); if (!ToIFieldOrErr) return ToIFieldOrErr.takeError(); auto MemberLocOrErr = Import(From->getMemberLocation()); if (!MemberLocOrErr) return MemberLocOrErr.takeError(); return new (ToContext) CXXCtorInitializer( ToContext, cast_or_null(*ToIFieldOrErr), *MemberLocOrErr, *LParenLocOrErr, *ToExprOrErr, *RParenLocOrErr); } else if (From->isDelegatingInitializer()) { auto ToTInfoOrErr = Import(From->getTypeSourceInfo()); if (!ToTInfoOrErr) return ToTInfoOrErr.takeError(); return new (ToContext) CXXCtorInitializer(ToContext, *ToTInfoOrErr, *LParenLocOrErr, *ToExprOrErr, *RParenLocOrErr); } else { // FIXME: assert? return make_error(); } } Expected ASTImporter::Import(const CXXBaseSpecifier *BaseSpec) { auto Pos = ImportedCXXBaseSpecifiers.find(BaseSpec); if (Pos != ImportedCXXBaseSpecifiers.end()) return Pos->second; Expected ToSourceRange = Import(BaseSpec->getSourceRange()); if (!ToSourceRange) return ToSourceRange.takeError(); Expected ToTSI = Import(BaseSpec->getTypeSourceInfo()); if (!ToTSI) return ToTSI.takeError(); ExpectedSLoc ToEllipsisLoc = Import(BaseSpec->getEllipsisLoc()); if (!ToEllipsisLoc) return ToEllipsisLoc.takeError(); CXXBaseSpecifier *Imported = new (ToContext) CXXBaseSpecifier( *ToSourceRange, BaseSpec->isVirtual(), BaseSpec->isBaseOfClass(), BaseSpec->getAccessSpecifierAsWritten(), *ToTSI, *ToEllipsisLoc); ImportedCXXBaseSpecifiers[BaseSpec] = Imported; return Imported; } Error ASTImporter::ImportDefinition(Decl *From) { ExpectedDecl ToOrErr = Import(From); if (!ToOrErr) return ToOrErr.takeError(); Decl *To = *ToOrErr; auto *FromDC = cast(From); ASTNodeImporter Importer(*this); if (auto *ToRecord = dyn_cast(To)) { if (!ToRecord->getDefinition()) { return Importer.ImportDefinition( cast(FromDC), ToRecord, ASTNodeImporter::IDK_Everything); } } if (auto *ToEnum = dyn_cast(To)) { if (!ToEnum->getDefinition()) { return Importer.ImportDefinition( cast(FromDC), ToEnum, ASTNodeImporter::IDK_Everything); } } if (auto *ToIFace = dyn_cast(To)) { if (!ToIFace->getDefinition()) { return Importer.ImportDefinition( cast(FromDC), ToIFace, ASTNodeImporter::IDK_Everything); } } if (auto *ToProto = dyn_cast(To)) { if (!ToProto->getDefinition()) { return Importer.ImportDefinition( cast(FromDC), ToProto, ASTNodeImporter::IDK_Everything); } } return Importer.ImportDeclContext(FromDC, true); } Expected ASTImporter::Import(DeclarationName FromName) { if (!FromName) return DeclarationName{}; switch (FromName.getNameKind()) { case DeclarationName::Identifier: return DeclarationName(Import(FromName.getAsIdentifierInfo())); case DeclarationName::ObjCZeroArgSelector: case DeclarationName::ObjCOneArgSelector: case DeclarationName::ObjCMultiArgSelector: if (auto ToSelOrErr = Import(FromName.getObjCSelector())) return DeclarationName(*ToSelOrErr); else return ToSelOrErr.takeError(); case DeclarationName::CXXConstructorName: { if (auto ToTyOrErr = Import(FromName.getCXXNameType())) return ToContext.DeclarationNames.getCXXConstructorName( ToContext.getCanonicalType(*ToTyOrErr)); else return ToTyOrErr.takeError(); } case DeclarationName::CXXDestructorName: { if (auto ToTyOrErr = Import(FromName.getCXXNameType())) return ToContext.DeclarationNames.getCXXDestructorName( ToContext.getCanonicalType(*ToTyOrErr)); else return ToTyOrErr.takeError(); } case DeclarationName::CXXDeductionGuideName: { if (auto ToTemplateOrErr = Import(FromName.getCXXDeductionGuideTemplate())) return ToContext.DeclarationNames.getCXXDeductionGuideName( cast(*ToTemplateOrErr)); else return ToTemplateOrErr.takeError(); } case DeclarationName::CXXConversionFunctionName: { if (auto ToTyOrErr = Import(FromName.getCXXNameType())) return ToContext.DeclarationNames.getCXXConversionFunctionName( ToContext.getCanonicalType(*ToTyOrErr)); else return ToTyOrErr.takeError(); } case DeclarationName::CXXOperatorName: return ToContext.DeclarationNames.getCXXOperatorName( FromName.getCXXOverloadedOperator()); case DeclarationName::CXXLiteralOperatorName: return ToContext.DeclarationNames.getCXXLiteralOperatorName( Import(FromName.getCXXLiteralIdentifier())); case DeclarationName::CXXUsingDirective: // FIXME: STATICS! return DeclarationName::getUsingDirectiveName(); } llvm_unreachable("Invalid DeclarationName Kind!"); } IdentifierInfo *ASTImporter::Import(const IdentifierInfo *FromId) { if (!FromId) return nullptr; IdentifierInfo *ToId = &ToContext.Idents.get(FromId->getName()); if (!ToId->getBuiltinID() && FromId->getBuiltinID()) ToId->setBuiltinID(FromId->getBuiltinID()); return ToId; } Expected ASTImporter::Import(Selector FromSel) { if (FromSel.isNull()) return Selector{}; SmallVector Idents; Idents.push_back(Import(FromSel.getIdentifierInfoForSlot(0))); for (unsigned I = 1, N = FromSel.getNumArgs(); I < N; ++I) Idents.push_back(Import(FromSel.getIdentifierInfoForSlot(I))); return ToContext.Selectors.getSelector(FromSel.getNumArgs(), Idents.data()); } Expected ASTImporter::HandleNameConflict(DeclarationName Name, DeclContext *DC, unsigned IDNS, NamedDecl **Decls, unsigned NumDecls) { if (ODRHandling == ODRHandlingType::Conservative) // Report error at any name conflict. return make_error(ImportError::NameConflict); else // Allow to create the new Decl with the same name. return Name; } DiagnosticBuilder ASTImporter::ToDiag(SourceLocation Loc, unsigned DiagID) { if (LastDiagFromFrom) ToContext.getDiagnostics().notePriorDiagnosticFrom( FromContext.getDiagnostics()); LastDiagFromFrom = false; return ToContext.getDiagnostics().Report(Loc, DiagID); } DiagnosticBuilder ASTImporter::FromDiag(SourceLocation Loc, unsigned DiagID) { if (!LastDiagFromFrom) FromContext.getDiagnostics().notePriorDiagnosticFrom( ToContext.getDiagnostics()); LastDiagFromFrom = true; return FromContext.getDiagnostics().Report(Loc, DiagID); } void ASTImporter::CompleteDecl (Decl *D) { if (auto *ID = dyn_cast(D)) { if (!ID->getDefinition()) ID->startDefinition(); } else if (auto *PD = dyn_cast(D)) { if (!PD->getDefinition()) PD->startDefinition(); } else if (auto *TD = dyn_cast(D)) { if (!TD->getDefinition() && !TD->isBeingDefined()) { TD->startDefinition(); TD->setCompleteDefinition(true); } } else { assert(0 && "CompleteDecl called on a Decl that can't be completed"); } } Decl *ASTImporter::MapImported(Decl *From, Decl *To) { llvm::DenseMap::iterator Pos = ImportedDecls.find(From); assert((Pos == ImportedDecls.end() || Pos->second == To) && "Try to import an already imported Decl"); if (Pos != ImportedDecls.end()) return Pos->second; ImportedDecls[From] = To; // This mapping should be maintained only in this function. Therefore do not // check for additional consistency. ImportedFromDecls[To] = From; AddToLookupTable(To); return To; } llvm::Optional ASTImporter::getImportDeclErrorIfAny(Decl *FromD) const { auto Pos = ImportDeclErrors.find(FromD); if (Pos != ImportDeclErrors.end()) return Pos->second; else return Optional(); } void ASTImporter::setImportDeclError(Decl *From, ImportError Error) { auto InsertRes = ImportDeclErrors.insert({From, Error}); (void)InsertRes; // Either we set the error for the first time, or we already had set one and // now we want to set the same error. assert(InsertRes.second || InsertRes.first->second.Error == Error.Error); } bool ASTImporter::IsStructurallyEquivalent(QualType From, QualType To, bool Complain) { llvm::DenseMap::iterator Pos = ImportedTypes.find(From.getTypePtr()); if (Pos != ImportedTypes.end()) { if (ExpectedType ToFromOrErr = Import(From)) { if (ToContext.hasSameType(*ToFromOrErr, To)) return true; } else { llvm::consumeError(ToFromOrErr.takeError()); } } StructuralEquivalenceContext Ctx(FromContext, ToContext, NonEquivalentDecls, getStructuralEquivalenceKind(*this), false, Complain); return Ctx.IsEquivalent(From, To); } Index: vendor/llvm-project/release-10.x/clang/lib/Lex/Pragma.cpp =================================================================== --- vendor/llvm-project/release-10.x/clang/lib/Lex/Pragma.cpp (revision 359078) +++ vendor/llvm-project/release-10.x/clang/lib/Lex/Pragma.cpp (revision 359079) @@ -1,1917 +1,1920 @@ //===- Pragma.cpp - Pragma registration and handling ----------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This file implements the PragmaHandler/PragmaTable interfaces and implements // pragma related methods of the Preprocessor class. // //===----------------------------------------------------------------------===// #include "clang/Lex/Pragma.h" #include "clang/Basic/Diagnostic.h" #include "clang/Basic/FileManager.h" #include "clang/Basic/IdentifierTable.h" #include "clang/Basic/LLVM.h" #include "clang/Basic/LangOptions.h" #include "clang/Basic/Module.h" #include "clang/Basic/SourceLocation.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/TokenKinds.h" #include "clang/Lex/HeaderSearch.h" #include "clang/Lex/LexDiagnostic.h" #include "clang/Lex/Lexer.h" #include "clang/Lex/LiteralSupport.h" #include "clang/Lex/MacroInfo.h" #include "clang/Lex/ModuleLoader.h" #include "clang/Lex/PPCallbacks.h" #include "clang/Lex/Preprocessor.h" #include "clang/Lex/PreprocessorLexer.h" #include "clang/Lex/PreprocessorOptions.h" #include "clang/Lex/Token.h" #include "clang/Lex/TokenLexer.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/Timer.h" #include #include #include #include #include #include #include #include using namespace clang; // Out-of-line destructor to provide a home for the class. PragmaHandler::~PragmaHandler() = default; //===----------------------------------------------------------------------===// // EmptyPragmaHandler Implementation. //===----------------------------------------------------------------------===// EmptyPragmaHandler::EmptyPragmaHandler(StringRef Name) : PragmaHandler(Name) {} void EmptyPragmaHandler::HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, Token &FirstToken) {} //===----------------------------------------------------------------------===// // PragmaNamespace Implementation. //===----------------------------------------------------------------------===// PragmaNamespace::~PragmaNamespace() { llvm::DeleteContainerSeconds(Handlers); } /// FindHandler - Check to see if there is already a handler for the /// specified name. If not, return the handler for the null identifier if it /// exists, otherwise return null. If IgnoreNull is true (the default) then /// the null handler isn't returned on failure to match. PragmaHandler *PragmaNamespace::FindHandler(StringRef Name, bool IgnoreNull) const { if (PragmaHandler *Handler = Handlers.lookup(Name)) return Handler; return IgnoreNull ? nullptr : Handlers.lookup(StringRef()); } void PragmaNamespace::AddPragma(PragmaHandler *Handler) { assert(!Handlers.lookup(Handler->getName()) && "A handler with this name is already registered in this namespace"); Handlers[Handler->getName()] = Handler; } void PragmaNamespace::RemovePragmaHandler(PragmaHandler *Handler) { assert(Handlers.lookup(Handler->getName()) && "Handler not registered in this namespace"); Handlers.erase(Handler->getName()); } void PragmaNamespace::HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, Token &Tok) { // Read the 'namespace' that the directive is in, e.g. STDC. Do not macro // expand it, the user can have a STDC #define, that should not affect this. PP.LexUnexpandedToken(Tok); // Get the handler for this token. If there is no handler, ignore the pragma. PragmaHandler *Handler = FindHandler(Tok.getIdentifierInfo() ? Tok.getIdentifierInfo()->getName() : StringRef(), /*IgnoreNull=*/false); if (!Handler) { PP.Diag(Tok, diag::warn_pragma_ignored); return; } // Otherwise, pass it down. Handler->HandlePragma(PP, Introducer, Tok); } //===----------------------------------------------------------------------===// // Preprocessor Pragma Directive Handling. //===----------------------------------------------------------------------===// namespace { // TokenCollector provides the option to collect tokens that were "read" // and return them to the stream to be read later. // Currently used when reading _Pragma/__pragma directives. struct TokenCollector { Preprocessor &Self; bool Collect; SmallVector Tokens; Token &Tok; void lex() { if (Collect) Tokens.push_back(Tok); Self.Lex(Tok); } void revert() { assert(Collect && "did not collect tokens"); assert(!Tokens.empty() && "collected unexpected number of tokens"); // Push the ( "string" ) tokens into the token stream. auto Toks = std::make_unique(Tokens.size()); std::copy(Tokens.begin() + 1, Tokens.end(), Toks.get()); Toks[Tokens.size() - 1] = Tok; Self.EnterTokenStream(std::move(Toks), Tokens.size(), /*DisableMacroExpansion*/ true, /*IsReinject*/ true); // ... and return the pragma token unchanged. Tok = *Tokens.begin(); } }; } // namespace /// HandlePragmaDirective - The "\#pragma" directive has been parsed. Lex the /// rest of the pragma, passing it to the registered pragma handlers. void Preprocessor::HandlePragmaDirective(PragmaIntroducer Introducer) { if (Callbacks) Callbacks->PragmaDirective(Introducer.Loc, Introducer.Kind); if (!PragmasEnabled) return; ++NumPragma; // Invoke the first level of pragma handlers which reads the namespace id. Token Tok; PragmaHandlers->HandlePragma(*this, Introducer, Tok); // If the pragma handler didn't read the rest of the line, consume it now. if ((CurTokenLexer && CurTokenLexer->isParsingPreprocessorDirective()) || (CurPPLexer && CurPPLexer->ParsingPreprocessorDirective)) DiscardUntilEndOfDirective(); } /// Handle_Pragma - Read a _Pragma directive, slice it up, process it, then /// return the first token after the directive. The _Pragma token has just /// been read into 'Tok'. void Preprocessor::Handle_Pragma(Token &Tok) { // C11 6.10.3.4/3: // all pragma unary operator expressions within [a completely // macro-replaced preprocessing token sequence] are [...] processed [after // rescanning is complete] // // This means that we execute _Pragma operators in two cases: // // 1) on token sequences that would otherwise be produced as the output of // phase 4 of preprocessing, and // 2) on token sequences formed as the macro-replaced token sequence of a // macro argument // // Case #2 appears to be a wording bug: only _Pragmas that would survive to // the end of phase 4 should actually be executed. Discussion on the WG14 // mailing list suggests that a _Pragma operator is notionally checked early, // but only pragmas that survive to the end of phase 4 should be executed. // // In Case #2, we check the syntax now, but then put the tokens back into the // token stream for later consumption. TokenCollector Toks = {*this, InMacroArgPreExpansion, {}, Tok}; // Remember the pragma token location. SourceLocation PragmaLoc = Tok.getLocation(); // Read the '('. Toks.lex(); if (Tok.isNot(tok::l_paren)) { Diag(PragmaLoc, diag::err__Pragma_malformed); return; } // Read the '"..."'. Toks.lex(); if (!tok::isStringLiteral(Tok.getKind())) { Diag(PragmaLoc, diag::err__Pragma_malformed); // Skip bad tokens, and the ')', if present. if (Tok.isNot(tok::r_paren) && Tok.isNot(tok::eof)) Lex(Tok); while (Tok.isNot(tok::r_paren) && !Tok.isAtStartOfLine() && Tok.isNot(tok::eof)) Lex(Tok); if (Tok.is(tok::r_paren)) Lex(Tok); return; } if (Tok.hasUDSuffix()) { Diag(Tok, diag::err_invalid_string_udl); // Skip this token, and the ')', if present. Lex(Tok); if (Tok.is(tok::r_paren)) Lex(Tok); return; } // Remember the string. Token StrTok = Tok; // Read the ')'. Toks.lex(); if (Tok.isNot(tok::r_paren)) { Diag(PragmaLoc, diag::err__Pragma_malformed); return; } // If we're expanding a macro argument, put the tokens back. if (InMacroArgPreExpansion) { Toks.revert(); return; } SourceLocation RParenLoc = Tok.getLocation(); std::string StrVal = getSpelling(StrTok); // The _Pragma is lexically sound. Destringize according to C11 6.10.9.1: // "The string literal is destringized by deleting any encoding prefix, // deleting the leading and trailing double-quotes, replacing each escape // sequence \" by a double-quote, and replacing each escape sequence \\ by a // single backslash." if (StrVal[0] == 'L' || StrVal[0] == 'U' || (StrVal[0] == 'u' && StrVal[1] != '8')) StrVal.erase(StrVal.begin()); else if (StrVal[0] == 'u') StrVal.erase(StrVal.begin(), StrVal.begin() + 2); if (StrVal[0] == 'R') { // FIXME: C++11 does not specify how to handle raw-string-literals here. // We strip off the 'R', the quotes, the d-char-sequences, and the parens. assert(StrVal[1] == '"' && StrVal[StrVal.size() - 1] == '"' && "Invalid raw string token!"); // Measure the length of the d-char-sequence. unsigned NumDChars = 0; while (StrVal[2 + NumDChars] != '(') { assert(NumDChars < (StrVal.size() - 5) / 2 && "Invalid raw string token!"); ++NumDChars; } assert(StrVal[StrVal.size() - 2 - NumDChars] == ')'); // Remove 'R " d-char-sequence' and 'd-char-sequence "'. We'll replace the // parens below. StrVal.erase(0, 2 + NumDChars); StrVal.erase(StrVal.size() - 1 - NumDChars); } else { assert(StrVal[0] == '"' && StrVal[StrVal.size()-1] == '"' && "Invalid string token!"); // Remove escaped quotes and escapes. unsigned ResultPos = 1; for (size_t i = 1, e = StrVal.size() - 1; i != e; ++i) { // Skip escapes. \\ -> '\' and \" -> '"'. if (StrVal[i] == '\\' && i + 1 < e && (StrVal[i + 1] == '\\' || StrVal[i + 1] == '"')) ++i; StrVal[ResultPos++] = StrVal[i]; } StrVal.erase(StrVal.begin() + ResultPos, StrVal.end() - 1); } // Remove the front quote, replacing it with a space, so that the pragma // contents appear to have a space before them. StrVal[0] = ' '; // Replace the terminating quote with a \n. StrVal[StrVal.size()-1] = '\n'; // Plop the string (including the newline and trailing null) into a buffer // where we can lex it. Token TmpTok; TmpTok.startToken(); CreateString(StrVal, TmpTok); SourceLocation TokLoc = TmpTok.getLocation(); // Make and enter a lexer object so that we lex and expand the tokens just // like any others. Lexer *TL = Lexer::Create_PragmaLexer(TokLoc, PragmaLoc, RParenLoc, StrVal.size(), *this); EnterSourceFileWithLexer(TL, nullptr); // With everything set up, lex this as a #pragma directive. HandlePragmaDirective({PIK__Pragma, PragmaLoc}); // Finally, return whatever came after the pragma directive. return Lex(Tok); } /// HandleMicrosoft__pragma - Like Handle_Pragma except the pragma text /// is not enclosed within a string literal. void Preprocessor::HandleMicrosoft__pragma(Token &Tok) { // During macro pre-expansion, check the syntax now but put the tokens back // into the token stream for later consumption. Same as Handle_Pragma. TokenCollector Toks = {*this, InMacroArgPreExpansion, {}, Tok}; // Remember the pragma token location. SourceLocation PragmaLoc = Tok.getLocation(); // Read the '('. Toks.lex(); if (Tok.isNot(tok::l_paren)) { Diag(PragmaLoc, diag::err__Pragma_malformed); return; } // Get the tokens enclosed within the __pragma(), as well as the final ')'. SmallVector PragmaToks; int NumParens = 0; Toks.lex(); while (Tok.isNot(tok::eof)) { PragmaToks.push_back(Tok); if (Tok.is(tok::l_paren)) NumParens++; else if (Tok.is(tok::r_paren) && NumParens-- == 0) break; Toks.lex(); } if (Tok.is(tok::eof)) { Diag(PragmaLoc, diag::err_unterminated___pragma); return; } // If we're expanding a macro argument, put the tokens back. if (InMacroArgPreExpansion) { Toks.revert(); return; } PragmaToks.front().setFlag(Token::LeadingSpace); // Replace the ')' with an EOD to mark the end of the pragma. PragmaToks.back().setKind(tok::eod); Token *TokArray = new Token[PragmaToks.size()]; std::copy(PragmaToks.begin(), PragmaToks.end(), TokArray); // Push the tokens onto the stack. EnterTokenStream(TokArray, PragmaToks.size(), true, true, /*IsReinject*/ false); // With everything set up, lex this as a #pragma directive. HandlePragmaDirective({PIK___pragma, PragmaLoc}); // Finally, return whatever came after the pragma directive. return Lex(Tok); } /// HandlePragmaOnce - Handle \#pragma once. OnceTok is the 'once'. void Preprocessor::HandlePragmaOnce(Token &OnceTok) { // Don't honor the 'once' when handling the primary source file, unless // this is a prefix to a TU, which indicates we're generating a PCH file, or // when the main file is a header (e.g. when -xc-header is provided on the // commandline). if (isInPrimaryFile() && TUKind != TU_Prefix && !getLangOpts().IsHeaderFile) { Diag(OnceTok, diag::pp_pragma_once_in_main_file); return; } // Get the current file lexer we're looking at. Ignore _Pragma 'files' etc. // Mark the file as a once-only file now. HeaderInfo.MarkFileIncludeOnce(getCurrentFileLexer()->getFileEntry()); } void Preprocessor::HandlePragmaMark() { assert(CurPPLexer && "No current lexer?"); CurLexer->ReadToEndOfLine(); } /// HandlePragmaPoison - Handle \#pragma GCC poison. PoisonTok is the 'poison'. void Preprocessor::HandlePragmaPoison() { Token Tok; while (true) { // Read the next token to poison. While doing this, pretend that we are // skipping while reading the identifier to poison. // This avoids errors on code like: // #pragma GCC poison X // #pragma GCC poison X if (CurPPLexer) CurPPLexer->LexingRawMode = true; LexUnexpandedToken(Tok); if (CurPPLexer) CurPPLexer->LexingRawMode = false; // If we reached the end of line, we're done. if (Tok.is(tok::eod)) return; // Can only poison identifiers. if (Tok.isNot(tok::raw_identifier)) { Diag(Tok, diag::err_pp_invalid_poison); return; } // Look up the identifier info for the token. We disabled identifier lookup // by saying we're skipping contents, so we need to do this manually. IdentifierInfo *II = LookUpIdentifierInfo(Tok); // Already poisoned. if (II->isPoisoned()) continue; // If this is a macro identifier, emit a warning. if (isMacroDefined(II)) Diag(Tok, diag::pp_poisoning_existing_macro); // Finally, poison it! II->setIsPoisoned(); if (II->isFromAST()) II->setChangedSinceDeserialization(); } } /// HandlePragmaSystemHeader - Implement \#pragma GCC system_header. We know /// that the whole directive has been parsed. void Preprocessor::HandlePragmaSystemHeader(Token &SysHeaderTok) { if (isInPrimaryFile()) { Diag(SysHeaderTok, diag::pp_pragma_sysheader_in_main_file); return; } // Get the current file lexer we're looking at. Ignore _Pragma 'files' etc. PreprocessorLexer *TheLexer = getCurrentFileLexer(); // Mark the file as a system header. HeaderInfo.MarkFileSystemHeader(TheLexer->getFileEntry()); PresumedLoc PLoc = SourceMgr.getPresumedLoc(SysHeaderTok.getLocation()); if (PLoc.isInvalid()) return; unsigned FilenameID = SourceMgr.getLineTableFilenameID(PLoc.getFilename()); // Notify the client, if desired, that we are in a new source file. if (Callbacks) Callbacks->FileChanged(SysHeaderTok.getLocation(), PPCallbacks::SystemHeaderPragma, SrcMgr::C_System); // Emit a line marker. This will change any source locations from this point // forward to realize they are in a system header. // Create a line note with this information. SourceMgr.AddLineNote(SysHeaderTok.getLocation(), PLoc.getLine() + 1, FilenameID, /*IsEntry=*/false, /*IsExit=*/false, SrcMgr::C_System); } /// HandlePragmaDependency - Handle \#pragma GCC dependency "foo" blah. void Preprocessor::HandlePragmaDependency(Token &DependencyTok) { Token FilenameTok; if (LexHeaderName(FilenameTok, /*AllowConcatenation*/false)) return; // If the next token wasn't a header-name, diagnose the error. if (FilenameTok.isNot(tok::header_name)) { Diag(FilenameTok.getLocation(), diag::err_pp_expects_filename); return; } // Reserve a buffer to get the spelling. SmallString<128> FilenameBuffer; bool Invalid = false; StringRef Filename = getSpelling(FilenameTok, FilenameBuffer, &Invalid); if (Invalid) return; bool isAngled = GetIncludeFilenameSpelling(FilenameTok.getLocation(), Filename); // If GetIncludeFilenameSpelling set the start ptr to null, there was an // error. if (Filename.empty()) return; // Search include directories for this file. const DirectoryLookup *CurDir; Optional File = LookupFile(FilenameTok.getLocation(), Filename, isAngled, nullptr, nullptr, CurDir, nullptr, nullptr, nullptr, nullptr, nullptr); if (!File) { if (!SuppressIncludeNotFoundError) Diag(FilenameTok, diag::err_pp_file_not_found) << Filename; return; } const FileEntry *CurFile = getCurrentFileLexer()->getFileEntry(); // If this file is older than the file it depends on, emit a diagnostic. if (CurFile && CurFile->getModificationTime() < File->getModificationTime()) { // Lex tokens at the end of the message and include them in the message. std::string Message; Lex(DependencyTok); while (DependencyTok.isNot(tok::eod)) { Message += getSpelling(DependencyTok) + " "; Lex(DependencyTok); } // Remove the trailing ' ' if present. if (!Message.empty()) Message.erase(Message.end()-1); Diag(FilenameTok, diag::pp_out_of_date_dependency) << Message; } } /// ParsePragmaPushOrPopMacro - Handle parsing of pragma push_macro/pop_macro. /// Return the IdentifierInfo* associated with the macro to push or pop. IdentifierInfo *Preprocessor::ParsePragmaPushOrPopMacro(Token &Tok) { // Remember the pragma token location. Token PragmaTok = Tok; // Read the '('. Lex(Tok); if (Tok.isNot(tok::l_paren)) { Diag(PragmaTok.getLocation(), diag::err_pragma_push_pop_macro_malformed) << getSpelling(PragmaTok); return nullptr; } // Read the macro name string. Lex(Tok); if (Tok.isNot(tok::string_literal)) { Diag(PragmaTok.getLocation(), diag::err_pragma_push_pop_macro_malformed) << getSpelling(PragmaTok); return nullptr; } if (Tok.hasUDSuffix()) { Diag(Tok, diag::err_invalid_string_udl); return nullptr; } // Remember the macro string. std::string StrVal = getSpelling(Tok); // Read the ')'. Lex(Tok); if (Tok.isNot(tok::r_paren)) { Diag(PragmaTok.getLocation(), diag::err_pragma_push_pop_macro_malformed) << getSpelling(PragmaTok); return nullptr; } assert(StrVal[0] == '"' && StrVal[StrVal.size()-1] == '"' && "Invalid string token!"); // Create a Token from the string. Token MacroTok; MacroTok.startToken(); MacroTok.setKind(tok::raw_identifier); CreateString(StringRef(&StrVal[1], StrVal.size() - 2), MacroTok); // Get the IdentifierInfo of MacroToPushTok. return LookUpIdentifierInfo(MacroTok); } /// Handle \#pragma push_macro. /// /// The syntax is: /// \code /// #pragma push_macro("macro") /// \endcode void Preprocessor::HandlePragmaPushMacro(Token &PushMacroTok) { // Parse the pragma directive and get the macro IdentifierInfo*. IdentifierInfo *IdentInfo = ParsePragmaPushOrPopMacro(PushMacroTok); if (!IdentInfo) return; // Get the MacroInfo associated with IdentInfo. MacroInfo *MI = getMacroInfo(IdentInfo); if (MI) { // Allow the original MacroInfo to be redefined later. MI->setIsAllowRedefinitionsWithoutWarning(true); } // Push the cloned MacroInfo so we can retrieve it later. PragmaPushMacroInfo[IdentInfo].push_back(MI); } /// Handle \#pragma pop_macro. /// /// The syntax is: /// \code /// #pragma pop_macro("macro") /// \endcode void Preprocessor::HandlePragmaPopMacro(Token &PopMacroTok) { SourceLocation MessageLoc = PopMacroTok.getLocation(); // Parse the pragma directive and get the macro IdentifierInfo*. IdentifierInfo *IdentInfo = ParsePragmaPushOrPopMacro(PopMacroTok); if (!IdentInfo) return; // Find the vector associated with the macro. llvm::DenseMap>::iterator iter = PragmaPushMacroInfo.find(IdentInfo); if (iter != PragmaPushMacroInfo.end()) { // Forget the MacroInfo currently associated with IdentInfo. if (MacroInfo *MI = getMacroInfo(IdentInfo)) { if (MI->isWarnIfUnused()) WarnUnusedMacroLocs.erase(MI->getDefinitionLoc()); appendMacroDirective(IdentInfo, AllocateUndefMacroDirective(MessageLoc)); } // Get the MacroInfo we want to reinstall. MacroInfo *MacroToReInstall = iter->second.back(); if (MacroToReInstall) // Reinstall the previously pushed macro. appendDefMacroDirective(IdentInfo, MacroToReInstall, MessageLoc); // Pop PragmaPushMacroInfo stack. iter->second.pop_back(); if (iter->second.empty()) PragmaPushMacroInfo.erase(iter); } else { Diag(MessageLoc, diag::warn_pragma_pop_macro_no_push) << IdentInfo->getName(); } } void Preprocessor::HandlePragmaIncludeAlias(Token &Tok) { // We will either get a quoted filename or a bracketed filename, and we // have to track which we got. The first filename is the source name, // and the second name is the mapped filename. If the first is quoted, // the second must be as well (cannot mix and match quotes and brackets). // Get the open paren Lex(Tok); if (Tok.isNot(tok::l_paren)) { Diag(Tok, diag::warn_pragma_include_alias_expected) << "("; return; } // We expect either a quoted string literal, or a bracketed name Token SourceFilenameTok; if (LexHeaderName(SourceFilenameTok)) return; StringRef SourceFileName; SmallString<128> FileNameBuffer; if (SourceFilenameTok.is(tok::header_name)) { SourceFileName = getSpelling(SourceFilenameTok, FileNameBuffer); } else { Diag(Tok, diag::warn_pragma_include_alias_expected_filename); return; } FileNameBuffer.clear(); // Now we expect a comma, followed by another include name Lex(Tok); if (Tok.isNot(tok::comma)) { Diag(Tok, diag::warn_pragma_include_alias_expected) << ","; return; } Token ReplaceFilenameTok; if (LexHeaderName(ReplaceFilenameTok)) return; StringRef ReplaceFileName; if (ReplaceFilenameTok.is(tok::header_name)) { ReplaceFileName = getSpelling(ReplaceFilenameTok, FileNameBuffer); } else { Diag(Tok, diag::warn_pragma_include_alias_expected_filename); return; } // Finally, we expect the closing paren Lex(Tok); if (Tok.isNot(tok::r_paren)) { Diag(Tok, diag::warn_pragma_include_alias_expected) << ")"; return; } // Now that we have the source and target filenames, we need to make sure // they're both of the same type (angled vs non-angled) StringRef OriginalSource = SourceFileName; bool SourceIsAngled = GetIncludeFilenameSpelling(SourceFilenameTok.getLocation(), SourceFileName); bool ReplaceIsAngled = GetIncludeFilenameSpelling(ReplaceFilenameTok.getLocation(), ReplaceFileName); if (!SourceFileName.empty() && !ReplaceFileName.empty() && (SourceIsAngled != ReplaceIsAngled)) { unsigned int DiagID; if (SourceIsAngled) DiagID = diag::warn_pragma_include_alias_mismatch_angle; else DiagID = diag::warn_pragma_include_alias_mismatch_quote; Diag(SourceFilenameTok.getLocation(), DiagID) << SourceFileName << ReplaceFileName; return; } // Now we can let the include handler know about this mapping getHeaderSearchInfo().AddIncludeAlias(OriginalSource, ReplaceFileName); } // Lex a component of a module name: either an identifier or a string literal; // for components that can be expressed both ways, the two forms are equivalent. static bool LexModuleNameComponent( Preprocessor &PP, Token &Tok, std::pair &ModuleNameComponent, bool First) { PP.LexUnexpandedToken(Tok); if (Tok.is(tok::string_literal) && !Tok.hasUDSuffix()) { StringLiteralParser Literal(Tok, PP); if (Literal.hadError) return true; ModuleNameComponent = std::make_pair( PP.getIdentifierInfo(Literal.GetString()), Tok.getLocation()); } else if (!Tok.isAnnotation() && Tok.getIdentifierInfo()) { ModuleNameComponent = std::make_pair(Tok.getIdentifierInfo(), Tok.getLocation()); } else { PP.Diag(Tok.getLocation(), diag::err_pp_expected_module_name) << First; return true; } return false; } static bool LexModuleName( Preprocessor &PP, Token &Tok, llvm::SmallVectorImpl> &ModuleName) { while (true) { std::pair NameComponent; if (LexModuleNameComponent(PP, Tok, NameComponent, ModuleName.empty())) return true; ModuleName.push_back(NameComponent); PP.LexUnexpandedToken(Tok); if (Tok.isNot(tok::period)) return false; } } void Preprocessor::HandlePragmaModuleBuild(Token &Tok) { SourceLocation Loc = Tok.getLocation(); std::pair ModuleNameLoc; if (LexModuleNameComponent(*this, Tok, ModuleNameLoc, true)) return; IdentifierInfo *ModuleName = ModuleNameLoc.first; LexUnexpandedToken(Tok); if (Tok.isNot(tok::eod)) { Diag(Tok, diag::ext_pp_extra_tokens_at_eol) << "pragma"; DiscardUntilEndOfDirective(); } CurLexer->LexingRawMode = true; auto TryConsumeIdentifier = [&](StringRef Ident) -> bool { if (Tok.getKind() != tok::raw_identifier || Tok.getRawIdentifier() != Ident) return false; CurLexer->Lex(Tok); return true; }; // Scan forward looking for the end of the module. const char *Start = CurLexer->getBufferLocation(); const char *End = nullptr; unsigned NestingLevel = 1; while (true) { End = CurLexer->getBufferLocation(); CurLexer->Lex(Tok); if (Tok.is(tok::eof)) { Diag(Loc, diag::err_pp_module_build_missing_end); break; } if (Tok.isNot(tok::hash) || !Tok.isAtStartOfLine()) { // Token was part of module; keep going. continue; } // We hit something directive-shaped; check to see if this is the end // of the module build. CurLexer->ParsingPreprocessorDirective = true; CurLexer->Lex(Tok); if (TryConsumeIdentifier("pragma") && TryConsumeIdentifier("clang") && TryConsumeIdentifier("module")) { if (TryConsumeIdentifier("build")) // #pragma clang module build -> entering a nested module build. ++NestingLevel; else if (TryConsumeIdentifier("endbuild")) { // #pragma clang module endbuild -> leaving a module build. if (--NestingLevel == 0) break; } // We should either be looking at the EOD or more of the current directive // preceding the EOD. Either way we can ignore this token and keep going. assert(Tok.getKind() != tok::eof && "missing EOD before EOF"); } } CurLexer->LexingRawMode = false; // Load the extracted text as a preprocessed module. assert(CurLexer->getBuffer().begin() <= Start && Start <= CurLexer->getBuffer().end() && CurLexer->getBuffer().begin() <= End && End <= CurLexer->getBuffer().end() && "module source range not contained within same file buffer"); TheModuleLoader.createModuleFromSource(Loc, ModuleName->getName(), StringRef(Start, End - Start)); } void Preprocessor::HandlePragmaHdrstop(Token &Tok) { Lex(Tok); if (Tok.is(tok::l_paren)) { Diag(Tok.getLocation(), diag::warn_pp_hdrstop_filename_ignored); std::string FileName; if (!LexStringLiteral(Tok, FileName, "pragma hdrstop", false)) return; if (Tok.isNot(tok::r_paren)) { Diag(Tok, diag::err_expected) << tok::r_paren; return; } Lex(Tok); } if (Tok.isNot(tok::eod)) Diag(Tok.getLocation(), diag::ext_pp_extra_tokens_at_eol) << "pragma hdrstop"; if (creatingPCHWithPragmaHdrStop() && SourceMgr.isInMainFile(Tok.getLocation())) { assert(CurLexer && "no lexer for #pragma hdrstop processing"); Token &Result = Tok; Result.startToken(); CurLexer->FormTokenWithChars(Result, CurLexer->BufferEnd, tok::eof); CurLexer->cutOffLexing(); } if (usingPCHWithPragmaHdrStop()) SkippingUntilPragmaHdrStop = false; } /// AddPragmaHandler - Add the specified pragma handler to the preprocessor. /// If 'Namespace' is non-null, then it is a token required to exist on the /// pragma line before the pragma string starts, e.g. "STDC" or "GCC". void Preprocessor::AddPragmaHandler(StringRef Namespace, PragmaHandler *Handler) { PragmaNamespace *InsertNS = PragmaHandlers.get(); // If this is specified to be in a namespace, step down into it. if (!Namespace.empty()) { // If there is already a pragma handler with the name of this namespace, // we either have an error (directive with the same name as a namespace) or // we already have the namespace to insert into. if (PragmaHandler *Existing = PragmaHandlers->FindHandler(Namespace)) { InsertNS = Existing->getIfNamespace(); assert(InsertNS != nullptr && "Cannot have a pragma namespace and pragma" " handler with the same name!"); } else { // Otherwise, this namespace doesn't exist yet, create and insert the // handler for it. InsertNS = new PragmaNamespace(Namespace); PragmaHandlers->AddPragma(InsertNS); } } // Check to make sure we don't already have a pragma for this identifier. assert(!InsertNS->FindHandler(Handler->getName()) && "Pragma handler already exists for this identifier!"); InsertNS->AddPragma(Handler); } /// RemovePragmaHandler - Remove the specific pragma handler from the /// preprocessor. If \arg Namespace is non-null, then it should be the /// namespace that \arg Handler was added to. It is an error to remove /// a handler that has not been registered. void Preprocessor::RemovePragmaHandler(StringRef Namespace, PragmaHandler *Handler) { PragmaNamespace *NS = PragmaHandlers.get(); // If this is specified to be in a namespace, step down into it. if (!Namespace.empty()) { PragmaHandler *Existing = PragmaHandlers->FindHandler(Namespace); assert(Existing && "Namespace containing handler does not exist!"); NS = Existing->getIfNamespace(); assert(NS && "Invalid namespace, registered as a regular pragma handler!"); } NS->RemovePragmaHandler(Handler); // If this is a non-default namespace and it is now empty, remove it. if (NS != PragmaHandlers.get() && NS->IsEmpty()) { PragmaHandlers->RemovePragmaHandler(NS); delete NS; } } bool Preprocessor::LexOnOffSwitch(tok::OnOffSwitch &Result) { Token Tok; LexUnexpandedToken(Tok); if (Tok.isNot(tok::identifier)) { Diag(Tok, diag::ext_on_off_switch_syntax); return true; } IdentifierInfo *II = Tok.getIdentifierInfo(); if (II->isStr("ON")) Result = tok::OOS_ON; else if (II->isStr("OFF")) Result = tok::OOS_OFF; else if (II->isStr("DEFAULT")) Result = tok::OOS_DEFAULT; else { Diag(Tok, diag::ext_on_off_switch_syntax); return true; } // Verify that this is followed by EOD. LexUnexpandedToken(Tok); if (Tok.isNot(tok::eod)) Diag(Tok, diag::ext_pragma_syntax_eod); return false; } namespace { /// PragmaOnceHandler - "\#pragma once" marks the file as atomically included. struct PragmaOnceHandler : public PragmaHandler { PragmaOnceHandler() : PragmaHandler("once") {} void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, Token &OnceTok) override { PP.CheckEndOfDirective("pragma once"); PP.HandlePragmaOnce(OnceTok); } }; /// PragmaMarkHandler - "\#pragma mark ..." is ignored by the compiler, and the /// rest of the line is not lexed. struct PragmaMarkHandler : public PragmaHandler { PragmaMarkHandler() : PragmaHandler("mark") {} void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, Token &MarkTok) override { PP.HandlePragmaMark(); } }; /// PragmaPoisonHandler - "\#pragma poison x" marks x as not usable. struct PragmaPoisonHandler : public PragmaHandler { PragmaPoisonHandler() : PragmaHandler("poison") {} void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, Token &PoisonTok) override { PP.HandlePragmaPoison(); } }; /// PragmaSystemHeaderHandler - "\#pragma system_header" marks the current file /// as a system header, which silences warnings in it. struct PragmaSystemHeaderHandler : public PragmaHandler { PragmaSystemHeaderHandler() : PragmaHandler("system_header") {} void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, Token &SHToken) override { PP.HandlePragmaSystemHeader(SHToken); PP.CheckEndOfDirective("pragma"); } }; struct PragmaDependencyHandler : public PragmaHandler { PragmaDependencyHandler() : PragmaHandler("dependency") {} void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, Token &DepToken) override { PP.HandlePragmaDependency(DepToken); } }; struct PragmaDebugHandler : public PragmaHandler { PragmaDebugHandler() : PragmaHandler("__debug") {} void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, Token &DebugToken) override { Token Tok; PP.LexUnexpandedToken(Tok); if (Tok.isNot(tok::identifier)) { PP.Diag(Tok, diag::warn_pragma_diagnostic_invalid); return; } IdentifierInfo *II = Tok.getIdentifierInfo(); if (II->isStr("assert")) { if (!PP.getPreprocessorOpts().DisablePragmaDebugCrash) llvm_unreachable("This is an assertion!"); } else if (II->isStr("crash")) { + llvm::Timer T("crash", "pragma crash"); + llvm::TimeRegion R(&T); if (!PP.getPreprocessorOpts().DisablePragmaDebugCrash) LLVM_BUILTIN_TRAP; } else if (II->isStr("parser_crash")) { if (!PP.getPreprocessorOpts().DisablePragmaDebugCrash) { Token Crasher; Crasher.startToken(); Crasher.setKind(tok::annot_pragma_parser_crash); Crasher.setAnnotationRange(SourceRange(Tok.getLocation())); PP.EnterToken(Crasher, /*IsReinject*/ false); } } else if (II->isStr("dump")) { Token Identifier; PP.LexUnexpandedToken(Identifier); if (auto *DumpII = Identifier.getIdentifierInfo()) { Token DumpAnnot; DumpAnnot.startToken(); DumpAnnot.setKind(tok::annot_pragma_dump); DumpAnnot.setAnnotationRange( SourceRange(Tok.getLocation(), Identifier.getLocation())); DumpAnnot.setAnnotationValue(DumpII); PP.DiscardUntilEndOfDirective(); PP.EnterToken(DumpAnnot, /*IsReinject*/false); } else { PP.Diag(Identifier, diag::warn_pragma_debug_missing_argument) << II->getName(); } } else if (II->isStr("diag_mapping")) { Token DiagName; PP.LexUnexpandedToken(DiagName); if (DiagName.is(tok::eod)) PP.getDiagnostics().dump(); else if (DiagName.is(tok::string_literal) && !DiagName.hasUDSuffix()) { StringLiteralParser Literal(DiagName, PP); if (Literal.hadError) return; PP.getDiagnostics().dump(Literal.GetString()); } else { PP.Diag(DiagName, diag::warn_pragma_debug_missing_argument) << II->getName(); } } else if (II->isStr("llvm_fatal_error")) { if (!PP.getPreprocessorOpts().DisablePragmaDebugCrash) llvm::report_fatal_error("#pragma clang __debug llvm_fatal_error"); } else if (II->isStr("llvm_unreachable")) { if (!PP.getPreprocessorOpts().DisablePragmaDebugCrash) llvm_unreachable("#pragma clang __debug llvm_unreachable"); } else if (II->isStr("macro")) { Token MacroName; PP.LexUnexpandedToken(MacroName); auto *MacroII = MacroName.getIdentifierInfo(); if (MacroII) PP.dumpMacroInfo(MacroII); else PP.Diag(MacroName, diag::warn_pragma_debug_missing_argument) << II->getName(); } else if (II->isStr("module_map")) { llvm::SmallVector, 8> ModuleName; if (LexModuleName(PP, Tok, ModuleName)) return; ModuleMap &MM = PP.getHeaderSearchInfo().getModuleMap(); Module *M = nullptr; for (auto IIAndLoc : ModuleName) { M = MM.lookupModuleQualified(IIAndLoc.first->getName(), M); if (!M) { PP.Diag(IIAndLoc.second, diag::warn_pragma_debug_unknown_module) << IIAndLoc.first; return; } } M->dump(); } else if (II->isStr("overflow_stack")) { if (!PP.getPreprocessorOpts().DisablePragmaDebugCrash) DebugOverflowStack(); } else if (II->isStr("captured")) { HandleCaptured(PP); } else { PP.Diag(Tok, diag::warn_pragma_debug_unexpected_command) << II->getName(); } PPCallbacks *Callbacks = PP.getPPCallbacks(); if (Callbacks) Callbacks->PragmaDebug(Tok.getLocation(), II->getName()); } void HandleCaptured(Preprocessor &PP) { Token Tok; PP.LexUnexpandedToken(Tok); if (Tok.isNot(tok::eod)) { PP.Diag(Tok, diag::ext_pp_extra_tokens_at_eol) << "pragma clang __debug captured"; return; } SourceLocation NameLoc = Tok.getLocation(); MutableArrayRef Toks( PP.getPreprocessorAllocator().Allocate(1), 1); Toks[0].startToken(); Toks[0].setKind(tok::annot_pragma_captured); Toks[0].setLocation(NameLoc); PP.EnterTokenStream(Toks, /*DisableMacroExpansion=*/true, /*IsReinject=*/false); } // Disable MSVC warning about runtime stack overflow. #ifdef _MSC_VER #pragma warning(disable : 4717) #endif static void DebugOverflowStack(void (*P)() = nullptr) { void (*volatile Self)(void(*P)()) = DebugOverflowStack; Self(reinterpret_cast(Self)); } #ifdef _MSC_VER #pragma warning(default : 4717) #endif }; /// PragmaDiagnosticHandler - e.g. '\#pragma GCC diagnostic ignored "-Wformat"' struct PragmaDiagnosticHandler : public PragmaHandler { private: const char *Namespace; public: explicit PragmaDiagnosticHandler(const char *NS) : PragmaHandler("diagnostic"), Namespace(NS) {} void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, Token &DiagToken) override { SourceLocation DiagLoc = DiagToken.getLocation(); Token Tok; PP.LexUnexpandedToken(Tok); if (Tok.isNot(tok::identifier)) { PP.Diag(Tok, diag::warn_pragma_diagnostic_invalid); return; } IdentifierInfo *II = Tok.getIdentifierInfo(); PPCallbacks *Callbacks = PP.getPPCallbacks(); if (II->isStr("pop")) { if (!PP.getDiagnostics().popMappings(DiagLoc)) PP.Diag(Tok, diag::warn_pragma_diagnostic_cannot_pop); else if (Callbacks) Callbacks->PragmaDiagnosticPop(DiagLoc, Namespace); return; } else if (II->isStr("push")) { PP.getDiagnostics().pushMappings(DiagLoc); if (Callbacks) Callbacks->PragmaDiagnosticPush(DiagLoc, Namespace); return; } diag::Severity SV = llvm::StringSwitch(II->getName()) .Case("ignored", diag::Severity::Ignored) .Case("warning", diag::Severity::Warning) .Case("error", diag::Severity::Error) .Case("fatal", diag::Severity::Fatal) .Default(diag::Severity()); if (SV == diag::Severity()) { PP.Diag(Tok, diag::warn_pragma_diagnostic_invalid); return; } PP.LexUnexpandedToken(Tok); SourceLocation StringLoc = Tok.getLocation(); std::string WarningName; if (!PP.FinishLexStringLiteral(Tok, WarningName, "pragma diagnostic", /*AllowMacroExpansion=*/false)) return; if (Tok.isNot(tok::eod)) { PP.Diag(Tok.getLocation(), diag::warn_pragma_diagnostic_invalid_token); return; } if (WarningName.size() < 3 || WarningName[0] != '-' || (WarningName[1] != 'W' && WarningName[1] != 'R')) { PP.Diag(StringLoc, diag::warn_pragma_diagnostic_invalid_option); return; } diag::Flavor Flavor = WarningName[1] == 'W' ? diag::Flavor::WarningOrError : diag::Flavor::Remark; StringRef Group = StringRef(WarningName).substr(2); bool unknownDiag = false; if (Group == "everything") { // Special handling for pragma clang diagnostic ... "-Weverything". // There is no formal group named "everything", so there has to be a // special case for it. PP.getDiagnostics().setSeverityForAll(Flavor, SV, DiagLoc); } else unknownDiag = PP.getDiagnostics().setSeverityForGroup(Flavor, Group, SV, DiagLoc); if (unknownDiag) PP.Diag(StringLoc, diag::warn_pragma_diagnostic_unknown_warning) << WarningName; else if (Callbacks) Callbacks->PragmaDiagnostic(DiagLoc, Namespace, SV, WarningName); } }; /// "\#pragma hdrstop []" struct PragmaHdrstopHandler : public PragmaHandler { PragmaHdrstopHandler() : PragmaHandler("hdrstop") {} void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, Token &DepToken) override { PP.HandlePragmaHdrstop(DepToken); } }; /// "\#pragma warning(...)". MSVC's diagnostics do not map cleanly to clang's /// diagnostics, so we don't really implement this pragma. We parse it and /// ignore it to avoid -Wunknown-pragma warnings. struct PragmaWarningHandler : public PragmaHandler { PragmaWarningHandler() : PragmaHandler("warning") {} void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, Token &Tok) override { // Parse things like: // warning(push, 1) // warning(pop) // warning(disable : 1 2 3 ; error : 4 5 6 ; suppress : 7 8 9) SourceLocation DiagLoc = Tok.getLocation(); PPCallbacks *Callbacks = PP.getPPCallbacks(); PP.Lex(Tok); if (Tok.isNot(tok::l_paren)) { PP.Diag(Tok, diag::warn_pragma_warning_expected) << "("; return; } PP.Lex(Tok); IdentifierInfo *II = Tok.getIdentifierInfo(); if (II && II->isStr("push")) { // #pragma warning( push[ ,n ] ) int Level = -1; PP.Lex(Tok); if (Tok.is(tok::comma)) { PP.Lex(Tok); uint64_t Value; if (Tok.is(tok::numeric_constant) && PP.parseSimpleIntegerLiteral(Tok, Value)) Level = int(Value); if (Level < 0 || Level > 4) { PP.Diag(Tok, diag::warn_pragma_warning_push_level); return; } } if (Callbacks) Callbacks->PragmaWarningPush(DiagLoc, Level); } else if (II && II->isStr("pop")) { // #pragma warning( pop ) PP.Lex(Tok); if (Callbacks) Callbacks->PragmaWarningPop(DiagLoc); } else { // #pragma warning( warning-specifier : warning-number-list // [; warning-specifier : warning-number-list...] ) while (true) { II = Tok.getIdentifierInfo(); if (!II && !Tok.is(tok::numeric_constant)) { PP.Diag(Tok, diag::warn_pragma_warning_spec_invalid); return; } // Figure out which warning specifier this is. bool SpecifierValid; StringRef Specifier; llvm::SmallString<1> SpecifierBuf; if (II) { Specifier = II->getName(); SpecifierValid = llvm::StringSwitch(Specifier) .Cases("default", "disable", "error", "once", "suppress", true) .Default(false); // If we read a correct specifier, snatch next token (that should be // ":", checked later). if (SpecifierValid) PP.Lex(Tok); } else { // Token is a numeric constant. It should be either 1, 2, 3 or 4. uint64_t Value; Specifier = PP.getSpelling(Tok, SpecifierBuf); if (PP.parseSimpleIntegerLiteral(Tok, Value)) { SpecifierValid = (Value >= 1) && (Value <= 4); } else SpecifierValid = false; // Next token already snatched by parseSimpleIntegerLiteral. } if (!SpecifierValid) { PP.Diag(Tok, diag::warn_pragma_warning_spec_invalid); return; } if (Tok.isNot(tok::colon)) { PP.Diag(Tok, diag::warn_pragma_warning_expected) << ":"; return; } // Collect the warning ids. SmallVector Ids; PP.Lex(Tok); while (Tok.is(tok::numeric_constant)) { uint64_t Value; if (!PP.parseSimpleIntegerLiteral(Tok, Value) || Value == 0 || Value > std::numeric_limits::max()) { PP.Diag(Tok, diag::warn_pragma_warning_expected_number); return; } Ids.push_back(int(Value)); } if (Callbacks) Callbacks->PragmaWarning(DiagLoc, Specifier, Ids); // Parse the next specifier if there is a semicolon. if (Tok.isNot(tok::semi)) break; PP.Lex(Tok); } } if (Tok.isNot(tok::r_paren)) { PP.Diag(Tok, diag::warn_pragma_warning_expected) << ")"; return; } PP.Lex(Tok); if (Tok.isNot(tok::eod)) PP.Diag(Tok, diag::ext_pp_extra_tokens_at_eol) << "pragma warning"; } }; /// "\#pragma execution_character_set(...)". MSVC supports this pragma only /// for "UTF-8". We parse it and ignore it if UTF-8 is provided and warn /// otherwise to avoid -Wunknown-pragma warnings. struct PragmaExecCharsetHandler : public PragmaHandler { PragmaExecCharsetHandler() : PragmaHandler("execution_character_set") {} void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, Token &Tok) override { // Parse things like: // execution_character_set(push, "UTF-8") // execution_character_set(pop) SourceLocation DiagLoc = Tok.getLocation(); PPCallbacks *Callbacks = PP.getPPCallbacks(); PP.Lex(Tok); if (Tok.isNot(tok::l_paren)) { PP.Diag(Tok, diag::warn_pragma_exec_charset_expected) << "("; return; } PP.Lex(Tok); IdentifierInfo *II = Tok.getIdentifierInfo(); if (II && II->isStr("push")) { // #pragma execution_character_set( push[ , string ] ) PP.Lex(Tok); if (Tok.is(tok::comma)) { PP.Lex(Tok); std::string ExecCharset; if (!PP.FinishLexStringLiteral(Tok, ExecCharset, "pragma execution_character_set", /*AllowMacroExpansion=*/false)) return; // MSVC supports either of these, but nothing else. if (ExecCharset != "UTF-8" && ExecCharset != "utf-8") { PP.Diag(Tok, diag::warn_pragma_exec_charset_push_invalid) << ExecCharset; return; } } if (Callbacks) Callbacks->PragmaExecCharsetPush(DiagLoc, "UTF-8"); } else if (II && II->isStr("pop")) { // #pragma execution_character_set( pop ) PP.Lex(Tok); if (Callbacks) Callbacks->PragmaExecCharsetPop(DiagLoc); } else { PP.Diag(Tok, diag::warn_pragma_exec_charset_spec_invalid); return; } if (Tok.isNot(tok::r_paren)) { PP.Diag(Tok, diag::warn_pragma_exec_charset_expected) << ")"; return; } PP.Lex(Tok); if (Tok.isNot(tok::eod)) PP.Diag(Tok, diag::ext_pp_extra_tokens_at_eol) << "pragma execution_character_set"; } }; /// PragmaIncludeAliasHandler - "\#pragma include_alias("...")". struct PragmaIncludeAliasHandler : public PragmaHandler { PragmaIncludeAliasHandler() : PragmaHandler("include_alias") {} void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, Token &IncludeAliasTok) override { PP.HandlePragmaIncludeAlias(IncludeAliasTok); } }; /// PragmaMessageHandler - Handle the microsoft and gcc \#pragma message /// extension. The syntax is: /// \code /// #pragma message(string) /// \endcode /// OR, in GCC mode: /// \code /// #pragma message string /// \endcode /// string is a string, which is fully macro expanded, and permits string /// concatenation, embedded escape characters, etc... See MSDN for more details. /// Also handles \#pragma GCC warning and \#pragma GCC error which take the same /// form as \#pragma message. struct PragmaMessageHandler : public PragmaHandler { private: const PPCallbacks::PragmaMessageKind Kind; const StringRef Namespace; static const char* PragmaKind(PPCallbacks::PragmaMessageKind Kind, bool PragmaNameOnly = false) { switch (Kind) { case PPCallbacks::PMK_Message: return PragmaNameOnly ? "message" : "pragma message"; case PPCallbacks::PMK_Warning: return PragmaNameOnly ? "warning" : "pragma warning"; case PPCallbacks::PMK_Error: return PragmaNameOnly ? "error" : "pragma error"; } llvm_unreachable("Unknown PragmaMessageKind!"); } public: PragmaMessageHandler(PPCallbacks::PragmaMessageKind Kind, StringRef Namespace = StringRef()) : PragmaHandler(PragmaKind(Kind, true)), Kind(Kind), Namespace(Namespace) {} void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, Token &Tok) override { SourceLocation MessageLoc = Tok.getLocation(); PP.Lex(Tok); bool ExpectClosingParen = false; switch (Tok.getKind()) { case tok::l_paren: // We have a MSVC style pragma message. ExpectClosingParen = true; // Read the string. PP.Lex(Tok); break; case tok::string_literal: // We have a GCC style pragma message, and we just read the string. break; default: PP.Diag(MessageLoc, diag::err_pragma_message_malformed) << Kind; return; } std::string MessageString; if (!PP.FinishLexStringLiteral(Tok, MessageString, PragmaKind(Kind), /*AllowMacroExpansion=*/true)) return; if (ExpectClosingParen) { if (Tok.isNot(tok::r_paren)) { PP.Diag(Tok.getLocation(), diag::err_pragma_message_malformed) << Kind; return; } PP.Lex(Tok); // eat the r_paren. } if (Tok.isNot(tok::eod)) { PP.Diag(Tok.getLocation(), diag::err_pragma_message_malformed) << Kind; return; } // Output the message. PP.Diag(MessageLoc, (Kind == PPCallbacks::PMK_Error) ? diag::err_pragma_message : diag::warn_pragma_message) << MessageString; // If the pragma is lexically sound, notify any interested PPCallbacks. if (PPCallbacks *Callbacks = PP.getPPCallbacks()) Callbacks->PragmaMessage(MessageLoc, Namespace, Kind, MessageString); } }; /// Handle the clang \#pragma module import extension. The syntax is: /// \code /// #pragma clang module import some.module.name /// \endcode struct PragmaModuleImportHandler : public PragmaHandler { PragmaModuleImportHandler() : PragmaHandler("import") {} void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, Token &Tok) override { SourceLocation ImportLoc = Tok.getLocation(); // Read the module name. llvm::SmallVector, 8> ModuleName; if (LexModuleName(PP, Tok, ModuleName)) return; if (Tok.isNot(tok::eod)) PP.Diag(Tok, diag::ext_pp_extra_tokens_at_eol) << "pragma"; // If we have a non-empty module path, load the named module. Module *Imported = PP.getModuleLoader().loadModule(ImportLoc, ModuleName, Module::Hidden, /*IsInclusionDirective=*/false); if (!Imported) return; PP.makeModuleVisible(Imported, ImportLoc); PP.EnterAnnotationToken(SourceRange(ImportLoc, ModuleName.back().second), tok::annot_module_include, Imported); if (auto *CB = PP.getPPCallbacks()) CB->moduleImport(ImportLoc, ModuleName, Imported); } }; /// Handle the clang \#pragma module begin extension. The syntax is: /// \code /// #pragma clang module begin some.module.name /// ... /// #pragma clang module end /// \endcode struct PragmaModuleBeginHandler : public PragmaHandler { PragmaModuleBeginHandler() : PragmaHandler("begin") {} void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, Token &Tok) override { SourceLocation BeginLoc = Tok.getLocation(); // Read the module name. llvm::SmallVector, 8> ModuleName; if (LexModuleName(PP, Tok, ModuleName)) return; if (Tok.isNot(tok::eod)) PP.Diag(Tok, diag::ext_pp_extra_tokens_at_eol) << "pragma"; // We can only enter submodules of the current module. StringRef Current = PP.getLangOpts().CurrentModule; if (ModuleName.front().first->getName() != Current) { PP.Diag(ModuleName.front().second, diag::err_pp_module_begin_wrong_module) << ModuleName.front().first << (ModuleName.size() > 1) << Current.empty() << Current; return; } // Find the module we're entering. We require that a module map for it // be loaded or implicitly loadable. auto &HSI = PP.getHeaderSearchInfo(); Module *M = HSI.lookupModule(Current); if (!M) { PP.Diag(ModuleName.front().second, diag::err_pp_module_begin_no_module_map) << Current; return; } for (unsigned I = 1; I != ModuleName.size(); ++I) { auto *NewM = M->findOrInferSubmodule(ModuleName[I].first->getName()); if (!NewM) { PP.Diag(ModuleName[I].second, diag::err_pp_module_begin_no_submodule) << M->getFullModuleName() << ModuleName[I].first; return; } M = NewM; } // If the module isn't available, it doesn't make sense to enter it. if (Preprocessor::checkModuleIsAvailable( PP.getLangOpts(), PP.getTargetInfo(), PP.getDiagnostics(), M)) { PP.Diag(BeginLoc, diag::note_pp_module_begin_here) << M->getTopLevelModuleName(); return; } // Enter the scope of the submodule. PP.EnterSubmodule(M, BeginLoc, /*ForPragma*/true); PP.EnterAnnotationToken(SourceRange(BeginLoc, ModuleName.back().second), tok::annot_module_begin, M); } }; /// Handle the clang \#pragma module end extension. struct PragmaModuleEndHandler : public PragmaHandler { PragmaModuleEndHandler() : PragmaHandler("end") {} void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, Token &Tok) override { SourceLocation Loc = Tok.getLocation(); PP.LexUnexpandedToken(Tok); if (Tok.isNot(tok::eod)) PP.Diag(Tok, diag::ext_pp_extra_tokens_at_eol) << "pragma"; Module *M = PP.LeaveSubmodule(/*ForPragma*/true); if (M) PP.EnterAnnotationToken(SourceRange(Loc), tok::annot_module_end, M); else PP.Diag(Loc, diag::err_pp_module_end_without_module_begin); } }; /// Handle the clang \#pragma module build extension. struct PragmaModuleBuildHandler : public PragmaHandler { PragmaModuleBuildHandler() : PragmaHandler("build") {} void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, Token &Tok) override { PP.HandlePragmaModuleBuild(Tok); } }; /// Handle the clang \#pragma module load extension. struct PragmaModuleLoadHandler : public PragmaHandler { PragmaModuleLoadHandler() : PragmaHandler("load") {} void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, Token &Tok) override { SourceLocation Loc = Tok.getLocation(); // Read the module name. llvm::SmallVector, 8> ModuleName; if (LexModuleName(PP, Tok, ModuleName)) return; if (Tok.isNot(tok::eod)) PP.Diag(Tok, diag::ext_pp_extra_tokens_at_eol) << "pragma"; // Load the module, don't make it visible. PP.getModuleLoader().loadModule(Loc, ModuleName, Module::Hidden, /*IsInclusionDirective=*/false); } }; /// PragmaPushMacroHandler - "\#pragma push_macro" saves the value of the /// macro on the top of the stack. struct PragmaPushMacroHandler : public PragmaHandler { PragmaPushMacroHandler() : PragmaHandler("push_macro") {} void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, Token &PushMacroTok) override { PP.HandlePragmaPushMacro(PushMacroTok); } }; /// PragmaPopMacroHandler - "\#pragma pop_macro" sets the value of the /// macro to the value on the top of the stack. struct PragmaPopMacroHandler : public PragmaHandler { PragmaPopMacroHandler() : PragmaHandler("pop_macro") {} void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, Token &PopMacroTok) override { PP.HandlePragmaPopMacro(PopMacroTok); } }; /// PragmaARCCFCodeAuditedHandler - /// \#pragma clang arc_cf_code_audited begin/end struct PragmaARCCFCodeAuditedHandler : public PragmaHandler { PragmaARCCFCodeAuditedHandler() : PragmaHandler("arc_cf_code_audited") {} void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, Token &NameTok) override { SourceLocation Loc = NameTok.getLocation(); bool IsBegin; Token Tok; // Lex the 'begin' or 'end'. PP.LexUnexpandedToken(Tok); const IdentifierInfo *BeginEnd = Tok.getIdentifierInfo(); if (BeginEnd && BeginEnd->isStr("begin")) { IsBegin = true; } else if (BeginEnd && BeginEnd->isStr("end")) { IsBegin = false; } else { PP.Diag(Tok.getLocation(), diag::err_pp_arc_cf_code_audited_syntax); return; } // Verify that this is followed by EOD. PP.LexUnexpandedToken(Tok); if (Tok.isNot(tok::eod)) PP.Diag(Tok, diag::ext_pp_extra_tokens_at_eol) << "pragma"; // The start location of the active audit. SourceLocation BeginLoc = PP.getPragmaARCCFCodeAuditedInfo().second; // The start location we want after processing this. SourceLocation NewLoc; if (IsBegin) { // Complain about attempts to re-enter an audit. if (BeginLoc.isValid()) { PP.Diag(Loc, diag::err_pp_double_begin_of_arc_cf_code_audited); PP.Diag(BeginLoc, diag::note_pragma_entered_here); } NewLoc = Loc; } else { // Complain about attempts to leave an audit that doesn't exist. if (!BeginLoc.isValid()) { PP.Diag(Loc, diag::err_pp_unmatched_end_of_arc_cf_code_audited); return; } NewLoc = SourceLocation(); } PP.setPragmaARCCFCodeAuditedInfo(NameTok.getIdentifierInfo(), NewLoc); } }; /// PragmaAssumeNonNullHandler - /// \#pragma clang assume_nonnull begin/end struct PragmaAssumeNonNullHandler : public PragmaHandler { PragmaAssumeNonNullHandler() : PragmaHandler("assume_nonnull") {} void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, Token &NameTok) override { SourceLocation Loc = NameTok.getLocation(); bool IsBegin; Token Tok; // Lex the 'begin' or 'end'. PP.LexUnexpandedToken(Tok); const IdentifierInfo *BeginEnd = Tok.getIdentifierInfo(); if (BeginEnd && BeginEnd->isStr("begin")) { IsBegin = true; } else if (BeginEnd && BeginEnd->isStr("end")) { IsBegin = false; } else { PP.Diag(Tok.getLocation(), diag::err_pp_assume_nonnull_syntax); return; } // Verify that this is followed by EOD. PP.LexUnexpandedToken(Tok); if (Tok.isNot(tok::eod)) PP.Diag(Tok, diag::ext_pp_extra_tokens_at_eol) << "pragma"; // The start location of the active audit. SourceLocation BeginLoc = PP.getPragmaAssumeNonNullLoc(); // The start location we want after processing this. SourceLocation NewLoc; PPCallbacks *Callbacks = PP.getPPCallbacks(); if (IsBegin) { // Complain about attempts to re-enter an audit. if (BeginLoc.isValid()) { PP.Diag(Loc, diag::err_pp_double_begin_of_assume_nonnull); PP.Diag(BeginLoc, diag::note_pragma_entered_here); } NewLoc = Loc; if (Callbacks) Callbacks->PragmaAssumeNonNullBegin(NewLoc); } else { // Complain about attempts to leave an audit that doesn't exist. if (!BeginLoc.isValid()) { PP.Diag(Loc, diag::err_pp_unmatched_end_of_assume_nonnull); return; } NewLoc = SourceLocation(); if (Callbacks) Callbacks->PragmaAssumeNonNullEnd(NewLoc); } PP.setPragmaAssumeNonNullLoc(NewLoc); } }; /// Handle "\#pragma region [...]" /// /// The syntax is /// \code /// #pragma region [optional name] /// #pragma endregion [optional comment] /// \endcode /// /// \note This is /// editor-only /// pragma, just skipped by compiler. struct PragmaRegionHandler : public PragmaHandler { PragmaRegionHandler(const char *pragma) : PragmaHandler(pragma) {} void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, Token &NameTok) override { // #pragma region: endregion matches can be verified // __pragma(region): no sense, but ignored by msvc // _Pragma is not valid for MSVC, but there isn't any point // to handle a _Pragma differently. } }; } // namespace /// RegisterBuiltinPragmas - Install the standard preprocessor pragmas: /// \#pragma GCC poison/system_header/dependency and \#pragma once. void Preprocessor::RegisterBuiltinPragmas() { AddPragmaHandler(new PragmaOnceHandler()); AddPragmaHandler(new PragmaMarkHandler()); AddPragmaHandler(new PragmaPushMacroHandler()); AddPragmaHandler(new PragmaPopMacroHandler()); AddPragmaHandler(new PragmaMessageHandler(PPCallbacks::PMK_Message)); // #pragma GCC ... AddPragmaHandler("GCC", new PragmaPoisonHandler()); AddPragmaHandler("GCC", new PragmaSystemHeaderHandler()); AddPragmaHandler("GCC", new PragmaDependencyHandler()); AddPragmaHandler("GCC", new PragmaDiagnosticHandler("GCC")); AddPragmaHandler("GCC", new PragmaMessageHandler(PPCallbacks::PMK_Warning, "GCC")); AddPragmaHandler("GCC", new PragmaMessageHandler(PPCallbacks::PMK_Error, "GCC")); // #pragma clang ... AddPragmaHandler("clang", new PragmaPoisonHandler()); AddPragmaHandler("clang", new PragmaSystemHeaderHandler()); AddPragmaHandler("clang", new PragmaDebugHandler()); AddPragmaHandler("clang", new PragmaDependencyHandler()); AddPragmaHandler("clang", new PragmaDiagnosticHandler("clang")); AddPragmaHandler("clang", new PragmaARCCFCodeAuditedHandler()); AddPragmaHandler("clang", new PragmaAssumeNonNullHandler()); // #pragma clang module ... auto *ModuleHandler = new PragmaNamespace("module"); AddPragmaHandler("clang", ModuleHandler); ModuleHandler->AddPragma(new PragmaModuleImportHandler()); ModuleHandler->AddPragma(new PragmaModuleBeginHandler()); ModuleHandler->AddPragma(new PragmaModuleEndHandler()); ModuleHandler->AddPragma(new PragmaModuleBuildHandler()); ModuleHandler->AddPragma(new PragmaModuleLoadHandler()); // Add region pragmas. AddPragmaHandler(new PragmaRegionHandler("region")); AddPragmaHandler(new PragmaRegionHandler("endregion")); // MS extensions. if (LangOpts.MicrosoftExt) { AddPragmaHandler(new PragmaWarningHandler()); AddPragmaHandler(new PragmaExecCharsetHandler()); AddPragmaHandler(new PragmaIncludeAliasHandler()); AddPragmaHandler(new PragmaHdrstopHandler()); } // Pragmas added by plugins for (PragmaHandlerRegistry::iterator it = PragmaHandlerRegistry::begin(), ie = PragmaHandlerRegistry::end(); it != ie; ++it) { AddPragmaHandler(it->instantiate().release()); } } /// Ignore all pragmas, useful for modes such as -Eonly which would otherwise /// warn about those pragmas being unknown. void Preprocessor::IgnorePragmas() { AddPragmaHandler(new EmptyPragmaHandler()); // Also ignore all pragmas in all namespaces created // in Preprocessor::RegisterBuiltinPragmas(). AddPragmaHandler("GCC", new EmptyPragmaHandler()); AddPragmaHandler("clang", new EmptyPragmaHandler()); } Index: vendor/llvm-project/release-10.x/clang/lib/Sema/SemaExpr.cpp =================================================================== --- vendor/llvm-project/release-10.x/clang/lib/Sema/SemaExpr.cpp (revision 359078) +++ vendor/llvm-project/release-10.x/clang/lib/Sema/SemaExpr.cpp (revision 359079) @@ -1,18162 +1,18159 @@ //===--- SemaExpr.cpp - Semantic Analysis for Expressions -----------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This file implements semantic analysis for expressions. // //===----------------------------------------------------------------------===// #include "TreeTransform.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" #include "clang/AST/ASTLambda.h" #include "clang/AST/ASTMutationListener.h" #include "clang/AST/CXXInheritance.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/EvaluatedExprVisitor.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/ExprObjC.h" #include "clang/AST/ExprOpenMP.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/TypeLoc.h" #include "clang/Basic/Builtins.h" #include "clang/Basic/FixedPoint.h" #include "clang/Basic/PartialDiagnostic.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/TargetInfo.h" #include "clang/Lex/LiteralSupport.h" #include "clang/Lex/Preprocessor.h" #include "clang/Sema/AnalysisBasedWarnings.h" #include "clang/Sema/DeclSpec.h" #include "clang/Sema/DelayedDiagnostic.h" #include "clang/Sema/Designator.h" #include "clang/Sema/Initialization.h" #include "clang/Sema/Lookup.h" #include "clang/Sema/Overload.h" #include "clang/Sema/ParsedTemplate.h" #include "clang/Sema/Scope.h" #include "clang/Sema/ScopeInfo.h" #include "clang/Sema/SemaFixItUtils.h" #include "clang/Sema/SemaInternal.h" #include "clang/Sema/Template.h" #include "llvm/Support/ConvertUTF.h" using namespace clang; using namespace sema; /// Determine whether the use of this declaration is valid, without /// emitting diagnostics. bool Sema::CanUseDecl(NamedDecl *D, bool TreatUnavailableAsInvalid) { // See if this is an auto-typed variable whose initializer we are parsing. if (ParsingInitForAutoVars.count(D)) return false; // See if this is a deleted function. if (FunctionDecl *FD = dyn_cast(D)) { if (FD->isDeleted()) return false; // If the function has a deduced return type, and we can't deduce it, // then we can't use it either. if (getLangOpts().CPlusPlus14 && FD->getReturnType()->isUndeducedType() && DeduceReturnType(FD, SourceLocation(), /*Diagnose*/ false)) return false; // See if this is an aligned allocation/deallocation function that is // unavailable. if (TreatUnavailableAsInvalid && isUnavailableAlignedAllocationFunction(*FD)) return false; } // See if this function is unavailable. if (TreatUnavailableAsInvalid && D->getAvailability() == AR_Unavailable && cast(CurContext)->getAvailability() != AR_Unavailable) return false; return true; } static void DiagnoseUnusedOfDecl(Sema &S, NamedDecl *D, SourceLocation Loc) { // Warn if this is used but marked unused. if (const auto *A = D->getAttr()) { // [[maybe_unused]] should not diagnose uses, but __attribute__((unused)) // should diagnose them. if (A->getSemanticSpelling() != UnusedAttr::CXX11_maybe_unused && A->getSemanticSpelling() != UnusedAttr::C2x_maybe_unused) { const Decl *DC = cast_or_null(S.getCurObjCLexicalContext()); if (DC && !DC->hasAttr()) S.Diag(Loc, diag::warn_used_but_marked_unused) << D->getDeclName(); } } } /// Emit a note explaining that this function is deleted. void Sema::NoteDeletedFunction(FunctionDecl *Decl) { assert(Decl && Decl->isDeleted()); if (Decl->isDefaulted()) { // If the method was explicitly defaulted, point at that declaration. if (!Decl->isImplicit()) Diag(Decl->getLocation(), diag::note_implicitly_deleted); // Try to diagnose why this special member function was implicitly // deleted. This might fail, if that reason no longer applies. DiagnoseDeletedDefaultedFunction(Decl); return; } auto *Ctor = dyn_cast(Decl); if (Ctor && Ctor->isInheritingConstructor()) return NoteDeletedInheritingConstructor(Ctor); Diag(Decl->getLocation(), diag::note_availability_specified_here) << Decl << 1; } /// Determine whether a FunctionDecl was ever declared with an /// explicit storage class. static bool hasAnyExplicitStorageClass(const FunctionDecl *D) { for (auto I : D->redecls()) { if (I->getStorageClass() != SC_None) return true; } return false; } /// Check whether we're in an extern inline function and referring to a /// variable or function with internal linkage (C11 6.7.4p3). /// /// This is only a warning because we used to silently accept this code, but /// in many cases it will not behave correctly. This is not enabled in C++ mode /// because the restriction language is a bit weaker (C++11 [basic.def.odr]p6) /// and so while there may still be user mistakes, most of the time we can't /// prove that there are errors. static void diagnoseUseOfInternalDeclInInlineFunction(Sema &S, const NamedDecl *D, SourceLocation Loc) { // This is disabled under C++; there are too many ways for this to fire in // contexts where the warning is a false positive, or where it is technically // correct but benign. if (S.getLangOpts().CPlusPlus) return; // Check if this is an inlined function or method. FunctionDecl *Current = S.getCurFunctionDecl(); if (!Current) return; if (!Current->isInlined()) return; if (!Current->isExternallyVisible()) return; // Check if the decl has internal linkage. if (D->getFormalLinkage() != InternalLinkage) return; // Downgrade from ExtWarn to Extension if // (1) the supposedly external inline function is in the main file, // and probably won't be included anywhere else. // (2) the thing we're referencing is a pure function. // (3) the thing we're referencing is another inline function. // This last can give us false negatives, but it's better than warning on // wrappers for simple C library functions. const FunctionDecl *UsedFn = dyn_cast(D); bool DowngradeWarning = S.getSourceManager().isInMainFile(Loc); if (!DowngradeWarning && UsedFn) DowngradeWarning = UsedFn->isInlined() || UsedFn->hasAttr(); S.Diag(Loc, DowngradeWarning ? diag::ext_internal_in_extern_inline_quiet : diag::ext_internal_in_extern_inline) << /*IsVar=*/!UsedFn << D; S.MaybeSuggestAddingStaticToDecl(Current); S.Diag(D->getCanonicalDecl()->getLocation(), diag::note_entity_declared_at) << D; } void Sema::MaybeSuggestAddingStaticToDecl(const FunctionDecl *Cur) { const FunctionDecl *First = Cur->getFirstDecl(); // Suggest "static" on the function, if possible. if (!hasAnyExplicitStorageClass(First)) { SourceLocation DeclBegin = First->getSourceRange().getBegin(); Diag(DeclBegin, diag::note_convert_inline_to_static) << Cur << FixItHint::CreateInsertion(DeclBegin, "static "); } } /// Determine whether the use of this declaration is valid, and /// emit any corresponding diagnostics. /// /// This routine diagnoses various problems with referencing /// declarations that can occur when using a declaration. For example, /// it might warn if a deprecated or unavailable declaration is being /// used, or produce an error (and return true) if a C++0x deleted /// function is being used. /// /// \returns true if there was an error (this declaration cannot be /// referenced), false otherwise. /// bool Sema::DiagnoseUseOfDecl(NamedDecl *D, ArrayRef Locs, const ObjCInterfaceDecl *UnknownObjCClass, bool ObjCPropertyAccess, bool AvoidPartialAvailabilityChecks, ObjCInterfaceDecl *ClassReceiver) { SourceLocation Loc = Locs.front(); if (getLangOpts().CPlusPlus && isa(D)) { // If there were any diagnostics suppressed by template argument deduction, // emit them now. auto Pos = SuppressedDiagnostics.find(D->getCanonicalDecl()); if (Pos != SuppressedDiagnostics.end()) { for (const PartialDiagnosticAt &Suppressed : Pos->second) Diag(Suppressed.first, Suppressed.second); // Clear out the list of suppressed diagnostics, so that we don't emit // them again for this specialization. However, we don't obsolete this // entry from the table, because we want to avoid ever emitting these // diagnostics again. Pos->second.clear(); } // C++ [basic.start.main]p3: // The function 'main' shall not be used within a program. if (cast(D)->isMain()) Diag(Loc, diag::ext_main_used); diagnoseUnavailableAlignedAllocation(*cast(D), Loc); } // See if this is an auto-typed variable whose initializer we are parsing. if (ParsingInitForAutoVars.count(D)) { if (isa(D)) { Diag(Loc, diag::err_binding_cannot_appear_in_own_initializer) << D->getDeclName(); } else { Diag(Loc, diag::err_auto_variable_cannot_appear_in_own_initializer) << D->getDeclName() << cast(D)->getType(); } return true; } if (FunctionDecl *FD = dyn_cast(D)) { // See if this is a deleted function. if (FD->isDeleted()) { auto *Ctor = dyn_cast(FD); if (Ctor && Ctor->isInheritingConstructor()) Diag(Loc, diag::err_deleted_inherited_ctor_use) << Ctor->getParent() << Ctor->getInheritedConstructor().getConstructor()->getParent(); else Diag(Loc, diag::err_deleted_function_use); NoteDeletedFunction(FD); return true; } // [expr.prim.id]p4 // A program that refers explicitly or implicitly to a function with a // trailing requires-clause whose constraint-expression is not satisfied, // other than to declare it, is ill-formed. [...] // // See if this is a function with constraints that need to be satisfied. // Check this before deducing the return type, as it might instantiate the // definition. if (FD->getTrailingRequiresClause()) { ConstraintSatisfaction Satisfaction; if (CheckFunctionConstraints(FD, Satisfaction, Loc)) // A diagnostic will have already been generated (non-constant // constraint expression, for example) return true; if (!Satisfaction.IsSatisfied) { Diag(Loc, diag::err_reference_to_function_with_unsatisfied_constraints) << D; DiagnoseUnsatisfiedConstraint(Satisfaction); return true; } } // If the function has a deduced return type, and we can't deduce it, // then we can't use it either. if (getLangOpts().CPlusPlus14 && FD->getReturnType()->isUndeducedType() && DeduceReturnType(FD, Loc)) return true; if (getLangOpts().CUDA && !CheckCUDACall(Loc, FD)) return true; } if (auto *MD = dyn_cast(D)) { // Lambdas are only default-constructible or assignable in C++2a onwards. if (MD->getParent()->isLambda() && ((isa(MD) && cast(MD)->isDefaultConstructor()) || MD->isCopyAssignmentOperator() || MD->isMoveAssignmentOperator())) { Diag(Loc, diag::warn_cxx17_compat_lambda_def_ctor_assign) << !isa(MD); } } auto getReferencedObjCProp = [](const NamedDecl *D) -> const ObjCPropertyDecl * { if (const auto *MD = dyn_cast(D)) return MD->findPropertyDecl(); return nullptr; }; if (const ObjCPropertyDecl *ObjCPDecl = getReferencedObjCProp(D)) { if (diagnoseArgIndependentDiagnoseIfAttrs(ObjCPDecl, Loc)) return true; } else if (diagnoseArgIndependentDiagnoseIfAttrs(D, Loc)) { return true; } // [OpenMP 4.0], 2.15 declare reduction Directive, Restrictions // Only the variables omp_in and omp_out are allowed in the combiner. // Only the variables omp_priv and omp_orig are allowed in the // initializer-clause. auto *DRD = dyn_cast(CurContext); if (LangOpts.OpenMP && DRD && !CurContext->containsDecl(D) && isa(D)) { Diag(Loc, diag::err_omp_wrong_var_in_declare_reduction) << getCurFunction()->HasOMPDeclareReductionCombiner; Diag(D->getLocation(), diag::note_entity_declared_at) << D; return true; } // [OpenMP 5.0], 2.19.7.3. declare mapper Directive, Restrictions // List-items in map clauses on this construct may only refer to the declared // variable var and entities that could be referenced by a procedure defined // at the same location auto *DMD = dyn_cast(CurContext); if (LangOpts.OpenMP && DMD && !CurContext->containsDecl(D) && isa(D)) { Diag(Loc, diag::err_omp_declare_mapper_wrong_var) << DMD->getVarName().getAsString(); Diag(D->getLocation(), diag::note_entity_declared_at) << D; return true; } DiagnoseAvailabilityOfDecl(D, Locs, UnknownObjCClass, ObjCPropertyAccess, AvoidPartialAvailabilityChecks, ClassReceiver); DiagnoseUnusedOfDecl(*this, D, Loc); diagnoseUseOfInternalDeclInInlineFunction(*this, D, Loc); if (isa(D) && isa(D->getDeclContext()) && !isUnevaluatedContext()) { // C++ [expr.prim.req.nested] p3 // A local parameter shall only appear as an unevaluated operand // (Clause 8) within the constraint-expression. Diag(Loc, diag::err_requires_expr_parameter_referenced_in_evaluated_context) << D; Diag(D->getLocation(), diag::note_entity_declared_at) << D; return true; } return false; } /// DiagnoseSentinelCalls - This routine checks whether a call or /// message-send is to a declaration with the sentinel attribute, and /// if so, it checks that the requirements of the sentinel are /// satisfied. void Sema::DiagnoseSentinelCalls(NamedDecl *D, SourceLocation Loc, ArrayRef Args) { const SentinelAttr *attr = D->getAttr(); if (!attr) return; // The number of formal parameters of the declaration. unsigned numFormalParams; // The kind of declaration. This is also an index into a %select in // the diagnostic. enum CalleeType { CT_Function, CT_Method, CT_Block } calleeType; if (ObjCMethodDecl *MD = dyn_cast(D)) { numFormalParams = MD->param_size(); calleeType = CT_Method; } else if (FunctionDecl *FD = dyn_cast(D)) { numFormalParams = FD->param_size(); calleeType = CT_Function; } else if (isa(D)) { QualType type = cast(D)->getType(); const FunctionType *fn = nullptr; if (const PointerType *ptr = type->getAs()) { fn = ptr->getPointeeType()->getAs(); if (!fn) return; calleeType = CT_Function; } else if (const BlockPointerType *ptr = type->getAs()) { fn = ptr->getPointeeType()->castAs(); calleeType = CT_Block; } else { return; } if (const FunctionProtoType *proto = dyn_cast(fn)) { numFormalParams = proto->getNumParams(); } else { numFormalParams = 0; } } else { return; } // "nullPos" is the number of formal parameters at the end which // effectively count as part of the variadic arguments. This is // useful if you would prefer to not have *any* formal parameters, // but the language forces you to have at least one. unsigned nullPos = attr->getNullPos(); assert((nullPos == 0 || nullPos == 1) && "invalid null position on sentinel"); numFormalParams = (nullPos > numFormalParams ? 0 : numFormalParams - nullPos); // The number of arguments which should follow the sentinel. unsigned numArgsAfterSentinel = attr->getSentinel(); // If there aren't enough arguments for all the formal parameters, // the sentinel, and the args after the sentinel, complain. if (Args.size() < numFormalParams + numArgsAfterSentinel + 1) { Diag(Loc, diag::warn_not_enough_argument) << D->getDeclName(); Diag(D->getLocation(), diag::note_sentinel_here) << int(calleeType); return; } // Otherwise, find the sentinel expression. Expr *sentinelExpr = Args[Args.size() - numArgsAfterSentinel - 1]; if (!sentinelExpr) return; if (sentinelExpr->isValueDependent()) return; if (Context.isSentinelNullExpr(sentinelExpr)) return; // Pick a reasonable string to insert. Optimistically use 'nil', 'nullptr', // or 'NULL' if those are actually defined in the context. Only use // 'nil' for ObjC methods, where it's much more likely that the // variadic arguments form a list of object pointers. SourceLocation MissingNilLoc = getLocForEndOfToken(sentinelExpr->getEndLoc()); std::string NullValue; if (calleeType == CT_Method && PP.isMacroDefined("nil")) NullValue = "nil"; else if (getLangOpts().CPlusPlus11) NullValue = "nullptr"; else if (PP.isMacroDefined("NULL")) NullValue = "NULL"; else NullValue = "(void*) 0"; if (MissingNilLoc.isInvalid()) Diag(Loc, diag::warn_missing_sentinel) << int(calleeType); else Diag(MissingNilLoc, diag::warn_missing_sentinel) << int(calleeType) << FixItHint::CreateInsertion(MissingNilLoc, ", " + NullValue); Diag(D->getLocation(), diag::note_sentinel_here) << int(calleeType); } SourceRange Sema::getExprRange(Expr *E) const { return E ? E->getSourceRange() : SourceRange(); } //===----------------------------------------------------------------------===// // Standard Promotions and Conversions //===----------------------------------------------------------------------===// /// DefaultFunctionArrayConversion (C99 6.3.2.1p3, C99 6.3.2.1p4). ExprResult Sema::DefaultFunctionArrayConversion(Expr *E, bool Diagnose) { // Handle any placeholder expressions which made it here. if (E->getType()->isPlaceholderType()) { ExprResult result = CheckPlaceholderExpr(E); if (result.isInvalid()) return ExprError(); E = result.get(); } QualType Ty = E->getType(); assert(!Ty.isNull() && "DefaultFunctionArrayConversion - missing type"); if (Ty->isFunctionType()) { if (auto *DRE = dyn_cast(E->IgnoreParenCasts())) if (auto *FD = dyn_cast(DRE->getDecl())) if (!checkAddressOfFunctionIsAvailable(FD, Diagnose, E->getExprLoc())) return ExprError(); E = ImpCastExprToType(E, Context.getPointerType(Ty), CK_FunctionToPointerDecay).get(); } else if (Ty->isArrayType()) { // In C90 mode, arrays only promote to pointers if the array expression is // an lvalue. The relevant legalese is C90 6.2.2.1p3: "an lvalue that has // type 'array of type' is converted to an expression that has type 'pointer // to type'...". In C99 this was changed to: C99 6.3.2.1p3: "an expression // that has type 'array of type' ...". The relevant change is "an lvalue" // (C90) to "an expression" (C99). // // C++ 4.2p1: // An lvalue or rvalue of type "array of N T" or "array of unknown bound of // T" can be converted to an rvalue of type "pointer to T". // if (getLangOpts().C99 || getLangOpts().CPlusPlus || E->isLValue()) E = ImpCastExprToType(E, Context.getArrayDecayedType(Ty), CK_ArrayToPointerDecay).get(); } return E; } static void CheckForNullPointerDereference(Sema &S, Expr *E) { // Check to see if we are dereferencing a null pointer. If so, // and if not volatile-qualified, this is undefined behavior that the // optimizer will delete, so warn about it. People sometimes try to use this // to get a deterministic trap and are surprised by clang's behavior. This // only handles the pattern "*null", which is a very syntactic check. const auto *UO = dyn_cast(E->IgnoreParenCasts()); if (UO && UO->getOpcode() == UO_Deref && UO->getSubExpr()->getType()->isPointerType()) { const LangAS AS = UO->getSubExpr()->getType()->getPointeeType().getAddressSpace(); if ((!isTargetAddressSpace(AS) || (isTargetAddressSpace(AS) && toTargetAddressSpace(AS) == 0)) && UO->getSubExpr()->IgnoreParenCasts()->isNullPointerConstant( S.Context, Expr::NPC_ValueDependentIsNotNull) && !UO->getType().isVolatileQualified()) { S.DiagRuntimeBehavior(UO->getOperatorLoc(), UO, S.PDiag(diag::warn_indirection_through_null) << UO->getSubExpr()->getSourceRange()); S.DiagRuntimeBehavior(UO->getOperatorLoc(), UO, S.PDiag(diag::note_indirection_through_null)); } } } static void DiagnoseDirectIsaAccess(Sema &S, const ObjCIvarRefExpr *OIRE, SourceLocation AssignLoc, const Expr* RHS) { const ObjCIvarDecl *IV = OIRE->getDecl(); if (!IV) return; DeclarationName MemberName = IV->getDeclName(); IdentifierInfo *Member = MemberName.getAsIdentifierInfo(); if (!Member || !Member->isStr("isa")) return; const Expr *Base = OIRE->getBase(); QualType BaseType = Base->getType(); if (OIRE->isArrow()) BaseType = BaseType->getPointeeType(); if (const ObjCObjectType *OTy = BaseType->getAs()) if (ObjCInterfaceDecl *IDecl = OTy->getInterface()) { ObjCInterfaceDecl *ClassDeclared = nullptr; ObjCIvarDecl *IV = IDecl->lookupInstanceVariable(Member, ClassDeclared); if (!ClassDeclared->getSuperClass() && (*ClassDeclared->ivar_begin()) == IV) { if (RHS) { NamedDecl *ObjectSetClass = S.LookupSingleName(S.TUScope, &S.Context.Idents.get("object_setClass"), SourceLocation(), S.LookupOrdinaryName); if (ObjectSetClass) { SourceLocation RHSLocEnd = S.getLocForEndOfToken(RHS->getEndLoc()); S.Diag(OIRE->getExprLoc(), diag::warn_objc_isa_assign) << FixItHint::CreateInsertion(OIRE->getBeginLoc(), "object_setClass(") << FixItHint::CreateReplacement( SourceRange(OIRE->getOpLoc(), AssignLoc), ",") << FixItHint::CreateInsertion(RHSLocEnd, ")"); } else S.Diag(OIRE->getLocation(), diag::warn_objc_isa_assign); } else { NamedDecl *ObjectGetClass = S.LookupSingleName(S.TUScope, &S.Context.Idents.get("object_getClass"), SourceLocation(), S.LookupOrdinaryName); if (ObjectGetClass) S.Diag(OIRE->getExprLoc(), diag::warn_objc_isa_use) << FixItHint::CreateInsertion(OIRE->getBeginLoc(), "object_getClass(") << FixItHint::CreateReplacement( SourceRange(OIRE->getOpLoc(), OIRE->getEndLoc()), ")"); else S.Diag(OIRE->getLocation(), diag::warn_objc_isa_use); } S.Diag(IV->getLocation(), diag::note_ivar_decl); } } } ExprResult Sema::DefaultLvalueConversion(Expr *E) { // Handle any placeholder expressions which made it here. if (E->getType()->isPlaceholderType()) { ExprResult result = CheckPlaceholderExpr(E); if (result.isInvalid()) return ExprError(); E = result.get(); } // C++ [conv.lval]p1: // A glvalue of a non-function, non-array type T can be // converted to a prvalue. if (!E->isGLValue()) return E; QualType T = E->getType(); assert(!T.isNull() && "r-value conversion on typeless expression?"); // We don't want to throw lvalue-to-rvalue casts on top of // expressions of certain types in C++. if (getLangOpts().CPlusPlus && (E->getType() == Context.OverloadTy || T->isDependentType() || T->isRecordType())) return E; // The C standard is actually really unclear on this point, and // DR106 tells us what the result should be but not why. It's // generally best to say that void types just doesn't undergo // lvalue-to-rvalue at all. Note that expressions of unqualified // 'void' type are never l-values, but qualified void can be. if (T->isVoidType()) return E; // OpenCL usually rejects direct accesses to values of 'half' type. if (getLangOpts().OpenCL && !getOpenCLOptions().isEnabled("cl_khr_fp16") && T->isHalfType()) { Diag(E->getExprLoc(), diag::err_opencl_half_load_store) << 0 << T; return ExprError(); } CheckForNullPointerDereference(*this, E); if (const ObjCIsaExpr *OISA = dyn_cast(E->IgnoreParenCasts())) { NamedDecl *ObjectGetClass = LookupSingleName(TUScope, &Context.Idents.get("object_getClass"), SourceLocation(), LookupOrdinaryName); if (ObjectGetClass) Diag(E->getExprLoc(), diag::warn_objc_isa_use) << FixItHint::CreateInsertion(OISA->getBeginLoc(), "object_getClass(") << FixItHint::CreateReplacement( SourceRange(OISA->getOpLoc(), OISA->getIsaMemberLoc()), ")"); else Diag(E->getExprLoc(), diag::warn_objc_isa_use); } else if (const ObjCIvarRefExpr *OIRE = dyn_cast(E->IgnoreParenCasts())) DiagnoseDirectIsaAccess(*this, OIRE, SourceLocation(), /* Expr*/nullptr); // C++ [conv.lval]p1: // [...] If T is a non-class type, the type of the prvalue is the // cv-unqualified version of T. Otherwise, the type of the // rvalue is T. // // C99 6.3.2.1p2: // If the lvalue has qualified type, the value has the unqualified // version of the type of the lvalue; otherwise, the value has the // type of the lvalue. if (T.hasQualifiers()) T = T.getUnqualifiedType(); // Under the MS ABI, lock down the inheritance model now. if (T->isMemberPointerType() && Context.getTargetInfo().getCXXABI().isMicrosoft()) (void)isCompleteType(E->getExprLoc(), T); ExprResult Res = CheckLValueToRValueConversionOperand(E); if (Res.isInvalid()) return Res; E = Res.get(); // Loading a __weak object implicitly retains the value, so we need a cleanup to // balance that. if (E->getType().getObjCLifetime() == Qualifiers::OCL_Weak) Cleanup.setExprNeedsCleanups(true); // C++ [conv.lval]p3: // If T is cv std::nullptr_t, the result is a null pointer constant. CastKind CK = T->isNullPtrType() ? CK_NullToPointer : CK_LValueToRValue; Res = ImplicitCastExpr::Create(Context, T, CK, E, nullptr, VK_RValue); // C11 6.3.2.1p2: // ... if the lvalue has atomic type, the value has the non-atomic version // of the type of the lvalue ... if (const AtomicType *Atomic = T->getAs()) { T = Atomic->getValueType().getUnqualifiedType(); Res = ImplicitCastExpr::Create(Context, T, CK_AtomicToNonAtomic, Res.get(), nullptr, VK_RValue); } return Res; } ExprResult Sema::DefaultFunctionArrayLvalueConversion(Expr *E, bool Diagnose) { ExprResult Res = DefaultFunctionArrayConversion(E, Diagnose); if (Res.isInvalid()) return ExprError(); Res = DefaultLvalueConversion(Res.get()); if (Res.isInvalid()) return ExprError(); return Res; } /// CallExprUnaryConversions - a special case of an unary conversion /// performed on a function designator of a call expression. ExprResult Sema::CallExprUnaryConversions(Expr *E) { QualType Ty = E->getType(); ExprResult Res = E; // Only do implicit cast for a function type, but not for a pointer // to function type. if (Ty->isFunctionType()) { Res = ImpCastExprToType(E, Context.getPointerType(Ty), CK_FunctionToPointerDecay).get(); if (Res.isInvalid()) return ExprError(); } Res = DefaultLvalueConversion(Res.get()); if (Res.isInvalid()) return ExprError(); return Res.get(); } /// UsualUnaryConversions - Performs various conversions that are common to most /// operators (C99 6.3). The conversions of array and function types are /// sometimes suppressed. For example, the array->pointer conversion doesn't /// apply if the array is an argument to the sizeof or address (&) operators. /// In these instances, this routine should *not* be called. ExprResult Sema::UsualUnaryConversions(Expr *E) { // First, convert to an r-value. ExprResult Res = DefaultFunctionArrayLvalueConversion(E); if (Res.isInvalid()) return ExprError(); E = Res.get(); QualType Ty = E->getType(); assert(!Ty.isNull() && "UsualUnaryConversions - missing type"); // Half FP have to be promoted to float unless it is natively supported if (Ty->isHalfType() && !getLangOpts().NativeHalfType) return ImpCastExprToType(Res.get(), Context.FloatTy, CK_FloatingCast); // Try to perform integral promotions if the object has a theoretically // promotable type. if (Ty->isIntegralOrUnscopedEnumerationType()) { // C99 6.3.1.1p2: // // The following may be used in an expression wherever an int or // unsigned int may be used: // - an object or expression with an integer type whose integer // conversion rank is less than or equal to the rank of int // and unsigned int. // - A bit-field of type _Bool, int, signed int, or unsigned int. // // If an int can represent all values of the original type, the // value is converted to an int; otherwise, it is converted to an // unsigned int. These are called the integer promotions. All // other types are unchanged by the integer promotions. QualType PTy = Context.isPromotableBitField(E); if (!PTy.isNull()) { E = ImpCastExprToType(E, PTy, CK_IntegralCast).get(); return E; } if (Ty->isPromotableIntegerType()) { QualType PT = Context.getPromotedIntegerType(Ty); E = ImpCastExprToType(E, PT, CK_IntegralCast).get(); return E; } } return E; } /// DefaultArgumentPromotion (C99 6.5.2.2p6). Used for function calls that /// do not have a prototype. Arguments that have type float or __fp16 /// are promoted to double. All other argument types are converted by /// UsualUnaryConversions(). ExprResult Sema::DefaultArgumentPromotion(Expr *E) { QualType Ty = E->getType(); assert(!Ty.isNull() && "DefaultArgumentPromotion - missing type"); ExprResult Res = UsualUnaryConversions(E); if (Res.isInvalid()) return ExprError(); E = Res.get(); // If this is a 'float' or '__fp16' (CVR qualified or typedef) // promote to double. // Note that default argument promotion applies only to float (and // half/fp16); it does not apply to _Float16. const BuiltinType *BTy = Ty->getAs(); if (BTy && (BTy->getKind() == BuiltinType::Half || BTy->getKind() == BuiltinType::Float)) { if (getLangOpts().OpenCL && !getOpenCLOptions().isEnabled("cl_khr_fp64")) { if (BTy->getKind() == BuiltinType::Half) { E = ImpCastExprToType(E, Context.FloatTy, CK_FloatingCast).get(); } } else { E = ImpCastExprToType(E, Context.DoubleTy, CK_FloatingCast).get(); } } // C++ performs lvalue-to-rvalue conversion as a default argument // promotion, even on class types, but note: // C++11 [conv.lval]p2: // When an lvalue-to-rvalue conversion occurs in an unevaluated // operand or a subexpression thereof the value contained in the // referenced object is not accessed. Otherwise, if the glvalue // has a class type, the conversion copy-initializes a temporary // of type T from the glvalue and the result of the conversion // is a prvalue for the temporary. // FIXME: add some way to gate this entire thing for correctness in // potentially potentially evaluated contexts. if (getLangOpts().CPlusPlus && E->isGLValue() && !isUnevaluatedContext()) { ExprResult Temp = PerformCopyInitialization( InitializedEntity::InitializeTemporary(E->getType()), E->getExprLoc(), E); if (Temp.isInvalid()) return ExprError(); E = Temp.get(); } return E; } /// Determine the degree of POD-ness for an expression. /// Incomplete types are considered POD, since this check can be performed /// when we're in an unevaluated context. Sema::VarArgKind Sema::isValidVarArgType(const QualType &Ty) { if (Ty->isIncompleteType()) { // C++11 [expr.call]p7: // After these conversions, if the argument does not have arithmetic, // enumeration, pointer, pointer to member, or class type, the program // is ill-formed. // // Since we've already performed array-to-pointer and function-to-pointer // decay, the only such type in C++ is cv void. This also handles // initializer lists as variadic arguments. if (Ty->isVoidType()) return VAK_Invalid; if (Ty->isObjCObjectType()) return VAK_Invalid; return VAK_Valid; } if (Ty.isDestructedType() == QualType::DK_nontrivial_c_struct) return VAK_Invalid; if (Ty.isCXX98PODType(Context)) return VAK_Valid; // C++11 [expr.call]p7: // Passing a potentially-evaluated argument of class type (Clause 9) // having a non-trivial copy constructor, a non-trivial move constructor, // or a non-trivial destructor, with no corresponding parameter, // is conditionally-supported with implementation-defined semantics. if (getLangOpts().CPlusPlus11 && !Ty->isDependentType()) if (CXXRecordDecl *Record = Ty->getAsCXXRecordDecl()) if (!Record->hasNonTrivialCopyConstructor() && !Record->hasNonTrivialMoveConstructor() && !Record->hasNonTrivialDestructor()) return VAK_ValidInCXX11; if (getLangOpts().ObjCAutoRefCount && Ty->isObjCLifetimeType()) return VAK_Valid; if (Ty->isObjCObjectType()) return VAK_Invalid; if (getLangOpts().MSVCCompat) return VAK_MSVCUndefined; // FIXME: In C++11, these cases are conditionally-supported, meaning we're // permitted to reject them. We should consider doing so. return VAK_Undefined; } void Sema::checkVariadicArgument(const Expr *E, VariadicCallType CT) { // Don't allow one to pass an Objective-C interface to a vararg. const QualType &Ty = E->getType(); VarArgKind VAK = isValidVarArgType(Ty); // Complain about passing non-POD types through varargs. switch (VAK) { case VAK_ValidInCXX11: DiagRuntimeBehavior( E->getBeginLoc(), nullptr, PDiag(diag::warn_cxx98_compat_pass_non_pod_arg_to_vararg) << Ty << CT); LLVM_FALLTHROUGH; case VAK_Valid: if (Ty->isRecordType()) { // This is unlikely to be what the user intended. If the class has a // 'c_str' member function, the user probably meant to call that. DiagRuntimeBehavior(E->getBeginLoc(), nullptr, PDiag(diag::warn_pass_class_arg_to_vararg) << Ty << CT << hasCStrMethod(E) << ".c_str()"); } break; case VAK_Undefined: case VAK_MSVCUndefined: DiagRuntimeBehavior(E->getBeginLoc(), nullptr, PDiag(diag::warn_cannot_pass_non_pod_arg_to_vararg) << getLangOpts().CPlusPlus11 << Ty << CT); break; case VAK_Invalid: if (Ty.isDestructedType() == QualType::DK_nontrivial_c_struct) Diag(E->getBeginLoc(), diag::err_cannot_pass_non_trivial_c_struct_to_vararg) << Ty << CT; else if (Ty->isObjCObjectType()) DiagRuntimeBehavior(E->getBeginLoc(), nullptr, PDiag(diag::err_cannot_pass_objc_interface_to_vararg) << Ty << CT); else Diag(E->getBeginLoc(), diag::err_cannot_pass_to_vararg) << isa(E) << Ty << CT; break; } } /// DefaultVariadicArgumentPromotion - Like DefaultArgumentPromotion, but /// will create a trap if the resulting type is not a POD type. ExprResult Sema::DefaultVariadicArgumentPromotion(Expr *E, VariadicCallType CT, FunctionDecl *FDecl) { if (const BuiltinType *PlaceholderTy = E->getType()->getAsPlaceholderType()) { // Strip the unbridged-cast placeholder expression off, if applicable. if (PlaceholderTy->getKind() == BuiltinType::ARCUnbridgedCast && (CT == VariadicMethod || (FDecl && FDecl->hasAttr()))) { E = stripARCUnbridgedCast(E); // Otherwise, do normal placeholder checking. } else { ExprResult ExprRes = CheckPlaceholderExpr(E); if (ExprRes.isInvalid()) return ExprError(); E = ExprRes.get(); } } ExprResult ExprRes = DefaultArgumentPromotion(E); if (ExprRes.isInvalid()) return ExprError(); E = ExprRes.get(); // Diagnostics regarding non-POD argument types are // emitted along with format string checking in Sema::CheckFunctionCall(). if (isValidVarArgType(E->getType()) == VAK_Undefined) { // Turn this into a trap. CXXScopeSpec SS; SourceLocation TemplateKWLoc; UnqualifiedId Name; Name.setIdentifier(PP.getIdentifierInfo("__builtin_trap"), E->getBeginLoc()); ExprResult TrapFn = ActOnIdExpression(TUScope, SS, TemplateKWLoc, Name, /*HasTrailingLParen=*/true, /*IsAddressOfOperand=*/false); if (TrapFn.isInvalid()) return ExprError(); ExprResult Call = BuildCallExpr(TUScope, TrapFn.get(), E->getBeginLoc(), None, E->getEndLoc()); if (Call.isInvalid()) return ExprError(); ExprResult Comma = ActOnBinOp(TUScope, E->getBeginLoc(), tok::comma, Call.get(), E); if (Comma.isInvalid()) return ExprError(); return Comma.get(); } if (!getLangOpts().CPlusPlus && RequireCompleteType(E->getExprLoc(), E->getType(), diag::err_call_incomplete_argument)) return ExprError(); return E; } /// Converts an integer to complex float type. Helper function of /// UsualArithmeticConversions() /// /// \return false if the integer expression is an integer type and is /// successfully converted to the complex type. static bool handleIntegerToComplexFloatConversion(Sema &S, ExprResult &IntExpr, ExprResult &ComplexExpr, QualType IntTy, QualType ComplexTy, bool SkipCast) { if (IntTy->isComplexType() || IntTy->isRealFloatingType()) return true; if (SkipCast) return false; if (IntTy->isIntegerType()) { QualType fpTy = cast(ComplexTy)->getElementType(); IntExpr = S.ImpCastExprToType(IntExpr.get(), fpTy, CK_IntegralToFloating); IntExpr = S.ImpCastExprToType(IntExpr.get(), ComplexTy, CK_FloatingRealToComplex); } else { assert(IntTy->isComplexIntegerType()); IntExpr = S.ImpCastExprToType(IntExpr.get(), ComplexTy, CK_IntegralComplexToFloatingComplex); } return false; } /// Handle arithmetic conversion with complex types. Helper function of /// UsualArithmeticConversions() static QualType handleComplexFloatConversion(Sema &S, ExprResult &LHS, ExprResult &RHS, QualType LHSType, QualType RHSType, bool IsCompAssign) { // if we have an integer operand, the result is the complex type. if (!handleIntegerToComplexFloatConversion(S, RHS, LHS, RHSType, LHSType, /*skipCast*/false)) return LHSType; if (!handleIntegerToComplexFloatConversion(S, LHS, RHS, LHSType, RHSType, /*skipCast*/IsCompAssign)) return RHSType; // This handles complex/complex, complex/float, or float/complex. // When both operands are complex, the shorter operand is converted to the // type of the longer, and that is the type of the result. This corresponds // to what is done when combining two real floating-point operands. // The fun begins when size promotion occur across type domains. // From H&S 6.3.4: When one operand is complex and the other is a real // floating-point type, the less precise type is converted, within it's // real or complex domain, to the precision of the other type. For example, // when combining a "long double" with a "double _Complex", the // "double _Complex" is promoted to "long double _Complex". // Compute the rank of the two types, regardless of whether they are complex. int Order = S.Context.getFloatingTypeOrder(LHSType, RHSType); auto *LHSComplexType = dyn_cast(LHSType); auto *RHSComplexType = dyn_cast(RHSType); QualType LHSElementType = LHSComplexType ? LHSComplexType->getElementType() : LHSType; QualType RHSElementType = RHSComplexType ? RHSComplexType->getElementType() : RHSType; QualType ResultType = S.Context.getComplexType(LHSElementType); if (Order < 0) { // Promote the precision of the LHS if not an assignment. ResultType = S.Context.getComplexType(RHSElementType); if (!IsCompAssign) { if (LHSComplexType) LHS = S.ImpCastExprToType(LHS.get(), ResultType, CK_FloatingComplexCast); else LHS = S.ImpCastExprToType(LHS.get(), RHSElementType, CK_FloatingCast); } } else if (Order > 0) { // Promote the precision of the RHS. if (RHSComplexType) RHS = S.ImpCastExprToType(RHS.get(), ResultType, CK_FloatingComplexCast); else RHS = S.ImpCastExprToType(RHS.get(), LHSElementType, CK_FloatingCast); } return ResultType; } /// Handle arithmetic conversion from integer to float. Helper function /// of UsualArithmeticConversions() static QualType handleIntToFloatConversion(Sema &S, ExprResult &FloatExpr, ExprResult &IntExpr, QualType FloatTy, QualType IntTy, bool ConvertFloat, bool ConvertInt) { if (IntTy->isIntegerType()) { if (ConvertInt) // Convert intExpr to the lhs floating point type. IntExpr = S.ImpCastExprToType(IntExpr.get(), FloatTy, CK_IntegralToFloating); return FloatTy; } // Convert both sides to the appropriate complex float. assert(IntTy->isComplexIntegerType()); QualType result = S.Context.getComplexType(FloatTy); // _Complex int -> _Complex float if (ConvertInt) IntExpr = S.ImpCastExprToType(IntExpr.get(), result, CK_IntegralComplexToFloatingComplex); // float -> _Complex float if (ConvertFloat) FloatExpr = S.ImpCastExprToType(FloatExpr.get(), result, CK_FloatingRealToComplex); return result; } /// Handle arithmethic conversion with floating point types. Helper /// function of UsualArithmeticConversions() static QualType handleFloatConversion(Sema &S, ExprResult &LHS, ExprResult &RHS, QualType LHSType, QualType RHSType, bool IsCompAssign) { bool LHSFloat = LHSType->isRealFloatingType(); bool RHSFloat = RHSType->isRealFloatingType(); // If we have two real floating types, convert the smaller operand // to the bigger result. if (LHSFloat && RHSFloat) { int order = S.Context.getFloatingTypeOrder(LHSType, RHSType); if (order > 0) { RHS = S.ImpCastExprToType(RHS.get(), LHSType, CK_FloatingCast); return LHSType; } assert(order < 0 && "illegal float comparison"); if (!IsCompAssign) LHS = S.ImpCastExprToType(LHS.get(), RHSType, CK_FloatingCast); return RHSType; } if (LHSFloat) { // Half FP has to be promoted to float unless it is natively supported if (LHSType->isHalfType() && !S.getLangOpts().NativeHalfType) LHSType = S.Context.FloatTy; return handleIntToFloatConversion(S, LHS, RHS, LHSType, RHSType, /*ConvertFloat=*/!IsCompAssign, /*ConvertInt=*/ true); } assert(RHSFloat); return handleIntToFloatConversion(S, RHS, LHS, RHSType, LHSType, /*convertInt=*/ true, /*convertFloat=*/!IsCompAssign); } /// Diagnose attempts to convert between __float128 and long double if /// there is no support for such conversion. Helper function of /// UsualArithmeticConversions(). static bool unsupportedTypeConversion(const Sema &S, QualType LHSType, QualType RHSType) { /* No issue converting if at least one of the types is not a floating point type or the two types have the same rank. */ if (!LHSType->isFloatingType() || !RHSType->isFloatingType() || S.Context.getFloatingTypeOrder(LHSType, RHSType) == 0) return false; assert(LHSType->isFloatingType() && RHSType->isFloatingType() && "The remaining types must be floating point types."); auto *LHSComplex = LHSType->getAs(); auto *RHSComplex = RHSType->getAs(); QualType LHSElemType = LHSComplex ? LHSComplex->getElementType() : LHSType; QualType RHSElemType = RHSComplex ? RHSComplex->getElementType() : RHSType; // No issue if the two types have the same representation if (&S.Context.getFloatTypeSemantics(LHSElemType) == &S.Context.getFloatTypeSemantics(RHSElemType)) return false; bool Float128AndLongDouble = (LHSElemType == S.Context.Float128Ty && RHSElemType == S.Context.LongDoubleTy); Float128AndLongDouble |= (LHSElemType == S.Context.LongDoubleTy && RHSElemType == S.Context.Float128Ty); // We've handled the situation where __float128 and long double have the same // representation. We allow all conversions for all possible long double types // except PPC's double double. return Float128AndLongDouble && (&S.Context.getFloatTypeSemantics(S.Context.LongDoubleTy) == &llvm::APFloat::PPCDoubleDouble()); } typedef ExprResult PerformCastFn(Sema &S, Expr *operand, QualType toType); namespace { /// These helper callbacks are placed in an anonymous namespace to /// permit their use as function template parameters. ExprResult doIntegralCast(Sema &S, Expr *op, QualType toType) { return S.ImpCastExprToType(op, toType, CK_IntegralCast); } ExprResult doComplexIntegralCast(Sema &S, Expr *op, QualType toType) { return S.ImpCastExprToType(op, S.Context.getComplexType(toType), CK_IntegralComplexCast); } } /// Handle integer arithmetic conversions. Helper function of /// UsualArithmeticConversions() template static QualType handleIntegerConversion(Sema &S, ExprResult &LHS, ExprResult &RHS, QualType LHSType, QualType RHSType, bool IsCompAssign) { // The rules for this case are in C99 6.3.1.8 int order = S.Context.getIntegerTypeOrder(LHSType, RHSType); bool LHSSigned = LHSType->hasSignedIntegerRepresentation(); bool RHSSigned = RHSType->hasSignedIntegerRepresentation(); if (LHSSigned == RHSSigned) { // Same signedness; use the higher-ranked type if (order >= 0) { RHS = (*doRHSCast)(S, RHS.get(), LHSType); return LHSType; } else if (!IsCompAssign) LHS = (*doLHSCast)(S, LHS.get(), RHSType); return RHSType; } else if (order != (LHSSigned ? 1 : -1)) { // The unsigned type has greater than or equal rank to the // signed type, so use the unsigned type if (RHSSigned) { RHS = (*doRHSCast)(S, RHS.get(), LHSType); return LHSType; } else if (!IsCompAssign) LHS = (*doLHSCast)(S, LHS.get(), RHSType); return RHSType; } else if (S.Context.getIntWidth(LHSType) != S.Context.getIntWidth(RHSType)) { // The two types are different widths; if we are here, that // means the signed type is larger than the unsigned type, so // use the signed type. if (LHSSigned) { RHS = (*doRHSCast)(S, RHS.get(), LHSType); return LHSType; } else if (!IsCompAssign) LHS = (*doLHSCast)(S, LHS.get(), RHSType); return RHSType; } else { // The signed type is higher-ranked than the unsigned type, // but isn't actually any bigger (like unsigned int and long // on most 32-bit systems). Use the unsigned type corresponding // to the signed type. QualType result = S.Context.getCorrespondingUnsignedType(LHSSigned ? LHSType : RHSType); RHS = (*doRHSCast)(S, RHS.get(), result); if (!IsCompAssign) LHS = (*doLHSCast)(S, LHS.get(), result); return result; } } /// Handle conversions with GCC complex int extension. Helper function /// of UsualArithmeticConversions() static QualType handleComplexIntConversion(Sema &S, ExprResult &LHS, ExprResult &RHS, QualType LHSType, QualType RHSType, bool IsCompAssign) { const ComplexType *LHSComplexInt = LHSType->getAsComplexIntegerType(); const ComplexType *RHSComplexInt = RHSType->getAsComplexIntegerType(); if (LHSComplexInt && RHSComplexInt) { QualType LHSEltType = LHSComplexInt->getElementType(); QualType RHSEltType = RHSComplexInt->getElementType(); QualType ScalarType = handleIntegerConversion (S, LHS, RHS, LHSEltType, RHSEltType, IsCompAssign); return S.Context.getComplexType(ScalarType); } if (LHSComplexInt) { QualType LHSEltType = LHSComplexInt->getElementType(); QualType ScalarType = handleIntegerConversion (S, LHS, RHS, LHSEltType, RHSType, IsCompAssign); QualType ComplexType = S.Context.getComplexType(ScalarType); RHS = S.ImpCastExprToType(RHS.get(), ComplexType, CK_IntegralRealToComplex); return ComplexType; } assert(RHSComplexInt); QualType RHSEltType = RHSComplexInt->getElementType(); QualType ScalarType = handleIntegerConversion (S, LHS, RHS, LHSType, RHSEltType, IsCompAssign); QualType ComplexType = S.Context.getComplexType(ScalarType); if (!IsCompAssign) LHS = S.ImpCastExprToType(LHS.get(), ComplexType, CK_IntegralRealToComplex); return ComplexType; } /// Return the rank of a given fixed point or integer type. The value itself /// doesn't matter, but the values must be increasing with proper increasing /// rank as described in N1169 4.1.1. static unsigned GetFixedPointRank(QualType Ty) { const auto *BTy = Ty->getAs(); assert(BTy && "Expected a builtin type."); switch (BTy->getKind()) { case BuiltinType::ShortFract: case BuiltinType::UShortFract: case BuiltinType::SatShortFract: case BuiltinType::SatUShortFract: return 1; case BuiltinType::Fract: case BuiltinType::UFract: case BuiltinType::SatFract: case BuiltinType::SatUFract: return 2; case BuiltinType::LongFract: case BuiltinType::ULongFract: case BuiltinType::SatLongFract: case BuiltinType::SatULongFract: return 3; case BuiltinType::ShortAccum: case BuiltinType::UShortAccum: case BuiltinType::SatShortAccum: case BuiltinType::SatUShortAccum: return 4; case BuiltinType::Accum: case BuiltinType::UAccum: case BuiltinType::SatAccum: case BuiltinType::SatUAccum: return 5; case BuiltinType::LongAccum: case BuiltinType::ULongAccum: case BuiltinType::SatLongAccum: case BuiltinType::SatULongAccum: return 6; default: if (BTy->isInteger()) return 0; llvm_unreachable("Unexpected fixed point or integer type"); } } /// handleFixedPointConversion - Fixed point operations between fixed /// point types and integers or other fixed point types do not fall under /// usual arithmetic conversion since these conversions could result in loss /// of precsision (N1169 4.1.4). These operations should be calculated with /// the full precision of their result type (N1169 4.1.6.2.1). static QualType handleFixedPointConversion(Sema &S, QualType LHSTy, QualType RHSTy) { assert((LHSTy->isFixedPointType() || RHSTy->isFixedPointType()) && "Expected at least one of the operands to be a fixed point type"); assert((LHSTy->isFixedPointOrIntegerType() || RHSTy->isFixedPointOrIntegerType()) && "Special fixed point arithmetic operation conversions are only " "applied to ints or other fixed point types"); // If one operand has signed fixed-point type and the other operand has // unsigned fixed-point type, then the unsigned fixed-point operand is // converted to its corresponding signed fixed-point type and the resulting // type is the type of the converted operand. if (RHSTy->isSignedFixedPointType() && LHSTy->isUnsignedFixedPointType()) LHSTy = S.Context.getCorrespondingSignedFixedPointType(LHSTy); else if (RHSTy->isUnsignedFixedPointType() && LHSTy->isSignedFixedPointType()) RHSTy = S.Context.getCorrespondingSignedFixedPointType(RHSTy); // The result type is the type with the highest rank, whereby a fixed-point // conversion rank is always greater than an integer conversion rank; if the // type of either of the operands is a saturating fixedpoint type, the result // type shall be the saturating fixed-point type corresponding to the type // with the highest rank; the resulting value is converted (taking into // account rounding and overflow) to the precision of the resulting type. // Same ranks between signed and unsigned types are resolved earlier, so both // types are either signed or both unsigned at this point. unsigned LHSTyRank = GetFixedPointRank(LHSTy); unsigned RHSTyRank = GetFixedPointRank(RHSTy); QualType ResultTy = LHSTyRank > RHSTyRank ? LHSTy : RHSTy; if (LHSTy->isSaturatedFixedPointType() || RHSTy->isSaturatedFixedPointType()) ResultTy = S.Context.getCorrespondingSaturatedType(ResultTy); return ResultTy; } /// Check that the usual arithmetic conversions can be performed on this pair of /// expressions that might be of enumeration type. static void checkEnumArithmeticConversions(Sema &S, Expr *LHS, Expr *RHS, SourceLocation Loc, Sema::ArithConvKind ACK) { // C++2a [expr.arith.conv]p1: // If one operand is of enumeration type and the other operand is of a // different enumeration type or a floating-point type, this behavior is // deprecated ([depr.arith.conv.enum]). // // Warn on this in all language modes. Produce a deprecation warning in C++20. // Eventually we will presumably reject these cases (in C++23 onwards?). QualType L = LHS->getType(), R = RHS->getType(); bool LEnum = L->isUnscopedEnumerationType(), REnum = R->isUnscopedEnumerationType(); bool IsCompAssign = ACK == Sema::ACK_CompAssign; if ((!IsCompAssign && LEnum && R->isFloatingType()) || (REnum && L->isFloatingType())) { S.Diag(Loc, S.getLangOpts().CPlusPlus2a ? diag::warn_arith_conv_enum_float_cxx2a : diag::warn_arith_conv_enum_float) << LHS->getSourceRange() << RHS->getSourceRange() << (int)ACK << LEnum << L << R; } else if (!IsCompAssign && LEnum && REnum && !S.Context.hasSameUnqualifiedType(L, R)) { unsigned DiagID; if (!L->castAs()->getDecl()->hasNameForLinkage() || !R->castAs()->getDecl()->hasNameForLinkage()) { // If either enumeration type is unnamed, it's less likely that the // user cares about this, but this situation is still deprecated in // C++2a. Use a different warning group. DiagID = S.getLangOpts().CPlusPlus2a ? diag::warn_arith_conv_mixed_anon_enum_types_cxx2a : diag::warn_arith_conv_mixed_anon_enum_types; } else if (ACK == Sema::ACK_Conditional) { // Conditional expressions are separated out because they have // historically had a different warning flag. DiagID = S.getLangOpts().CPlusPlus2a ? diag::warn_conditional_mixed_enum_types_cxx2a : diag::warn_conditional_mixed_enum_types; } else if (ACK == Sema::ACK_Comparison) { // Comparison expressions are separated out because they have // historically had a different warning flag. DiagID = S.getLangOpts().CPlusPlus2a ? diag::warn_comparison_mixed_enum_types_cxx2a : diag::warn_comparison_mixed_enum_types; } else { DiagID = S.getLangOpts().CPlusPlus2a ? diag::warn_arith_conv_mixed_enum_types_cxx2a : diag::warn_arith_conv_mixed_enum_types; } S.Diag(Loc, DiagID) << LHS->getSourceRange() << RHS->getSourceRange() << (int)ACK << L << R; } } /// UsualArithmeticConversions - Performs various conversions that are common to /// binary operators (C99 6.3.1.8). If both operands aren't arithmetic, this /// routine returns the first non-arithmetic type found. The client is /// responsible for emitting appropriate error diagnostics. QualType Sema::UsualArithmeticConversions(ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, ArithConvKind ACK) { checkEnumArithmeticConversions(*this, LHS.get(), RHS.get(), Loc, ACK); if (ACK != ACK_CompAssign) { LHS = UsualUnaryConversions(LHS.get()); if (LHS.isInvalid()) return QualType(); } RHS = UsualUnaryConversions(RHS.get()); if (RHS.isInvalid()) return QualType(); // For conversion purposes, we ignore any qualifiers. // For example, "const float" and "float" are equivalent. QualType LHSType = Context.getCanonicalType(LHS.get()->getType()).getUnqualifiedType(); QualType RHSType = Context.getCanonicalType(RHS.get()->getType()).getUnqualifiedType(); // For conversion purposes, we ignore any atomic qualifier on the LHS. if (const AtomicType *AtomicLHS = LHSType->getAs()) LHSType = AtomicLHS->getValueType(); // If both types are identical, no conversion is needed. if (LHSType == RHSType) return LHSType; // If either side is a non-arithmetic type (e.g. a pointer), we are done. // The caller can deal with this (e.g. pointer + int). if (!LHSType->isArithmeticType() || !RHSType->isArithmeticType()) return QualType(); // Apply unary and bitfield promotions to the LHS's type. QualType LHSUnpromotedType = LHSType; if (LHSType->isPromotableIntegerType()) LHSType = Context.getPromotedIntegerType(LHSType); QualType LHSBitfieldPromoteTy = Context.isPromotableBitField(LHS.get()); if (!LHSBitfieldPromoteTy.isNull()) LHSType = LHSBitfieldPromoteTy; if (LHSType != LHSUnpromotedType && ACK != ACK_CompAssign) LHS = ImpCastExprToType(LHS.get(), LHSType, CK_IntegralCast); // If both types are identical, no conversion is needed. if (LHSType == RHSType) return LHSType; // At this point, we have two different arithmetic types. // Diagnose attempts to convert between __float128 and long double where // such conversions currently can't be handled. if (unsupportedTypeConversion(*this, LHSType, RHSType)) return QualType(); // Handle complex types first (C99 6.3.1.8p1). if (LHSType->isComplexType() || RHSType->isComplexType()) return handleComplexFloatConversion(*this, LHS, RHS, LHSType, RHSType, ACK == ACK_CompAssign); // Now handle "real" floating types (i.e. float, double, long double). if (LHSType->isRealFloatingType() || RHSType->isRealFloatingType()) return handleFloatConversion(*this, LHS, RHS, LHSType, RHSType, ACK == ACK_CompAssign); // Handle GCC complex int extension. if (LHSType->isComplexIntegerType() || RHSType->isComplexIntegerType()) return handleComplexIntConversion(*this, LHS, RHS, LHSType, RHSType, ACK == ACK_CompAssign); if (LHSType->isFixedPointType() || RHSType->isFixedPointType()) return handleFixedPointConversion(*this, LHSType, RHSType); // Finally, we have two differing integer types. return handleIntegerConversion (*this, LHS, RHS, LHSType, RHSType, ACK == ACK_CompAssign); } //===----------------------------------------------------------------------===// // Semantic Analysis for various Expression Types //===----------------------------------------------------------------------===// ExprResult Sema::ActOnGenericSelectionExpr(SourceLocation KeyLoc, SourceLocation DefaultLoc, SourceLocation RParenLoc, Expr *ControllingExpr, ArrayRef ArgTypes, ArrayRef ArgExprs) { unsigned NumAssocs = ArgTypes.size(); assert(NumAssocs == ArgExprs.size()); TypeSourceInfo **Types = new TypeSourceInfo*[NumAssocs]; for (unsigned i = 0; i < NumAssocs; ++i) { if (ArgTypes[i]) (void) GetTypeFromParser(ArgTypes[i], &Types[i]); else Types[i] = nullptr; } ExprResult ER = CreateGenericSelectionExpr(KeyLoc, DefaultLoc, RParenLoc, ControllingExpr, llvm::makeArrayRef(Types, NumAssocs), ArgExprs); delete [] Types; return ER; } ExprResult Sema::CreateGenericSelectionExpr(SourceLocation KeyLoc, SourceLocation DefaultLoc, SourceLocation RParenLoc, Expr *ControllingExpr, ArrayRef Types, ArrayRef Exprs) { unsigned NumAssocs = Types.size(); assert(NumAssocs == Exprs.size()); // Decay and strip qualifiers for the controlling expression type, and handle // placeholder type replacement. See committee discussion from WG14 DR423. { EnterExpressionEvaluationContext Unevaluated( *this, Sema::ExpressionEvaluationContext::Unevaluated); ExprResult R = DefaultFunctionArrayLvalueConversion(ControllingExpr); if (R.isInvalid()) return ExprError(); ControllingExpr = R.get(); } // The controlling expression is an unevaluated operand, so side effects are // likely unintended. if (!inTemplateInstantiation() && ControllingExpr->HasSideEffects(Context, false)) Diag(ControllingExpr->getExprLoc(), diag::warn_side_effects_unevaluated_context); bool TypeErrorFound = false, IsResultDependent = ControllingExpr->isTypeDependent(), ContainsUnexpandedParameterPack = ControllingExpr->containsUnexpandedParameterPack(); for (unsigned i = 0; i < NumAssocs; ++i) { if (Exprs[i]->containsUnexpandedParameterPack()) ContainsUnexpandedParameterPack = true; if (Types[i]) { if (Types[i]->getType()->containsUnexpandedParameterPack()) ContainsUnexpandedParameterPack = true; if (Types[i]->getType()->isDependentType()) { IsResultDependent = true; } else { // C11 6.5.1.1p2 "The type name in a generic association shall specify a // complete object type other than a variably modified type." unsigned D = 0; if (Types[i]->getType()->isIncompleteType()) D = diag::err_assoc_type_incomplete; else if (!Types[i]->getType()->isObjectType()) D = diag::err_assoc_type_nonobject; else if (Types[i]->getType()->isVariablyModifiedType()) D = diag::err_assoc_type_variably_modified; if (D != 0) { Diag(Types[i]->getTypeLoc().getBeginLoc(), D) << Types[i]->getTypeLoc().getSourceRange() << Types[i]->getType(); TypeErrorFound = true; } // C11 6.5.1.1p2 "No two generic associations in the same generic // selection shall specify compatible types." for (unsigned j = i+1; j < NumAssocs; ++j) if (Types[j] && !Types[j]->getType()->isDependentType() && Context.typesAreCompatible(Types[i]->getType(), Types[j]->getType())) { Diag(Types[j]->getTypeLoc().getBeginLoc(), diag::err_assoc_compatible_types) << Types[j]->getTypeLoc().getSourceRange() << Types[j]->getType() << Types[i]->getType(); Diag(Types[i]->getTypeLoc().getBeginLoc(), diag::note_compat_assoc) << Types[i]->getTypeLoc().getSourceRange() << Types[i]->getType(); TypeErrorFound = true; } } } } if (TypeErrorFound) return ExprError(); // If we determined that the generic selection is result-dependent, don't // try to compute the result expression. if (IsResultDependent) return GenericSelectionExpr::Create(Context, KeyLoc, ControllingExpr, Types, Exprs, DefaultLoc, RParenLoc, ContainsUnexpandedParameterPack); SmallVector CompatIndices; unsigned DefaultIndex = -1U; for (unsigned i = 0; i < NumAssocs; ++i) { if (!Types[i]) DefaultIndex = i; else if (Context.typesAreCompatible(ControllingExpr->getType(), Types[i]->getType())) CompatIndices.push_back(i); } // C11 6.5.1.1p2 "The controlling expression of a generic selection shall have // type compatible with at most one of the types named in its generic // association list." if (CompatIndices.size() > 1) { // We strip parens here because the controlling expression is typically // parenthesized in macro definitions. ControllingExpr = ControllingExpr->IgnoreParens(); Diag(ControllingExpr->getBeginLoc(), diag::err_generic_sel_multi_match) << ControllingExpr->getSourceRange() << ControllingExpr->getType() << (unsigned)CompatIndices.size(); for (unsigned I : CompatIndices) { Diag(Types[I]->getTypeLoc().getBeginLoc(), diag::note_compat_assoc) << Types[I]->getTypeLoc().getSourceRange() << Types[I]->getType(); } return ExprError(); } // C11 6.5.1.1p2 "If a generic selection has no default generic association, // its controlling expression shall have type compatible with exactly one of // the types named in its generic association list." if (DefaultIndex == -1U && CompatIndices.size() == 0) { // We strip parens here because the controlling expression is typically // parenthesized in macro definitions. ControllingExpr = ControllingExpr->IgnoreParens(); Diag(ControllingExpr->getBeginLoc(), diag::err_generic_sel_no_match) << ControllingExpr->getSourceRange() << ControllingExpr->getType(); return ExprError(); } // C11 6.5.1.1p3 "If a generic selection has a generic association with a // type name that is compatible with the type of the controlling expression, // then the result expression of the generic selection is the expression // in that generic association. Otherwise, the result expression of the // generic selection is the expression in the default generic association." unsigned ResultIndex = CompatIndices.size() ? CompatIndices[0] : DefaultIndex; return GenericSelectionExpr::Create( Context, KeyLoc, ControllingExpr, Types, Exprs, DefaultLoc, RParenLoc, ContainsUnexpandedParameterPack, ResultIndex); } /// getUDSuffixLoc - Create a SourceLocation for a ud-suffix, given the /// location of the token and the offset of the ud-suffix within it. static SourceLocation getUDSuffixLoc(Sema &S, SourceLocation TokLoc, unsigned Offset) { return Lexer::AdvanceToTokenCharacter(TokLoc, Offset, S.getSourceManager(), S.getLangOpts()); } /// BuildCookedLiteralOperatorCall - A user-defined literal was found. Look up /// the corresponding cooked (non-raw) literal operator, and build a call to it. static ExprResult BuildCookedLiteralOperatorCall(Sema &S, Scope *Scope, IdentifierInfo *UDSuffix, SourceLocation UDSuffixLoc, ArrayRef Args, SourceLocation LitEndLoc) { assert(Args.size() <= 2 && "too many arguments for literal operator"); QualType ArgTy[2]; for (unsigned ArgIdx = 0; ArgIdx != Args.size(); ++ArgIdx) { ArgTy[ArgIdx] = Args[ArgIdx]->getType(); if (ArgTy[ArgIdx]->isArrayType()) ArgTy[ArgIdx] = S.Context.getArrayDecayedType(ArgTy[ArgIdx]); } DeclarationName OpName = S.Context.DeclarationNames.getCXXLiteralOperatorName(UDSuffix); DeclarationNameInfo OpNameInfo(OpName, UDSuffixLoc); OpNameInfo.setCXXLiteralOperatorNameLoc(UDSuffixLoc); LookupResult R(S, OpName, UDSuffixLoc, Sema::LookupOrdinaryName); if (S.LookupLiteralOperator(Scope, R, llvm::makeArrayRef(ArgTy, Args.size()), /*AllowRaw*/ false, /*AllowTemplate*/ false, /*AllowStringTemplate*/ false, /*DiagnoseMissing*/ true) == Sema::LOLR_Error) return ExprError(); return S.BuildLiteralOperatorCall(R, OpNameInfo, Args, LitEndLoc); } /// ActOnStringLiteral - The specified tokens were lexed as pasted string /// fragments (e.g. "foo" "bar" L"baz"). The result string has to handle string /// concatenation ([C99 5.1.1.2, translation phase #6]), so it may come from /// multiple tokens. However, the common case is that StringToks points to one /// string. /// ExprResult Sema::ActOnStringLiteral(ArrayRef StringToks, Scope *UDLScope) { assert(!StringToks.empty() && "Must have at least one string!"); StringLiteralParser Literal(StringToks, PP); if (Literal.hadError) return ExprError(); SmallVector StringTokLocs; for (const Token &Tok : StringToks) StringTokLocs.push_back(Tok.getLocation()); QualType CharTy = Context.CharTy; StringLiteral::StringKind Kind = StringLiteral::Ascii; if (Literal.isWide()) { CharTy = Context.getWideCharType(); Kind = StringLiteral::Wide; } else if (Literal.isUTF8()) { if (getLangOpts().Char8) CharTy = Context.Char8Ty; Kind = StringLiteral::UTF8; } else if (Literal.isUTF16()) { CharTy = Context.Char16Ty; Kind = StringLiteral::UTF16; } else if (Literal.isUTF32()) { CharTy = Context.Char32Ty; Kind = StringLiteral::UTF32; } else if (Literal.isPascal()) { CharTy = Context.UnsignedCharTy; } // Warn on initializing an array of char from a u8 string literal; this // becomes ill-formed in C++2a. if (getLangOpts().CPlusPlus && !getLangOpts().CPlusPlus2a && !getLangOpts().Char8 && Kind == StringLiteral::UTF8) { Diag(StringTokLocs.front(), diag::warn_cxx2a_compat_utf8_string); // Create removals for all 'u8' prefixes in the string literal(s). This // ensures C++2a compatibility (but may change the program behavior when // built by non-Clang compilers for which the execution character set is // not always UTF-8). auto RemovalDiag = PDiag(diag::note_cxx2a_compat_utf8_string_remove_u8); SourceLocation RemovalDiagLoc; for (const Token &Tok : StringToks) { if (Tok.getKind() == tok::utf8_string_literal) { if (RemovalDiagLoc.isInvalid()) RemovalDiagLoc = Tok.getLocation(); RemovalDiag << FixItHint::CreateRemoval(CharSourceRange::getCharRange( Tok.getLocation(), Lexer::AdvanceToTokenCharacter(Tok.getLocation(), 2, getSourceManager(), getLangOpts()))); } } Diag(RemovalDiagLoc, RemovalDiag); } QualType StrTy = Context.getStringLiteralArrayType(CharTy, Literal.GetNumStringChars()); // Pass &StringTokLocs[0], StringTokLocs.size() to factory! StringLiteral *Lit = StringLiteral::Create(Context, Literal.GetString(), Kind, Literal.Pascal, StrTy, &StringTokLocs[0], StringTokLocs.size()); if (Literal.getUDSuffix().empty()) return Lit; // We're building a user-defined literal. IdentifierInfo *UDSuffix = &Context.Idents.get(Literal.getUDSuffix()); SourceLocation UDSuffixLoc = getUDSuffixLoc(*this, StringTokLocs[Literal.getUDSuffixToken()], Literal.getUDSuffixOffset()); // Make sure we're allowed user-defined literals here. if (!UDLScope) return ExprError(Diag(UDSuffixLoc, diag::err_invalid_string_udl)); // C++11 [lex.ext]p5: The literal L is treated as a call of the form // operator "" X (str, len) QualType SizeType = Context.getSizeType(); DeclarationName OpName = Context.DeclarationNames.getCXXLiteralOperatorName(UDSuffix); DeclarationNameInfo OpNameInfo(OpName, UDSuffixLoc); OpNameInfo.setCXXLiteralOperatorNameLoc(UDSuffixLoc); QualType ArgTy[] = { Context.getArrayDecayedType(StrTy), SizeType }; LookupResult R(*this, OpName, UDSuffixLoc, LookupOrdinaryName); switch (LookupLiteralOperator(UDLScope, R, ArgTy, /*AllowRaw*/ false, /*AllowTemplate*/ false, /*AllowStringTemplate*/ true, /*DiagnoseMissing*/ true)) { case LOLR_Cooked: { llvm::APInt Len(Context.getIntWidth(SizeType), Literal.GetNumStringChars()); IntegerLiteral *LenArg = IntegerLiteral::Create(Context, Len, SizeType, StringTokLocs[0]); Expr *Args[] = { Lit, LenArg }; return BuildLiteralOperatorCall(R, OpNameInfo, Args, StringTokLocs.back()); } case LOLR_StringTemplate: { TemplateArgumentListInfo ExplicitArgs; unsigned CharBits = Context.getIntWidth(CharTy); bool CharIsUnsigned = CharTy->isUnsignedIntegerType(); llvm::APSInt Value(CharBits, CharIsUnsigned); TemplateArgument TypeArg(CharTy); TemplateArgumentLocInfo TypeArgInfo(Context.getTrivialTypeSourceInfo(CharTy)); ExplicitArgs.addArgument(TemplateArgumentLoc(TypeArg, TypeArgInfo)); for (unsigned I = 0, N = Lit->getLength(); I != N; ++I) { Value = Lit->getCodeUnit(I); TemplateArgument Arg(Context, Value, CharTy); TemplateArgumentLocInfo ArgInfo; ExplicitArgs.addArgument(TemplateArgumentLoc(Arg, ArgInfo)); } return BuildLiteralOperatorCall(R, OpNameInfo, None, StringTokLocs.back(), &ExplicitArgs); } case LOLR_Raw: case LOLR_Template: case LOLR_ErrorNoDiagnostic: llvm_unreachable("unexpected literal operator lookup result"); case LOLR_Error: return ExprError(); } llvm_unreachable("unexpected literal operator lookup result"); } DeclRefExpr * Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK, SourceLocation Loc, const CXXScopeSpec *SS) { DeclarationNameInfo NameInfo(D->getDeclName(), Loc); return BuildDeclRefExpr(D, Ty, VK, NameInfo, SS); } DeclRefExpr * Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK, const DeclarationNameInfo &NameInfo, const CXXScopeSpec *SS, NamedDecl *FoundD, SourceLocation TemplateKWLoc, const TemplateArgumentListInfo *TemplateArgs) { NestedNameSpecifierLoc NNS = SS ? SS->getWithLocInContext(Context) : NestedNameSpecifierLoc(); return BuildDeclRefExpr(D, Ty, VK, NameInfo, NNS, FoundD, TemplateKWLoc, TemplateArgs); } NonOdrUseReason Sema::getNonOdrUseReasonInCurrentContext(ValueDecl *D) { // A declaration named in an unevaluated operand never constitutes an odr-use. if (isUnevaluatedContext()) return NOUR_Unevaluated; // C++2a [basic.def.odr]p4: // A variable x whose name appears as a potentially-evaluated expression e // is odr-used by e unless [...] x is a reference that is usable in // constant expressions. if (VarDecl *VD = dyn_cast(D)) { if (VD->getType()->isReferenceType() && !(getLangOpts().OpenMP && isOpenMPCapturedDecl(D)) && VD->isUsableInConstantExpressions(Context)) return NOUR_Constant; } // All remaining non-variable cases constitute an odr-use. For variables, we // need to wait and see how the expression is used. return NOUR_None; } /// BuildDeclRefExpr - Build an expression that references a /// declaration that does not require a closure capture. DeclRefExpr * Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK, const DeclarationNameInfo &NameInfo, NestedNameSpecifierLoc NNS, NamedDecl *FoundD, SourceLocation TemplateKWLoc, const TemplateArgumentListInfo *TemplateArgs) { bool RefersToCapturedVariable = isa(D) && NeedToCaptureVariable(cast(D), NameInfo.getLoc()); DeclRefExpr *E = DeclRefExpr::Create( Context, NNS, TemplateKWLoc, D, RefersToCapturedVariable, NameInfo, Ty, VK, FoundD, TemplateArgs, getNonOdrUseReasonInCurrentContext(D)); MarkDeclRefReferenced(E); // C++ [except.spec]p17: // An exception-specification is considered to be needed when: // - in an expression, the function is the unique lookup result or // the selected member of a set of overloaded functions. // // We delay doing this until after we've built the function reference and // marked it as used so that: // a) if the function is defaulted, we get errors from defining it before / // instead of errors from computing its exception specification, and // b) if the function is a defaulted comparison, we can use the body we // build when defining it as input to the exception specification // computation rather than computing a new body. if (auto *FPT = Ty->getAs()) { if (isUnresolvedExceptionSpec(FPT->getExceptionSpecType())) { if (auto *NewFPT = ResolveExceptionSpec(NameInfo.getLoc(), FPT)) E->setType(Context.getQualifiedType(NewFPT, Ty.getQualifiers())); } } if (getLangOpts().ObjCWeak && isa(D) && Ty.getObjCLifetime() == Qualifiers::OCL_Weak && !isUnevaluatedContext() && !Diags.isIgnored(diag::warn_arc_repeated_use_of_weak, E->getBeginLoc())) getCurFunction()->recordUseOfWeak(E); FieldDecl *FD = dyn_cast(D); if (IndirectFieldDecl *IFD = dyn_cast(D)) FD = IFD->getAnonField(); if (FD) { UnusedPrivateFields.remove(FD); // Just in case we're building an illegal pointer-to-member. if (FD->isBitField()) E->setObjectKind(OK_BitField); } // C++ [expr.prim]/8: The expression [...] is a bit-field if the identifier // designates a bit-field. if (auto *BD = dyn_cast(D)) if (auto *BE = BD->getBinding()) E->setObjectKind(BE->getObjectKind()); return E; } /// Decomposes the given name into a DeclarationNameInfo, its location, and /// possibly a list of template arguments. /// /// If this produces template arguments, it is permitted to call /// DecomposeTemplateName. /// /// This actually loses a lot of source location information for /// non-standard name kinds; we should consider preserving that in /// some way. void Sema::DecomposeUnqualifiedId(const UnqualifiedId &Id, TemplateArgumentListInfo &Buffer, DeclarationNameInfo &NameInfo, const TemplateArgumentListInfo *&TemplateArgs) { if (Id.getKind() == UnqualifiedIdKind::IK_TemplateId) { Buffer.setLAngleLoc(Id.TemplateId->LAngleLoc); Buffer.setRAngleLoc(Id.TemplateId->RAngleLoc); ASTTemplateArgsPtr TemplateArgsPtr(Id.TemplateId->getTemplateArgs(), Id.TemplateId->NumArgs); translateTemplateArguments(TemplateArgsPtr, Buffer); TemplateName TName = Id.TemplateId->Template.get(); SourceLocation TNameLoc = Id.TemplateId->TemplateNameLoc; NameInfo = Context.getNameForTemplate(TName, TNameLoc); TemplateArgs = &Buffer; } else { NameInfo = GetNameFromUnqualifiedId(Id); TemplateArgs = nullptr; } } static void emitEmptyLookupTypoDiagnostic( const TypoCorrection &TC, Sema &SemaRef, const CXXScopeSpec &SS, DeclarationName Typo, SourceLocation TypoLoc, ArrayRef Args, unsigned DiagnosticID, unsigned DiagnosticSuggestID) { DeclContext *Ctx = SS.isEmpty() ? nullptr : SemaRef.computeDeclContext(SS, false); if (!TC) { // Emit a special diagnostic for failed member lookups. // FIXME: computing the declaration context might fail here (?) if (Ctx) SemaRef.Diag(TypoLoc, diag::err_no_member) << Typo << Ctx << SS.getRange(); else SemaRef.Diag(TypoLoc, DiagnosticID) << Typo; return; } std::string CorrectedStr = TC.getAsString(SemaRef.getLangOpts()); bool DroppedSpecifier = TC.WillReplaceSpecifier() && Typo.getAsString() == CorrectedStr; unsigned NoteID = TC.getCorrectionDeclAs() ? diag::note_implicit_param_decl : diag::note_previous_decl; if (!Ctx) SemaRef.diagnoseTypo(TC, SemaRef.PDiag(DiagnosticSuggestID) << Typo, SemaRef.PDiag(NoteID)); else SemaRef.diagnoseTypo(TC, SemaRef.PDiag(diag::err_no_member_suggest) << Typo << Ctx << DroppedSpecifier << SS.getRange(), SemaRef.PDiag(NoteID)); } /// Diagnose an empty lookup. /// /// \return false if new lookup candidates were found bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R, CorrectionCandidateCallback &CCC, TemplateArgumentListInfo *ExplicitTemplateArgs, ArrayRef Args, TypoExpr **Out) { DeclarationName Name = R.getLookupName(); unsigned diagnostic = diag::err_undeclared_var_use; unsigned diagnostic_suggest = diag::err_undeclared_var_use_suggest; if (Name.getNameKind() == DeclarationName::CXXOperatorName || Name.getNameKind() == DeclarationName::CXXLiteralOperatorName || Name.getNameKind() == DeclarationName::CXXConversionFunctionName) { diagnostic = diag::err_undeclared_use; diagnostic_suggest = diag::err_undeclared_use_suggest; } // If the original lookup was an unqualified lookup, fake an // unqualified lookup. This is useful when (for example) the // original lookup would not have found something because it was a // dependent name. DeclContext *DC = SS.isEmpty() ? CurContext : nullptr; while (DC) { if (isa(DC)) { LookupQualifiedName(R, DC); if (!R.empty()) { // Don't give errors about ambiguities in this lookup. R.suppressDiagnostics(); // During a default argument instantiation the CurContext points // to a CXXMethodDecl; but we can't apply a this-> fixit inside a // function parameter list, hence add an explicit check. bool isDefaultArgument = !CodeSynthesisContexts.empty() && CodeSynthesisContexts.back().Kind == CodeSynthesisContext::DefaultFunctionArgumentInstantiation; CXXMethodDecl *CurMethod = dyn_cast(CurContext); bool isInstance = CurMethod && CurMethod->isInstance() && DC == CurMethod->getParent() && !isDefaultArgument; // Give a code modification hint to insert 'this->'. // TODO: fixit for inserting 'Base::' in the other cases. // Actually quite difficult! if (getLangOpts().MSVCCompat) diagnostic = diag::ext_found_via_dependent_bases_lookup; if (isInstance) { Diag(R.getNameLoc(), diagnostic) << Name << FixItHint::CreateInsertion(R.getNameLoc(), "this->"); CheckCXXThisCapture(R.getNameLoc()); } else { Diag(R.getNameLoc(), diagnostic) << Name; } // Do we really want to note all of these? for (NamedDecl *D : R) Diag(D->getLocation(), diag::note_dependent_var_use); // Return true if we are inside a default argument instantiation // and the found name refers to an instance member function, otherwise // the function calling DiagnoseEmptyLookup will try to create an // implicit member call and this is wrong for default argument. if (isDefaultArgument && ((*R.begin())->isCXXInstanceMember())) { Diag(R.getNameLoc(), diag::err_member_call_without_object); return true; } // Tell the callee to try to recover. return false; } R.clear(); } DC = DC->getLookupParent(); } // We didn't find anything, so try to correct for a typo. TypoCorrection Corrected; if (S && Out) { SourceLocation TypoLoc = R.getNameLoc(); assert(!ExplicitTemplateArgs && "Diagnosing an empty lookup with explicit template args!"); *Out = CorrectTypoDelayed( R.getLookupNameInfo(), R.getLookupKind(), S, &SS, CCC, [=](const TypoCorrection &TC) { emitEmptyLookupTypoDiagnostic(TC, *this, SS, Name, TypoLoc, Args, diagnostic, diagnostic_suggest); }, nullptr, CTK_ErrorRecovery); if (*Out) return true; } else if (S && (Corrected = CorrectTypo(R.getLookupNameInfo(), R.getLookupKind(), S, &SS, CCC, CTK_ErrorRecovery))) { std::string CorrectedStr(Corrected.getAsString(getLangOpts())); bool DroppedSpecifier = Corrected.WillReplaceSpecifier() && Name.getAsString() == CorrectedStr; R.setLookupName(Corrected.getCorrection()); bool AcceptableWithRecovery = false; bool AcceptableWithoutRecovery = false; NamedDecl *ND = Corrected.getFoundDecl(); if (ND) { if (Corrected.isOverloaded()) { OverloadCandidateSet OCS(R.getNameLoc(), OverloadCandidateSet::CSK_Normal); OverloadCandidateSet::iterator Best; for (NamedDecl *CD : Corrected) { if (FunctionTemplateDecl *FTD = dyn_cast(CD)) AddTemplateOverloadCandidate( FTD, DeclAccessPair::make(FTD, AS_none), ExplicitTemplateArgs, Args, OCS); else if (FunctionDecl *FD = dyn_cast(CD)) if (!ExplicitTemplateArgs || ExplicitTemplateArgs->size() == 0) AddOverloadCandidate(FD, DeclAccessPair::make(FD, AS_none), Args, OCS); } switch (OCS.BestViableFunction(*this, R.getNameLoc(), Best)) { case OR_Success: ND = Best->FoundDecl; Corrected.setCorrectionDecl(ND); break; default: // FIXME: Arbitrarily pick the first declaration for the note. Corrected.setCorrectionDecl(ND); break; } } R.addDecl(ND); if (getLangOpts().CPlusPlus && ND->isCXXClassMember()) { CXXRecordDecl *Record = nullptr; if (Corrected.getCorrectionSpecifier()) { const Type *Ty = Corrected.getCorrectionSpecifier()->getAsType(); Record = Ty->getAsCXXRecordDecl(); } if (!Record) Record = cast( ND->getDeclContext()->getRedeclContext()); R.setNamingClass(Record); } auto *UnderlyingND = ND->getUnderlyingDecl(); AcceptableWithRecovery = isa(UnderlyingND) || isa(UnderlyingND); // FIXME: If we ended up with a typo for a type name or // Objective-C class name, we're in trouble because the parser // is in the wrong place to recover. Suggest the typo // correction, but don't make it a fix-it since we're not going // to recover well anyway. AcceptableWithoutRecovery = isa(UnderlyingND) || getAsTypeTemplateDecl(UnderlyingND) || isa(UnderlyingND); } else { // FIXME: We found a keyword. Suggest it, but don't provide a fix-it // because we aren't able to recover. AcceptableWithoutRecovery = true; } if (AcceptableWithRecovery || AcceptableWithoutRecovery) { unsigned NoteID = Corrected.getCorrectionDeclAs() ? diag::note_implicit_param_decl : diag::note_previous_decl; if (SS.isEmpty()) diagnoseTypo(Corrected, PDiag(diagnostic_suggest) << Name, PDiag(NoteID), AcceptableWithRecovery); else diagnoseTypo(Corrected, PDiag(diag::err_no_member_suggest) << Name << computeDeclContext(SS, false) << DroppedSpecifier << SS.getRange(), PDiag(NoteID), AcceptableWithRecovery); // Tell the callee whether to try to recover. return !AcceptableWithRecovery; } } R.clear(); // Emit a special diagnostic for failed member lookups. // FIXME: computing the declaration context might fail here (?) if (!SS.isEmpty()) { Diag(R.getNameLoc(), diag::err_no_member) << Name << computeDeclContext(SS, false) << SS.getRange(); return true; } // Give up, we can't recover. Diag(R.getNameLoc(), diagnostic) << Name; return true; } /// In Microsoft mode, if we are inside a template class whose parent class has /// dependent base classes, and we can't resolve an unqualified identifier, then /// assume the identifier is a member of a dependent base class. We can only /// recover successfully in static methods, instance methods, and other contexts /// where 'this' is available. This doesn't precisely match MSVC's /// instantiation model, but it's close enough. static Expr * recoverFromMSUnqualifiedLookup(Sema &S, ASTContext &Context, DeclarationNameInfo &NameInfo, SourceLocation TemplateKWLoc, const TemplateArgumentListInfo *TemplateArgs) { // Only try to recover from lookup into dependent bases in static methods or // contexts where 'this' is available. QualType ThisType = S.getCurrentThisType(); const CXXRecordDecl *RD = nullptr; if (!ThisType.isNull()) RD = ThisType->getPointeeType()->getAsCXXRecordDecl(); else if (auto *MD = dyn_cast(S.CurContext)) RD = MD->getParent(); if (!RD || !RD->hasAnyDependentBases()) return nullptr; // Diagnose this as unqualified lookup into a dependent base class. If 'this' // is available, suggest inserting 'this->' as a fixit. SourceLocation Loc = NameInfo.getLoc(); auto DB = S.Diag(Loc, diag::ext_undeclared_unqual_id_with_dependent_base); DB << NameInfo.getName() << RD; if (!ThisType.isNull()) { DB << FixItHint::CreateInsertion(Loc, "this->"); return CXXDependentScopeMemberExpr::Create( Context, /*This=*/nullptr, ThisType, /*IsArrow=*/true, /*Op=*/SourceLocation(), NestedNameSpecifierLoc(), TemplateKWLoc, /*FirstQualifierFoundInScope=*/nullptr, NameInfo, TemplateArgs); } // Synthesize a fake NNS that points to the derived class. This will // perform name lookup during template instantiation. CXXScopeSpec SS; auto *NNS = NestedNameSpecifier::Create(Context, nullptr, true, RD->getTypeForDecl()); SS.MakeTrivial(Context, NNS, SourceRange(Loc, Loc)); return DependentScopeDeclRefExpr::Create( Context, SS.getWithLocInContext(Context), TemplateKWLoc, NameInfo, TemplateArgs); } ExprResult Sema::ActOnIdExpression(Scope *S, CXXScopeSpec &SS, SourceLocation TemplateKWLoc, UnqualifiedId &Id, bool HasTrailingLParen, bool IsAddressOfOperand, CorrectionCandidateCallback *CCC, bool IsInlineAsmIdentifier, Token *KeywordReplacement) { assert(!(IsAddressOfOperand && HasTrailingLParen) && "cannot be direct & operand and have a trailing lparen"); if (SS.isInvalid()) return ExprError(); TemplateArgumentListInfo TemplateArgsBuffer; // Decompose the UnqualifiedId into the following data. DeclarationNameInfo NameInfo; const TemplateArgumentListInfo *TemplateArgs; DecomposeUnqualifiedId(Id, TemplateArgsBuffer, NameInfo, TemplateArgs); DeclarationName Name = NameInfo.getName(); IdentifierInfo *II = Name.getAsIdentifierInfo(); SourceLocation NameLoc = NameInfo.getLoc(); if (II && II->isEditorPlaceholder()) { // FIXME: When typed placeholders are supported we can create a typed // placeholder expression node. return ExprError(); } // C++ [temp.dep.expr]p3: // An id-expression is type-dependent if it contains: // -- an identifier that was declared with a dependent type, // (note: handled after lookup) // -- a template-id that is dependent, // (note: handled in BuildTemplateIdExpr) // -- a conversion-function-id that specifies a dependent type, // -- a nested-name-specifier that contains a class-name that // names a dependent type. // Determine whether this is a member of an unknown specialization; // we need to handle these differently. bool DependentID = false; if (Name.getNameKind() == DeclarationName::CXXConversionFunctionName && Name.getCXXNameType()->isDependentType()) { DependentID = true; } else if (SS.isSet()) { if (DeclContext *DC = computeDeclContext(SS, false)) { if (RequireCompleteDeclContext(SS, DC)) return ExprError(); } else { DependentID = true; } } if (DependentID) return ActOnDependentIdExpression(SS, TemplateKWLoc, NameInfo, IsAddressOfOperand, TemplateArgs); // Perform the required lookup. LookupResult R(*this, NameInfo, (Id.getKind() == UnqualifiedIdKind::IK_ImplicitSelfParam) ? LookupObjCImplicitSelfParam : LookupOrdinaryName); if (TemplateKWLoc.isValid() || TemplateArgs) { // Lookup the template name again to correctly establish the context in // which it was found. This is really unfortunate as we already did the // lookup to determine that it was a template name in the first place. If // this becomes a performance hit, we can work harder to preserve those // results until we get here but it's likely not worth it. bool MemberOfUnknownSpecialization; AssumedTemplateKind AssumedTemplate; if (LookupTemplateName(R, S, SS, QualType(), /*EnteringContext=*/false, MemberOfUnknownSpecialization, TemplateKWLoc, &AssumedTemplate)) return ExprError(); if (MemberOfUnknownSpecialization || (R.getResultKind() == LookupResult::NotFoundInCurrentInstantiation)) return ActOnDependentIdExpression(SS, TemplateKWLoc, NameInfo, IsAddressOfOperand, TemplateArgs); } else { bool IvarLookupFollowUp = II && !SS.isSet() && getCurMethodDecl(); LookupParsedName(R, S, &SS, !IvarLookupFollowUp); // If the result might be in a dependent base class, this is a dependent // id-expression. if (R.getResultKind() == LookupResult::NotFoundInCurrentInstantiation) return ActOnDependentIdExpression(SS, TemplateKWLoc, NameInfo, IsAddressOfOperand, TemplateArgs); // If this reference is in an Objective-C method, then we need to do // some special Objective-C lookup, too. if (IvarLookupFollowUp) { ExprResult E(LookupInObjCMethod(R, S, II, true)); if (E.isInvalid()) return ExprError(); if (Expr *Ex = E.getAs()) return Ex; } } if (R.isAmbiguous()) return ExprError(); // This could be an implicitly declared function reference (legal in C90, // extension in C99, forbidden in C++). if (R.empty() && HasTrailingLParen && II && !getLangOpts().CPlusPlus) { NamedDecl *D = ImplicitlyDefineFunction(NameLoc, *II, S); if (D) R.addDecl(D); } // Determine whether this name might be a candidate for // argument-dependent lookup. bool ADL = UseArgumentDependentLookup(SS, R, HasTrailingLParen); if (R.empty() && !ADL) { if (SS.isEmpty() && getLangOpts().MSVCCompat) { if (Expr *E = recoverFromMSUnqualifiedLookup(*this, Context, NameInfo, TemplateKWLoc, TemplateArgs)) return E; } // Don't diagnose an empty lookup for inline assembly. if (IsInlineAsmIdentifier) return ExprError(); // If this name wasn't predeclared and if this is not a function // call, diagnose the problem. TypoExpr *TE = nullptr; DefaultFilterCCC DefaultValidator(II, SS.isValid() ? SS.getScopeRep() : nullptr); DefaultValidator.IsAddressOfOperand = IsAddressOfOperand; assert((!CCC || CCC->IsAddressOfOperand == IsAddressOfOperand) && "Typo correction callback misconfigured"); if (CCC) { // Make sure the callback knows what the typo being diagnosed is. CCC->setTypoName(II); if (SS.isValid()) CCC->setTypoNNS(SS.getScopeRep()); } // FIXME: DiagnoseEmptyLookup produces bad diagnostics if we're looking for // a template name, but we happen to have always already looked up the name // before we get here if it must be a template name. if (DiagnoseEmptyLookup(S, SS, R, CCC ? *CCC : DefaultValidator, nullptr, None, &TE)) { if (TE && KeywordReplacement) { auto &State = getTypoExprState(TE); auto BestTC = State.Consumer->getNextCorrection(); if (BestTC.isKeyword()) { auto *II = BestTC.getCorrectionAsIdentifierInfo(); if (State.DiagHandler) State.DiagHandler(BestTC); KeywordReplacement->startToken(); KeywordReplacement->setKind(II->getTokenID()); KeywordReplacement->setIdentifierInfo(II); KeywordReplacement->setLocation(BestTC.getCorrectionRange().getBegin()); // Clean up the state associated with the TypoExpr, since it has // now been diagnosed (without a call to CorrectDelayedTyposInExpr). clearDelayedTypo(TE); // Signal that a correction to a keyword was performed by returning a // valid-but-null ExprResult. return (Expr*)nullptr; } State.Consumer->resetCorrectionStream(); } return TE ? TE : ExprError(); } assert(!R.empty() && "DiagnoseEmptyLookup returned false but added no results"); // If we found an Objective-C instance variable, let // LookupInObjCMethod build the appropriate expression to // reference the ivar. if (ObjCIvarDecl *Ivar = R.getAsSingle()) { R.clear(); ExprResult E(LookupInObjCMethod(R, S, Ivar->getIdentifier())); // In a hopelessly buggy code, Objective-C instance variable // lookup fails and no expression will be built to reference it. if (!E.isInvalid() && !E.get()) return ExprError(); return E; } } // This is guaranteed from this point on. assert(!R.empty() || ADL); // Check whether this might be a C++ implicit instance member access. // C++ [class.mfct.non-static]p3: // When an id-expression that is not part of a class member access // syntax and not used to form a pointer to member is used in the // body of a non-static member function of class X, if name lookup // resolves the name in the id-expression to a non-static non-type // member of some class C, the id-expression is transformed into a // class member access expression using (*this) as the // postfix-expression to the left of the . operator. // // But we don't actually need to do this for '&' operands if R // resolved to a function or overloaded function set, because the // expression is ill-formed if it actually works out to be a // non-static member function: // // C++ [expr.ref]p4: // Otherwise, if E1.E2 refers to a non-static member function. . . // [t]he expression can be used only as the left-hand operand of a // member function call. // // There are other safeguards against such uses, but it's important // to get this right here so that we don't end up making a // spuriously dependent expression if we're inside a dependent // instance method. if (!R.empty() && (*R.begin())->isCXXClassMember()) { bool MightBeImplicitMember; if (!IsAddressOfOperand) MightBeImplicitMember = true; else if (!SS.isEmpty()) MightBeImplicitMember = false; else if (R.isOverloadedResult()) MightBeImplicitMember = false; else if (R.isUnresolvableResult()) MightBeImplicitMember = true; else MightBeImplicitMember = isa(R.getFoundDecl()) || isa(R.getFoundDecl()) || isa(R.getFoundDecl()); if (MightBeImplicitMember) return BuildPossibleImplicitMemberExpr(SS, TemplateKWLoc, R, TemplateArgs, S); } if (TemplateArgs || TemplateKWLoc.isValid()) { // In C++1y, if this is a variable template id, then check it // in BuildTemplateIdExpr(). // The single lookup result must be a variable template declaration. if (Id.getKind() == UnqualifiedIdKind::IK_TemplateId && Id.TemplateId && Id.TemplateId->Kind == TNK_Var_template) { assert(R.getAsSingle() && "There should only be one declaration found."); } return BuildTemplateIdExpr(SS, TemplateKWLoc, R, ADL, TemplateArgs); } return BuildDeclarationNameExpr(SS, R, ADL); } /// BuildQualifiedDeclarationNameExpr - Build a C++ qualified /// declaration name, generally during template instantiation. /// There's a large number of things which don't need to be done along /// this path. ExprResult Sema::BuildQualifiedDeclarationNameExpr( CXXScopeSpec &SS, const DeclarationNameInfo &NameInfo, bool IsAddressOfOperand, const Scope *S, TypeSourceInfo **RecoveryTSI) { DeclContext *DC = computeDeclContext(SS, false); if (!DC) return BuildDependentDeclRefExpr(SS, /*TemplateKWLoc=*/SourceLocation(), NameInfo, /*TemplateArgs=*/nullptr); if (RequireCompleteDeclContext(SS, DC)) return ExprError(); LookupResult R(*this, NameInfo, LookupOrdinaryName); LookupQualifiedName(R, DC); if (R.isAmbiguous()) return ExprError(); if (R.getResultKind() == LookupResult::NotFoundInCurrentInstantiation) return BuildDependentDeclRefExpr(SS, /*TemplateKWLoc=*/SourceLocation(), NameInfo, /*TemplateArgs=*/nullptr); if (R.empty()) { Diag(NameInfo.getLoc(), diag::err_no_member) << NameInfo.getName() << DC << SS.getRange(); return ExprError(); } if (const TypeDecl *TD = R.getAsSingle()) { // Diagnose a missing typename if this resolved unambiguously to a type in // a dependent context. If we can recover with a type, downgrade this to // a warning in Microsoft compatibility mode. unsigned DiagID = diag::err_typename_missing; if (RecoveryTSI && getLangOpts().MSVCCompat) DiagID = diag::ext_typename_missing; SourceLocation Loc = SS.getBeginLoc(); auto D = Diag(Loc, DiagID); D << SS.getScopeRep() << NameInfo.getName().getAsString() << SourceRange(Loc, NameInfo.getEndLoc()); // Don't recover if the caller isn't expecting us to or if we're in a SFINAE // context. if (!RecoveryTSI) return ExprError(); // Only issue the fixit if we're prepared to recover. D << FixItHint::CreateInsertion(Loc, "typename "); // Recover by pretending this was an elaborated type. QualType Ty = Context.getTypeDeclType(TD); TypeLocBuilder TLB; TLB.pushTypeSpec(Ty).setNameLoc(NameInfo.getLoc()); QualType ET = getElaboratedType(ETK_None, SS, Ty); ElaboratedTypeLoc QTL = TLB.push(ET); QTL.setElaboratedKeywordLoc(SourceLocation()); QTL.setQualifierLoc(SS.getWithLocInContext(Context)); *RecoveryTSI = TLB.getTypeSourceInfo(Context, ET); return ExprEmpty(); } // Defend against this resolving to an implicit member access. We usually // won't get here if this might be a legitimate a class member (we end up in // BuildMemberReferenceExpr instead), but this can be valid if we're forming // a pointer-to-member or in an unevaluated context in C++11. if (!R.empty() && (*R.begin())->isCXXClassMember() && !IsAddressOfOperand) return BuildPossibleImplicitMemberExpr(SS, /*TemplateKWLoc=*/SourceLocation(), R, /*TemplateArgs=*/nullptr, S); return BuildDeclarationNameExpr(SS, R, /* ADL */ false); } /// The parser has read a name in, and Sema has detected that we're currently /// inside an ObjC method. Perform some additional checks and determine if we /// should form a reference to an ivar. /// /// Ideally, most of this would be done by lookup, but there's /// actually quite a lot of extra work involved. DeclResult Sema::LookupIvarInObjCMethod(LookupResult &Lookup, Scope *S, IdentifierInfo *II) { SourceLocation Loc = Lookup.getNameLoc(); ObjCMethodDecl *CurMethod = getCurMethodDecl(); // Check for error condition which is already reported. if (!CurMethod) return DeclResult(true); // There are two cases to handle here. 1) scoped lookup could have failed, // in which case we should look for an ivar. 2) scoped lookup could have // found a decl, but that decl is outside the current instance method (i.e. // a global variable). In these two cases, we do a lookup for an ivar with // this name, if the lookup sucedes, we replace it our current decl. // If we're in a class method, we don't normally want to look for // ivars. But if we don't find anything else, and there's an // ivar, that's an error. bool IsClassMethod = CurMethod->isClassMethod(); bool LookForIvars; if (Lookup.empty()) LookForIvars = true; else if (IsClassMethod) LookForIvars = false; else LookForIvars = (Lookup.isSingleResult() && Lookup.getFoundDecl()->isDefinedOutsideFunctionOrMethod()); ObjCInterfaceDecl *IFace = nullptr; if (LookForIvars) { IFace = CurMethod->getClassInterface(); ObjCInterfaceDecl *ClassDeclared; ObjCIvarDecl *IV = nullptr; if (IFace && (IV = IFace->lookupInstanceVariable(II, ClassDeclared))) { // Diagnose using an ivar in a class method. if (IsClassMethod) { Diag(Loc, diag::err_ivar_use_in_class_method) << IV->getDeclName(); return DeclResult(true); } // Diagnose the use of an ivar outside of the declaring class. if (IV->getAccessControl() == ObjCIvarDecl::Private && !declaresSameEntity(ClassDeclared, IFace) && !getLangOpts().DebuggerSupport) Diag(Loc, diag::err_private_ivar_access) << IV->getDeclName(); // Success. return IV; } } else if (CurMethod->isInstanceMethod()) { // We should warn if a local variable hides an ivar. if (ObjCInterfaceDecl *IFace = CurMethod->getClassInterface()) { ObjCInterfaceDecl *ClassDeclared; if (ObjCIvarDecl *IV = IFace->lookupInstanceVariable(II, ClassDeclared)) { if (IV->getAccessControl() != ObjCIvarDecl::Private || declaresSameEntity(IFace, ClassDeclared)) Diag(Loc, diag::warn_ivar_use_hidden) << IV->getDeclName(); } } } else if (Lookup.isSingleResult() && Lookup.getFoundDecl()->isDefinedOutsideFunctionOrMethod()) { // If accessing a stand-alone ivar in a class method, this is an error. if (const ObjCIvarDecl *IV = dyn_cast(Lookup.getFoundDecl())) { Diag(Loc, diag::err_ivar_use_in_class_method) << IV->getDeclName(); return DeclResult(true); } } // Didn't encounter an error, didn't find an ivar. return DeclResult(false); } ExprResult Sema::BuildIvarRefExpr(Scope *S, SourceLocation Loc, ObjCIvarDecl *IV) { ObjCMethodDecl *CurMethod = getCurMethodDecl(); assert(CurMethod && CurMethod->isInstanceMethod() && "should not reference ivar from this context"); ObjCInterfaceDecl *IFace = CurMethod->getClassInterface(); assert(IFace && "should not reference ivar from this context"); // If we're referencing an invalid decl, just return this as a silent // error node. The error diagnostic was already emitted on the decl. if (IV->isInvalidDecl()) return ExprError(); // Check if referencing a field with __attribute__((deprecated)). if (DiagnoseUseOfDecl(IV, Loc)) return ExprError(); // FIXME: This should use a new expr for a direct reference, don't // turn this into Self->ivar, just return a BareIVarExpr or something. IdentifierInfo &II = Context.Idents.get("self"); UnqualifiedId SelfName; SelfName.setIdentifier(&II, SourceLocation()); SelfName.setKind(UnqualifiedIdKind::IK_ImplicitSelfParam); CXXScopeSpec SelfScopeSpec; SourceLocation TemplateKWLoc; ExprResult SelfExpr = ActOnIdExpression(S, SelfScopeSpec, TemplateKWLoc, SelfName, /*HasTrailingLParen=*/false, /*IsAddressOfOperand=*/false); if (SelfExpr.isInvalid()) return ExprError(); SelfExpr = DefaultLvalueConversion(SelfExpr.get()); if (SelfExpr.isInvalid()) return ExprError(); MarkAnyDeclReferenced(Loc, IV, true); ObjCMethodFamily MF = CurMethod->getMethodFamily(); if (MF != OMF_init && MF != OMF_dealloc && MF != OMF_finalize && !IvarBacksCurrentMethodAccessor(IFace, CurMethod, IV)) Diag(Loc, diag::warn_direct_ivar_access) << IV->getDeclName(); ObjCIvarRefExpr *Result = new (Context) ObjCIvarRefExpr(IV, IV->getUsageType(SelfExpr.get()->getType()), Loc, IV->getLocation(), SelfExpr.get(), true, true); if (IV->getType().getObjCLifetime() == Qualifiers::OCL_Weak) { if (!isUnevaluatedContext() && !Diags.isIgnored(diag::warn_arc_repeated_use_of_weak, Loc)) getCurFunction()->recordUseOfWeak(Result); } if (getLangOpts().ObjCAutoRefCount) if (const BlockDecl *BD = CurContext->getInnermostBlockDecl()) ImplicitlyRetainedSelfLocs.push_back({Loc, BD}); return Result; } /// The parser has read a name in, and Sema has detected that we're currently /// inside an ObjC method. Perform some additional checks and determine if we /// should form a reference to an ivar. If so, build an expression referencing /// that ivar. ExprResult Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S, IdentifierInfo *II, bool AllowBuiltinCreation) { // FIXME: Integrate this lookup step into LookupParsedName. DeclResult Ivar = LookupIvarInObjCMethod(Lookup, S, II); if (Ivar.isInvalid()) return ExprError(); if (Ivar.isUsable()) return BuildIvarRefExpr(S, Lookup.getNameLoc(), cast(Ivar.get())); if (Lookup.empty() && II && AllowBuiltinCreation) LookupBuiltin(Lookup); // Sentinel value saying that we didn't do anything special. return ExprResult(false); } /// Cast a base object to a member's actual type. /// /// Logically this happens in three phases: /// /// * First we cast from the base type to the naming class. /// The naming class is the class into which we were looking /// when we found the member; it's the qualifier type if a /// qualifier was provided, and otherwise it's the base type. /// /// * Next we cast from the naming class to the declaring class. /// If the member we found was brought into a class's scope by /// a using declaration, this is that class; otherwise it's /// the class declaring the member. /// /// * Finally we cast from the declaring class to the "true" /// declaring class of the member. This conversion does not /// obey access control. ExprResult Sema::PerformObjectMemberConversion(Expr *From, NestedNameSpecifier *Qualifier, NamedDecl *FoundDecl, NamedDecl *Member) { CXXRecordDecl *RD = dyn_cast(Member->getDeclContext()); if (!RD) return From; QualType DestRecordType; QualType DestType; QualType FromRecordType; QualType FromType = From->getType(); bool PointerConversions = false; if (isa(Member)) { DestRecordType = Context.getCanonicalType(Context.getTypeDeclType(RD)); auto FromPtrType = FromType->getAs(); DestRecordType = Context.getAddrSpaceQualType( DestRecordType, FromPtrType ? FromType->getPointeeType().getAddressSpace() : FromType.getAddressSpace()); if (FromPtrType) { DestType = Context.getPointerType(DestRecordType); FromRecordType = FromPtrType->getPointeeType(); PointerConversions = true; } else { DestType = DestRecordType; FromRecordType = FromType; } } else if (CXXMethodDecl *Method = dyn_cast(Member)) { if (Method->isStatic()) return From; DestType = Method->getThisType(); DestRecordType = DestType->getPointeeType(); if (FromType->getAs()) { FromRecordType = FromType->getPointeeType(); PointerConversions = true; } else { FromRecordType = FromType; DestType = DestRecordType; } LangAS FromAS = FromRecordType.getAddressSpace(); LangAS DestAS = DestRecordType.getAddressSpace(); if (FromAS != DestAS) { QualType FromRecordTypeWithoutAS = Context.removeAddrSpaceQualType(FromRecordType); QualType FromTypeWithDestAS = Context.getAddrSpaceQualType(FromRecordTypeWithoutAS, DestAS); if (PointerConversions) FromTypeWithDestAS = Context.getPointerType(FromTypeWithDestAS); From = ImpCastExprToType(From, FromTypeWithDestAS, CK_AddressSpaceConversion, From->getValueKind()) .get(); } } else { // No conversion necessary. return From; } if (DestType->isDependentType() || FromType->isDependentType()) return From; // If the unqualified types are the same, no conversion is necessary. if (Context.hasSameUnqualifiedType(FromRecordType, DestRecordType)) return From; SourceRange FromRange = From->getSourceRange(); SourceLocation FromLoc = FromRange.getBegin(); ExprValueKind VK = From->getValueKind(); // C++ [class.member.lookup]p8: // [...] Ambiguities can often be resolved by qualifying a name with its // class name. // // If the member was a qualified name and the qualified referred to a // specific base subobject type, we'll cast to that intermediate type // first and then to the object in which the member is declared. That allows // one to resolve ambiguities in, e.g., a diamond-shaped hierarchy such as: // // class Base { public: int x; }; // class Derived1 : public Base { }; // class Derived2 : public Base { }; // class VeryDerived : public Derived1, public Derived2 { void f(); }; // // void VeryDerived::f() { // x = 17; // error: ambiguous base subobjects // Derived1::x = 17; // okay, pick the Base subobject of Derived1 // } if (Qualifier && Qualifier->getAsType()) { QualType QType = QualType(Qualifier->getAsType(), 0); assert(QType->isRecordType() && "lookup done with non-record type"); QualType QRecordType = QualType(QType->getAs(), 0); // In C++98, the qualifier type doesn't actually have to be a base // type of the object type, in which case we just ignore it. // Otherwise build the appropriate casts. if (IsDerivedFrom(FromLoc, FromRecordType, QRecordType)) { CXXCastPath BasePath; if (CheckDerivedToBaseConversion(FromRecordType, QRecordType, FromLoc, FromRange, &BasePath)) return ExprError(); if (PointerConversions) QType = Context.getPointerType(QType); From = ImpCastExprToType(From, QType, CK_UncheckedDerivedToBase, VK, &BasePath).get(); FromType = QType; FromRecordType = QRecordType; // If the qualifier type was the same as the destination type, // we're done. if (Context.hasSameUnqualifiedType(FromRecordType, DestRecordType)) return From; } } bool IgnoreAccess = false; // If we actually found the member through a using declaration, cast // down to the using declaration's type. // // Pointer equality is fine here because only one declaration of a // class ever has member declarations. if (FoundDecl->getDeclContext() != Member->getDeclContext()) { assert(isa(FoundDecl)); QualType URecordType = Context.getTypeDeclType( cast(FoundDecl->getDeclContext())); // We only need to do this if the naming-class to declaring-class // conversion is non-trivial. if (!Context.hasSameUnqualifiedType(FromRecordType, URecordType)) { assert(IsDerivedFrom(FromLoc, FromRecordType, URecordType)); CXXCastPath BasePath; if (CheckDerivedToBaseConversion(FromRecordType, URecordType, FromLoc, FromRange, &BasePath)) return ExprError(); QualType UType = URecordType; if (PointerConversions) UType = Context.getPointerType(UType); From = ImpCastExprToType(From, UType, CK_UncheckedDerivedToBase, VK, &BasePath).get(); FromType = UType; FromRecordType = URecordType; } // We don't do access control for the conversion from the // declaring class to the true declaring class. IgnoreAccess = true; } CXXCastPath BasePath; if (CheckDerivedToBaseConversion(FromRecordType, DestRecordType, FromLoc, FromRange, &BasePath, IgnoreAccess)) return ExprError(); return ImpCastExprToType(From, DestType, CK_UncheckedDerivedToBase, VK, &BasePath); } bool Sema::UseArgumentDependentLookup(const CXXScopeSpec &SS, const LookupResult &R, bool HasTrailingLParen) { // Only when used directly as the postfix-expression of a call. if (!HasTrailingLParen) return false; // Never if a scope specifier was provided. if (SS.isSet()) return false; // Only in C++ or ObjC++. if (!getLangOpts().CPlusPlus) return false; // Turn off ADL when we find certain kinds of declarations during // normal lookup: for (NamedDecl *D : R) { // C++0x [basic.lookup.argdep]p3: // -- a declaration of a class member // Since using decls preserve this property, we check this on the // original decl. if (D->isCXXClassMember()) return false; // C++0x [basic.lookup.argdep]p3: // -- a block-scope function declaration that is not a // using-declaration // NOTE: we also trigger this for function templates (in fact, we // don't check the decl type at all, since all other decl types // turn off ADL anyway). if (isa(D)) D = cast(D)->getTargetDecl(); else if (D->getLexicalDeclContext()->isFunctionOrMethod()) return false; // C++0x [basic.lookup.argdep]p3: // -- a declaration that is neither a function or a function // template // And also for builtin functions. if (isa(D)) { FunctionDecl *FDecl = cast(D); // But also builtin functions. if (FDecl->getBuiltinID() && FDecl->isImplicit()) return false; } else if (!isa(D)) return false; } return true; } /// Diagnoses obvious problems with the use of the given declaration /// as an expression. This is only actually called for lookups that /// were not overloaded, and it doesn't promise that the declaration /// will in fact be used. static bool CheckDeclInExpr(Sema &S, SourceLocation Loc, NamedDecl *D) { if (D->isInvalidDecl()) return true; if (isa(D)) { S.Diag(Loc, diag::err_unexpected_typedef) << D->getDeclName(); return true; } if (isa(D)) { S.Diag(Loc, diag::err_unexpected_interface) << D->getDeclName(); return true; } if (isa(D)) { S.Diag(Loc, diag::err_unexpected_namespace) << D->getDeclName(); return true; } return false; } // Certain multiversion types should be treated as overloaded even when there is // only one result. static bool ShouldLookupResultBeMultiVersionOverload(const LookupResult &R) { assert(R.isSingleResult() && "Expected only a single result"); const auto *FD = dyn_cast(R.getFoundDecl()); return FD && (FD->isCPUDispatchMultiVersion() || FD->isCPUSpecificMultiVersion()); } ExprResult Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS, LookupResult &R, bool NeedsADL, bool AcceptInvalidDecl) { // If this is a single, fully-resolved result and we don't need ADL, // just build an ordinary singleton decl ref. if (!NeedsADL && R.isSingleResult() && !R.getAsSingle() && !ShouldLookupResultBeMultiVersionOverload(R)) return BuildDeclarationNameExpr(SS, R.getLookupNameInfo(), R.getFoundDecl(), R.getRepresentativeDecl(), nullptr, AcceptInvalidDecl); // We only need to check the declaration if there's exactly one // result, because in the overloaded case the results can only be // functions and function templates. if (R.isSingleResult() && !ShouldLookupResultBeMultiVersionOverload(R) && CheckDeclInExpr(*this, R.getNameLoc(), R.getFoundDecl())) return ExprError(); // Otherwise, just build an unresolved lookup expression. Suppress // any lookup-related diagnostics; we'll hash these out later, when // we've picked a target. R.suppressDiagnostics(); UnresolvedLookupExpr *ULE = UnresolvedLookupExpr::Create(Context, R.getNamingClass(), SS.getWithLocInContext(Context), R.getLookupNameInfo(), NeedsADL, R.isOverloadedResult(), R.begin(), R.end()); return ULE; } static void diagnoseUncapturableValueReference(Sema &S, SourceLocation loc, ValueDecl *var, DeclContext *DC); /// Complete semantic analysis for a reference to the given declaration. ExprResult Sema::BuildDeclarationNameExpr( const CXXScopeSpec &SS, const DeclarationNameInfo &NameInfo, NamedDecl *D, NamedDecl *FoundD, const TemplateArgumentListInfo *TemplateArgs, bool AcceptInvalidDecl) { assert(D && "Cannot refer to a NULL declaration"); assert(!isa(D) && "Cannot refer unambiguously to a function template"); SourceLocation Loc = NameInfo.getLoc(); if (CheckDeclInExpr(*this, Loc, D)) return ExprError(); if (TemplateDecl *Template = dyn_cast(D)) { // Specifically diagnose references to class templates that are missing // a template argument list. diagnoseMissingTemplateArguments(TemplateName(Template), Loc); return ExprError(); } // Make sure that we're referring to a value. ValueDecl *VD = dyn_cast(D); if (!VD) { Diag(Loc, diag::err_ref_non_value) << D << SS.getRange(); Diag(D->getLocation(), diag::note_declared_at); return ExprError(); } // Check whether this declaration can be used. Note that we suppress // this check when we're going to perform argument-dependent lookup // on this function name, because this might not be the function // that overload resolution actually selects. if (DiagnoseUseOfDecl(VD, Loc)) return ExprError(); // Only create DeclRefExpr's for valid Decl's. if (VD->isInvalidDecl() && !AcceptInvalidDecl) return ExprError(); // Handle members of anonymous structs and unions. If we got here, // and the reference is to a class member indirect field, then this // must be the subject of a pointer-to-member expression. if (IndirectFieldDecl *indirectField = dyn_cast(VD)) if (!indirectField->isCXXClassMember()) return BuildAnonymousStructUnionMemberReference(SS, NameInfo.getLoc(), indirectField); { QualType type = VD->getType(); if (type.isNull()) return ExprError(); ExprValueKind valueKind = VK_RValue; switch (D->getKind()) { // Ignore all the non-ValueDecl kinds. #define ABSTRACT_DECL(kind) #define VALUE(type, base) #define DECL(type, base) \ case Decl::type: #include "clang/AST/DeclNodes.inc" llvm_unreachable("invalid value decl kind"); // These shouldn't make it here. case Decl::ObjCAtDefsField: llvm_unreachable("forming non-member reference to ivar?"); // Enum constants are always r-values and never references. // Unresolved using declarations are dependent. case Decl::EnumConstant: case Decl::UnresolvedUsingValue: case Decl::OMPDeclareReduction: case Decl::OMPDeclareMapper: valueKind = VK_RValue; break; // Fields and indirect fields that got here must be for // pointer-to-member expressions; we just call them l-values for // internal consistency, because this subexpression doesn't really // exist in the high-level semantics. case Decl::Field: case Decl::IndirectField: case Decl::ObjCIvar: assert(getLangOpts().CPlusPlus && "building reference to field in C?"); // These can't have reference type in well-formed programs, but // for internal consistency we do this anyway. type = type.getNonReferenceType(); valueKind = VK_LValue; break; // Non-type template parameters are either l-values or r-values // depending on the type. case Decl::NonTypeTemplateParm: { if (const ReferenceType *reftype = type->getAs()) { type = reftype->getPointeeType(); valueKind = VK_LValue; // even if the parameter is an r-value reference break; } // For non-references, we need to strip qualifiers just in case // the template parameter was declared as 'const int' or whatever. valueKind = VK_RValue; type = type.getUnqualifiedType(); break; } case Decl::Var: case Decl::VarTemplateSpecialization: case Decl::VarTemplatePartialSpecialization: case Decl::Decomposition: case Decl::OMPCapturedExpr: // In C, "extern void blah;" is valid and is an r-value. if (!getLangOpts().CPlusPlus && !type.hasQualifiers() && type->isVoidType()) { valueKind = VK_RValue; break; } LLVM_FALLTHROUGH; case Decl::ImplicitParam: case Decl::ParmVar: { // These are always l-values. valueKind = VK_LValue; type = type.getNonReferenceType(); // FIXME: Does the addition of const really only apply in // potentially-evaluated contexts? Since the variable isn't actually // captured in an unevaluated context, it seems that the answer is no. if (!isUnevaluatedContext()) { QualType CapturedType = getCapturedDeclRefType(cast(VD), Loc); if (!CapturedType.isNull()) type = CapturedType; } break; } case Decl::Binding: { // These are always lvalues. valueKind = VK_LValue; type = type.getNonReferenceType(); // FIXME: Support lambda-capture of BindingDecls, once CWG actually // decides how that's supposed to work. auto *BD = cast(VD); if (BD->getDeclContext() != CurContext) { auto *DD = dyn_cast_or_null(BD->getDecomposedDecl()); if (DD && DD->hasLocalStorage()) diagnoseUncapturableValueReference(*this, Loc, BD, CurContext); } break; } case Decl::Function: { if (unsigned BID = cast(VD)->getBuiltinID()) { if (!Context.BuiltinInfo.isPredefinedLibFunction(BID)) { type = Context.BuiltinFnTy; valueKind = VK_RValue; break; } } const FunctionType *fty = type->castAs(); // If we're referring to a function with an __unknown_anytype // result type, make the entire expression __unknown_anytype. if (fty->getReturnType() == Context.UnknownAnyTy) { type = Context.UnknownAnyTy; valueKind = VK_RValue; break; } // Functions are l-values in C++. if (getLangOpts().CPlusPlus) { valueKind = VK_LValue; break; } // C99 DR 316 says that, if a function type comes from a // function definition (without a prototype), that type is only // used for checking compatibility. Therefore, when referencing // the function, we pretend that we don't have the full function // type. if (!cast(VD)->hasPrototype() && isa(fty)) type = Context.getFunctionNoProtoType(fty->getReturnType(), fty->getExtInfo()); // Functions are r-values in C. valueKind = VK_RValue; break; } case Decl::CXXDeductionGuide: llvm_unreachable("building reference to deduction guide"); case Decl::MSProperty: valueKind = VK_LValue; break; case Decl::CXXMethod: // If we're referring to a method with an __unknown_anytype // result type, make the entire expression __unknown_anytype. // This should only be possible with a type written directly. if (const FunctionProtoType *proto = dyn_cast(VD->getType())) if (proto->getReturnType() == Context.UnknownAnyTy) { type = Context.UnknownAnyTy; valueKind = VK_RValue; break; } // C++ methods are l-values if static, r-values if non-static. if (cast(VD)->isStatic()) { valueKind = VK_LValue; break; } LLVM_FALLTHROUGH; case Decl::CXXConversion: case Decl::CXXDestructor: case Decl::CXXConstructor: valueKind = VK_RValue; break; } return BuildDeclRefExpr(VD, type, valueKind, NameInfo, &SS, FoundD, /*FIXME: TemplateKWLoc*/ SourceLocation(), TemplateArgs); } } static void ConvertUTF8ToWideString(unsigned CharByteWidth, StringRef Source, SmallString<32> &Target) { Target.resize(CharByteWidth * (Source.size() + 1)); char *ResultPtr = &Target[0]; const llvm::UTF8 *ErrorPtr; bool success = llvm::ConvertUTF8toWide(CharByteWidth, Source, ResultPtr, ErrorPtr); (void)success; assert(success); Target.resize(ResultPtr - &Target[0]); } ExprResult Sema::BuildPredefinedExpr(SourceLocation Loc, PredefinedExpr::IdentKind IK) { // Pick the current block, lambda, captured statement or function. Decl *currentDecl = nullptr; if (const BlockScopeInfo *BSI = getCurBlock()) currentDecl = BSI->TheDecl; else if (const LambdaScopeInfo *LSI = getCurLambda()) currentDecl = LSI->CallOperator; else if (const CapturedRegionScopeInfo *CSI = getCurCapturedRegion()) currentDecl = CSI->TheCapturedDecl; else currentDecl = getCurFunctionOrMethodDecl(); if (!currentDecl) { Diag(Loc, diag::ext_predef_outside_function); currentDecl = Context.getTranslationUnitDecl(); } QualType ResTy; StringLiteral *SL = nullptr; if (cast(currentDecl)->isDependentContext()) ResTy = Context.DependentTy; else { // Pre-defined identifiers are of type char[x], where x is the length of // the string. auto Str = PredefinedExpr::ComputeName(IK, currentDecl); unsigned Length = Str.length(); llvm::APInt LengthI(32, Length + 1); if (IK == PredefinedExpr::LFunction || IK == PredefinedExpr::LFuncSig) { ResTy = Context.adjustStringLiteralBaseType(Context.WideCharTy.withConst()); SmallString<32> RawChars; ConvertUTF8ToWideString(Context.getTypeSizeInChars(ResTy).getQuantity(), Str, RawChars); ResTy = Context.getConstantArrayType(ResTy, LengthI, nullptr, ArrayType::Normal, /*IndexTypeQuals*/ 0); SL = StringLiteral::Create(Context, RawChars, StringLiteral::Wide, /*Pascal*/ false, ResTy, Loc); } else { ResTy = Context.adjustStringLiteralBaseType(Context.CharTy.withConst()); ResTy = Context.getConstantArrayType(ResTy, LengthI, nullptr, ArrayType::Normal, /*IndexTypeQuals*/ 0); SL = StringLiteral::Create(Context, Str, StringLiteral::Ascii, /*Pascal*/ false, ResTy, Loc); } } return PredefinedExpr::Create(Context, Loc, ResTy, IK, SL); } ExprResult Sema::ActOnPredefinedExpr(SourceLocation Loc, tok::TokenKind Kind) { PredefinedExpr::IdentKind IK; switch (Kind) { default: llvm_unreachable("Unknown simple primary expr!"); case tok::kw___func__: IK = PredefinedExpr::Func; break; // [C99 6.4.2.2] case tok::kw___FUNCTION__: IK = PredefinedExpr::Function; break; case tok::kw___FUNCDNAME__: IK = PredefinedExpr::FuncDName; break; // [MS] case tok::kw___FUNCSIG__: IK = PredefinedExpr::FuncSig; break; // [MS] case tok::kw_L__FUNCTION__: IK = PredefinedExpr::LFunction; break; // [MS] case tok::kw_L__FUNCSIG__: IK = PredefinedExpr::LFuncSig; break; // [MS] case tok::kw___PRETTY_FUNCTION__: IK = PredefinedExpr::PrettyFunction; break; } return BuildPredefinedExpr(Loc, IK); } ExprResult Sema::ActOnCharacterConstant(const Token &Tok, Scope *UDLScope) { SmallString<16> CharBuffer; bool Invalid = false; StringRef ThisTok = PP.getSpelling(Tok, CharBuffer, &Invalid); if (Invalid) return ExprError(); CharLiteralParser Literal(ThisTok.begin(), ThisTok.end(), Tok.getLocation(), PP, Tok.getKind()); if (Literal.hadError()) return ExprError(); QualType Ty; if (Literal.isWide()) Ty = Context.WideCharTy; // L'x' -> wchar_t in C and C++. else if (Literal.isUTF8() && getLangOpts().Char8) Ty = Context.Char8Ty; // u8'x' -> char8_t when it exists. else if (Literal.isUTF16()) Ty = Context.Char16Ty; // u'x' -> char16_t in C11 and C++11. else if (Literal.isUTF32()) Ty = Context.Char32Ty; // U'x' -> char32_t in C11 and C++11. else if (!getLangOpts().CPlusPlus || Literal.isMultiChar()) Ty = Context.IntTy; // 'x' -> int in C, 'wxyz' -> int in C++. else Ty = Context.CharTy; // 'x' -> char in C++ CharacterLiteral::CharacterKind Kind = CharacterLiteral::Ascii; if (Literal.isWide()) Kind = CharacterLiteral::Wide; else if (Literal.isUTF16()) Kind = CharacterLiteral::UTF16; else if (Literal.isUTF32()) Kind = CharacterLiteral::UTF32; else if (Literal.isUTF8()) Kind = CharacterLiteral::UTF8; Expr *Lit = new (Context) CharacterLiteral(Literal.getValue(), Kind, Ty, Tok.getLocation()); if (Literal.getUDSuffix().empty()) return Lit; // We're building a user-defined literal. IdentifierInfo *UDSuffix = &Context.Idents.get(Literal.getUDSuffix()); SourceLocation UDSuffixLoc = getUDSuffixLoc(*this, Tok.getLocation(), Literal.getUDSuffixOffset()); // Make sure we're allowed user-defined literals here. if (!UDLScope) return ExprError(Diag(UDSuffixLoc, diag::err_invalid_character_udl)); // C++11 [lex.ext]p6: The literal L is treated as a call of the form // operator "" X (ch) return BuildCookedLiteralOperatorCall(*this, UDLScope, UDSuffix, UDSuffixLoc, Lit, Tok.getLocation()); } ExprResult Sema::ActOnIntegerConstant(SourceLocation Loc, uint64_t Val) { unsigned IntSize = Context.getTargetInfo().getIntWidth(); return IntegerLiteral::Create(Context, llvm::APInt(IntSize, Val), Context.IntTy, Loc); } static Expr *BuildFloatingLiteral(Sema &S, NumericLiteralParser &Literal, QualType Ty, SourceLocation Loc) { const llvm::fltSemantics &Format = S.Context.getFloatTypeSemantics(Ty); using llvm::APFloat; APFloat Val(Format); APFloat::opStatus result = Literal.GetFloatValue(Val); // Overflow is always an error, but underflow is only an error if // we underflowed to zero (APFloat reports denormals as underflow). if ((result & APFloat::opOverflow) || ((result & APFloat::opUnderflow) && Val.isZero())) { unsigned diagnostic; SmallString<20> buffer; if (result & APFloat::opOverflow) { diagnostic = diag::warn_float_overflow; APFloat::getLargest(Format).toString(buffer); } else { diagnostic = diag::warn_float_underflow; APFloat::getSmallest(Format).toString(buffer); } S.Diag(Loc, diagnostic) << Ty << StringRef(buffer.data(), buffer.size()); } bool isExact = (result == APFloat::opOK); return FloatingLiteral::Create(S.Context, Val, isExact, Ty, Loc); } bool Sema::CheckLoopHintExpr(Expr *E, SourceLocation Loc) { assert(E && "Invalid expression"); if (E->isValueDependent()) return false; QualType QT = E->getType(); if (!QT->isIntegerType() || QT->isBooleanType() || QT->isCharType()) { Diag(E->getExprLoc(), diag::err_pragma_loop_invalid_argument_type) << QT; return true; } llvm::APSInt ValueAPS; ExprResult R = VerifyIntegerConstantExpression(E, &ValueAPS); if (R.isInvalid()) return true; bool ValueIsPositive = ValueAPS.isStrictlyPositive(); if (!ValueIsPositive || ValueAPS.getActiveBits() > 31) { Diag(E->getExprLoc(), diag::err_pragma_loop_invalid_argument_value) << ValueAPS.toString(10) << ValueIsPositive; return true; } return false; } ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) { // Fast path for a single digit (which is quite common). A single digit // cannot have a trigraph, escaped newline, radix prefix, or suffix. if (Tok.getLength() == 1) { const char Val = PP.getSpellingOfSingleCharacterNumericConstant(Tok); return ActOnIntegerConstant(Tok.getLocation(), Val-'0'); } SmallString<128> SpellingBuffer; // NumericLiteralParser wants to overread by one character. Add padding to // the buffer in case the token is copied to the buffer. If getSpelling() // returns a StringRef to the memory buffer, it should have a null char at // the EOF, so it is also safe. SpellingBuffer.resize(Tok.getLength() + 1); // Get the spelling of the token, which eliminates trigraphs, etc. bool Invalid = false; StringRef TokSpelling = PP.getSpelling(Tok, SpellingBuffer, &Invalid); if (Invalid) return ExprError(); NumericLiteralParser Literal(TokSpelling, Tok.getLocation(), PP); if (Literal.hadError) return ExprError(); if (Literal.hasUDSuffix()) { // We're building a user-defined literal. IdentifierInfo *UDSuffix = &Context.Idents.get(Literal.getUDSuffix()); SourceLocation UDSuffixLoc = getUDSuffixLoc(*this, Tok.getLocation(), Literal.getUDSuffixOffset()); // Make sure we're allowed user-defined literals here. if (!UDLScope) return ExprError(Diag(UDSuffixLoc, diag::err_invalid_numeric_udl)); QualType CookedTy; if (Literal.isFloatingLiteral()) { // C++11 [lex.ext]p4: If S contains a literal operator with parameter type // long double, the literal is treated as a call of the form // operator "" X (f L) CookedTy = Context.LongDoubleTy; } else { // C++11 [lex.ext]p3: If S contains a literal operator with parameter type // unsigned long long, the literal is treated as a call of the form // operator "" X (n ULL) CookedTy = Context.UnsignedLongLongTy; } DeclarationName OpName = Context.DeclarationNames.getCXXLiteralOperatorName(UDSuffix); DeclarationNameInfo OpNameInfo(OpName, UDSuffixLoc); OpNameInfo.setCXXLiteralOperatorNameLoc(UDSuffixLoc); SourceLocation TokLoc = Tok.getLocation(); // Perform literal operator lookup to determine if we're building a raw // literal or a cooked one. LookupResult R(*this, OpName, UDSuffixLoc, LookupOrdinaryName); switch (LookupLiteralOperator(UDLScope, R, CookedTy, /*AllowRaw*/ true, /*AllowTemplate*/ true, /*AllowStringTemplate*/ false, /*DiagnoseMissing*/ !Literal.isImaginary)) { case LOLR_ErrorNoDiagnostic: // Lookup failure for imaginary constants isn't fatal, there's still the // GNU extension producing _Complex types. break; case LOLR_Error: return ExprError(); case LOLR_Cooked: { Expr *Lit; if (Literal.isFloatingLiteral()) { Lit = BuildFloatingLiteral(*this, Literal, CookedTy, Tok.getLocation()); } else { llvm::APInt ResultVal(Context.getTargetInfo().getLongLongWidth(), 0); if (Literal.GetIntegerValue(ResultVal)) Diag(Tok.getLocation(), diag::err_integer_literal_too_large) << /* Unsigned */ 1; Lit = IntegerLiteral::Create(Context, ResultVal, CookedTy, Tok.getLocation()); } return BuildLiteralOperatorCall(R, OpNameInfo, Lit, TokLoc); } case LOLR_Raw: { // C++11 [lit.ext]p3, p4: If S contains a raw literal operator, the // literal is treated as a call of the form // operator "" X ("n") unsigned Length = Literal.getUDSuffixOffset(); QualType StrTy = Context.getConstantArrayType( Context.adjustStringLiteralBaseType(Context.CharTy.withConst()), llvm::APInt(32, Length + 1), nullptr, ArrayType::Normal, 0); Expr *Lit = StringLiteral::Create( Context, StringRef(TokSpelling.data(), Length), StringLiteral::Ascii, /*Pascal*/false, StrTy, &TokLoc, 1); return BuildLiteralOperatorCall(R, OpNameInfo, Lit, TokLoc); } case LOLR_Template: { // C++11 [lit.ext]p3, p4: Otherwise (S contains a literal operator // template), L is treated as a call fo the form // operator "" X <'c1', 'c2', ... 'ck'>() // where n is the source character sequence c1 c2 ... ck. TemplateArgumentListInfo ExplicitArgs; unsigned CharBits = Context.getIntWidth(Context.CharTy); bool CharIsUnsigned = Context.CharTy->isUnsignedIntegerType(); llvm::APSInt Value(CharBits, CharIsUnsigned); for (unsigned I = 0, N = Literal.getUDSuffixOffset(); I != N; ++I) { Value = TokSpelling[I]; TemplateArgument Arg(Context, Value, Context.CharTy); TemplateArgumentLocInfo ArgInfo; ExplicitArgs.addArgument(TemplateArgumentLoc(Arg, ArgInfo)); } return BuildLiteralOperatorCall(R, OpNameInfo, None, TokLoc, &ExplicitArgs); } case LOLR_StringTemplate: llvm_unreachable("unexpected literal operator lookup result"); } } Expr *Res; if (Literal.isFixedPointLiteral()) { QualType Ty; if (Literal.isAccum) { if (Literal.isHalf) { Ty = Context.ShortAccumTy; } else if (Literal.isLong) { Ty = Context.LongAccumTy; } else { Ty = Context.AccumTy; } } else if (Literal.isFract) { if (Literal.isHalf) { Ty = Context.ShortFractTy; } else if (Literal.isLong) { Ty = Context.LongFractTy; } else { Ty = Context.FractTy; } } if (Literal.isUnsigned) Ty = Context.getCorrespondingUnsignedType(Ty); bool isSigned = !Literal.isUnsigned; unsigned scale = Context.getFixedPointScale(Ty); unsigned bit_width = Context.getTypeInfo(Ty).Width; llvm::APInt Val(bit_width, 0, isSigned); bool Overflowed = Literal.GetFixedPointValue(Val, scale); bool ValIsZero = Val.isNullValue() && !Overflowed; auto MaxVal = Context.getFixedPointMax(Ty).getValue(); if (Literal.isFract && Val == MaxVal + 1 && !ValIsZero) // Clause 6.4.4 - The value of a constant shall be in the range of // representable values for its type, with exception for constants of a // fract type with a value of exactly 1; such a constant shall denote // the maximal value for the type. --Val; else if (Val.ugt(MaxVal) || Overflowed) Diag(Tok.getLocation(), diag::err_too_large_for_fixed_point); Res = FixedPointLiteral::CreateFromRawInt(Context, Val, Ty, Tok.getLocation(), scale); } else if (Literal.isFloatingLiteral()) { QualType Ty; if (Literal.isHalf){ if (getOpenCLOptions().isEnabled("cl_khr_fp16")) Ty = Context.HalfTy; else { Diag(Tok.getLocation(), diag::err_half_const_requires_fp16); return ExprError(); } } else if (Literal.isFloat) Ty = Context.FloatTy; else if (Literal.isLong) Ty = Context.LongDoubleTy; else if (Literal.isFloat16) Ty = Context.Float16Ty; else if (Literal.isFloat128) Ty = Context.Float128Ty; else Ty = Context.DoubleTy; Res = BuildFloatingLiteral(*this, Literal, Ty, Tok.getLocation()); if (Ty == Context.DoubleTy) { if (getLangOpts().SinglePrecisionConstants) { const BuiltinType *BTy = Ty->getAs(); if (BTy->getKind() != BuiltinType::Float) { Res = ImpCastExprToType(Res, Context.FloatTy, CK_FloatingCast).get(); } } else if (getLangOpts().OpenCL && !getOpenCLOptions().isEnabled("cl_khr_fp64")) { // Impose single-precision float type when cl_khr_fp64 is not enabled. Diag(Tok.getLocation(), diag::warn_double_const_requires_fp64); Res = ImpCastExprToType(Res, Context.FloatTy, CK_FloatingCast).get(); } } } else if (!Literal.isIntegerLiteral()) { return ExprError(); } else { QualType Ty; // 'long long' is a C99 or C++11 feature. if (!getLangOpts().C99 && Literal.isLongLong) { if (getLangOpts().CPlusPlus) Diag(Tok.getLocation(), getLangOpts().CPlusPlus11 ? diag::warn_cxx98_compat_longlong : diag::ext_cxx11_longlong); else Diag(Tok.getLocation(), diag::ext_c99_longlong); } // Get the value in the widest-possible width. unsigned MaxWidth = Context.getTargetInfo().getIntMaxTWidth(); llvm::APInt ResultVal(MaxWidth, 0); if (Literal.GetIntegerValue(ResultVal)) { // If this value didn't fit into uintmax_t, error and force to ull. Diag(Tok.getLocation(), diag::err_integer_literal_too_large) << /* Unsigned */ 1; Ty = Context.UnsignedLongLongTy; assert(Context.getTypeSize(Ty) == ResultVal.getBitWidth() && "long long is not intmax_t?"); } else { // If this value fits into a ULL, try to figure out what else it fits into // according to the rules of C99 6.4.4.1p5. // Octal, Hexadecimal, and integers with a U suffix are allowed to // be an unsigned int. bool AllowUnsigned = Literal.isUnsigned || Literal.getRadix() != 10; // Check from smallest to largest, picking the smallest type we can. unsigned Width = 0; // Microsoft specific integer suffixes are explicitly sized. if (Literal.MicrosoftInteger) { if (Literal.MicrosoftInteger == 8 && !Literal.isUnsigned) { Width = 8; Ty = Context.CharTy; } else { Width = Literal.MicrosoftInteger; Ty = Context.getIntTypeForBitwidth(Width, /*Signed=*/!Literal.isUnsigned); } } if (Ty.isNull() && !Literal.isLong && !Literal.isLongLong) { // Are int/unsigned possibilities? unsigned IntSize = Context.getTargetInfo().getIntWidth(); // Does it fit in a unsigned int? if (ResultVal.isIntN(IntSize)) { // Does it fit in a signed int? if (!Literal.isUnsigned && ResultVal[IntSize-1] == 0) Ty = Context.IntTy; else if (AllowUnsigned) Ty = Context.UnsignedIntTy; Width = IntSize; } } // Are long/unsigned long possibilities? if (Ty.isNull() && !Literal.isLongLong) { unsigned LongSize = Context.getTargetInfo().getLongWidth(); // Does it fit in a unsigned long? if (ResultVal.isIntN(LongSize)) { // Does it fit in a signed long? if (!Literal.isUnsigned && ResultVal[LongSize-1] == 0) Ty = Context.LongTy; else if (AllowUnsigned) Ty = Context.UnsignedLongTy; // Check according to the rules of C90 6.1.3.2p5. C++03 [lex.icon]p2 // is compatible. else if (!getLangOpts().C99 && !getLangOpts().CPlusPlus11) { const unsigned LongLongSize = Context.getTargetInfo().getLongLongWidth(); Diag(Tok.getLocation(), getLangOpts().CPlusPlus ? Literal.isLong ? diag::warn_old_implicitly_unsigned_long_cxx : /*C++98 UB*/ diag:: ext_old_implicitly_unsigned_long_cxx : diag::warn_old_implicitly_unsigned_long) << (LongLongSize > LongSize ? /*will have type 'long long'*/ 0 : /*will be ill-formed*/ 1); Ty = Context.UnsignedLongTy; } Width = LongSize; } } // Check long long if needed. if (Ty.isNull()) { unsigned LongLongSize = Context.getTargetInfo().getLongLongWidth(); // Does it fit in a unsigned long long? if (ResultVal.isIntN(LongLongSize)) { // Does it fit in a signed long long? // To be compatible with MSVC, hex integer literals ending with the // LL or i64 suffix are always signed in Microsoft mode. if (!Literal.isUnsigned && (ResultVal[LongLongSize-1] == 0 || (getLangOpts().MSVCCompat && Literal.isLongLong))) Ty = Context.LongLongTy; else if (AllowUnsigned) Ty = Context.UnsignedLongLongTy; Width = LongLongSize; } } // If we still couldn't decide a type, we probably have something that // does not fit in a signed long long, but has no U suffix. if (Ty.isNull()) { Diag(Tok.getLocation(), diag::ext_integer_literal_too_large_for_signed); Ty = Context.UnsignedLongLongTy; Width = Context.getTargetInfo().getLongLongWidth(); } if (ResultVal.getBitWidth() != Width) ResultVal = ResultVal.trunc(Width); } Res = IntegerLiteral::Create(Context, ResultVal, Ty, Tok.getLocation()); } // If this is an imaginary literal, create the ImaginaryLiteral wrapper. if (Literal.isImaginary) { Res = new (Context) ImaginaryLiteral(Res, Context.getComplexType(Res->getType())); Diag(Tok.getLocation(), diag::ext_imaginary_constant); } return Res; } ExprResult Sema::ActOnParenExpr(SourceLocation L, SourceLocation R, Expr *E) { assert(E && "ActOnParenExpr() missing expr"); return new (Context) ParenExpr(L, R, E); } static bool CheckVecStepTraitOperandType(Sema &S, QualType T, SourceLocation Loc, SourceRange ArgRange) { // [OpenCL 1.1 6.11.12] "The vec_step built-in function takes a built-in // scalar or vector data type argument..." // Every built-in scalar type (OpenCL 1.1 6.1.1) is either an arithmetic // type (C99 6.2.5p18) or void. if (!(T->isArithmeticType() || T->isVoidType() || T->isVectorType())) { S.Diag(Loc, diag::err_vecstep_non_scalar_vector_type) << T << ArgRange; return true; } assert((T->isVoidType() || !T->isIncompleteType()) && "Scalar types should always be complete"); return false; } static bool CheckExtensionTraitOperandType(Sema &S, QualType T, SourceLocation Loc, SourceRange ArgRange, UnaryExprOrTypeTrait TraitKind) { // Invalid types must be hard errors for SFINAE in C++. if (S.LangOpts.CPlusPlus) return true; // C99 6.5.3.4p1: if (T->isFunctionType() && (TraitKind == UETT_SizeOf || TraitKind == UETT_AlignOf || TraitKind == UETT_PreferredAlignOf)) { // sizeof(function)/alignof(function) is allowed as an extension. S.Diag(Loc, diag::ext_sizeof_alignof_function_type) << TraitKind << ArgRange; return false; } // Allow sizeof(void)/alignof(void) as an extension, unless in OpenCL where // this is an error (OpenCL v1.1 s6.3.k) if (T->isVoidType()) { unsigned DiagID = S.LangOpts.OpenCL ? diag::err_opencl_sizeof_alignof_type : diag::ext_sizeof_alignof_void_type; S.Diag(Loc, DiagID) << TraitKind << ArgRange; return false; } return true; } static bool CheckObjCTraitOperandConstraints(Sema &S, QualType T, SourceLocation Loc, SourceRange ArgRange, UnaryExprOrTypeTrait TraitKind) { // Reject sizeof(interface) and sizeof(interface) if the // runtime doesn't allow it. if (!S.LangOpts.ObjCRuntime.allowsSizeofAlignof() && T->isObjCObjectType()) { S.Diag(Loc, diag::err_sizeof_nonfragile_interface) << T << (TraitKind == UETT_SizeOf) << ArgRange; return true; } return false; } /// Check whether E is a pointer from a decayed array type (the decayed /// pointer type is equal to T) and emit a warning if it is. static void warnOnSizeofOnArrayDecay(Sema &S, SourceLocation Loc, QualType T, Expr *E) { // Don't warn if the operation changed the type. if (T != E->getType()) return; // Now look for array decays. ImplicitCastExpr *ICE = dyn_cast(E); if (!ICE || ICE->getCastKind() != CK_ArrayToPointerDecay) return; S.Diag(Loc, diag::warn_sizeof_array_decay) << ICE->getSourceRange() << ICE->getType() << ICE->getSubExpr()->getType(); } /// Check the constraints on expression operands to unary type expression /// and type traits. /// /// Completes any types necessary and validates the constraints on the operand /// expression. The logic mostly mirrors the type-based overload, but may modify /// the expression as it completes the type for that expression through template /// instantiation, etc. bool Sema::CheckUnaryExprOrTypeTraitOperand(Expr *E, UnaryExprOrTypeTrait ExprKind) { QualType ExprTy = E->getType(); assert(!ExprTy->isReferenceType()); bool IsUnevaluatedOperand = (ExprKind == UETT_SizeOf || ExprKind == UETT_AlignOf || ExprKind == UETT_PreferredAlignOf); if (IsUnevaluatedOperand) { ExprResult Result = CheckUnevaluatedOperand(E); if (Result.isInvalid()) return true; E = Result.get(); } if (ExprKind == UETT_VecStep) return CheckVecStepTraitOperandType(*this, ExprTy, E->getExprLoc(), E->getSourceRange()); // Whitelist some types as extensions if (!CheckExtensionTraitOperandType(*this, ExprTy, E->getExprLoc(), E->getSourceRange(), ExprKind)) return false; // 'alignof' applied to an expression only requires the base element type of // the expression to be complete. 'sizeof' requires the expression's type to // be complete (and will attempt to complete it if it's an array of unknown // bound). if (ExprKind == UETT_AlignOf || ExprKind == UETT_PreferredAlignOf) { if (RequireCompleteType(E->getExprLoc(), Context.getBaseElementType(E->getType()), diag::err_sizeof_alignof_incomplete_type, ExprKind, E->getSourceRange())) return true; } else { if (RequireCompleteExprType(E, diag::err_sizeof_alignof_incomplete_type, ExprKind, E->getSourceRange())) return true; } // Completing the expression's type may have changed it. ExprTy = E->getType(); assert(!ExprTy->isReferenceType()); if (ExprTy->isFunctionType()) { Diag(E->getExprLoc(), diag::err_sizeof_alignof_function_type) << ExprKind << E->getSourceRange(); return true; } // The operand for sizeof and alignof is in an unevaluated expression context, // so side effects could result in unintended consequences. if (IsUnevaluatedOperand && !inTemplateInstantiation() && E->HasSideEffects(Context, false)) Diag(E->getExprLoc(), diag::warn_side_effects_unevaluated_context); if (CheckObjCTraitOperandConstraints(*this, ExprTy, E->getExprLoc(), E->getSourceRange(), ExprKind)) return true; if (ExprKind == UETT_SizeOf) { if (DeclRefExpr *DeclRef = dyn_cast(E->IgnoreParens())) { if (ParmVarDecl *PVD = dyn_cast(DeclRef->getFoundDecl())) { QualType OType = PVD->getOriginalType(); QualType Type = PVD->getType(); if (Type->isPointerType() && OType->isArrayType()) { Diag(E->getExprLoc(), diag::warn_sizeof_array_param) << Type << OType; Diag(PVD->getLocation(), diag::note_declared_at); } } } // Warn on "sizeof(array op x)" and "sizeof(x op array)", where the array // decays into a pointer and returns an unintended result. This is most // likely a typo for "sizeof(array) op x". if (BinaryOperator *BO = dyn_cast(E->IgnoreParens())) { warnOnSizeofOnArrayDecay(*this, BO->getOperatorLoc(), BO->getType(), BO->getLHS()); warnOnSizeofOnArrayDecay(*this, BO->getOperatorLoc(), BO->getType(), BO->getRHS()); } } return false; } /// Check the constraints on operands to unary expression and type /// traits. /// /// This will complete any types necessary, and validate the various constraints /// on those operands. /// /// The UsualUnaryConversions() function is *not* called by this routine. /// C99 6.3.2.1p[2-4] all state: /// Except when it is the operand of the sizeof operator ... /// /// C++ [expr.sizeof]p4 /// The lvalue-to-rvalue, array-to-pointer, and function-to-pointer /// standard conversions are not applied to the operand of sizeof. /// /// This policy is followed for all of the unary trait expressions. bool Sema::CheckUnaryExprOrTypeTraitOperand(QualType ExprType, SourceLocation OpLoc, SourceRange ExprRange, UnaryExprOrTypeTrait ExprKind) { if (ExprType->isDependentType()) return false; // C++ [expr.sizeof]p2: // When applied to a reference or a reference type, the result // is the size of the referenced type. // C++11 [expr.alignof]p3: // When alignof is applied to a reference type, the result // shall be the alignment of the referenced type. if (const ReferenceType *Ref = ExprType->getAs()) ExprType = Ref->getPointeeType(); // C11 6.5.3.4/3, C++11 [expr.alignof]p3: // When alignof or _Alignof is applied to an array type, the result // is the alignment of the element type. if (ExprKind == UETT_AlignOf || ExprKind == UETT_PreferredAlignOf || ExprKind == UETT_OpenMPRequiredSimdAlign) ExprType = Context.getBaseElementType(ExprType); if (ExprKind == UETT_VecStep) return CheckVecStepTraitOperandType(*this, ExprType, OpLoc, ExprRange); // Whitelist some types as extensions if (!CheckExtensionTraitOperandType(*this, ExprType, OpLoc, ExprRange, ExprKind)) return false; if (RequireCompleteType(OpLoc, ExprType, diag::err_sizeof_alignof_incomplete_type, ExprKind, ExprRange)) return true; if (ExprType->isFunctionType()) { Diag(OpLoc, diag::err_sizeof_alignof_function_type) << ExprKind << ExprRange; return true; } if (CheckObjCTraitOperandConstraints(*this, ExprType, OpLoc, ExprRange, ExprKind)) return true; return false; } static bool CheckAlignOfExpr(Sema &S, Expr *E, UnaryExprOrTypeTrait ExprKind) { // Cannot know anything else if the expression is dependent. if (E->isTypeDependent()) return false; if (E->getObjectKind() == OK_BitField) { S.Diag(E->getExprLoc(), diag::err_sizeof_alignof_typeof_bitfield) << 1 << E->getSourceRange(); return true; } ValueDecl *D = nullptr; Expr *Inner = E->IgnoreParens(); if (DeclRefExpr *DRE = dyn_cast(Inner)) { D = DRE->getDecl(); } else if (MemberExpr *ME = dyn_cast(Inner)) { D = ME->getMemberDecl(); } // If it's a field, require the containing struct to have a // complete definition so that we can compute the layout. // // This can happen in C++11 onwards, either by naming the member // in a way that is not transformed into a member access expression // (in an unevaluated operand, for instance), or by naming the member // in a trailing-return-type. // // For the record, since __alignof__ on expressions is a GCC // extension, GCC seems to permit this but always gives the // nonsensical answer 0. // // We don't really need the layout here --- we could instead just // directly check for all the appropriate alignment-lowing // attributes --- but that would require duplicating a lot of // logic that just isn't worth duplicating for such a marginal // use-case. if (FieldDecl *FD = dyn_cast_or_null(D)) { // Fast path this check, since we at least know the record has a // definition if we can find a member of it. if (!FD->getParent()->isCompleteDefinition()) { S.Diag(E->getExprLoc(), diag::err_alignof_member_of_incomplete_type) << E->getSourceRange(); return true; } // Otherwise, if it's a field, and the field doesn't have // reference type, then it must have a complete type (or be a // flexible array member, which we explicitly want to // white-list anyway), which makes the following checks trivial. if (!FD->getType()->isReferenceType()) return false; } return S.CheckUnaryExprOrTypeTraitOperand(E, ExprKind); } bool Sema::CheckVecStepExpr(Expr *E) { E = E->IgnoreParens(); // Cannot know anything else if the expression is dependent. if (E->isTypeDependent()) return false; return CheckUnaryExprOrTypeTraitOperand(E, UETT_VecStep); } static void captureVariablyModifiedType(ASTContext &Context, QualType T, CapturingScopeInfo *CSI) { assert(T->isVariablyModifiedType()); assert(CSI != nullptr); // We're going to walk down into the type and look for VLA expressions. do { const Type *Ty = T.getTypePtr(); switch (Ty->getTypeClass()) { #define TYPE(Class, Base) #define ABSTRACT_TYPE(Class, Base) #define NON_CANONICAL_TYPE(Class, Base) #define DEPENDENT_TYPE(Class, Base) case Type::Class: #define NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Class, Base) #include "clang/AST/TypeNodes.inc" T = QualType(); break; // These types are never variably-modified. case Type::Builtin: case Type::Complex: case Type::Vector: case Type::ExtVector: case Type::Record: case Type::Enum: case Type::Elaborated: case Type::TemplateSpecialization: case Type::ObjCObject: case Type::ObjCInterface: case Type::ObjCObjectPointer: case Type::ObjCTypeParam: case Type::Pipe: llvm_unreachable("type class is never variably-modified!"); case Type::Adjusted: T = cast(Ty)->getOriginalType(); break; case Type::Decayed: T = cast(Ty)->getPointeeType(); break; case Type::Pointer: T = cast(Ty)->getPointeeType(); break; case Type::BlockPointer: T = cast(Ty)->getPointeeType(); break; case Type::LValueReference: case Type::RValueReference: T = cast(Ty)->getPointeeType(); break; case Type::MemberPointer: T = cast(Ty)->getPointeeType(); break; case Type::ConstantArray: case Type::IncompleteArray: // Losing element qualification here is fine. T = cast(Ty)->getElementType(); break; case Type::VariableArray: { // Losing element qualification here is fine. const VariableArrayType *VAT = cast(Ty); // Unknown size indication requires no size computation. // Otherwise, evaluate and record it. auto Size = VAT->getSizeExpr(); if (Size && !CSI->isVLATypeCaptured(VAT) && (isa(CSI) || isa(CSI))) CSI->addVLATypeCapture(Size->getExprLoc(), VAT, Context.getSizeType()); T = VAT->getElementType(); break; } case Type::FunctionProto: case Type::FunctionNoProto: T = cast(Ty)->getReturnType(); break; case Type::Paren: case Type::TypeOf: case Type::UnaryTransform: case Type::Attributed: case Type::SubstTemplateTypeParm: case Type::PackExpansion: case Type::MacroQualified: // Keep walking after single level desugaring. T = T.getSingleStepDesugaredType(Context); break; case Type::Typedef: T = cast(Ty)->desugar(); break; case Type::Decltype: T = cast(Ty)->desugar(); break; case Type::Auto: case Type::DeducedTemplateSpecialization: T = cast(Ty)->getDeducedType(); break; case Type::TypeOfExpr: T = cast(Ty)->getUnderlyingExpr()->getType(); break; case Type::Atomic: T = cast(Ty)->getValueType(); break; } } while (!T.isNull() && T->isVariablyModifiedType()); } /// Build a sizeof or alignof expression given a type operand. ExprResult Sema::CreateUnaryExprOrTypeTraitExpr(TypeSourceInfo *TInfo, SourceLocation OpLoc, UnaryExprOrTypeTrait ExprKind, SourceRange R) { if (!TInfo) return ExprError(); QualType T = TInfo->getType(); if (!T->isDependentType() && CheckUnaryExprOrTypeTraitOperand(T, OpLoc, R, ExprKind)) return ExprError(); if (T->isVariablyModifiedType() && FunctionScopes.size() > 1) { if (auto *TT = T->getAs()) { for (auto I = FunctionScopes.rbegin(), E = std::prev(FunctionScopes.rend()); I != E; ++I) { auto *CSI = dyn_cast(*I); if (CSI == nullptr) break; DeclContext *DC = nullptr; if (auto *LSI = dyn_cast(CSI)) DC = LSI->CallOperator; else if (auto *CRSI = dyn_cast(CSI)) DC = CRSI->TheCapturedDecl; else if (auto *BSI = dyn_cast(CSI)) DC = BSI->TheDecl; if (DC) { if (DC->containsDecl(TT->getDecl())) break; captureVariablyModifiedType(Context, T, CSI); } } } } // C99 6.5.3.4p4: the type (an unsigned integer type) is size_t. return new (Context) UnaryExprOrTypeTraitExpr( ExprKind, TInfo, Context.getSizeType(), OpLoc, R.getEnd()); } /// Build a sizeof or alignof expression given an expression /// operand. ExprResult Sema::CreateUnaryExprOrTypeTraitExpr(Expr *E, SourceLocation OpLoc, UnaryExprOrTypeTrait ExprKind) { ExprResult PE = CheckPlaceholderExpr(E); if (PE.isInvalid()) return ExprError(); E = PE.get(); // Verify that the operand is valid. bool isInvalid = false; if (E->isTypeDependent()) { // Delay type-checking for type-dependent expressions. } else if (ExprKind == UETT_AlignOf || ExprKind == UETT_PreferredAlignOf) { isInvalid = CheckAlignOfExpr(*this, E, ExprKind); } else if (ExprKind == UETT_VecStep) { isInvalid = CheckVecStepExpr(E); } else if (ExprKind == UETT_OpenMPRequiredSimdAlign) { Diag(E->getExprLoc(), diag::err_openmp_default_simd_align_expr); isInvalid = true; } else if (E->refersToBitField()) { // C99 6.5.3.4p1. Diag(E->getExprLoc(), diag::err_sizeof_alignof_typeof_bitfield) << 0; isInvalid = true; } else { isInvalid = CheckUnaryExprOrTypeTraitOperand(E, UETT_SizeOf); } if (isInvalid) return ExprError(); if (ExprKind == UETT_SizeOf && E->getType()->isVariableArrayType()) { PE = TransformToPotentiallyEvaluated(E); if (PE.isInvalid()) return ExprError(); E = PE.get(); } // C99 6.5.3.4p4: the type (an unsigned integer type) is size_t. return new (Context) UnaryExprOrTypeTraitExpr( ExprKind, E, Context.getSizeType(), OpLoc, E->getSourceRange().getEnd()); } /// ActOnUnaryExprOrTypeTraitExpr - Handle @c sizeof(type) and @c sizeof @c /// expr and the same for @c alignof and @c __alignof /// Note that the ArgRange is invalid if isType is false. ExprResult Sema::ActOnUnaryExprOrTypeTraitExpr(SourceLocation OpLoc, UnaryExprOrTypeTrait ExprKind, bool IsType, void *TyOrEx, SourceRange ArgRange) { // If error parsing type, ignore. if (!TyOrEx) return ExprError(); if (IsType) { TypeSourceInfo *TInfo; (void) GetTypeFromParser(ParsedType::getFromOpaquePtr(TyOrEx), &TInfo); return CreateUnaryExprOrTypeTraitExpr(TInfo, OpLoc, ExprKind, ArgRange); } Expr *ArgEx = (Expr *)TyOrEx; ExprResult Result = CreateUnaryExprOrTypeTraitExpr(ArgEx, OpLoc, ExprKind); return Result; } static QualType CheckRealImagOperand(Sema &S, ExprResult &V, SourceLocation Loc, bool IsReal) { if (V.get()->isTypeDependent()) return S.Context.DependentTy; // _Real and _Imag are only l-values for normal l-values. if (V.get()->getObjectKind() != OK_Ordinary) { V = S.DefaultLvalueConversion(V.get()); if (V.isInvalid()) return QualType(); } // These operators return the element type of a complex type. if (const ComplexType *CT = V.get()->getType()->getAs()) return CT->getElementType(); // Otherwise they pass through real integer and floating point types here. if (V.get()->getType()->isArithmeticType()) return V.get()->getType(); // Test for placeholders. ExprResult PR = S.CheckPlaceholderExpr(V.get()); if (PR.isInvalid()) return QualType(); if (PR.get() != V.get()) { V = PR; return CheckRealImagOperand(S, V, Loc, IsReal); } // Reject anything else. S.Diag(Loc, diag::err_realimag_invalid_type) << V.get()->getType() << (IsReal ? "__real" : "__imag"); return QualType(); } ExprResult Sema::ActOnPostfixUnaryOp(Scope *S, SourceLocation OpLoc, tok::TokenKind Kind, Expr *Input) { UnaryOperatorKind Opc; switch (Kind) { default: llvm_unreachable("Unknown unary op!"); case tok::plusplus: Opc = UO_PostInc; break; case tok::minusminus: Opc = UO_PostDec; break; } // Since this might is a postfix expression, get rid of ParenListExprs. ExprResult Result = MaybeConvertParenListExprToParenExpr(S, Input); if (Result.isInvalid()) return ExprError(); Input = Result.get(); return BuildUnaryOp(S, OpLoc, Opc, Input); } /// Diagnose if arithmetic on the given ObjC pointer is illegal. /// /// \return true on error static bool checkArithmeticOnObjCPointer(Sema &S, SourceLocation opLoc, Expr *op) { assert(op->getType()->isObjCObjectPointerType()); if (S.LangOpts.ObjCRuntime.allowsPointerArithmetic() && !S.LangOpts.ObjCSubscriptingLegacyRuntime) return false; S.Diag(opLoc, diag::err_arithmetic_nonfragile_interface) << op->getType()->castAs()->getPointeeType() << op->getSourceRange(); return true; } static bool isMSPropertySubscriptExpr(Sema &S, Expr *Base) { auto *BaseNoParens = Base->IgnoreParens(); if (auto *MSProp = dyn_cast(BaseNoParens)) return MSProp->getPropertyDecl()->getType()->isArrayType(); return isa(BaseNoParens); } ExprResult Sema::ActOnArraySubscriptExpr(Scope *S, Expr *base, SourceLocation lbLoc, Expr *idx, SourceLocation rbLoc) { if (base && !base->getType().isNull() && base->getType()->isSpecificPlaceholderType(BuiltinType::OMPArraySection)) return ActOnOMPArraySectionExpr(base, lbLoc, idx, SourceLocation(), /*Length=*/nullptr, rbLoc); // Since this might be a postfix expression, get rid of ParenListExprs. if (isa(base)) { ExprResult result = MaybeConvertParenListExprToParenExpr(S, base); if (result.isInvalid()) return ExprError(); base = result.get(); } // A comma-expression as the index is deprecated in C++2a onwards. if (getLangOpts().CPlusPlus2a && ((isa(idx) && cast(idx)->isCommaOp()) || (isa(idx) && cast(idx)->getOperator() == OO_Comma))) { Diag(idx->getExprLoc(), diag::warn_deprecated_comma_subscript) << SourceRange(base->getBeginLoc(), rbLoc); } // Handle any non-overload placeholder types in the base and index // expressions. We can't handle overloads here because the other // operand might be an overloadable type, in which case the overload // resolution for the operator overload should get the first crack // at the overload. bool IsMSPropertySubscript = false; if (base->getType()->isNonOverloadPlaceholderType()) { IsMSPropertySubscript = isMSPropertySubscriptExpr(*this, base); if (!IsMSPropertySubscript) { ExprResult result = CheckPlaceholderExpr(base); if (result.isInvalid()) return ExprError(); base = result.get(); } } if (idx->getType()->isNonOverloadPlaceholderType()) { ExprResult result = CheckPlaceholderExpr(idx); if (result.isInvalid()) return ExprError(); idx = result.get(); } // Build an unanalyzed expression if either operand is type-dependent. if (getLangOpts().CPlusPlus && (base->isTypeDependent() || idx->isTypeDependent())) { return new (Context) ArraySubscriptExpr(base, idx, Context.DependentTy, VK_LValue, OK_Ordinary, rbLoc); } // MSDN, property (C++) // https://msdn.microsoft.com/en-us/library/yhfk0thd(v=vs.120).aspx // This attribute can also be used in the declaration of an empty array in a // class or structure definition. For example: // __declspec(property(get=GetX, put=PutX)) int x[]; // The above statement indicates that x[] can be used with one or more array // indices. In this case, i=p->x[a][b] will be turned into i=p->GetX(a, b), // and p->x[a][b] = i will be turned into p->PutX(a, b, i); if (IsMSPropertySubscript) { // Build MS property subscript expression if base is MS property reference // or MS property subscript. return new (Context) MSPropertySubscriptExpr( base, idx, Context.PseudoObjectTy, VK_LValue, OK_Ordinary, rbLoc); } // Use C++ overloaded-operator rules if either operand has record // type. The spec says to do this if either type is *overloadable*, // but enum types can't declare subscript operators or conversion // operators, so there's nothing interesting for overload resolution // to do if there aren't any record types involved. // // ObjC pointers have their own subscripting logic that is not tied // to overload resolution and so should not take this path. if (getLangOpts().CPlusPlus && (base->getType()->isRecordType() || (!base->getType()->isObjCObjectPointerType() && idx->getType()->isRecordType()))) { return CreateOverloadedArraySubscriptExpr(lbLoc, rbLoc, base, idx); } ExprResult Res = CreateBuiltinArraySubscriptExpr(base, lbLoc, idx, rbLoc); if (!Res.isInvalid() && isa(Res.get())) CheckSubscriptAccessOfNoDeref(cast(Res.get())); return Res; } void Sema::CheckAddressOfNoDeref(const Expr *E) { ExpressionEvaluationContextRecord &LastRecord = ExprEvalContexts.back(); const Expr *StrippedExpr = E->IgnoreParenImpCasts(); // For expressions like `&(*s).b`, the base is recorded and what should be // checked. const MemberExpr *Member = nullptr; while ((Member = dyn_cast(StrippedExpr)) && !Member->isArrow()) StrippedExpr = Member->getBase()->IgnoreParenImpCasts(); LastRecord.PossibleDerefs.erase(StrippedExpr); } void Sema::CheckSubscriptAccessOfNoDeref(const ArraySubscriptExpr *E) { QualType ResultTy = E->getType(); ExpressionEvaluationContextRecord &LastRecord = ExprEvalContexts.back(); // Bail if the element is an array since it is not memory access. if (isa(ResultTy)) return; if (ResultTy->hasAttr(attr::NoDeref)) { LastRecord.PossibleDerefs.insert(E); return; } // Check if the base type is a pointer to a member access of a struct // marked with noderef. const Expr *Base = E->getBase(); QualType BaseTy = Base->getType(); if (!(isa(BaseTy) || isa(BaseTy))) // Not a pointer access return; const MemberExpr *Member = nullptr; while ((Member = dyn_cast(Base->IgnoreParenCasts())) && Member->isArrow()) Base = Member->getBase(); if (const auto *Ptr = dyn_cast(Base->getType())) { if (Ptr->getPointeeType()->hasAttr(attr::NoDeref)) LastRecord.PossibleDerefs.insert(E); } } ExprResult Sema::ActOnOMPArraySectionExpr(Expr *Base, SourceLocation LBLoc, Expr *LowerBound, SourceLocation ColonLoc, Expr *Length, SourceLocation RBLoc) { if (Base->getType()->isPlaceholderType() && !Base->getType()->isSpecificPlaceholderType( BuiltinType::OMPArraySection)) { ExprResult Result = CheckPlaceholderExpr(Base); if (Result.isInvalid()) return ExprError(); Base = Result.get(); } if (LowerBound && LowerBound->getType()->isNonOverloadPlaceholderType()) { ExprResult Result = CheckPlaceholderExpr(LowerBound); if (Result.isInvalid()) return ExprError(); Result = DefaultLvalueConversion(Result.get()); if (Result.isInvalid()) return ExprError(); LowerBound = Result.get(); } if (Length && Length->getType()->isNonOverloadPlaceholderType()) { ExprResult Result = CheckPlaceholderExpr(Length); if (Result.isInvalid()) return ExprError(); Result = DefaultLvalueConversion(Result.get()); if (Result.isInvalid()) return ExprError(); Length = Result.get(); } // Build an unanalyzed expression if either operand is type-dependent. if (Base->isTypeDependent() || (LowerBound && (LowerBound->isTypeDependent() || LowerBound->isValueDependent())) || (Length && (Length->isTypeDependent() || Length->isValueDependent()))) { return new (Context) OMPArraySectionExpr(Base, LowerBound, Length, Context.DependentTy, VK_LValue, OK_Ordinary, ColonLoc, RBLoc); } // Perform default conversions. QualType OriginalTy = OMPArraySectionExpr::getBaseOriginalType(Base); QualType ResultTy; if (OriginalTy->isAnyPointerType()) { ResultTy = OriginalTy->getPointeeType(); } else if (OriginalTy->isArrayType()) { ResultTy = OriginalTy->getAsArrayTypeUnsafe()->getElementType(); } else { return ExprError( Diag(Base->getExprLoc(), diag::err_omp_typecheck_section_value) << Base->getSourceRange()); } // C99 6.5.2.1p1 if (LowerBound) { auto Res = PerformOpenMPImplicitIntegerConversion(LowerBound->getExprLoc(), LowerBound); if (Res.isInvalid()) return ExprError(Diag(LowerBound->getExprLoc(), diag::err_omp_typecheck_section_not_integer) << 0 << LowerBound->getSourceRange()); LowerBound = Res.get(); if (LowerBound->getType()->isSpecificBuiltinType(BuiltinType::Char_S) || LowerBound->getType()->isSpecificBuiltinType(BuiltinType::Char_U)) Diag(LowerBound->getExprLoc(), diag::warn_omp_section_is_char) << 0 << LowerBound->getSourceRange(); } if (Length) { auto Res = PerformOpenMPImplicitIntegerConversion(Length->getExprLoc(), Length); if (Res.isInvalid()) return ExprError(Diag(Length->getExprLoc(), diag::err_omp_typecheck_section_not_integer) << 1 << Length->getSourceRange()); Length = Res.get(); if (Length->getType()->isSpecificBuiltinType(BuiltinType::Char_S) || Length->getType()->isSpecificBuiltinType(BuiltinType::Char_U)) Diag(Length->getExprLoc(), diag::warn_omp_section_is_char) << 1 << Length->getSourceRange(); } // C99 6.5.2.1p1: "shall have type "pointer to *object* type". Similarly, // C++ [expr.sub]p1: The type "T" shall be a completely-defined object // type. Note that functions are not objects, and that (in C99 parlance) // incomplete types are not object types. if (ResultTy->isFunctionType()) { Diag(Base->getExprLoc(), diag::err_omp_section_function_type) << ResultTy << Base->getSourceRange(); return ExprError(); } if (RequireCompleteType(Base->getExprLoc(), ResultTy, diag::err_omp_section_incomplete_type, Base)) return ExprError(); if (LowerBound && !OriginalTy->isAnyPointerType()) { Expr::EvalResult Result; if (LowerBound->EvaluateAsInt(Result, Context)) { // OpenMP 4.5, [2.4 Array Sections] // The array section must be a subset of the original array. llvm::APSInt LowerBoundValue = Result.Val.getInt(); if (LowerBoundValue.isNegative()) { Diag(LowerBound->getExprLoc(), diag::err_omp_section_not_subset_of_array) << LowerBound->getSourceRange(); return ExprError(); } } } if (Length) { Expr::EvalResult Result; if (Length->EvaluateAsInt(Result, Context)) { // OpenMP 4.5, [2.4 Array Sections] // The length must evaluate to non-negative integers. llvm::APSInt LengthValue = Result.Val.getInt(); if (LengthValue.isNegative()) { Diag(Length->getExprLoc(), diag::err_omp_section_length_negative) << LengthValue.toString(/*Radix=*/10, /*Signed=*/true) << Length->getSourceRange(); return ExprError(); } } } else if (ColonLoc.isValid() && (OriginalTy.isNull() || (!OriginalTy->isConstantArrayType() && !OriginalTy->isVariableArrayType()))) { // OpenMP 4.5, [2.4 Array Sections] // When the size of the array dimension is not known, the length must be // specified explicitly. Diag(ColonLoc, diag::err_omp_section_length_undefined) << (!OriginalTy.isNull() && OriginalTy->isArrayType()); return ExprError(); } if (!Base->getType()->isSpecificPlaceholderType( BuiltinType::OMPArraySection)) { ExprResult Result = DefaultFunctionArrayLvalueConversion(Base); if (Result.isInvalid()) return ExprError(); Base = Result.get(); } return new (Context) OMPArraySectionExpr(Base, LowerBound, Length, Context.OMPArraySectionTy, VK_LValue, OK_Ordinary, ColonLoc, RBLoc); } ExprResult Sema::CreateBuiltinArraySubscriptExpr(Expr *Base, SourceLocation LLoc, Expr *Idx, SourceLocation RLoc) { Expr *LHSExp = Base; Expr *RHSExp = Idx; ExprValueKind VK = VK_LValue; ExprObjectKind OK = OK_Ordinary; // Per C++ core issue 1213, the result is an xvalue if either operand is // a non-lvalue array, and an lvalue otherwise. if (getLangOpts().CPlusPlus11) { for (auto *Op : {LHSExp, RHSExp}) { Op = Op->IgnoreImplicit(); if (Op->getType()->isArrayType() && !Op->isLValue()) VK = VK_XValue; } } // Perform default conversions. if (!LHSExp->getType()->getAs()) { ExprResult Result = DefaultFunctionArrayLvalueConversion(LHSExp); if (Result.isInvalid()) return ExprError(); LHSExp = Result.get(); } ExprResult Result = DefaultFunctionArrayLvalueConversion(RHSExp); if (Result.isInvalid()) return ExprError(); RHSExp = Result.get(); QualType LHSTy = LHSExp->getType(), RHSTy = RHSExp->getType(); // C99 6.5.2.1p2: the expression e1[e2] is by definition precisely equivalent // to the expression *((e1)+(e2)). This means the array "Base" may actually be // in the subscript position. As a result, we need to derive the array base // and index from the expression types. Expr *BaseExpr, *IndexExpr; QualType ResultType; if (LHSTy->isDependentType() || RHSTy->isDependentType()) { BaseExpr = LHSExp; IndexExpr = RHSExp; ResultType = Context.DependentTy; } else if (const PointerType *PTy = LHSTy->getAs()) { BaseExpr = LHSExp; IndexExpr = RHSExp; ResultType = PTy->getPointeeType(); } else if (const ObjCObjectPointerType *PTy = LHSTy->getAs()) { BaseExpr = LHSExp; IndexExpr = RHSExp; // Use custom logic if this should be the pseudo-object subscript // expression. if (!LangOpts.isSubscriptPointerArithmetic()) return BuildObjCSubscriptExpression(RLoc, BaseExpr, IndexExpr, nullptr, nullptr); ResultType = PTy->getPointeeType(); } else if (const PointerType *PTy = RHSTy->getAs()) { // Handle the uncommon case of "123[Ptr]". BaseExpr = RHSExp; IndexExpr = LHSExp; ResultType = PTy->getPointeeType(); } else if (const ObjCObjectPointerType *PTy = RHSTy->getAs()) { // Handle the uncommon case of "123[Ptr]". BaseExpr = RHSExp; IndexExpr = LHSExp; ResultType = PTy->getPointeeType(); if (!LangOpts.isSubscriptPointerArithmetic()) { Diag(LLoc, diag::err_subscript_nonfragile_interface) << ResultType << BaseExpr->getSourceRange(); return ExprError(); } } else if (const VectorType *VTy = LHSTy->getAs()) { BaseExpr = LHSExp; // vectors: V[123] IndexExpr = RHSExp; // We apply C++ DR1213 to vector subscripting too. if (getLangOpts().CPlusPlus11 && LHSExp->getValueKind() == VK_RValue) { ExprResult Materialized = TemporaryMaterializationConversion(LHSExp); if (Materialized.isInvalid()) return ExprError(); LHSExp = Materialized.get(); } VK = LHSExp->getValueKind(); if (VK != VK_RValue) OK = OK_VectorComponent; ResultType = VTy->getElementType(); QualType BaseType = BaseExpr->getType(); Qualifiers BaseQuals = BaseType.getQualifiers(); Qualifiers MemberQuals = ResultType.getQualifiers(); Qualifiers Combined = BaseQuals + MemberQuals; if (Combined != MemberQuals) ResultType = Context.getQualifiedType(ResultType, Combined); } else if (LHSTy->isArrayType()) { // If we see an array that wasn't promoted by // DefaultFunctionArrayLvalueConversion, it must be an array that // wasn't promoted because of the C90 rule that doesn't // allow promoting non-lvalue arrays. Warn, then // force the promotion here. Diag(LHSExp->getBeginLoc(), diag::ext_subscript_non_lvalue) << LHSExp->getSourceRange(); LHSExp = ImpCastExprToType(LHSExp, Context.getArrayDecayedType(LHSTy), CK_ArrayToPointerDecay).get(); LHSTy = LHSExp->getType(); BaseExpr = LHSExp; IndexExpr = RHSExp; ResultType = LHSTy->getAs()->getPointeeType(); } else if (RHSTy->isArrayType()) { // Same as previous, except for 123[f().a] case Diag(RHSExp->getBeginLoc(), diag::ext_subscript_non_lvalue) << RHSExp->getSourceRange(); RHSExp = ImpCastExprToType(RHSExp, Context.getArrayDecayedType(RHSTy), CK_ArrayToPointerDecay).get(); RHSTy = RHSExp->getType(); BaseExpr = RHSExp; IndexExpr = LHSExp; ResultType = RHSTy->getAs()->getPointeeType(); } else { return ExprError(Diag(LLoc, diag::err_typecheck_subscript_value) << LHSExp->getSourceRange() << RHSExp->getSourceRange()); } // C99 6.5.2.1p1 if (!IndexExpr->getType()->isIntegerType() && !IndexExpr->isTypeDependent()) return ExprError(Diag(LLoc, diag::err_typecheck_subscript_not_integer) << IndexExpr->getSourceRange()); if ((IndexExpr->getType()->isSpecificBuiltinType(BuiltinType::Char_S) || IndexExpr->getType()->isSpecificBuiltinType(BuiltinType::Char_U)) && !IndexExpr->isTypeDependent()) Diag(LLoc, diag::warn_subscript_is_char) << IndexExpr->getSourceRange(); // C99 6.5.2.1p1: "shall have type "pointer to *object* type". Similarly, // C++ [expr.sub]p1: The type "T" shall be a completely-defined object // type. Note that Functions are not objects, and that (in C99 parlance) // incomplete types are not object types. if (ResultType->isFunctionType()) { Diag(BaseExpr->getBeginLoc(), diag::err_subscript_function_type) << ResultType << BaseExpr->getSourceRange(); return ExprError(); } if (ResultType->isVoidType() && !getLangOpts().CPlusPlus) { // GNU extension: subscripting on pointer to void Diag(LLoc, diag::ext_gnu_subscript_void_type) << BaseExpr->getSourceRange(); // C forbids expressions of unqualified void type from being l-values. // See IsCForbiddenLValueType. if (!ResultType.hasQualifiers()) VK = VK_RValue; } else if (!ResultType->isDependentType() && RequireCompleteType(LLoc, ResultType, diag::err_subscript_incomplete_type, BaseExpr)) return ExprError(); assert(VK == VK_RValue || LangOpts.CPlusPlus || !ResultType.isCForbiddenLValueType()); if (LHSExp->IgnoreParenImpCasts()->getType()->isVariablyModifiedType() && FunctionScopes.size() > 1) { if (auto *TT = LHSExp->IgnoreParenImpCasts()->getType()->getAs()) { for (auto I = FunctionScopes.rbegin(), E = std::prev(FunctionScopes.rend()); I != E; ++I) { auto *CSI = dyn_cast(*I); if (CSI == nullptr) break; DeclContext *DC = nullptr; if (auto *LSI = dyn_cast(CSI)) DC = LSI->CallOperator; else if (auto *CRSI = dyn_cast(CSI)) DC = CRSI->TheCapturedDecl; else if (auto *BSI = dyn_cast(CSI)) DC = BSI->TheDecl; if (DC) { if (DC->containsDecl(TT->getDecl())) break; captureVariablyModifiedType( Context, LHSExp->IgnoreParenImpCasts()->getType(), CSI); } } } } return new (Context) ArraySubscriptExpr(LHSExp, RHSExp, ResultType, VK, OK, RLoc); } bool Sema::CheckCXXDefaultArgExpr(SourceLocation CallLoc, FunctionDecl *FD, ParmVarDecl *Param) { if (Param->hasUnparsedDefaultArg()) { Diag(CallLoc, diag::err_use_of_default_argument_to_function_declared_later) << FD << cast(FD->getDeclContext())->getDeclName(); Diag(UnparsedDefaultArgLocs[Param], diag::note_default_argument_declared_here); return true; } if (Param->hasUninstantiatedDefaultArg()) { Expr *UninstExpr = Param->getUninstantiatedDefaultArg(); EnterExpressionEvaluationContext EvalContext( *this, ExpressionEvaluationContext::PotentiallyEvaluated, Param); // Instantiate the expression. // // FIXME: Pass in a correct Pattern argument, otherwise // getTemplateInstantiationArgs uses the lexical context of FD, e.g. // // template // struct A { // static int FooImpl(); // // template // // bug: default argument A::FooImpl() is evaluated with 2-level // // template argument list [[T], [Tp]], should be [[Tp]]. // friend A Foo(int a); // }; // // template // A Foo(int a = A::FooImpl()); MultiLevelTemplateArgumentList MutiLevelArgList = getTemplateInstantiationArgs(FD, nullptr, /*RelativeToPrimary=*/true); InstantiatingTemplate Inst(*this, CallLoc, Param, MutiLevelArgList.getInnermost()); if (Inst.isInvalid()) return true; if (Inst.isAlreadyInstantiating()) { Diag(Param->getBeginLoc(), diag::err_recursive_default_argument) << FD; Param->setInvalidDecl(); return true; } ExprResult Result; { // C++ [dcl.fct.default]p5: // The names in the [default argument] expression are bound, and // the semantic constraints are checked, at the point where the // default argument expression appears. ContextRAII SavedContext(*this, FD); LocalInstantiationScope Local(*this); runWithSufficientStackSpace(CallLoc, [&] { Result = SubstInitializer(UninstExpr, MutiLevelArgList, /*DirectInit*/false); }); } if (Result.isInvalid()) return true; // Check the expression as an initializer for the parameter. InitializedEntity Entity = InitializedEntity::InitializeParameter(Context, Param); InitializationKind Kind = InitializationKind::CreateCopy( Param->getLocation(), /*FIXME:EqualLoc*/ UninstExpr->getBeginLoc()); Expr *ResultE = Result.getAs(); InitializationSequence InitSeq(*this, Entity, Kind, ResultE); Result = InitSeq.Perform(*this, Entity, Kind, ResultE); if (Result.isInvalid()) return true; Result = ActOnFinishFullExpr(Result.getAs(), Param->getOuterLocStart(), /*DiscardedValue*/ false); if (Result.isInvalid()) return true; // Remember the instantiated default argument. Param->setDefaultArg(Result.getAs()); if (ASTMutationListener *L = getASTMutationListener()) { L->DefaultArgumentInstantiated(Param); } } // If the default argument expression is not set yet, we are building it now. if (!Param->hasInit()) { Diag(Param->getBeginLoc(), diag::err_recursive_default_argument) << FD; Param->setInvalidDecl(); return true; } // If the default expression creates temporaries, we need to // push them to the current stack of expression temporaries so they'll // be properly destroyed. // FIXME: We should really be rebuilding the default argument with new // bound temporaries; see the comment in PR5810. // We don't need to do that with block decls, though, because // blocks in default argument expression can never capture anything. if (auto Init = dyn_cast(Param->getInit())) { // Set the "needs cleanups" bit regardless of whether there are // any explicit objects. Cleanup.setExprNeedsCleanups(Init->cleanupsHaveSideEffects()); // Append all the objects to the cleanup list. Right now, this // should always be a no-op, because blocks in default argument // expressions should never be able to capture anything. assert(!Init->getNumObjects() && "default argument expression has capturing blocks?"); } // We already type-checked the argument, so we know it works. // Just mark all of the declarations in this potentially-evaluated expression // as being "referenced". EnterExpressionEvaluationContext EvalContext( *this, ExpressionEvaluationContext::PotentiallyEvaluated, Param); MarkDeclarationsReferencedInExpr(Param->getDefaultArg(), /*SkipLocalVariables=*/true); return false; } ExprResult Sema::BuildCXXDefaultArgExpr(SourceLocation CallLoc, FunctionDecl *FD, ParmVarDecl *Param) { if (CheckCXXDefaultArgExpr(CallLoc, FD, Param)) return ExprError(); return CXXDefaultArgExpr::Create(Context, CallLoc, Param, CurContext); } Sema::VariadicCallType Sema::getVariadicCallType(FunctionDecl *FDecl, const FunctionProtoType *Proto, Expr *Fn) { if (Proto && Proto->isVariadic()) { if (dyn_cast_or_null(FDecl)) return VariadicConstructor; else if (Fn && Fn->getType()->isBlockPointerType()) return VariadicBlock; else if (FDecl) { if (CXXMethodDecl *Method = dyn_cast_or_null(FDecl)) if (Method->isInstance()) return VariadicMethod; } else if (Fn && Fn->getType() == Context.BoundMemberTy) return VariadicMethod; return VariadicFunction; } return VariadicDoesNotApply; } namespace { class FunctionCallCCC final : public FunctionCallFilterCCC { public: FunctionCallCCC(Sema &SemaRef, const IdentifierInfo *FuncName, unsigned NumArgs, MemberExpr *ME) : FunctionCallFilterCCC(SemaRef, NumArgs, false, ME), FunctionName(FuncName) {} bool ValidateCandidate(const TypoCorrection &candidate) override { if (!candidate.getCorrectionSpecifier() || candidate.getCorrectionAsIdentifierInfo() != FunctionName) { return false; } return FunctionCallFilterCCC::ValidateCandidate(candidate); } std::unique_ptr clone() override { return std::make_unique(*this); } private: const IdentifierInfo *const FunctionName; }; } static TypoCorrection TryTypoCorrectionForCall(Sema &S, Expr *Fn, FunctionDecl *FDecl, ArrayRef Args) { MemberExpr *ME = dyn_cast(Fn); DeclarationName FuncName = FDecl->getDeclName(); SourceLocation NameLoc = ME ? ME->getMemberLoc() : Fn->getBeginLoc(); FunctionCallCCC CCC(S, FuncName.getAsIdentifierInfo(), Args.size(), ME); if (TypoCorrection Corrected = S.CorrectTypo( DeclarationNameInfo(FuncName, NameLoc), Sema::LookupOrdinaryName, S.getScopeForContext(S.CurContext), nullptr, CCC, Sema::CTK_ErrorRecovery)) { if (NamedDecl *ND = Corrected.getFoundDecl()) { if (Corrected.isOverloaded()) { OverloadCandidateSet OCS(NameLoc, OverloadCandidateSet::CSK_Normal); OverloadCandidateSet::iterator Best; for (NamedDecl *CD : Corrected) { if (FunctionDecl *FD = dyn_cast(CD)) S.AddOverloadCandidate(FD, DeclAccessPair::make(FD, AS_none), Args, OCS); } switch (OCS.BestViableFunction(S, NameLoc, Best)) { case OR_Success: ND = Best->FoundDecl; Corrected.setCorrectionDecl(ND); break; default: break; } } ND = ND->getUnderlyingDecl(); if (isa(ND) || isa(ND)) return Corrected; } } return TypoCorrection(); } /// ConvertArgumentsForCall - Converts the arguments specified in /// Args/NumArgs to the parameter types of the function FDecl with /// function prototype Proto. Call is the call expression itself, and /// Fn is the function expression. For a C++ member function, this /// routine does not attempt to convert the object argument. Returns /// true if the call is ill-formed. bool Sema::ConvertArgumentsForCall(CallExpr *Call, Expr *Fn, FunctionDecl *FDecl, const FunctionProtoType *Proto, ArrayRef Args, SourceLocation RParenLoc, bool IsExecConfig) { // Bail out early if calling a builtin with custom typechecking. if (FDecl) if (unsigned ID = FDecl->getBuiltinID()) if (Context.BuiltinInfo.hasCustomTypechecking(ID)) return false; // C99 6.5.2.2p7 - the arguments are implicitly converted, as if by // assignment, to the types of the corresponding parameter, ... unsigned NumParams = Proto->getNumParams(); bool Invalid = false; unsigned MinArgs = FDecl ? FDecl->getMinRequiredArguments() : NumParams; unsigned FnKind = Fn->getType()->isBlockPointerType() ? 1 /* block */ : (IsExecConfig ? 3 /* kernel function (exec config) */ : 0 /* function */); // If too few arguments are available (and we don't have default // arguments for the remaining parameters), don't make the call. if (Args.size() < NumParams) { if (Args.size() < MinArgs) { TypoCorrection TC; if (FDecl && (TC = TryTypoCorrectionForCall(*this, Fn, FDecl, Args))) { unsigned diag_id = MinArgs == NumParams && !Proto->isVariadic() ? diag::err_typecheck_call_too_few_args_suggest : diag::err_typecheck_call_too_few_args_at_least_suggest; diagnoseTypo(TC, PDiag(diag_id) << FnKind << MinArgs << static_cast(Args.size()) << TC.getCorrectionRange()); } else if (MinArgs == 1 && FDecl && FDecl->getParamDecl(0)->getDeclName()) Diag(RParenLoc, MinArgs == NumParams && !Proto->isVariadic() ? diag::err_typecheck_call_too_few_args_one : diag::err_typecheck_call_too_few_args_at_least_one) << FnKind << FDecl->getParamDecl(0) << Fn->getSourceRange(); else Diag(RParenLoc, MinArgs == NumParams && !Proto->isVariadic() ? diag::err_typecheck_call_too_few_args : diag::err_typecheck_call_too_few_args_at_least) << FnKind << MinArgs << static_cast(Args.size()) << Fn->getSourceRange(); // Emit the location of the prototype. if (!TC && FDecl && !FDecl->getBuiltinID() && !IsExecConfig) Diag(FDecl->getBeginLoc(), diag::note_callee_decl) << FDecl; return true; } // We reserve space for the default arguments when we create // the call expression, before calling ConvertArgumentsForCall. assert((Call->getNumArgs() == NumParams) && "We should have reserved space for the default arguments before!"); } // If too many are passed and not variadic, error on the extras and drop // them. if (Args.size() > NumParams) { if (!Proto->isVariadic()) { TypoCorrection TC; if (FDecl && (TC = TryTypoCorrectionForCall(*this, Fn, FDecl, Args))) { unsigned diag_id = MinArgs == NumParams && !Proto->isVariadic() ? diag::err_typecheck_call_too_many_args_suggest : diag::err_typecheck_call_too_many_args_at_most_suggest; diagnoseTypo(TC, PDiag(diag_id) << FnKind << NumParams << static_cast(Args.size()) << TC.getCorrectionRange()); } else if (NumParams == 1 && FDecl && FDecl->getParamDecl(0)->getDeclName()) Diag(Args[NumParams]->getBeginLoc(), MinArgs == NumParams ? diag::err_typecheck_call_too_many_args_one : diag::err_typecheck_call_too_many_args_at_most_one) << FnKind << FDecl->getParamDecl(0) << static_cast(Args.size()) << Fn->getSourceRange() << SourceRange(Args[NumParams]->getBeginLoc(), Args.back()->getEndLoc()); else Diag(Args[NumParams]->getBeginLoc(), MinArgs == NumParams ? diag::err_typecheck_call_too_many_args : diag::err_typecheck_call_too_many_args_at_most) << FnKind << NumParams << static_cast(Args.size()) << Fn->getSourceRange() << SourceRange(Args[NumParams]->getBeginLoc(), Args.back()->getEndLoc()); // Emit the location of the prototype. if (!TC && FDecl && !FDecl->getBuiltinID() && !IsExecConfig) Diag(FDecl->getBeginLoc(), diag::note_callee_decl) << FDecl; // This deletes the extra arguments. Call->shrinkNumArgs(NumParams); return true; } } SmallVector AllArgs; VariadicCallType CallType = getVariadicCallType(FDecl, Proto, Fn); Invalid = GatherArgumentsForCall(Call->getBeginLoc(), FDecl, Proto, 0, Args, AllArgs, CallType); if (Invalid) return true; unsigned TotalNumArgs = AllArgs.size(); for (unsigned i = 0; i < TotalNumArgs; ++i) Call->setArg(i, AllArgs[i]); return false; } bool Sema::GatherArgumentsForCall(SourceLocation CallLoc, FunctionDecl *FDecl, const FunctionProtoType *Proto, unsigned FirstParam, ArrayRef Args, SmallVectorImpl &AllArgs, VariadicCallType CallType, bool AllowExplicit, bool IsListInitialization) { unsigned NumParams = Proto->getNumParams(); bool Invalid = false; size_t ArgIx = 0; // Continue to check argument types (even if we have too few/many args). for (unsigned i = FirstParam; i < NumParams; i++) { QualType ProtoArgType = Proto->getParamType(i); Expr *Arg; ParmVarDecl *Param = FDecl ? FDecl->getParamDecl(i) : nullptr; if (ArgIx < Args.size()) { Arg = Args[ArgIx++]; if (RequireCompleteType(Arg->getBeginLoc(), ProtoArgType, diag::err_call_incomplete_argument, Arg)) return true; // Strip the unbridged-cast placeholder expression off, if applicable. bool CFAudited = false; if (Arg->getType() == Context.ARCUnbridgedCastTy && FDecl && FDecl->hasAttr() && (!Param || !Param->hasAttr())) Arg = stripARCUnbridgedCast(Arg); else if (getLangOpts().ObjCAutoRefCount && FDecl && FDecl->hasAttr() && (!Param || !Param->hasAttr())) CFAudited = true; if (Proto->getExtParameterInfo(i).isNoEscape()) if (auto *BE = dyn_cast(Arg->IgnoreParenNoopCasts(Context))) BE->getBlockDecl()->setDoesNotEscape(); InitializedEntity Entity = Param ? InitializedEntity::InitializeParameter(Context, Param, ProtoArgType) : InitializedEntity::InitializeParameter( Context, ProtoArgType, Proto->isParamConsumed(i)); // Remember that parameter belongs to a CF audited API. if (CFAudited) Entity.setParameterCFAudited(); ExprResult ArgE = PerformCopyInitialization( Entity, SourceLocation(), Arg, IsListInitialization, AllowExplicit); if (ArgE.isInvalid()) return true; Arg = ArgE.getAs(); } else { assert(Param && "can't use default arguments without a known callee"); ExprResult ArgExpr = BuildCXXDefaultArgExpr(CallLoc, FDecl, Param); if (ArgExpr.isInvalid()) return true; Arg = ArgExpr.getAs(); } // Check for array bounds violations for each argument to the call. This // check only triggers warnings when the argument isn't a more complex Expr // with its own checking, such as a BinaryOperator. CheckArrayAccess(Arg); // Check for violations of C99 static array rules (C99 6.7.5.3p7). CheckStaticArrayArgument(CallLoc, Param, Arg); AllArgs.push_back(Arg); } // If this is a variadic call, handle args passed through "...". if (CallType != VariadicDoesNotApply) { // Assume that extern "C" functions with variadic arguments that // return __unknown_anytype aren't *really* variadic. if (Proto->getReturnType() == Context.UnknownAnyTy && FDecl && FDecl->isExternC()) { for (Expr *A : Args.slice(ArgIx)) { QualType paramType; // ignored ExprResult arg = checkUnknownAnyArg(CallLoc, A, paramType); Invalid |= arg.isInvalid(); AllArgs.push_back(arg.get()); } // Otherwise do argument promotion, (C99 6.5.2.2p7). } else { for (Expr *A : Args.slice(ArgIx)) { ExprResult Arg = DefaultVariadicArgumentPromotion(A, CallType, FDecl); Invalid |= Arg.isInvalid(); // Copy blocks to the heap. if (A->getType()->isBlockPointerType()) maybeExtendBlockObject(Arg); AllArgs.push_back(Arg.get()); } } // Check for array bounds violations. for (Expr *A : Args.slice(ArgIx)) CheckArrayAccess(A); } return Invalid; } static void DiagnoseCalleeStaticArrayParam(Sema &S, ParmVarDecl *PVD) { TypeLoc TL = PVD->getTypeSourceInfo()->getTypeLoc(); if (DecayedTypeLoc DTL = TL.getAs()) TL = DTL.getOriginalLoc(); if (ArrayTypeLoc ATL = TL.getAs()) S.Diag(PVD->getLocation(), diag::note_callee_static_array) << ATL.getLocalSourceRange(); } /// CheckStaticArrayArgument - If the given argument corresponds to a static /// array parameter, check that it is non-null, and that if it is formed by /// array-to-pointer decay, the underlying array is sufficiently large. /// /// C99 6.7.5.3p7: If the keyword static also appears within the [ and ] of the /// array type derivation, then for each call to the function, the value of the /// corresponding actual argument shall provide access to the first element of /// an array with at least as many elements as specified by the size expression. void Sema::CheckStaticArrayArgument(SourceLocation CallLoc, ParmVarDecl *Param, const Expr *ArgExpr) { // Static array parameters are not supported in C++. if (!Param || getLangOpts().CPlusPlus) return; QualType OrigTy = Param->getOriginalType(); const ArrayType *AT = Context.getAsArrayType(OrigTy); if (!AT || AT->getSizeModifier() != ArrayType::Static) return; if (ArgExpr->isNullPointerConstant(Context, Expr::NPC_NeverValueDependent)) { Diag(CallLoc, diag::warn_null_arg) << ArgExpr->getSourceRange(); DiagnoseCalleeStaticArrayParam(*this, Param); return; } const ConstantArrayType *CAT = dyn_cast(AT); if (!CAT) return; const ConstantArrayType *ArgCAT = Context.getAsConstantArrayType(ArgExpr->IgnoreParenCasts()->getType()); if (!ArgCAT) return; if (getASTContext().hasSameUnqualifiedType(CAT->getElementType(), ArgCAT->getElementType())) { if (ArgCAT->getSize().ult(CAT->getSize())) { Diag(CallLoc, diag::warn_static_array_too_small) << ArgExpr->getSourceRange() << (unsigned)ArgCAT->getSize().getZExtValue() << (unsigned)CAT->getSize().getZExtValue() << 0; DiagnoseCalleeStaticArrayParam(*this, Param); } return; } Optional ArgSize = getASTContext().getTypeSizeInCharsIfKnown(ArgCAT); Optional ParmSize = getASTContext().getTypeSizeInCharsIfKnown(CAT); if (ArgSize && ParmSize && *ArgSize < *ParmSize) { Diag(CallLoc, diag::warn_static_array_too_small) << ArgExpr->getSourceRange() << (unsigned)ArgSize->getQuantity() << (unsigned)ParmSize->getQuantity() << 1; DiagnoseCalleeStaticArrayParam(*this, Param); } } /// Given a function expression of unknown-any type, try to rebuild it /// to have a function type. static ExprResult rebuildUnknownAnyFunction(Sema &S, Expr *fn); /// Is the given type a placeholder that we need to lower out /// immediately during argument processing? static bool isPlaceholderToRemoveAsArg(QualType type) { // Placeholders are never sugared. const BuiltinType *placeholder = dyn_cast(type); if (!placeholder) return false; switch (placeholder->getKind()) { // Ignore all the non-placeholder types. #define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \ case BuiltinType::Id: #include "clang/Basic/OpenCLImageTypes.def" #define EXT_OPAQUE_TYPE(ExtType, Id, Ext) \ case BuiltinType::Id: #include "clang/Basic/OpenCLExtensionTypes.def" // In practice we'll never use this, since all SVE types are sugared // via TypedefTypes rather than exposed directly as BuiltinTypes. #define SVE_TYPE(Name, Id, SingletonId) \ case BuiltinType::Id: #include "clang/Basic/AArch64SVEACLETypes.def" #define PLACEHOLDER_TYPE(ID, SINGLETON_ID) #define BUILTIN_TYPE(ID, SINGLETON_ID) case BuiltinType::ID: #include "clang/AST/BuiltinTypes.def" return false; // We cannot lower out overload sets; they might validly be resolved // by the call machinery. case BuiltinType::Overload: return false; // Unbridged casts in ARC can be handled in some call positions and // should be left in place. case BuiltinType::ARCUnbridgedCast: return false; // Pseudo-objects should be converted as soon as possible. case BuiltinType::PseudoObject: return true; // The debugger mode could theoretically but currently does not try // to resolve unknown-typed arguments based on known parameter types. case BuiltinType::UnknownAny: return true; // These are always invalid as call arguments and should be reported. case BuiltinType::BoundMember: case BuiltinType::BuiltinFn: case BuiltinType::OMPArraySection: return true; } llvm_unreachable("bad builtin type kind"); } /// Check an argument list for placeholders that we won't try to /// handle later. static bool checkArgsForPlaceholders(Sema &S, MultiExprArg args) { // Apply this processing to all the arguments at once instead of // dying at the first failure. bool hasInvalid = false; for (size_t i = 0, e = args.size(); i != e; i++) { if (isPlaceholderToRemoveAsArg(args[i]->getType())) { ExprResult result = S.CheckPlaceholderExpr(args[i]); if (result.isInvalid()) hasInvalid = true; else args[i] = result.get(); } else if (hasInvalid) { (void)S.CorrectDelayedTyposInExpr(args[i]); } } return hasInvalid; } /// If a builtin function has a pointer argument with no explicit address /// space, then it should be able to accept a pointer to any address /// space as input. In order to do this, we need to replace the /// standard builtin declaration with one that uses the same address space /// as the call. /// /// \returns nullptr If this builtin is not a candidate for a rewrite i.e. /// it does not contain any pointer arguments without /// an address space qualifer. Otherwise the rewritten /// FunctionDecl is returned. /// TODO: Handle pointer return types. static FunctionDecl *rewriteBuiltinFunctionDecl(Sema *Sema, ASTContext &Context, FunctionDecl *FDecl, MultiExprArg ArgExprs) { QualType DeclType = FDecl->getType(); const FunctionProtoType *FT = dyn_cast(DeclType); if (!Context.BuiltinInfo.hasPtrArgsOrResult(FDecl->getBuiltinID()) || !FT || ArgExprs.size() < FT->getNumParams()) return nullptr; bool NeedsNewDecl = false; unsigned i = 0; SmallVector OverloadParams; for (QualType ParamType : FT->param_types()) { // Convert array arguments to pointer to simplify type lookup. ExprResult ArgRes = Sema->DefaultFunctionArrayLvalueConversion(ArgExprs[i++]); if (ArgRes.isInvalid()) return nullptr; Expr *Arg = ArgRes.get(); QualType ArgType = Arg->getType(); if (!ParamType->isPointerType() || ParamType.hasAddressSpace() || !ArgType->isPointerType() || !ArgType->getPointeeType().hasAddressSpace()) { OverloadParams.push_back(ParamType); continue; } QualType PointeeType = ParamType->getPointeeType(); if (PointeeType.hasAddressSpace()) continue; NeedsNewDecl = true; LangAS AS = ArgType->getPointeeType().getAddressSpace(); PointeeType = Context.getAddrSpaceQualType(PointeeType, AS); OverloadParams.push_back(Context.getPointerType(PointeeType)); } if (!NeedsNewDecl) return nullptr; FunctionProtoType::ExtProtoInfo EPI; EPI.Variadic = FT->isVariadic(); QualType OverloadTy = Context.getFunctionType(FT->getReturnType(), OverloadParams, EPI); DeclContext *Parent = FDecl->getParent(); FunctionDecl *OverloadDecl = FunctionDecl::Create(Context, Parent, FDecl->getLocation(), FDecl->getLocation(), FDecl->getIdentifier(), OverloadTy, /*TInfo=*/nullptr, SC_Extern, false, /*hasPrototype=*/true); SmallVector Params; FT = cast(OverloadTy); for (unsigned i = 0, e = FT->getNumParams(); i != e; ++i) { QualType ParamType = FT->getParamType(i); ParmVarDecl *Parm = ParmVarDecl::Create(Context, OverloadDecl, SourceLocation(), SourceLocation(), nullptr, ParamType, /*TInfo=*/nullptr, SC_None, nullptr); Parm->setScopeInfo(0, i); Params.push_back(Parm); } OverloadDecl->setParams(Params); return OverloadDecl; } static void checkDirectCallValidity(Sema &S, const Expr *Fn, FunctionDecl *Callee, MultiExprArg ArgExprs) { // `Callee` (when called with ArgExprs) may be ill-formed. enable_if (and // similar attributes) really don't like it when functions are called with an // invalid number of args. if (S.TooManyArguments(Callee->getNumParams(), ArgExprs.size(), /*PartialOverloading=*/false) && !Callee->isVariadic()) return; if (Callee->getMinRequiredArguments() > ArgExprs.size()) return; if (const EnableIfAttr *Attr = S.CheckEnableIf(Callee, ArgExprs, true)) { S.Diag(Fn->getBeginLoc(), isa(Callee) ? diag::err_ovl_no_viable_member_function_in_call : diag::err_ovl_no_viable_function_in_call) << Callee << Callee->getSourceRange(); S.Diag(Callee->getLocation(), diag::note_ovl_candidate_disabled_by_function_cond_attr) << Attr->getCond()->getSourceRange() << Attr->getMessage(); return; } } static bool enclosingClassIsRelatedToClassInWhichMembersWereFound( const UnresolvedMemberExpr *const UME, Sema &S) { const auto GetFunctionLevelDCIfCXXClass = [](Sema &S) -> const CXXRecordDecl * { const DeclContext *const DC = S.getFunctionLevelDeclContext(); if (!DC || !DC->getParent()) return nullptr; // If the call to some member function was made from within a member // function body 'M' return return 'M's parent. if (const auto *MD = dyn_cast(DC)) return MD->getParent()->getCanonicalDecl(); // else the call was made from within a default member initializer of a // class, so return the class. if (const auto *RD = dyn_cast(DC)) return RD->getCanonicalDecl(); return nullptr; }; // If our DeclContext is neither a member function nor a class (in the // case of a lambda in a default member initializer), we can't have an // enclosing 'this'. const CXXRecordDecl *const CurParentClass = GetFunctionLevelDCIfCXXClass(S); if (!CurParentClass) return false; // The naming class for implicit member functions call is the class in which // name lookup starts. const CXXRecordDecl *const NamingClass = UME->getNamingClass()->getCanonicalDecl(); assert(NamingClass && "Must have naming class even for implicit access"); // If the unresolved member functions were found in a 'naming class' that is // related (either the same or derived from) to the class that contains the // member function that itself contained the implicit member access. return CurParentClass == NamingClass || CurParentClass->isDerivedFrom(NamingClass); } static void tryImplicitlyCaptureThisIfImplicitMemberFunctionAccessWithDependentArgs( Sema &S, const UnresolvedMemberExpr *const UME, SourceLocation CallLoc) { if (!UME) return; LambdaScopeInfo *const CurLSI = S.getCurLambda(); // Only try and implicitly capture 'this' within a C++ Lambda if it hasn't // already been captured, or if this is an implicit member function call (if // it isn't, an attempt to capture 'this' should already have been made). if (!CurLSI || CurLSI->ImpCaptureStyle == CurLSI->ImpCap_None || !UME->isImplicitAccess() || CurLSI->isCXXThisCaptured()) return; // Check if the naming class in which the unresolved members were found is // related (same as or is a base of) to the enclosing class. if (!enclosingClassIsRelatedToClassInWhichMembersWereFound(UME, S)) return; DeclContext *EnclosingFunctionCtx = S.CurContext->getParent()->getParent(); // If the enclosing function is not dependent, then this lambda is // capture ready, so if we can capture this, do so. if (!EnclosingFunctionCtx->isDependentContext()) { // If the current lambda and all enclosing lambdas can capture 'this' - // then go ahead and capture 'this' (since our unresolved overload set // contains at least one non-static member function). if (!S.CheckCXXThisCapture(CallLoc, /*Explcit*/ false, /*Diagnose*/ false)) S.CheckCXXThisCapture(CallLoc); } else if (S.CurContext->isDependentContext()) { // ... since this is an implicit member reference, that might potentially // involve a 'this' capture, mark 'this' for potential capture in // enclosing lambdas. if (CurLSI->ImpCaptureStyle != CurLSI->ImpCap_None) CurLSI->addPotentialThisCapture(CallLoc); } } ExprResult Sema::ActOnCallExpr(Scope *Scope, Expr *Fn, SourceLocation LParenLoc, MultiExprArg ArgExprs, SourceLocation RParenLoc, Expr *ExecConfig) { ExprResult Call = BuildCallExpr(Scope, Fn, LParenLoc, ArgExprs, RParenLoc, ExecConfig); if (Call.isInvalid()) return Call; // Diagnose uses of the C++20 "ADL-only template-id call" feature in earlier // language modes. if (auto *ULE = dyn_cast(Fn)) { if (ULE->hasExplicitTemplateArgs() && ULE->decls_begin() == ULE->decls_end()) { Diag(Fn->getExprLoc(), getLangOpts().CPlusPlus2a ? diag::warn_cxx17_compat_adl_only_template_id : diag::ext_adl_only_template_id) << ULE->getName(); } } return Call; } /// BuildCallExpr - Handle a call to Fn with the specified array of arguments. /// This provides the location of the left/right parens and a list of comma /// locations. ExprResult Sema::BuildCallExpr(Scope *Scope, Expr *Fn, SourceLocation LParenLoc, MultiExprArg ArgExprs, SourceLocation RParenLoc, Expr *ExecConfig, bool IsExecConfig) { // Since this might be a postfix expression, get rid of ParenListExprs. ExprResult Result = MaybeConvertParenListExprToParenExpr(Scope, Fn); if (Result.isInvalid()) return ExprError(); Fn = Result.get(); if (checkArgsForPlaceholders(*this, ArgExprs)) return ExprError(); if (getLangOpts().CPlusPlus) { // If this is a pseudo-destructor expression, build the call immediately. if (isa(Fn)) { if (!ArgExprs.empty()) { // Pseudo-destructor calls should not have any arguments. Diag(Fn->getBeginLoc(), diag::err_pseudo_dtor_call_with_args) << FixItHint::CreateRemoval( SourceRange(ArgExprs.front()->getBeginLoc(), ArgExprs.back()->getEndLoc())); } return CallExpr::Create(Context, Fn, /*Args=*/{}, Context.VoidTy, VK_RValue, RParenLoc); } if (Fn->getType() == Context.PseudoObjectTy) { ExprResult result = CheckPlaceholderExpr(Fn); if (result.isInvalid()) return ExprError(); Fn = result.get(); } // Determine whether this is a dependent call inside a C++ template, // in which case we won't do any semantic analysis now. if (Fn->isTypeDependent() || Expr::hasAnyTypeDependentArguments(ArgExprs)) { if (ExecConfig) { return CUDAKernelCallExpr::Create( Context, Fn, cast(ExecConfig), ArgExprs, Context.DependentTy, VK_RValue, RParenLoc); } else { tryImplicitlyCaptureThisIfImplicitMemberFunctionAccessWithDependentArgs( *this, dyn_cast(Fn->IgnoreParens()), Fn->getBeginLoc()); return CallExpr::Create(Context, Fn, ArgExprs, Context.DependentTy, VK_RValue, RParenLoc); } } // Determine whether this is a call to an object (C++ [over.call.object]). if (Fn->getType()->isRecordType()) return BuildCallToObjectOfClassType(Scope, Fn, LParenLoc, ArgExprs, RParenLoc); if (Fn->getType() == Context.UnknownAnyTy) { ExprResult result = rebuildUnknownAnyFunction(*this, Fn); if (result.isInvalid()) return ExprError(); Fn = result.get(); } if (Fn->getType() == Context.BoundMemberTy) { return BuildCallToMemberFunction(Scope, Fn, LParenLoc, ArgExprs, RParenLoc); } } // Check for overloaded calls. This can happen even in C due to extensions. if (Fn->getType() == Context.OverloadTy) { OverloadExpr::FindResult find = OverloadExpr::find(Fn); // We aren't supposed to apply this logic if there's an '&' involved. if (!find.HasFormOfMemberPointer) { if (Expr::hasAnyTypeDependentArguments(ArgExprs)) return CallExpr::Create(Context, Fn, ArgExprs, Context.DependentTy, VK_RValue, RParenLoc); OverloadExpr *ovl = find.Expression; if (UnresolvedLookupExpr *ULE = dyn_cast(ovl)) return BuildOverloadedCallExpr( Scope, Fn, ULE, LParenLoc, ArgExprs, RParenLoc, ExecConfig, /*AllowTypoCorrection=*/true, find.IsAddressOfOperand); return BuildCallToMemberFunction(Scope, Fn, LParenLoc, ArgExprs, RParenLoc); } } // If we're directly calling a function, get the appropriate declaration. if (Fn->getType() == Context.UnknownAnyTy) { ExprResult result = rebuildUnknownAnyFunction(*this, Fn); if (result.isInvalid()) return ExprError(); Fn = result.get(); } Expr *NakedFn = Fn->IgnoreParens(); bool CallingNDeclIndirectly = false; NamedDecl *NDecl = nullptr; if (UnaryOperator *UnOp = dyn_cast(NakedFn)) { if (UnOp->getOpcode() == UO_AddrOf) { CallingNDeclIndirectly = true; NakedFn = UnOp->getSubExpr()->IgnoreParens(); } } if (auto *DRE = dyn_cast(NakedFn)) { NDecl = DRE->getDecl(); FunctionDecl *FDecl = dyn_cast(NDecl); if (FDecl && FDecl->getBuiltinID()) { // Rewrite the function decl for this builtin by replacing parameters // with no explicit address space with the address space of the arguments // in ArgExprs. if ((FDecl = rewriteBuiltinFunctionDecl(this, Context, FDecl, ArgExprs))) { NDecl = FDecl; Fn = DeclRefExpr::Create( Context, FDecl->getQualifierLoc(), SourceLocation(), FDecl, false, SourceLocation(), FDecl->getType(), Fn->getValueKind(), FDecl, nullptr, DRE->isNonOdrUse()); } } } else if (isa(NakedFn)) NDecl = cast(NakedFn)->getMemberDecl(); if (FunctionDecl *FD = dyn_cast_or_null(NDecl)) { if (CallingNDeclIndirectly && !checkAddressOfFunctionIsAvailable( FD, /*Complain=*/true, Fn->getBeginLoc())) return ExprError(); if (getLangOpts().OpenCL && checkOpenCLDisabledDecl(*FD, *Fn)) return ExprError(); checkDirectCallValidity(*this, Fn, FD, ArgExprs); } return BuildResolvedCallExpr(Fn, NDecl, LParenLoc, ArgExprs, RParenLoc, ExecConfig, IsExecConfig); } /// ActOnAsTypeExpr - create a new asType (bitcast) from the arguments. /// /// __builtin_astype( value, dst type ) /// ExprResult Sema::ActOnAsTypeExpr(Expr *E, ParsedType ParsedDestTy, SourceLocation BuiltinLoc, SourceLocation RParenLoc) { ExprValueKind VK = VK_RValue; ExprObjectKind OK = OK_Ordinary; QualType DstTy = GetTypeFromParser(ParsedDestTy); QualType SrcTy = E->getType(); if (Context.getTypeSize(DstTy) != Context.getTypeSize(SrcTy)) return ExprError(Diag(BuiltinLoc, diag::err_invalid_astype_of_different_size) << DstTy << SrcTy << E->getSourceRange()); return new (Context) AsTypeExpr(E, DstTy, VK, OK, BuiltinLoc, RParenLoc); } /// ActOnConvertVectorExpr - create a new convert-vector expression from the /// provided arguments. /// /// __builtin_convertvector( value, dst type ) /// ExprResult Sema::ActOnConvertVectorExpr(Expr *E, ParsedType ParsedDestTy, SourceLocation BuiltinLoc, SourceLocation RParenLoc) { TypeSourceInfo *TInfo; GetTypeFromParser(ParsedDestTy, &TInfo); return SemaConvertVectorExpr(E, TInfo, BuiltinLoc, RParenLoc); } /// BuildResolvedCallExpr - Build a call to a resolved expression, /// i.e. an expression not of \p OverloadTy. The expression should /// unary-convert to an expression of function-pointer or /// block-pointer type. /// /// \param NDecl the declaration being called, if available ExprResult Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl, SourceLocation LParenLoc, ArrayRef Args, SourceLocation RParenLoc, Expr *Config, bool IsExecConfig, ADLCallKind UsesADL) { FunctionDecl *FDecl = dyn_cast_or_null(NDecl); unsigned BuiltinID = (FDecl ? FDecl->getBuiltinID() : 0); // Functions with 'interrupt' attribute cannot be called directly. if (FDecl && FDecl->hasAttr()) { Diag(Fn->getExprLoc(), diag::err_anyx86_interrupt_called); return ExprError(); } // Interrupt handlers don't save off the VFP regs automatically on ARM, // so there's some risk when calling out to non-interrupt handler functions // that the callee might not preserve them. This is easy to diagnose here, // but can be very challenging to debug. if (auto *Caller = getCurFunctionDecl()) if (Caller->hasAttr()) { bool VFP = Context.getTargetInfo().hasFeature("vfp"); if (VFP && (!FDecl || !FDecl->hasAttr())) Diag(Fn->getExprLoc(), diag::warn_arm_interrupt_calling_convention); } // Promote the function operand. // We special-case function promotion here because we only allow promoting // builtin functions to function pointers in the callee of a call. ExprResult Result; QualType ResultTy; if (BuiltinID && Fn->getType()->isSpecificBuiltinType(BuiltinType::BuiltinFn)) { // Extract the return type from the (builtin) function pointer type. // FIXME Several builtins still have setType in // Sema::CheckBuiltinFunctionCall. One should review their definitions in // Builtins.def to ensure they are correct before removing setType calls. QualType FnPtrTy = Context.getPointerType(FDecl->getType()); Result = ImpCastExprToType(Fn, FnPtrTy, CK_BuiltinFnToFnPtr).get(); ResultTy = FDecl->getCallResultType(); } else { Result = CallExprUnaryConversions(Fn); ResultTy = Context.BoolTy; } if (Result.isInvalid()) return ExprError(); Fn = Result.get(); // Check for a valid function type, but only if it is not a builtin which // requires custom type checking. These will be handled by // CheckBuiltinFunctionCall below just after creation of the call expression. const FunctionType *FuncT = nullptr; if (!BuiltinID || !Context.BuiltinInfo.hasCustomTypechecking(BuiltinID)) { retry: if (const PointerType *PT = Fn->getType()->getAs()) { // C99 6.5.2.2p1 - "The expression that denotes the called function shall // have type pointer to function". FuncT = PT->getPointeeType()->getAs(); if (!FuncT) return ExprError(Diag(LParenLoc, diag::err_typecheck_call_not_function) << Fn->getType() << Fn->getSourceRange()); } else if (const BlockPointerType *BPT = Fn->getType()->getAs()) { FuncT = BPT->getPointeeType()->castAs(); } else { // Handle calls to expressions of unknown-any type. if (Fn->getType() == Context.UnknownAnyTy) { ExprResult rewrite = rebuildUnknownAnyFunction(*this, Fn); if (rewrite.isInvalid()) return ExprError(); Fn = rewrite.get(); goto retry; } return ExprError(Diag(LParenLoc, diag::err_typecheck_call_not_function) << Fn->getType() << Fn->getSourceRange()); } } // Get the number of parameters in the function prototype, if any. // We will allocate space for max(Args.size(), NumParams) arguments // in the call expression. const auto *Proto = dyn_cast_or_null(FuncT); unsigned NumParams = Proto ? Proto->getNumParams() : 0; CallExpr *TheCall; if (Config) { assert(UsesADL == ADLCallKind::NotADL && "CUDAKernelCallExpr should not use ADL"); TheCall = CUDAKernelCallExpr::Create(Context, Fn, cast(Config), Args, ResultTy, VK_RValue, RParenLoc, NumParams); } else { TheCall = CallExpr::Create(Context, Fn, Args, ResultTy, VK_RValue, RParenLoc, NumParams, UsesADL); } if (!getLangOpts().CPlusPlus) { // Forget about the nulled arguments since typo correction // do not handle them well. TheCall->shrinkNumArgs(Args.size()); // C cannot always handle TypoExpr nodes in builtin calls and direct // function calls as their argument checking don't necessarily handle // dependent types properly, so make sure any TypoExprs have been // dealt with. ExprResult Result = CorrectDelayedTyposInExpr(TheCall); if (!Result.isUsable()) return ExprError(); CallExpr *TheOldCall = TheCall; TheCall = dyn_cast(Result.get()); bool CorrectedTypos = TheCall != TheOldCall; if (!TheCall) return Result; Args = llvm::makeArrayRef(TheCall->getArgs(), TheCall->getNumArgs()); // A new call expression node was created if some typos were corrected. // However it may not have been constructed with enough storage. In this // case, rebuild the node with enough storage. The waste of space is // immaterial since this only happens when some typos were corrected. if (CorrectedTypos && Args.size() < NumParams) { if (Config) TheCall = CUDAKernelCallExpr::Create( Context, Fn, cast(Config), Args, ResultTy, VK_RValue, RParenLoc, NumParams); else TheCall = CallExpr::Create(Context, Fn, Args, ResultTy, VK_RValue, RParenLoc, NumParams, UsesADL); } // We can now handle the nulled arguments for the default arguments. TheCall->setNumArgsUnsafe(std::max(Args.size(), NumParams)); } // Bail out early if calling a builtin with custom type checking. if (BuiltinID && Context.BuiltinInfo.hasCustomTypechecking(BuiltinID)) return CheckBuiltinFunctionCall(FDecl, BuiltinID, TheCall); if (getLangOpts().CUDA) { if (Config) { // CUDA: Kernel calls must be to global functions if (FDecl && !FDecl->hasAttr()) return ExprError(Diag(LParenLoc,diag::err_kern_call_not_global_function) << FDecl << Fn->getSourceRange()); // CUDA: Kernel function must have 'void' return type if (!FuncT->getReturnType()->isVoidType() && !FuncT->getReturnType()->getAs() && !FuncT->getReturnType()->isInstantiationDependentType()) return ExprError(Diag(LParenLoc, diag::err_kern_type_not_void_return) << Fn->getType() << Fn->getSourceRange()); } else { // CUDA: Calls to global functions must be configured if (FDecl && FDecl->hasAttr()) return ExprError(Diag(LParenLoc, diag::err_global_call_not_config) << FDecl << Fn->getSourceRange()); } } // Check for a valid return type if (CheckCallReturnType(FuncT->getReturnType(), Fn->getBeginLoc(), TheCall, FDecl)) return ExprError(); // We know the result type of the call, set it. TheCall->setType(FuncT->getCallResultType(Context)); TheCall->setValueKind(Expr::getValueKindForType(FuncT->getReturnType())); if (Proto) { if (ConvertArgumentsForCall(TheCall, Fn, FDecl, Proto, Args, RParenLoc, IsExecConfig)) return ExprError(); } else { assert(isa(FuncT) && "Unknown FunctionType!"); if (FDecl) { // Check if we have too few/too many template arguments, based // on our knowledge of the function definition. const FunctionDecl *Def = nullptr; if (FDecl->hasBody(Def) && Args.size() != Def->param_size()) { Proto = Def->getType()->getAs(); if (!Proto || !(Proto->isVariadic() && Args.size() >= Def->param_size())) Diag(RParenLoc, diag::warn_call_wrong_number_of_arguments) << (Args.size() > Def->param_size()) << FDecl << Fn->getSourceRange(); } // If the function we're calling isn't a function prototype, but we have // a function prototype from a prior declaratiom, use that prototype. if (!FDecl->hasPrototype()) Proto = FDecl->getType()->getAs(); } // Promote the arguments (C99 6.5.2.2p6). for (unsigned i = 0, e = Args.size(); i != e; i++) { Expr *Arg = Args[i]; if (Proto && i < Proto->getNumParams()) { InitializedEntity Entity = InitializedEntity::InitializeParameter( Context, Proto->getParamType(i), Proto->isParamConsumed(i)); ExprResult ArgE = PerformCopyInitialization(Entity, SourceLocation(), Arg); if (ArgE.isInvalid()) return true; Arg = ArgE.getAs(); } else { ExprResult ArgE = DefaultArgumentPromotion(Arg); if (ArgE.isInvalid()) return true; Arg = ArgE.getAs(); } if (RequireCompleteType(Arg->getBeginLoc(), Arg->getType(), diag::err_call_incomplete_argument, Arg)) return ExprError(); TheCall->setArg(i, Arg); } } if (CXXMethodDecl *Method = dyn_cast_or_null(FDecl)) if (!Method->isStatic()) return ExprError(Diag(LParenLoc, diag::err_member_call_without_object) << Fn->getSourceRange()); // Check for sentinels if (NDecl) DiagnoseSentinelCalls(NDecl, LParenLoc, Args); // Do special checking on direct calls to functions. if (FDecl) { if (CheckFunctionCall(FDecl, TheCall, Proto)) return ExprError(); checkFortifiedBuiltinMemoryFunction(FDecl, TheCall); if (BuiltinID) return CheckBuiltinFunctionCall(FDecl, BuiltinID, TheCall); } else if (NDecl) { if (CheckPointerCall(NDecl, TheCall, Proto)) return ExprError(); } else { if (CheckOtherCall(TheCall, Proto)) return ExprError(); } return MaybeBindToTemporary(TheCall); } ExprResult Sema::ActOnCompoundLiteral(SourceLocation LParenLoc, ParsedType Ty, SourceLocation RParenLoc, Expr *InitExpr) { assert(Ty && "ActOnCompoundLiteral(): missing type"); assert(InitExpr && "ActOnCompoundLiteral(): missing expression"); TypeSourceInfo *TInfo; QualType literalType = GetTypeFromParser(Ty, &TInfo); if (!TInfo) TInfo = Context.getTrivialTypeSourceInfo(literalType); return BuildCompoundLiteralExpr(LParenLoc, TInfo, RParenLoc, InitExpr); } ExprResult Sema::BuildCompoundLiteralExpr(SourceLocation LParenLoc, TypeSourceInfo *TInfo, SourceLocation RParenLoc, Expr *LiteralExpr) { QualType literalType = TInfo->getType(); if (literalType->isArrayType()) { if (RequireCompleteType(LParenLoc, Context.getBaseElementType(literalType), diag::err_illegal_decl_array_incomplete_type, SourceRange(LParenLoc, LiteralExpr->getSourceRange().getEnd()))) return ExprError(); if (literalType->isVariableArrayType()) return ExprError(Diag(LParenLoc, diag::err_variable_object_no_init) << SourceRange(LParenLoc, LiteralExpr->getSourceRange().getEnd())); } else if (!literalType->isDependentType() && RequireCompleteType(LParenLoc, literalType, diag::err_typecheck_decl_incomplete_type, SourceRange(LParenLoc, LiteralExpr->getSourceRange().getEnd()))) return ExprError(); InitializedEntity Entity = InitializedEntity::InitializeCompoundLiteralInit(TInfo); InitializationKind Kind = InitializationKind::CreateCStyleCast(LParenLoc, SourceRange(LParenLoc, RParenLoc), /*InitList=*/true); InitializationSequence InitSeq(*this, Entity, Kind, LiteralExpr); ExprResult Result = InitSeq.Perform(*this, Entity, Kind, LiteralExpr, &literalType); if (Result.isInvalid()) return ExprError(); LiteralExpr = Result.get(); bool isFileScope = !CurContext->isFunctionOrMethod(); // In C, compound literals are l-values for some reason. // For GCC compatibility, in C++, file-scope array compound literals with // constant initializers are also l-values, and compound literals are // otherwise prvalues. // // (GCC also treats C++ list-initialized file-scope array prvalues with // constant initializers as l-values, but that's non-conforming, so we don't // follow it there.) // // FIXME: It would be better to handle the lvalue cases as materializing and // lifetime-extending a temporary object, but our materialized temporaries // representation only supports lifetime extension from a variable, not "out // of thin air". // FIXME: For C++, we might want to instead lifetime-extend only if a pointer // is bound to the result of applying array-to-pointer decay to the compound // literal. // FIXME: GCC supports compound literals of reference type, which should // obviously have a value kind derived from the kind of reference involved. ExprValueKind VK = (getLangOpts().CPlusPlus && !(isFileScope && literalType->isArrayType())) ? VK_RValue : VK_LValue; if (isFileScope) if (auto ILE = dyn_cast(LiteralExpr)) for (unsigned i = 0, j = ILE->getNumInits(); i != j; i++) { Expr *Init = ILE->getInit(i); ILE->setInit(i, ConstantExpr::Create(Context, Init)); } auto *E = new (Context) CompoundLiteralExpr(LParenLoc, TInfo, literalType, VK, LiteralExpr, isFileScope); if (isFileScope) { if (!LiteralExpr->isTypeDependent() && !LiteralExpr->isValueDependent() && !literalType->isDependentType()) // C99 6.5.2.5p3 if (CheckForConstantInitializer(LiteralExpr, literalType)) return ExprError(); } else if (literalType.getAddressSpace() != LangAS::opencl_private && literalType.getAddressSpace() != LangAS::Default) { // Embedded-C extensions to C99 6.5.2.5: // "If the compound literal occurs inside the body of a function, the // type name shall not be qualified by an address-space qualifier." Diag(LParenLoc, diag::err_compound_literal_with_address_space) << SourceRange(LParenLoc, LiteralExpr->getSourceRange().getEnd()); return ExprError(); } // Compound literals that have automatic storage duration are destroyed at // the end of the scope. Emit diagnostics if it is or contains a C union type // that is non-trivial to destruct. if (!isFileScope) if (E->getType().hasNonTrivialToPrimitiveDestructCUnion()) checkNonTrivialCUnion(E->getType(), E->getExprLoc(), NTCUC_CompoundLiteral, NTCUK_Destruct); if (E->getType().hasNonTrivialToPrimitiveDefaultInitializeCUnion() || E->getType().hasNonTrivialToPrimitiveCopyCUnion()) checkNonTrivialCUnionInInitializer(E->getInitializer(), E->getInitializer()->getExprLoc()); return MaybeBindToTemporary(E); } ExprResult Sema::ActOnInitList(SourceLocation LBraceLoc, MultiExprArg InitArgList, SourceLocation RBraceLoc) { // Only produce each kind of designated initialization diagnostic once. SourceLocation FirstDesignator; bool DiagnosedArrayDesignator = false; bool DiagnosedNestedDesignator = false; bool DiagnosedMixedDesignator = false; // Check that any designated initializers are syntactically valid in the // current language mode. for (unsigned I = 0, E = InitArgList.size(); I != E; ++I) { if (auto *DIE = dyn_cast(InitArgList[I])) { if (FirstDesignator.isInvalid()) FirstDesignator = DIE->getBeginLoc(); if (!getLangOpts().CPlusPlus) break; if (!DiagnosedNestedDesignator && DIE->size() > 1) { DiagnosedNestedDesignator = true; Diag(DIE->getBeginLoc(), diag::ext_designated_init_nested) << DIE->getDesignatorsSourceRange(); } for (auto &Desig : DIE->designators()) { if (!Desig.isFieldDesignator() && !DiagnosedArrayDesignator) { DiagnosedArrayDesignator = true; Diag(Desig.getBeginLoc(), diag::ext_designated_init_array) << Desig.getSourceRange(); } } if (!DiagnosedMixedDesignator && !isa(InitArgList[0])) { DiagnosedMixedDesignator = true; Diag(DIE->getBeginLoc(), diag::ext_designated_init_mixed) << DIE->getSourceRange(); Diag(InitArgList[0]->getBeginLoc(), diag::note_designated_init_mixed) << InitArgList[0]->getSourceRange(); } } else if (getLangOpts().CPlusPlus && !DiagnosedMixedDesignator && isa(InitArgList[0])) { DiagnosedMixedDesignator = true; auto *DIE = cast(InitArgList[0]); Diag(DIE->getBeginLoc(), diag::ext_designated_init_mixed) << DIE->getSourceRange(); Diag(InitArgList[I]->getBeginLoc(), diag::note_designated_init_mixed) << InitArgList[I]->getSourceRange(); } } if (FirstDesignator.isValid()) { // Only diagnose designated initiaization as a C++20 extension if we didn't // already diagnose use of (non-C++20) C99 designator syntax. if (getLangOpts().CPlusPlus && !DiagnosedArrayDesignator && !DiagnosedNestedDesignator && !DiagnosedMixedDesignator) { Diag(FirstDesignator, getLangOpts().CPlusPlus2a ? diag::warn_cxx17_compat_designated_init : diag::ext_cxx_designated_init); } else if (!getLangOpts().CPlusPlus && !getLangOpts().C99) { Diag(FirstDesignator, diag::ext_designated_init); } } return BuildInitList(LBraceLoc, InitArgList, RBraceLoc); } ExprResult Sema::BuildInitList(SourceLocation LBraceLoc, MultiExprArg InitArgList, SourceLocation RBraceLoc) { // Semantic analysis for initializers is done by ActOnDeclarator() and // CheckInitializer() - it requires knowledge of the object being initialized. // Immediately handle non-overload placeholders. Overloads can be // resolved contextually, but everything else here can't. for (unsigned I = 0, E = InitArgList.size(); I != E; ++I) { if (InitArgList[I]->getType()->isNonOverloadPlaceholderType()) { ExprResult result = CheckPlaceholderExpr(InitArgList[I]); // Ignore failures; dropping the entire initializer list because // of one failure would be terrible for indexing/etc. if (result.isInvalid()) continue; InitArgList[I] = result.get(); } } InitListExpr *E = new (Context) InitListExpr(Context, LBraceLoc, InitArgList, RBraceLoc); E->setType(Context.VoidTy); // FIXME: just a place holder for now. return E; } /// Do an explicit extend of the given block pointer if we're in ARC. void Sema::maybeExtendBlockObject(ExprResult &E) { assert(E.get()->getType()->isBlockPointerType()); assert(E.get()->isRValue()); // Only do this in an r-value context. if (!getLangOpts().ObjCAutoRefCount) return; E = ImplicitCastExpr::Create(Context, E.get()->getType(), CK_ARCExtendBlockObject, E.get(), /*base path*/ nullptr, VK_RValue); Cleanup.setExprNeedsCleanups(true); } /// Prepare a conversion of the given expression to an ObjC object /// pointer type. CastKind Sema::PrepareCastToObjCObjectPointer(ExprResult &E) { QualType type = E.get()->getType(); if (type->isObjCObjectPointerType()) { return CK_BitCast; } else if (type->isBlockPointerType()) { maybeExtendBlockObject(E); return CK_BlockPointerToObjCPointerCast; } else { assert(type->isPointerType()); return CK_CPointerToObjCPointerCast; } } /// Prepares for a scalar cast, performing all the necessary stages /// except the final cast and returning the kind required. CastKind Sema::PrepareScalarCast(ExprResult &Src, QualType DestTy) { // Both Src and Dest are scalar types, i.e. arithmetic or pointer. // Also, callers should have filtered out the invalid cases with // pointers. Everything else should be possible. QualType SrcTy = Src.get()->getType(); if (Context.hasSameUnqualifiedType(SrcTy, DestTy)) return CK_NoOp; switch (Type::ScalarTypeKind SrcKind = SrcTy->getScalarTypeKind()) { case Type::STK_MemberPointer: llvm_unreachable("member pointer type in C"); case Type::STK_CPointer: case Type::STK_BlockPointer: case Type::STK_ObjCObjectPointer: switch (DestTy->getScalarTypeKind()) { case Type::STK_CPointer: { LangAS SrcAS = SrcTy->getPointeeType().getAddressSpace(); LangAS DestAS = DestTy->getPointeeType().getAddressSpace(); if (SrcAS != DestAS) return CK_AddressSpaceConversion; if (Context.hasCvrSimilarType(SrcTy, DestTy)) return CK_NoOp; return CK_BitCast; } case Type::STK_BlockPointer: return (SrcKind == Type::STK_BlockPointer ? CK_BitCast : CK_AnyPointerToBlockPointerCast); case Type::STK_ObjCObjectPointer: if (SrcKind == Type::STK_ObjCObjectPointer) return CK_BitCast; if (SrcKind == Type::STK_CPointer) return CK_CPointerToObjCPointerCast; maybeExtendBlockObject(Src); return CK_BlockPointerToObjCPointerCast; case Type::STK_Bool: return CK_PointerToBoolean; case Type::STK_Integral: return CK_PointerToIntegral; case Type::STK_Floating: case Type::STK_FloatingComplex: case Type::STK_IntegralComplex: case Type::STK_MemberPointer: case Type::STK_FixedPoint: llvm_unreachable("illegal cast from pointer"); } llvm_unreachable("Should have returned before this"); case Type::STK_FixedPoint: switch (DestTy->getScalarTypeKind()) { case Type::STK_FixedPoint: return CK_FixedPointCast; case Type::STK_Bool: return CK_FixedPointToBoolean; case Type::STK_Integral: return CK_FixedPointToIntegral; case Type::STK_Floating: case Type::STK_IntegralComplex: case Type::STK_FloatingComplex: Diag(Src.get()->getExprLoc(), diag::err_unimplemented_conversion_with_fixed_point_type) << DestTy; return CK_IntegralCast; case Type::STK_CPointer: case Type::STK_ObjCObjectPointer: case Type::STK_BlockPointer: case Type::STK_MemberPointer: llvm_unreachable("illegal cast to pointer type"); } llvm_unreachable("Should have returned before this"); case Type::STK_Bool: // casting from bool is like casting from an integer case Type::STK_Integral: switch (DestTy->getScalarTypeKind()) { case Type::STK_CPointer: case Type::STK_ObjCObjectPointer: case Type::STK_BlockPointer: if (Src.get()->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) return CK_NullToPointer; return CK_IntegralToPointer; case Type::STK_Bool: return CK_IntegralToBoolean; case Type::STK_Integral: return CK_IntegralCast; case Type::STK_Floating: return CK_IntegralToFloating; case Type::STK_IntegralComplex: Src = ImpCastExprToType(Src.get(), DestTy->castAs()->getElementType(), CK_IntegralCast); return CK_IntegralRealToComplex; case Type::STK_FloatingComplex: Src = ImpCastExprToType(Src.get(), DestTy->castAs()->getElementType(), CK_IntegralToFloating); return CK_FloatingRealToComplex; case Type::STK_MemberPointer: llvm_unreachable("member pointer type in C"); case Type::STK_FixedPoint: return CK_IntegralToFixedPoint; } llvm_unreachable("Should have returned before this"); case Type::STK_Floating: switch (DestTy->getScalarTypeKind()) { case Type::STK_Floating: return CK_FloatingCast; case Type::STK_Bool: return CK_FloatingToBoolean; case Type::STK_Integral: return CK_FloatingToIntegral; case Type::STK_FloatingComplex: Src = ImpCastExprToType(Src.get(), DestTy->castAs()->getElementType(), CK_FloatingCast); return CK_FloatingRealToComplex; case Type::STK_IntegralComplex: Src = ImpCastExprToType(Src.get(), DestTy->castAs()->getElementType(), CK_FloatingToIntegral); return CK_IntegralRealToComplex; case Type::STK_CPointer: case Type::STK_ObjCObjectPointer: case Type::STK_BlockPointer: llvm_unreachable("valid float->pointer cast?"); case Type::STK_MemberPointer: llvm_unreachable("member pointer type in C"); case Type::STK_FixedPoint: Diag(Src.get()->getExprLoc(), diag::err_unimplemented_conversion_with_fixed_point_type) << SrcTy; return CK_IntegralCast; } llvm_unreachable("Should have returned before this"); case Type::STK_FloatingComplex: switch (DestTy->getScalarTypeKind()) { case Type::STK_FloatingComplex: return CK_FloatingComplexCast; case Type::STK_IntegralComplex: return CK_FloatingComplexToIntegralComplex; case Type::STK_Floating: { QualType ET = SrcTy->castAs()->getElementType(); if (Context.hasSameType(ET, DestTy)) return CK_FloatingComplexToReal; Src = ImpCastExprToType(Src.get(), ET, CK_FloatingComplexToReal); return CK_FloatingCast; } case Type::STK_Bool: return CK_FloatingComplexToBoolean; case Type::STK_Integral: Src = ImpCastExprToType(Src.get(), SrcTy->castAs()->getElementType(), CK_FloatingComplexToReal); return CK_FloatingToIntegral; case Type::STK_CPointer: case Type::STK_ObjCObjectPointer: case Type::STK_BlockPointer: llvm_unreachable("valid complex float->pointer cast?"); case Type::STK_MemberPointer: llvm_unreachable("member pointer type in C"); case Type::STK_FixedPoint: Diag(Src.get()->getExprLoc(), diag::err_unimplemented_conversion_with_fixed_point_type) << SrcTy; return CK_IntegralCast; } llvm_unreachable("Should have returned before this"); case Type::STK_IntegralComplex: switch (DestTy->getScalarTypeKind()) { case Type::STK_FloatingComplex: return CK_IntegralComplexToFloatingComplex; case Type::STK_IntegralComplex: return CK_IntegralComplexCast; case Type::STK_Integral: { QualType ET = SrcTy->castAs()->getElementType(); if (Context.hasSameType(ET, DestTy)) return CK_IntegralComplexToReal; Src = ImpCastExprToType(Src.get(), ET, CK_IntegralComplexToReal); return CK_IntegralCast; } case Type::STK_Bool: return CK_IntegralComplexToBoolean; case Type::STK_Floating: Src = ImpCastExprToType(Src.get(), SrcTy->castAs()->getElementType(), CK_IntegralComplexToReal); return CK_IntegralToFloating; case Type::STK_CPointer: case Type::STK_ObjCObjectPointer: case Type::STK_BlockPointer: llvm_unreachable("valid complex int->pointer cast?"); case Type::STK_MemberPointer: llvm_unreachable("member pointer type in C"); case Type::STK_FixedPoint: Diag(Src.get()->getExprLoc(), diag::err_unimplemented_conversion_with_fixed_point_type) << SrcTy; return CK_IntegralCast; } llvm_unreachable("Should have returned before this"); } llvm_unreachable("Unhandled scalar cast"); } static bool breakDownVectorType(QualType type, uint64_t &len, QualType &eltType) { // Vectors are simple. if (const VectorType *vecType = type->getAs()) { len = vecType->getNumElements(); eltType = vecType->getElementType(); assert(eltType->isScalarType()); return true; } // We allow lax conversion to and from non-vector types, but only if // they're real types (i.e. non-complex, non-pointer scalar types). if (!type->isRealType()) return false; len = 1; eltType = type; return true; } /// Are the two types lax-compatible vector types? That is, given /// that one of them is a vector, do they have equal storage sizes, /// where the storage size is the number of elements times the element /// size? /// /// This will also return false if either of the types is neither a /// vector nor a real type. bool Sema::areLaxCompatibleVectorTypes(QualType srcTy, QualType destTy) { assert(destTy->isVectorType() || srcTy->isVectorType()); // Disallow lax conversions between scalars and ExtVectors (these // conversions are allowed for other vector types because common headers // depend on them). Most scalar OP ExtVector cases are handled by the // splat path anyway, which does what we want (convert, not bitcast). // What this rules out for ExtVectors is crazy things like char4*float. if (srcTy->isScalarType() && destTy->isExtVectorType()) return false; if (destTy->isScalarType() && srcTy->isExtVectorType()) return false; uint64_t srcLen, destLen; QualType srcEltTy, destEltTy; if (!breakDownVectorType(srcTy, srcLen, srcEltTy)) return false; if (!breakDownVectorType(destTy, destLen, destEltTy)) return false; // ASTContext::getTypeSize will return the size rounded up to a // power of 2, so instead of using that, we need to use the raw // element size multiplied by the element count. uint64_t srcEltSize = Context.getTypeSize(srcEltTy); uint64_t destEltSize = Context.getTypeSize(destEltTy); return (srcLen * srcEltSize == destLen * destEltSize); } /// Is this a legal conversion between two types, one of which is /// known to be a vector type? bool Sema::isLaxVectorConversion(QualType srcTy, QualType destTy) { assert(destTy->isVectorType() || srcTy->isVectorType()); switch (Context.getLangOpts().getLaxVectorConversions()) { case LangOptions::LaxVectorConversionKind::None: return false; case LangOptions::LaxVectorConversionKind::Integer: if (!srcTy->isIntegralOrEnumerationType()) { auto *Vec = srcTy->getAs(); if (!Vec || !Vec->getElementType()->isIntegralOrEnumerationType()) return false; } if (!destTy->isIntegralOrEnumerationType()) { auto *Vec = destTy->getAs(); if (!Vec || !Vec->getElementType()->isIntegralOrEnumerationType()) return false; } // OK, integer (vector) -> integer (vector) bitcast. break; case LangOptions::LaxVectorConversionKind::All: break; } return areLaxCompatibleVectorTypes(srcTy, destTy); } bool Sema::CheckVectorCast(SourceRange R, QualType VectorTy, QualType Ty, CastKind &Kind) { assert(VectorTy->isVectorType() && "Not a vector type!"); if (Ty->isVectorType() || Ty->isIntegralType(Context)) { if (!areLaxCompatibleVectorTypes(Ty, VectorTy)) return Diag(R.getBegin(), Ty->isVectorType() ? diag::err_invalid_conversion_between_vectors : diag::err_invalid_conversion_between_vector_and_integer) << VectorTy << Ty << R; } else return Diag(R.getBegin(), diag::err_invalid_conversion_between_vector_and_scalar) << VectorTy << Ty << R; Kind = CK_BitCast; return false; } ExprResult Sema::prepareVectorSplat(QualType VectorTy, Expr *SplattedExpr) { QualType DestElemTy = VectorTy->castAs()->getElementType(); if (DestElemTy == SplattedExpr->getType()) return SplattedExpr; assert(DestElemTy->isFloatingType() || DestElemTy->isIntegralOrEnumerationType()); CastKind CK; if (VectorTy->isExtVectorType() && SplattedExpr->getType()->isBooleanType()) { // OpenCL requires that we convert `true` boolean expressions to -1, but // only when splatting vectors. if (DestElemTy->isFloatingType()) { // To avoid having to have a CK_BooleanToSignedFloating cast kind, we cast // in two steps: boolean to signed integral, then to floating. ExprResult CastExprRes = ImpCastExprToType(SplattedExpr, Context.IntTy, CK_BooleanToSignedIntegral); SplattedExpr = CastExprRes.get(); CK = CK_IntegralToFloating; } else { CK = CK_BooleanToSignedIntegral; } } else { ExprResult CastExprRes = SplattedExpr; CK = PrepareScalarCast(CastExprRes, DestElemTy); if (CastExprRes.isInvalid()) return ExprError(); SplattedExpr = CastExprRes.get(); } return ImpCastExprToType(SplattedExpr, DestElemTy, CK); } ExprResult Sema::CheckExtVectorCast(SourceRange R, QualType DestTy, Expr *CastExpr, CastKind &Kind) { assert(DestTy->isExtVectorType() && "Not an extended vector type!"); QualType SrcTy = CastExpr->getType(); // If SrcTy is a VectorType, the total size must match to explicitly cast to // an ExtVectorType. // In OpenCL, casts between vectors of different types are not allowed. // (See OpenCL 6.2). if (SrcTy->isVectorType()) { if (!areLaxCompatibleVectorTypes(SrcTy, DestTy) || (getLangOpts().OpenCL && !Context.hasSameUnqualifiedType(DestTy, SrcTy))) { Diag(R.getBegin(),diag::err_invalid_conversion_between_ext_vectors) << DestTy << SrcTy << R; return ExprError(); } Kind = CK_BitCast; return CastExpr; } // All non-pointer scalars can be cast to ExtVector type. The appropriate // conversion will take place first from scalar to elt type, and then // splat from elt type to vector. if (SrcTy->isPointerType()) return Diag(R.getBegin(), diag::err_invalid_conversion_between_vector_and_scalar) << DestTy << SrcTy << R; Kind = CK_VectorSplat; return prepareVectorSplat(DestTy, CastExpr); } ExprResult Sema::ActOnCastExpr(Scope *S, SourceLocation LParenLoc, Declarator &D, ParsedType &Ty, SourceLocation RParenLoc, Expr *CastExpr) { assert(!D.isInvalidType() && (CastExpr != nullptr) && "ActOnCastExpr(): missing type or expr"); TypeSourceInfo *castTInfo = GetTypeForDeclaratorCast(D, CastExpr->getType()); if (D.isInvalidType()) return ExprError(); if (getLangOpts().CPlusPlus) { // Check that there are no default arguments (C++ only). CheckExtraCXXDefaultArguments(D); } else { // Make sure any TypoExprs have been dealt with. ExprResult Res = CorrectDelayedTyposInExpr(CastExpr); if (!Res.isUsable()) return ExprError(); CastExpr = Res.get(); } checkUnusedDeclAttributes(D); QualType castType = castTInfo->getType(); Ty = CreateParsedType(castType, castTInfo); bool isVectorLiteral = false; // Check for an altivec or OpenCL literal, // i.e. all the elements are integer constants. ParenExpr *PE = dyn_cast(CastExpr); ParenListExpr *PLE = dyn_cast(CastExpr); if ((getLangOpts().AltiVec || getLangOpts().ZVector || getLangOpts().OpenCL) && castType->isVectorType() && (PE || PLE)) { if (PLE && PLE->getNumExprs() == 0) { Diag(PLE->getExprLoc(), diag::err_altivec_empty_initializer); return ExprError(); } if (PE || PLE->getNumExprs() == 1) { Expr *E = (PE ? PE->getSubExpr() : PLE->getExpr(0)); if (!E->getType()->isVectorType()) isVectorLiteral = true; } else isVectorLiteral = true; } // If this is a vector initializer, '(' type ')' '(' init, ..., init ')' // then handle it as such. if (isVectorLiteral) return BuildVectorLiteral(LParenLoc, RParenLoc, CastExpr, castTInfo); // If the Expr being casted is a ParenListExpr, handle it specially. // This is not an AltiVec-style cast, so turn the ParenListExpr into a // sequence of BinOp comma operators. if (isa(CastExpr)) { ExprResult Result = MaybeConvertParenListExprToParenExpr(S, CastExpr); if (Result.isInvalid()) return ExprError(); CastExpr = Result.get(); } if (getLangOpts().CPlusPlus && !castType->isVoidType() && !getSourceManager().isInSystemMacro(LParenLoc)) Diag(LParenLoc, diag::warn_old_style_cast) << CastExpr->getSourceRange(); CheckTollFreeBridgeCast(castType, CastExpr); CheckObjCBridgeRelatedCast(castType, CastExpr); DiscardMisalignedMemberAddress(castType.getTypePtr(), CastExpr); return BuildCStyleCastExpr(LParenLoc, castTInfo, RParenLoc, CastExpr); } ExprResult Sema::BuildVectorLiteral(SourceLocation LParenLoc, SourceLocation RParenLoc, Expr *E, TypeSourceInfo *TInfo) { assert((isa(E) || isa(E)) && "Expected paren or paren list expression"); Expr **exprs; unsigned numExprs; Expr *subExpr; SourceLocation LiteralLParenLoc, LiteralRParenLoc; if (ParenListExpr *PE = dyn_cast(E)) { LiteralLParenLoc = PE->getLParenLoc(); LiteralRParenLoc = PE->getRParenLoc(); exprs = PE->getExprs(); numExprs = PE->getNumExprs(); } else { // isa by assertion at function entrance LiteralLParenLoc = cast(E)->getLParen(); LiteralRParenLoc = cast(E)->getRParen(); subExpr = cast(E)->getSubExpr(); exprs = &subExpr; numExprs = 1; } QualType Ty = TInfo->getType(); assert(Ty->isVectorType() && "Expected vector type"); SmallVector initExprs; const VectorType *VTy = Ty->castAs(); unsigned numElems = VTy->getNumElements(); // '(...)' form of vector initialization in AltiVec: the number of // initializers must be one or must match the size of the vector. // If a single value is specified in the initializer then it will be // replicated to all the components of the vector if (VTy->getVectorKind() == VectorType::AltiVecVector) { // The number of initializers must be one or must match the size of the // vector. If a single value is specified in the initializer then it will // be replicated to all the components of the vector if (numExprs == 1) { QualType ElemTy = VTy->getElementType(); ExprResult Literal = DefaultLvalueConversion(exprs[0]); if (Literal.isInvalid()) return ExprError(); Literal = ImpCastExprToType(Literal.get(), ElemTy, PrepareScalarCast(Literal, ElemTy)); return BuildCStyleCastExpr(LParenLoc, TInfo, RParenLoc, Literal.get()); } else if (numExprs < numElems) { Diag(E->getExprLoc(), diag::err_incorrect_number_of_vector_initializers); return ExprError(); } else initExprs.append(exprs, exprs + numExprs); } else { // For OpenCL, when the number of initializers is a single value, // it will be replicated to all components of the vector. if (getLangOpts().OpenCL && VTy->getVectorKind() == VectorType::GenericVector && numExprs == 1) { QualType ElemTy = VTy->getElementType(); ExprResult Literal = DefaultLvalueConversion(exprs[0]); if (Literal.isInvalid()) return ExprError(); Literal = ImpCastExprToType(Literal.get(), ElemTy, PrepareScalarCast(Literal, ElemTy)); return BuildCStyleCastExpr(LParenLoc, TInfo, RParenLoc, Literal.get()); } initExprs.append(exprs, exprs + numExprs); } // FIXME: This means that pretty-printing the final AST will produce curly // braces instead of the original commas. InitListExpr *initE = new (Context) InitListExpr(Context, LiteralLParenLoc, initExprs, LiteralRParenLoc); initE->setType(Ty); return BuildCompoundLiteralExpr(LParenLoc, TInfo, RParenLoc, initE); } /// This is not an AltiVec-style cast or or C++ direct-initialization, so turn /// the ParenListExpr into a sequence of comma binary operators. ExprResult Sema::MaybeConvertParenListExprToParenExpr(Scope *S, Expr *OrigExpr) { ParenListExpr *E = dyn_cast(OrigExpr); if (!E) return OrigExpr; ExprResult Result(E->getExpr(0)); for (unsigned i = 1, e = E->getNumExprs(); i != e && !Result.isInvalid(); ++i) Result = ActOnBinOp(S, E->getExprLoc(), tok::comma, Result.get(), E->getExpr(i)); if (Result.isInvalid()) return ExprError(); return ActOnParenExpr(E->getLParenLoc(), E->getRParenLoc(), Result.get()); } ExprResult Sema::ActOnParenListExpr(SourceLocation L, SourceLocation R, MultiExprArg Val) { return ParenListExpr::Create(Context, L, Val, R); } /// Emit a specialized diagnostic when one expression is a null pointer /// constant and the other is not a pointer. Returns true if a diagnostic is /// emitted. bool Sema::DiagnoseConditionalForNull(Expr *LHSExpr, Expr *RHSExpr, SourceLocation QuestionLoc) { Expr *NullExpr = LHSExpr; Expr *NonPointerExpr = RHSExpr; Expr::NullPointerConstantKind NullKind = NullExpr->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNotNull); if (NullKind == Expr::NPCK_NotNull) { NullExpr = RHSExpr; NonPointerExpr = LHSExpr; NullKind = NullExpr->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNotNull); } if (NullKind == Expr::NPCK_NotNull) return false; if (NullKind == Expr::NPCK_ZeroExpression) return false; if (NullKind == Expr::NPCK_ZeroLiteral) { // In this case, check to make sure that we got here from a "NULL" // string in the source code. NullExpr = NullExpr->IgnoreParenImpCasts(); SourceLocation loc = NullExpr->getExprLoc(); if (!findMacroSpelling(loc, "NULL")) return false; } int DiagType = (NullKind == Expr::NPCK_CXX11_nullptr); Diag(QuestionLoc, diag::err_typecheck_cond_incompatible_operands_null) << NonPointerExpr->getType() << DiagType << NonPointerExpr->getSourceRange(); return true; } /// Return false if the condition expression is valid, true otherwise. static bool checkCondition(Sema &S, Expr *Cond, SourceLocation QuestionLoc) { QualType CondTy = Cond->getType(); // OpenCL v1.1 s6.3.i says the condition cannot be a floating point type. if (S.getLangOpts().OpenCL && CondTy->isFloatingType()) { S.Diag(QuestionLoc, diag::err_typecheck_cond_expect_nonfloat) << CondTy << Cond->getSourceRange(); return true; } // C99 6.5.15p2 if (CondTy->isScalarType()) return false; S.Diag(QuestionLoc, diag::err_typecheck_cond_expect_scalar) << CondTy << Cond->getSourceRange(); return true; } /// Handle when one or both operands are void type. static QualType checkConditionalVoidType(Sema &S, ExprResult &LHS, ExprResult &RHS) { Expr *LHSExpr = LHS.get(); Expr *RHSExpr = RHS.get(); if (!LHSExpr->getType()->isVoidType()) S.Diag(RHSExpr->getBeginLoc(), diag::ext_typecheck_cond_one_void) << RHSExpr->getSourceRange(); if (!RHSExpr->getType()->isVoidType()) S.Diag(LHSExpr->getBeginLoc(), diag::ext_typecheck_cond_one_void) << LHSExpr->getSourceRange(); LHS = S.ImpCastExprToType(LHS.get(), S.Context.VoidTy, CK_ToVoid); RHS = S.ImpCastExprToType(RHS.get(), S.Context.VoidTy, CK_ToVoid); return S.Context.VoidTy; } /// Return false if the NullExpr can be promoted to PointerTy, /// true otherwise. static bool checkConditionalNullPointer(Sema &S, ExprResult &NullExpr, QualType PointerTy) { if ((!PointerTy->isAnyPointerType() && !PointerTy->isBlockPointerType()) || !NullExpr.get()->isNullPointerConstant(S.Context, Expr::NPC_ValueDependentIsNull)) return true; NullExpr = S.ImpCastExprToType(NullExpr.get(), PointerTy, CK_NullToPointer); return false; } /// Checks compatibility between two pointers and return the resulting /// type. static QualType checkConditionalPointerCompatibility(Sema &S, ExprResult &LHS, ExprResult &RHS, SourceLocation Loc) { QualType LHSTy = LHS.get()->getType(); QualType RHSTy = RHS.get()->getType(); if (S.Context.hasSameType(LHSTy, RHSTy)) { // Two identical pointers types are always compatible. return LHSTy; } QualType lhptee, rhptee; // Get the pointee types. bool IsBlockPointer = false; if (const BlockPointerType *LHSBTy = LHSTy->getAs()) { lhptee = LHSBTy->getPointeeType(); rhptee = RHSTy->castAs()->getPointeeType(); IsBlockPointer = true; } else { lhptee = LHSTy->castAs()->getPointeeType(); rhptee = RHSTy->castAs()->getPointeeType(); } // C99 6.5.15p6: If both operands are pointers to compatible types or to // differently qualified versions of compatible types, the result type is // a pointer to an appropriately qualified version of the composite // type. // Only CVR-qualifiers exist in the standard, and the differently-qualified // clause doesn't make sense for our extensions. E.g. address space 2 should // be incompatible with address space 3: they may live on different devices or // anything. Qualifiers lhQual = lhptee.getQualifiers(); Qualifiers rhQual = rhptee.getQualifiers(); LangAS ResultAddrSpace = LangAS::Default; LangAS LAddrSpace = lhQual.getAddressSpace(); LangAS RAddrSpace = rhQual.getAddressSpace(); // OpenCL v1.1 s6.5 - Conversion between pointers to distinct address // spaces is disallowed. if (lhQual.isAddressSpaceSupersetOf(rhQual)) ResultAddrSpace = LAddrSpace; else if (rhQual.isAddressSpaceSupersetOf(lhQual)) ResultAddrSpace = RAddrSpace; else { S.Diag(Loc, diag::err_typecheck_op_on_nonoverlapping_address_space_pointers) << LHSTy << RHSTy << 2 << LHS.get()->getSourceRange() << RHS.get()->getSourceRange(); return QualType(); } unsigned MergedCVRQual = lhQual.getCVRQualifiers() | rhQual.getCVRQualifiers(); auto LHSCastKind = CK_BitCast, RHSCastKind = CK_BitCast; lhQual.removeCVRQualifiers(); rhQual.removeCVRQualifiers(); // OpenCL v2.0 specification doesn't extend compatibility of type qualifiers // (C99 6.7.3) for address spaces. We assume that the check should behave in // the same manner as it's defined for CVR qualifiers, so for OpenCL two // qual types are compatible iff // * corresponded types are compatible // * CVR qualifiers are equal // * address spaces are equal // Thus for conditional operator we merge CVR and address space unqualified // pointees and if there is a composite type we return a pointer to it with // merged qualifiers. LHSCastKind = LAddrSpace == ResultAddrSpace ? CK_BitCast : CK_AddressSpaceConversion; RHSCastKind = RAddrSpace == ResultAddrSpace ? CK_BitCast : CK_AddressSpaceConversion; lhQual.removeAddressSpace(); rhQual.removeAddressSpace(); lhptee = S.Context.getQualifiedType(lhptee.getUnqualifiedType(), lhQual); rhptee = S.Context.getQualifiedType(rhptee.getUnqualifiedType(), rhQual); QualType CompositeTy = S.Context.mergeTypes(lhptee, rhptee); if (CompositeTy.isNull()) { // In this situation, we assume void* type. No especially good // reason, but this is what gcc does, and we do have to pick // to get a consistent AST. QualType incompatTy; incompatTy = S.Context.getPointerType( S.Context.getAddrSpaceQualType(S.Context.VoidTy, ResultAddrSpace)); LHS = S.ImpCastExprToType(LHS.get(), incompatTy, LHSCastKind); RHS = S.ImpCastExprToType(RHS.get(), incompatTy, RHSCastKind); // FIXME: For OpenCL the warning emission and cast to void* leaves a room // for casts between types with incompatible address space qualifiers. // For the following code the compiler produces casts between global and // local address spaces of the corresponded innermost pointees: // local int *global *a; // global int *global *b; // a = (0 ? a : b); // see C99 6.5.16.1.p1. S.Diag(Loc, diag::ext_typecheck_cond_incompatible_pointers) << LHSTy << RHSTy << LHS.get()->getSourceRange() << RHS.get()->getSourceRange(); return incompatTy; } // The pointer types are compatible. // In case of OpenCL ResultTy should have the address space qualifier // which is a superset of address spaces of both the 2nd and the 3rd // operands of the conditional operator. QualType ResultTy = [&, ResultAddrSpace]() { if (S.getLangOpts().OpenCL) { Qualifiers CompositeQuals = CompositeTy.getQualifiers(); CompositeQuals.setAddressSpace(ResultAddrSpace); return S.Context .getQualifiedType(CompositeTy.getUnqualifiedType(), CompositeQuals) .withCVRQualifiers(MergedCVRQual); } return CompositeTy.withCVRQualifiers(MergedCVRQual); }(); if (IsBlockPointer) ResultTy = S.Context.getBlockPointerType(ResultTy); else ResultTy = S.Context.getPointerType(ResultTy); LHS = S.ImpCastExprToType(LHS.get(), ResultTy, LHSCastKind); RHS = S.ImpCastExprToType(RHS.get(), ResultTy, RHSCastKind); return ResultTy; } /// Return the resulting type when the operands are both block pointers. static QualType checkConditionalBlockPointerCompatibility(Sema &S, ExprResult &LHS, ExprResult &RHS, SourceLocation Loc) { QualType LHSTy = LHS.get()->getType(); QualType RHSTy = RHS.get()->getType(); if (!LHSTy->isBlockPointerType() || !RHSTy->isBlockPointerType()) { if (LHSTy->isVoidPointerType() || RHSTy->isVoidPointerType()) { QualType destType = S.Context.getPointerType(S.Context.VoidTy); LHS = S.ImpCastExprToType(LHS.get(), destType, CK_BitCast); RHS = S.ImpCastExprToType(RHS.get(), destType, CK_BitCast); return destType; } S.Diag(Loc, diag::err_typecheck_cond_incompatible_operands) << LHSTy << RHSTy << LHS.get()->getSourceRange() << RHS.get()->getSourceRange(); return QualType(); } // We have 2 block pointer types. return checkConditionalPointerCompatibility(S, LHS, RHS, Loc); } /// Return the resulting type when the operands are both pointers. static QualType checkConditionalObjectPointersCompatibility(Sema &S, ExprResult &LHS, ExprResult &RHS, SourceLocation Loc) { // get the pointer types QualType LHSTy = LHS.get()->getType(); QualType RHSTy = RHS.get()->getType(); // get the "pointed to" types QualType lhptee = LHSTy->castAs()->getPointeeType(); QualType rhptee = RHSTy->castAs()->getPointeeType(); // ignore qualifiers on void (C99 6.5.15p3, clause 6) if (lhptee->isVoidType() && rhptee->isIncompleteOrObjectType()) { // Figure out necessary qualifiers (C99 6.5.15p6) QualType destPointee = S.Context.getQualifiedType(lhptee, rhptee.getQualifiers()); QualType destType = S.Context.getPointerType(destPointee); // Add qualifiers if necessary. LHS = S.ImpCastExprToType(LHS.get(), destType, CK_NoOp); // Promote to void*. RHS = S.ImpCastExprToType(RHS.get(), destType, CK_BitCast); return destType; } if (rhptee->isVoidType() && lhptee->isIncompleteOrObjectType()) { QualType destPointee = S.Context.getQualifiedType(rhptee, lhptee.getQualifiers()); QualType destType = S.Context.getPointerType(destPointee); // Add qualifiers if necessary. RHS = S.ImpCastExprToType(RHS.get(), destType, CK_NoOp); // Promote to void*. LHS = S.ImpCastExprToType(LHS.get(), destType, CK_BitCast); return destType; } return checkConditionalPointerCompatibility(S, LHS, RHS, Loc); } /// Return false if the first expression is not an integer and the second /// expression is not a pointer, true otherwise. static bool checkPointerIntegerMismatch(Sema &S, ExprResult &Int, Expr* PointerExpr, SourceLocation Loc, bool IsIntFirstExpr) { if (!PointerExpr->getType()->isPointerType() || !Int.get()->getType()->isIntegerType()) return false; Expr *Expr1 = IsIntFirstExpr ? Int.get() : PointerExpr; Expr *Expr2 = IsIntFirstExpr ? PointerExpr : Int.get(); S.Diag(Loc, diag::ext_typecheck_cond_pointer_integer_mismatch) << Expr1->getType() << Expr2->getType() << Expr1->getSourceRange() << Expr2->getSourceRange(); Int = S.ImpCastExprToType(Int.get(), PointerExpr->getType(), CK_IntegralToPointer); return true; } /// Simple conversion between integer and floating point types. /// /// Used when handling the OpenCL conditional operator where the /// condition is a vector while the other operands are scalar. /// /// OpenCL v1.1 s6.3.i and s6.11.6 together require that the scalar /// types are either integer or floating type. Between the two /// operands, the type with the higher rank is defined as the "result /// type". The other operand needs to be promoted to the same type. No /// other type promotion is allowed. We cannot use /// UsualArithmeticConversions() for this purpose, since it always /// promotes promotable types. static QualType OpenCLArithmeticConversions(Sema &S, ExprResult &LHS, ExprResult &RHS, SourceLocation QuestionLoc) { LHS = S.DefaultFunctionArrayLvalueConversion(LHS.get()); if (LHS.isInvalid()) return QualType(); RHS = S.DefaultFunctionArrayLvalueConversion(RHS.get()); if (RHS.isInvalid()) return QualType(); // For conversion purposes, we ignore any qualifiers. // For example, "const float" and "float" are equivalent. QualType LHSType = S.Context.getCanonicalType(LHS.get()->getType()).getUnqualifiedType(); QualType RHSType = S.Context.getCanonicalType(RHS.get()->getType()).getUnqualifiedType(); if (!LHSType->isIntegerType() && !LHSType->isRealFloatingType()) { S.Diag(QuestionLoc, diag::err_typecheck_cond_expect_int_float) << LHSType << LHS.get()->getSourceRange(); return QualType(); } if (!RHSType->isIntegerType() && !RHSType->isRealFloatingType()) { S.Diag(QuestionLoc, diag::err_typecheck_cond_expect_int_float) << RHSType << RHS.get()->getSourceRange(); return QualType(); } // If both types are identical, no conversion is needed. if (LHSType == RHSType) return LHSType; // Now handle "real" floating types (i.e. float, double, long double). if (LHSType->isRealFloatingType() || RHSType->isRealFloatingType()) return handleFloatConversion(S, LHS, RHS, LHSType, RHSType, /*IsCompAssign = */ false); // Finally, we have two differing integer types. return handleIntegerConversion (S, LHS, RHS, LHSType, RHSType, /*IsCompAssign = */ false); } /// Convert scalar operands to a vector that matches the /// condition in length. /// /// Used when handling the OpenCL conditional operator where the /// condition is a vector while the other operands are scalar. /// /// We first compute the "result type" for the scalar operands /// according to OpenCL v1.1 s6.3.i. Both operands are then converted /// into a vector of that type where the length matches the condition /// vector type. s6.11.6 requires that the element types of the result /// and the condition must have the same number of bits. static QualType OpenCLConvertScalarsToVectors(Sema &S, ExprResult &LHS, ExprResult &RHS, QualType CondTy, SourceLocation QuestionLoc) { QualType ResTy = OpenCLArithmeticConversions(S, LHS, RHS, QuestionLoc); if (ResTy.isNull()) return QualType(); const VectorType *CV = CondTy->getAs(); assert(CV); // Determine the vector result type unsigned NumElements = CV->getNumElements(); QualType VectorTy = S.Context.getExtVectorType(ResTy, NumElements); // Ensure that all types have the same number of bits if (S.Context.getTypeSize(CV->getElementType()) != S.Context.getTypeSize(ResTy)) { // Since VectorTy is created internally, it does not pretty print // with an OpenCL name. Instead, we just print a description. std::string EleTyName = ResTy.getUnqualifiedType().getAsString(); SmallString<64> Str; llvm::raw_svector_ostream OS(Str); OS << "(vector of " << NumElements << " '" << EleTyName << "' values)"; S.Diag(QuestionLoc, diag::err_conditional_vector_element_size) << CondTy << OS.str(); return QualType(); } // Convert operands to the vector result type LHS = S.ImpCastExprToType(LHS.get(), VectorTy, CK_VectorSplat); RHS = S.ImpCastExprToType(RHS.get(), VectorTy, CK_VectorSplat); return VectorTy; } /// Return false if this is a valid OpenCL condition vector static bool checkOpenCLConditionVector(Sema &S, Expr *Cond, SourceLocation QuestionLoc) { // OpenCL v1.1 s6.11.6 says the elements of the vector must be of // integral type. const VectorType *CondTy = Cond->getType()->getAs(); assert(CondTy); QualType EleTy = CondTy->getElementType(); if (EleTy->isIntegerType()) return false; S.Diag(QuestionLoc, diag::err_typecheck_cond_expect_nonfloat) << Cond->getType() << Cond->getSourceRange(); return true; } /// Return false if the vector condition type and the vector /// result type are compatible. /// /// OpenCL v1.1 s6.11.6 requires that both vector types have the same /// number of elements, and their element types have the same number /// of bits. static bool checkVectorResult(Sema &S, QualType CondTy, QualType VecResTy, SourceLocation QuestionLoc) { const VectorType *CV = CondTy->getAs(); const VectorType *RV = VecResTy->getAs(); assert(CV && RV); if (CV->getNumElements() != RV->getNumElements()) { S.Diag(QuestionLoc, diag::err_conditional_vector_size) << CondTy << VecResTy; return true; } QualType CVE = CV->getElementType(); QualType RVE = RV->getElementType(); if (S.Context.getTypeSize(CVE) != S.Context.getTypeSize(RVE)) { S.Diag(QuestionLoc, diag::err_conditional_vector_element_size) << CondTy << VecResTy; return true; } return false; } /// Return the resulting type for the conditional operator in /// OpenCL (aka "ternary selection operator", OpenCL v1.1 /// s6.3.i) when the condition is a vector type. static QualType OpenCLCheckVectorConditional(Sema &S, ExprResult &Cond, ExprResult &LHS, ExprResult &RHS, SourceLocation QuestionLoc) { Cond = S.DefaultFunctionArrayLvalueConversion(Cond.get()); if (Cond.isInvalid()) return QualType(); QualType CondTy = Cond.get()->getType(); if (checkOpenCLConditionVector(S, Cond.get(), QuestionLoc)) return QualType(); // If either operand is a vector then find the vector type of the // result as specified in OpenCL v1.1 s6.3.i. if (LHS.get()->getType()->isVectorType() || RHS.get()->getType()->isVectorType()) { QualType VecResTy = S.CheckVectorOperands(LHS, RHS, QuestionLoc, /*isCompAssign*/false, /*AllowBothBool*/true, /*AllowBoolConversions*/false); if (VecResTy.isNull()) return QualType(); // The result type must match the condition type as specified in // OpenCL v1.1 s6.11.6. if (checkVectorResult(S, CondTy, VecResTy, QuestionLoc)) return QualType(); return VecResTy; } // Both operands are scalar. return OpenCLConvertScalarsToVectors(S, LHS, RHS, CondTy, QuestionLoc); } /// Return true if the Expr is block type static bool checkBlockType(Sema &S, const Expr *E) { if (const CallExpr *CE = dyn_cast(E)) { QualType Ty = CE->getCallee()->getType(); if (Ty->isBlockPointerType()) { S.Diag(E->getExprLoc(), diag::err_opencl_ternary_with_block); return true; } } return false; } /// Note that LHS is not null here, even if this is the gnu "x ?: y" extension. /// In that case, LHS = cond. /// C99 6.5.15 QualType Sema::CheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, ExprResult &RHS, ExprValueKind &VK, ExprObjectKind &OK, SourceLocation QuestionLoc) { ExprResult LHSResult = CheckPlaceholderExpr(LHS.get()); if (!LHSResult.isUsable()) return QualType(); LHS = LHSResult; ExprResult RHSResult = CheckPlaceholderExpr(RHS.get()); if (!RHSResult.isUsable()) return QualType(); RHS = RHSResult; // C++ is sufficiently different to merit its own checker. if (getLangOpts().CPlusPlus) return CXXCheckConditionalOperands(Cond, LHS, RHS, VK, OK, QuestionLoc); VK = VK_RValue; OK = OK_Ordinary; // The OpenCL operator with a vector condition is sufficiently // different to merit its own checker. if (getLangOpts().OpenCL && Cond.get()->getType()->isVectorType()) return OpenCLCheckVectorConditional(*this, Cond, LHS, RHS, QuestionLoc); // First, check the condition. Cond = UsualUnaryConversions(Cond.get()); if (Cond.isInvalid()) return QualType(); if (checkCondition(*this, Cond.get(), QuestionLoc)) return QualType(); // Now check the two expressions. if (LHS.get()->getType()->isVectorType() || RHS.get()->getType()->isVectorType()) return CheckVectorOperands(LHS, RHS, QuestionLoc, /*isCompAssign*/false, /*AllowBothBool*/true, /*AllowBoolConversions*/false); QualType ResTy = UsualArithmeticConversions(LHS, RHS, QuestionLoc, ACK_Conditional); if (LHS.isInvalid() || RHS.isInvalid()) return QualType(); QualType LHSTy = LHS.get()->getType(); QualType RHSTy = RHS.get()->getType(); // Diagnose attempts to convert between __float128 and long double where // such conversions currently can't be handled. if (unsupportedTypeConversion(*this, LHSTy, RHSTy)) { Diag(QuestionLoc, diag::err_typecheck_cond_incompatible_operands) << LHSTy << RHSTy << LHS.get()->getSourceRange() << RHS.get()->getSourceRange(); return QualType(); } // OpenCL v2.0 s6.12.5 - Blocks cannot be used as expressions of the ternary // selection operator (?:). if (getLangOpts().OpenCL && (checkBlockType(*this, LHS.get()) | checkBlockType(*this, RHS.get()))) { return QualType(); } // If both operands have arithmetic type, do the usual arithmetic conversions // to find a common type: C99 6.5.15p3,5. if (LHSTy->isArithmeticType() && RHSTy->isArithmeticType()) { LHS = ImpCastExprToType(LHS.get(), ResTy, PrepareScalarCast(LHS, ResTy)); RHS = ImpCastExprToType(RHS.get(), ResTy, PrepareScalarCast(RHS, ResTy)); return ResTy; } // If both operands are the same structure or union type, the result is that // type. if (const RecordType *LHSRT = LHSTy->getAs()) { // C99 6.5.15p3 if (const RecordType *RHSRT = RHSTy->getAs()) if (LHSRT->getDecl() == RHSRT->getDecl()) // "If both the operands have structure or union type, the result has // that type." This implies that CV qualifiers are dropped. return LHSTy.getUnqualifiedType(); // FIXME: Type of conditional expression must be complete in C mode. } // C99 6.5.15p5: "If both operands have void type, the result has void type." // The following || allows only one side to be void (a GCC-ism). if (LHSTy->isVoidType() || RHSTy->isVoidType()) { return checkConditionalVoidType(*this, LHS, RHS); } // C99 6.5.15p6 - "if one operand is a null pointer constant, the result has // the type of the other operand." if (!checkConditionalNullPointer(*this, RHS, LHSTy)) return LHSTy; if (!checkConditionalNullPointer(*this, LHS, RHSTy)) return RHSTy; // All objective-c pointer type analysis is done here. QualType compositeType = FindCompositeObjCPointerType(LHS, RHS, QuestionLoc); if (LHS.isInvalid() || RHS.isInvalid()) return QualType(); if (!compositeType.isNull()) return compositeType; // Handle block pointer types. if (LHSTy->isBlockPointerType() || RHSTy->isBlockPointerType()) return checkConditionalBlockPointerCompatibility(*this, LHS, RHS, QuestionLoc); // Check constraints for C object pointers types (C99 6.5.15p3,6). if (LHSTy->isPointerType() && RHSTy->isPointerType()) return checkConditionalObjectPointersCompatibility(*this, LHS, RHS, QuestionLoc); // GCC compatibility: soften pointer/integer mismatch. Note that // null pointers have been filtered out by this point. if (checkPointerIntegerMismatch(*this, LHS, RHS.get(), QuestionLoc, /*IsIntFirstExpr=*/true)) return RHSTy; if (checkPointerIntegerMismatch(*this, RHS, LHS.get(), QuestionLoc, /*IsIntFirstExpr=*/false)) return LHSTy; // Emit a better diagnostic if one of the expressions is a null pointer // constant and the other is not a pointer type. In this case, the user most // likely forgot to take the address of the other expression. if (DiagnoseConditionalForNull(LHS.get(), RHS.get(), QuestionLoc)) return QualType(); // Otherwise, the operands are not compatible. Diag(QuestionLoc, diag::err_typecheck_cond_incompatible_operands) << LHSTy << RHSTy << LHS.get()->getSourceRange() << RHS.get()->getSourceRange(); return QualType(); } /// FindCompositeObjCPointerType - Helper method to find composite type of /// two objective-c pointer types of the two input expressions. QualType Sema::FindCompositeObjCPointerType(ExprResult &LHS, ExprResult &RHS, SourceLocation QuestionLoc) { QualType LHSTy = LHS.get()->getType(); QualType RHSTy = RHS.get()->getType(); // Handle things like Class and struct objc_class*. Here we case the result // to the pseudo-builtin, because that will be implicitly cast back to the // redefinition type if an attempt is made to access its fields. if (LHSTy->isObjCClassType() && (Context.hasSameType(RHSTy, Context.getObjCClassRedefinitionType()))) { RHS = ImpCastExprToType(RHS.get(), LHSTy, CK_CPointerToObjCPointerCast); return LHSTy; } if (RHSTy->isObjCClassType() && (Context.hasSameType(LHSTy, Context.getObjCClassRedefinitionType()))) { LHS = ImpCastExprToType(LHS.get(), RHSTy, CK_CPointerToObjCPointerCast); return RHSTy; } // And the same for struct objc_object* / id if (LHSTy->isObjCIdType() && (Context.hasSameType(RHSTy, Context.getObjCIdRedefinitionType()))) { RHS = ImpCastExprToType(RHS.get(), LHSTy, CK_CPointerToObjCPointerCast); return LHSTy; } if (RHSTy->isObjCIdType() && (Context.hasSameType(LHSTy, Context.getObjCIdRedefinitionType()))) { LHS = ImpCastExprToType(LHS.get(), RHSTy, CK_CPointerToObjCPointerCast); return RHSTy; } // And the same for struct objc_selector* / SEL if (Context.isObjCSelType(LHSTy) && (Context.hasSameType(RHSTy, Context.getObjCSelRedefinitionType()))) { RHS = ImpCastExprToType(RHS.get(), LHSTy, CK_BitCast); return LHSTy; } if (Context.isObjCSelType(RHSTy) && (Context.hasSameType(LHSTy, Context.getObjCSelRedefinitionType()))) { LHS = ImpCastExprToType(LHS.get(), RHSTy, CK_BitCast); return RHSTy; } // Check constraints for Objective-C object pointers types. if (LHSTy->isObjCObjectPointerType() && RHSTy->isObjCObjectPointerType()) { if (Context.getCanonicalType(LHSTy) == Context.getCanonicalType(RHSTy)) { // Two identical object pointer types are always compatible. return LHSTy; } const ObjCObjectPointerType *LHSOPT = LHSTy->castAs(); const ObjCObjectPointerType *RHSOPT = RHSTy->castAs(); QualType compositeType = LHSTy; // If both operands are interfaces and either operand can be // assigned to the other, use that type as the composite // type. This allows // xxx ? (A*) a : (B*) b // where B is a subclass of A. // // Additionally, as for assignment, if either type is 'id' // allow silent coercion. Finally, if the types are // incompatible then make sure to use 'id' as the composite // type so the result is acceptable for sending messages to. // FIXME: Consider unifying with 'areComparableObjCPointerTypes'. // It could return the composite type. if (!(compositeType = Context.areCommonBaseCompatible(LHSOPT, RHSOPT)).isNull()) { // Nothing more to do. } else if (Context.canAssignObjCInterfaces(LHSOPT, RHSOPT)) { compositeType = RHSOPT->isObjCBuiltinType() ? RHSTy : LHSTy; } else if (Context.canAssignObjCInterfaces(RHSOPT, LHSOPT)) { compositeType = LHSOPT->isObjCBuiltinType() ? LHSTy : RHSTy; } else if ((LHSOPT->isObjCQualifiedIdType() || RHSOPT->isObjCQualifiedIdType()) && Context.ObjCQualifiedIdTypesAreCompatible(LHSOPT, RHSOPT, true)) { // Need to handle "id" explicitly. // GCC allows qualified id and any Objective-C type to devolve to // id. Currently localizing to here until clear this should be // part of ObjCQualifiedIdTypesAreCompatible. compositeType = Context.getObjCIdType(); } else if (LHSTy->isObjCIdType() || RHSTy->isObjCIdType()) { compositeType = Context.getObjCIdType(); } else { Diag(QuestionLoc, diag::ext_typecheck_cond_incompatible_operands) << LHSTy << RHSTy << LHS.get()->getSourceRange() << RHS.get()->getSourceRange(); QualType incompatTy = Context.getObjCIdType(); LHS = ImpCastExprToType(LHS.get(), incompatTy, CK_BitCast); RHS = ImpCastExprToType(RHS.get(), incompatTy, CK_BitCast); return incompatTy; } // The object pointer types are compatible. LHS = ImpCastExprToType(LHS.get(), compositeType, CK_BitCast); RHS = ImpCastExprToType(RHS.get(), compositeType, CK_BitCast); return compositeType; } // Check Objective-C object pointer types and 'void *' if (LHSTy->isVoidPointerType() && RHSTy->isObjCObjectPointerType()) { if (getLangOpts().ObjCAutoRefCount) { // ARC forbids the implicit conversion of object pointers to 'void *', // so these types are not compatible. Diag(QuestionLoc, diag::err_cond_voidptr_arc) << LHSTy << RHSTy << LHS.get()->getSourceRange() << RHS.get()->getSourceRange(); LHS = RHS = true; return QualType(); } QualType lhptee = LHSTy->castAs()->getPointeeType(); QualType rhptee = RHSTy->castAs()->getPointeeType(); QualType destPointee = Context.getQualifiedType(lhptee, rhptee.getQualifiers()); QualType destType = Context.getPointerType(destPointee); // Add qualifiers if necessary. LHS = ImpCastExprToType(LHS.get(), destType, CK_NoOp); // Promote to void*. RHS = ImpCastExprToType(RHS.get(), destType, CK_BitCast); return destType; } if (LHSTy->isObjCObjectPointerType() && RHSTy->isVoidPointerType()) { if (getLangOpts().ObjCAutoRefCount) { // ARC forbids the implicit conversion of object pointers to 'void *', // so these types are not compatible. Diag(QuestionLoc, diag::err_cond_voidptr_arc) << LHSTy << RHSTy << LHS.get()->getSourceRange() << RHS.get()->getSourceRange(); LHS = RHS = true; return QualType(); } QualType lhptee = LHSTy->castAs()->getPointeeType(); QualType rhptee = RHSTy->castAs()->getPointeeType(); QualType destPointee = Context.getQualifiedType(rhptee, lhptee.getQualifiers()); QualType destType = Context.getPointerType(destPointee); // Add qualifiers if necessary. RHS = ImpCastExprToType(RHS.get(), destType, CK_NoOp); // Promote to void*. LHS = ImpCastExprToType(LHS.get(), destType, CK_BitCast); return destType; } return QualType(); } /// SuggestParentheses - Emit a note with a fixit hint that wraps /// ParenRange in parentheses. static void SuggestParentheses(Sema &Self, SourceLocation Loc, const PartialDiagnostic &Note, SourceRange ParenRange) { SourceLocation EndLoc = Self.getLocForEndOfToken(ParenRange.getEnd()); if (ParenRange.getBegin().isFileID() && ParenRange.getEnd().isFileID() && EndLoc.isValid()) { Self.Diag(Loc, Note) << FixItHint::CreateInsertion(ParenRange.getBegin(), "(") << FixItHint::CreateInsertion(EndLoc, ")"); } else { // We can't display the parentheses, so just show the bare note. Self.Diag(Loc, Note) << ParenRange; } } static bool IsArithmeticOp(BinaryOperatorKind Opc) { return BinaryOperator::isAdditiveOp(Opc) || BinaryOperator::isMultiplicativeOp(Opc) || BinaryOperator::isShiftOp(Opc) || Opc == BO_And || Opc == BO_Or; // This only checks for bitwise-or and bitwise-and, but not bitwise-xor and // not any of the logical operators. Bitwise-xor is commonly used as a // logical-xor because there is no logical-xor operator. The logical // operators, including uses of xor, have a high false positive rate for // precedence warnings. } /// IsArithmeticBinaryExpr - Returns true if E is an arithmetic binary /// expression, either using a built-in or overloaded operator, /// and sets *OpCode to the opcode and *RHSExprs to the right-hand side /// expression. static bool IsArithmeticBinaryExpr(Expr *E, BinaryOperatorKind *Opcode, Expr **RHSExprs) { // Don't strip parenthesis: we should not warn if E is in parenthesis. E = E->IgnoreImpCasts(); E = E->IgnoreConversionOperator(); E = E->IgnoreImpCasts(); if (auto *MTE = dyn_cast(E)) { E = MTE->getSubExpr(); E = E->IgnoreImpCasts(); } // Built-in binary operator. if (BinaryOperator *OP = dyn_cast(E)) { if (IsArithmeticOp(OP->getOpcode())) { *Opcode = OP->getOpcode(); *RHSExprs = OP->getRHS(); return true; } } // Overloaded operator. if (CXXOperatorCallExpr *Call = dyn_cast(E)) { if (Call->getNumArgs() != 2) return false; // Make sure this is really a binary operator that is safe to pass into // BinaryOperator::getOverloadedOpcode(), e.g. it's not a subscript op. OverloadedOperatorKind OO = Call->getOperator(); if (OO < OO_Plus || OO > OO_Arrow || OO == OO_PlusPlus || OO == OO_MinusMinus) return false; BinaryOperatorKind OpKind = BinaryOperator::getOverloadedOpcode(OO); if (IsArithmeticOp(OpKind)) { *Opcode = OpKind; *RHSExprs = Call->getArg(1); return true; } } return false; } /// ExprLooksBoolean - Returns true if E looks boolean, i.e. it has boolean type /// or is a logical expression such as (x==y) which has int type, but is /// commonly interpreted as boolean. static bool ExprLooksBoolean(Expr *E) { E = E->IgnoreParenImpCasts(); if (E->getType()->isBooleanType()) return true; if (BinaryOperator *OP = dyn_cast(E)) return OP->isComparisonOp() || OP->isLogicalOp(); if (UnaryOperator *OP = dyn_cast(E)) return OP->getOpcode() == UO_LNot; if (E->getType()->isPointerType()) return true; // FIXME: What about overloaded operator calls returning "unspecified boolean // type"s (commonly pointer-to-members)? return false; } /// DiagnoseConditionalPrecedence - Emit a warning when a conditional operator /// and binary operator are mixed in a way that suggests the programmer assumed /// the conditional operator has higher precedence, for example: /// "int x = a + someBinaryCondition ? 1 : 2". static void DiagnoseConditionalPrecedence(Sema &Self, SourceLocation OpLoc, Expr *Condition, Expr *LHSExpr, Expr *RHSExpr) { BinaryOperatorKind CondOpcode; Expr *CondRHS; if (!IsArithmeticBinaryExpr(Condition, &CondOpcode, &CondRHS)) return; if (!ExprLooksBoolean(CondRHS)) return; // The condition is an arithmetic binary expression, with a right- // hand side that looks boolean, so warn. unsigned DiagID = BinaryOperator::isBitwiseOp(CondOpcode) ? diag::warn_precedence_bitwise_conditional : diag::warn_precedence_conditional; Self.Diag(OpLoc, DiagID) << Condition->getSourceRange() << BinaryOperator::getOpcodeStr(CondOpcode); SuggestParentheses( Self, OpLoc, Self.PDiag(diag::note_precedence_silence) << BinaryOperator::getOpcodeStr(CondOpcode), SourceRange(Condition->getBeginLoc(), Condition->getEndLoc())); SuggestParentheses(Self, OpLoc, Self.PDiag(diag::note_precedence_conditional_first), SourceRange(CondRHS->getBeginLoc(), RHSExpr->getEndLoc())); } /// Compute the nullability of a conditional expression. static QualType computeConditionalNullability(QualType ResTy, bool IsBin, QualType LHSTy, QualType RHSTy, ASTContext &Ctx) { if (!ResTy->isAnyPointerType()) return ResTy; auto GetNullability = [&Ctx](QualType Ty) { Optional Kind = Ty->getNullability(Ctx); if (Kind) return *Kind; return NullabilityKind::Unspecified; }; auto LHSKind = GetNullability(LHSTy), RHSKind = GetNullability(RHSTy); NullabilityKind MergedKind; // Compute nullability of a binary conditional expression. if (IsBin) { if (LHSKind == NullabilityKind::NonNull) MergedKind = NullabilityKind::NonNull; else MergedKind = RHSKind; // Compute nullability of a normal conditional expression. } else { if (LHSKind == NullabilityKind::Nullable || RHSKind == NullabilityKind::Nullable) MergedKind = NullabilityKind::Nullable; else if (LHSKind == NullabilityKind::NonNull) MergedKind = RHSKind; else if (RHSKind == NullabilityKind::NonNull) MergedKind = LHSKind; else MergedKind = NullabilityKind::Unspecified; } // Return if ResTy already has the correct nullability. if (GetNullability(ResTy) == MergedKind) return ResTy; // Strip all nullability from ResTy. while (ResTy->getNullability(Ctx)) ResTy = ResTy.getSingleStepDesugaredType(Ctx); // Create a new AttributedType with the new nullability kind. auto NewAttr = AttributedType::getNullabilityAttrKind(MergedKind); return Ctx.getAttributedType(NewAttr, ResTy, ResTy); } /// ActOnConditionalOp - Parse a ?: operation. Note that 'LHS' may be null /// in the case of a the GNU conditional expr extension. ExprResult Sema::ActOnConditionalOp(SourceLocation QuestionLoc, SourceLocation ColonLoc, Expr *CondExpr, Expr *LHSExpr, Expr *RHSExpr) { if (!getLangOpts().CPlusPlus) { // C cannot handle TypoExpr nodes in the condition because it // doesn't handle dependent types properly, so make sure any TypoExprs have // been dealt with before checking the operands. ExprResult CondResult = CorrectDelayedTyposInExpr(CondExpr); ExprResult LHSResult = CorrectDelayedTyposInExpr(LHSExpr); ExprResult RHSResult = CorrectDelayedTyposInExpr(RHSExpr); if (!CondResult.isUsable()) return ExprError(); if (LHSExpr) { if (!LHSResult.isUsable()) return ExprError(); } if (!RHSResult.isUsable()) return ExprError(); CondExpr = CondResult.get(); LHSExpr = LHSResult.get(); RHSExpr = RHSResult.get(); } // If this is the gnu "x ?: y" extension, analyze the types as though the LHS // was the condition. OpaqueValueExpr *opaqueValue = nullptr; Expr *commonExpr = nullptr; if (!LHSExpr) { commonExpr = CondExpr; // Lower out placeholder types first. This is important so that we don't // try to capture a placeholder. This happens in few cases in C++; such // as Objective-C++'s dictionary subscripting syntax. if (commonExpr->hasPlaceholderType()) { ExprResult result = CheckPlaceholderExpr(commonExpr); if (!result.isUsable()) return ExprError(); commonExpr = result.get(); } // We usually want to apply unary conversions *before* saving, except // in the special case of a C++ l-value conditional. if (!(getLangOpts().CPlusPlus && !commonExpr->isTypeDependent() && commonExpr->getValueKind() == RHSExpr->getValueKind() && commonExpr->isGLValue() && commonExpr->isOrdinaryOrBitFieldObject() && RHSExpr->isOrdinaryOrBitFieldObject() && Context.hasSameType(commonExpr->getType(), RHSExpr->getType()))) { ExprResult commonRes = UsualUnaryConversions(commonExpr); if (commonRes.isInvalid()) return ExprError(); commonExpr = commonRes.get(); } // If the common expression is a class or array prvalue, materialize it // so that we can safely refer to it multiple times. if (commonExpr->isRValue() && (commonExpr->getType()->isRecordType() || commonExpr->getType()->isArrayType())) { ExprResult MatExpr = TemporaryMaterializationConversion(commonExpr); if (MatExpr.isInvalid()) return ExprError(); commonExpr = MatExpr.get(); } opaqueValue = new (Context) OpaqueValueExpr(commonExpr->getExprLoc(), commonExpr->getType(), commonExpr->getValueKind(), commonExpr->getObjectKind(), commonExpr); LHSExpr = CondExpr = opaqueValue; } QualType LHSTy = LHSExpr->getType(), RHSTy = RHSExpr->getType(); ExprValueKind VK = VK_RValue; ExprObjectKind OK = OK_Ordinary; ExprResult Cond = CondExpr, LHS = LHSExpr, RHS = RHSExpr; QualType result = CheckConditionalOperands(Cond, LHS, RHS, VK, OK, QuestionLoc); if (result.isNull() || Cond.isInvalid() || LHS.isInvalid() || RHS.isInvalid()) return ExprError(); DiagnoseConditionalPrecedence(*this, QuestionLoc, Cond.get(), LHS.get(), RHS.get()); CheckBoolLikeConversion(Cond.get(), QuestionLoc); result = computeConditionalNullability(result, commonExpr, LHSTy, RHSTy, Context); if (!commonExpr) return new (Context) ConditionalOperator(Cond.get(), QuestionLoc, LHS.get(), ColonLoc, RHS.get(), result, VK, OK); return new (Context) BinaryConditionalOperator( commonExpr, opaqueValue, Cond.get(), LHS.get(), RHS.get(), QuestionLoc, ColonLoc, result, VK, OK); } // checkPointerTypesForAssignment - This is a very tricky routine (despite // being closely modeled after the C99 spec:-). The odd characteristic of this // routine is it effectively iqnores the qualifiers on the top level pointee. // This circumvents the usual type rules specified in 6.2.7p1 & 6.7.5.[1-3]. // FIXME: add a couple examples in this comment. static Sema::AssignConvertType checkPointerTypesForAssignment(Sema &S, QualType LHSType, QualType RHSType) { assert(LHSType.isCanonical() && "LHS not canonicalized!"); assert(RHSType.isCanonical() && "RHS not canonicalized!"); // get the "pointed to" type (ignoring qualifiers at the top level) const Type *lhptee, *rhptee; Qualifiers lhq, rhq; std::tie(lhptee, lhq) = cast(LHSType)->getPointeeType().split().asPair(); std::tie(rhptee, rhq) = cast(RHSType)->getPointeeType().split().asPair(); Sema::AssignConvertType ConvTy = Sema::Compatible; // C99 6.5.16.1p1: This following citation is common to constraints // 3 & 4 (below). ...and the type *pointed to* by the left has all the // qualifiers of the type *pointed to* by the right; // As a special case, 'non-__weak A *' -> 'non-__weak const *' is okay. if (lhq.getObjCLifetime() != rhq.getObjCLifetime() && lhq.compatiblyIncludesObjCLifetime(rhq)) { // Ignore lifetime for further calculation. lhq.removeObjCLifetime(); rhq.removeObjCLifetime(); } if (!lhq.compatiblyIncludes(rhq)) { // Treat address-space mismatches as fatal. if (!lhq.isAddressSpaceSupersetOf(rhq)) return Sema::IncompatiblePointerDiscardsQualifiers; // It's okay to add or remove GC or lifetime qualifiers when converting to // and from void*. else if (lhq.withoutObjCGCAttr().withoutObjCLifetime() .compatiblyIncludes( rhq.withoutObjCGCAttr().withoutObjCLifetime()) && (lhptee->isVoidType() || rhptee->isVoidType())) ; // keep old // Treat lifetime mismatches as fatal. else if (lhq.getObjCLifetime() != rhq.getObjCLifetime()) ConvTy = Sema::IncompatiblePointerDiscardsQualifiers; // For GCC/MS compatibility, other qualifier mismatches are treated // as still compatible in C. else ConvTy = Sema::CompatiblePointerDiscardsQualifiers; } // C99 6.5.16.1p1 (constraint 4): If one operand is a pointer to an object or // incomplete type and the other is a pointer to a qualified or unqualified // version of void... if (lhptee->isVoidType()) { if (rhptee->isIncompleteOrObjectType()) return ConvTy; // As an extension, we allow cast to/from void* to function pointer. assert(rhptee->isFunctionType()); return Sema::FunctionVoidPointer; } if (rhptee->isVoidType()) { if (lhptee->isIncompleteOrObjectType()) return ConvTy; // As an extension, we allow cast to/from void* to function pointer. assert(lhptee->isFunctionType()); return Sema::FunctionVoidPointer; } // C99 6.5.16.1p1 (constraint 3): both operands are pointers to qualified or // unqualified versions of compatible types, ... QualType ltrans = QualType(lhptee, 0), rtrans = QualType(rhptee, 0); if (!S.Context.typesAreCompatible(ltrans, rtrans)) { // Check if the pointee types are compatible ignoring the sign. // We explicitly check for char so that we catch "char" vs // "unsigned char" on systems where "char" is unsigned. if (lhptee->isCharType()) ltrans = S.Context.UnsignedCharTy; else if (lhptee->hasSignedIntegerRepresentation()) ltrans = S.Context.getCorrespondingUnsignedType(ltrans); if (rhptee->isCharType()) rtrans = S.Context.UnsignedCharTy; else if (rhptee->hasSignedIntegerRepresentation()) rtrans = S.Context.getCorrespondingUnsignedType(rtrans); if (ltrans == rtrans) { // Types are compatible ignoring the sign. Qualifier incompatibility // takes priority over sign incompatibility because the sign // warning can be disabled. if (ConvTy != Sema::Compatible) return ConvTy; return Sema::IncompatiblePointerSign; } // If we are a multi-level pointer, it's possible that our issue is simply // one of qualification - e.g. char ** -> const char ** is not allowed. If // the eventual target type is the same and the pointers have the same // level of indirection, this must be the issue. if (isa(lhptee) && isa(rhptee)) { do { std::tie(lhptee, lhq) = cast(lhptee)->getPointeeType().split().asPair(); std::tie(rhptee, rhq) = cast(rhptee)->getPointeeType().split().asPair(); // Inconsistent address spaces at this point is invalid, even if the // address spaces would be compatible. // FIXME: This doesn't catch address space mismatches for pointers of // different nesting levels, like: // __local int *** a; // int ** b = a; // It's not clear how to actually determine when such pointers are // invalidly incompatible. if (lhq.getAddressSpace() != rhq.getAddressSpace()) return Sema::IncompatibleNestedPointerAddressSpaceMismatch; } while (isa(lhptee) && isa(rhptee)); if (lhptee == rhptee) return Sema::IncompatibleNestedPointerQualifiers; } // General pointer incompatibility takes priority over qualifiers. return Sema::IncompatiblePointer; } if (!S.getLangOpts().CPlusPlus && S.IsFunctionConversion(ltrans, rtrans, ltrans)) return Sema::IncompatiblePointer; return ConvTy; } /// checkBlockPointerTypesForAssignment - This routine determines whether two /// block pointer types are compatible or whether a block and normal pointer /// are compatible. It is more restrict than comparing two function pointer // types. static Sema::AssignConvertType checkBlockPointerTypesForAssignment(Sema &S, QualType LHSType, QualType RHSType) { assert(LHSType.isCanonical() && "LHS not canonicalized!"); assert(RHSType.isCanonical() && "RHS not canonicalized!"); QualType lhptee, rhptee; // get the "pointed to" type (ignoring qualifiers at the top level) lhptee = cast(LHSType)->getPointeeType(); rhptee = cast(RHSType)->getPointeeType(); // In C++, the types have to match exactly. if (S.getLangOpts().CPlusPlus) return Sema::IncompatibleBlockPointer; Sema::AssignConvertType ConvTy = Sema::Compatible; // For blocks we enforce that qualifiers are identical. Qualifiers LQuals = lhptee.getLocalQualifiers(); Qualifiers RQuals = rhptee.getLocalQualifiers(); if (S.getLangOpts().OpenCL) { LQuals.removeAddressSpace(); RQuals.removeAddressSpace(); } if (LQuals != RQuals) ConvTy = Sema::CompatiblePointerDiscardsQualifiers; // FIXME: OpenCL doesn't define the exact compile time semantics for a block // assignment. // The current behavior is similar to C++ lambdas. A block might be // assigned to a variable iff its return type and parameters are compatible // (C99 6.2.7) with the corresponding return type and parameters of the LHS of // an assignment. Presumably it should behave in way that a function pointer // assignment does in C, so for each parameter and return type: // * CVR and address space of LHS should be a superset of CVR and address // space of RHS. // * unqualified types should be compatible. if (S.getLangOpts().OpenCL) { if (!S.Context.typesAreBlockPointerCompatible( S.Context.getQualifiedType(LHSType.getUnqualifiedType(), LQuals), S.Context.getQualifiedType(RHSType.getUnqualifiedType(), RQuals))) return Sema::IncompatibleBlockPointer; } else if (!S.Context.typesAreBlockPointerCompatible(LHSType, RHSType)) return Sema::IncompatibleBlockPointer; return ConvTy; } /// checkObjCPointerTypesForAssignment - Compares two objective-c pointer types /// for assignment compatibility. static Sema::AssignConvertType checkObjCPointerTypesForAssignment(Sema &S, QualType LHSType, QualType RHSType) { assert(LHSType.isCanonical() && "LHS was not canonicalized!"); assert(RHSType.isCanonical() && "RHS was not canonicalized!"); if (LHSType->isObjCBuiltinType()) { // Class is not compatible with ObjC object pointers. if (LHSType->isObjCClassType() && !RHSType->isObjCBuiltinType() && !RHSType->isObjCQualifiedClassType()) return Sema::IncompatiblePointer; return Sema::Compatible; } if (RHSType->isObjCBuiltinType()) { if (RHSType->isObjCClassType() && !LHSType->isObjCBuiltinType() && !LHSType->isObjCQualifiedClassType()) return Sema::IncompatiblePointer; return Sema::Compatible; } QualType lhptee = LHSType->castAs()->getPointeeType(); QualType rhptee = RHSType->castAs()->getPointeeType(); if (!lhptee.isAtLeastAsQualifiedAs(rhptee) && // make an exception for id

!LHSType->isObjCQualifiedIdType()) return Sema::CompatiblePointerDiscardsQualifiers; if (S.Context.typesAreCompatible(LHSType, RHSType)) return Sema::Compatible; if (LHSType->isObjCQualifiedIdType() || RHSType->isObjCQualifiedIdType()) return Sema::IncompatibleObjCQualifiedId; return Sema::IncompatiblePointer; } Sema::AssignConvertType Sema::CheckAssignmentConstraints(SourceLocation Loc, QualType LHSType, QualType RHSType) { // Fake up an opaque expression. We don't actually care about what // cast operations are required, so if CheckAssignmentConstraints // adds casts to this they'll be wasted, but fortunately that doesn't // usually happen on valid code. OpaqueValueExpr RHSExpr(Loc, RHSType, VK_RValue); ExprResult RHSPtr = &RHSExpr; CastKind K; return CheckAssignmentConstraints(LHSType, RHSPtr, K, /*ConvertRHS=*/false); } /// This helper function returns true if QT is a vector type that has element /// type ElementType. static bool isVector(QualType QT, QualType ElementType) { if (const VectorType *VT = QT->getAs()) return VT->getElementType() == ElementType; return false; } /// CheckAssignmentConstraints (C99 6.5.16) - This routine currently /// has code to accommodate several GCC extensions when type checking /// pointers. Here are some objectionable examples that GCC considers warnings: /// /// int a, *pint; /// short *pshort; /// struct foo *pfoo; /// /// pint = pshort; // warning: assignment from incompatible pointer type /// a = pint; // warning: assignment makes integer from pointer without a cast /// pint = a; // warning: assignment makes pointer from integer without a cast /// pint = pfoo; // warning: assignment from incompatible pointer type /// /// As a result, the code for dealing with pointers is more complex than the /// C99 spec dictates. /// /// Sets 'Kind' for any result kind except Incompatible. Sema::AssignConvertType Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS, CastKind &Kind, bool ConvertRHS) { QualType RHSType = RHS.get()->getType(); QualType OrigLHSType = LHSType; // Get canonical types. We're not formatting these types, just comparing // them. LHSType = Context.getCanonicalType(LHSType).getUnqualifiedType(); RHSType = Context.getCanonicalType(RHSType).getUnqualifiedType(); // Common case: no conversion required. if (LHSType == RHSType) { Kind = CK_NoOp; return Compatible; } // If we have an atomic type, try a non-atomic assignment, then just add an // atomic qualification step. if (const AtomicType *AtomicTy = dyn_cast(LHSType)) { Sema::AssignConvertType result = CheckAssignmentConstraints(AtomicTy->getValueType(), RHS, Kind); if (result != Compatible) return result; if (Kind != CK_NoOp && ConvertRHS) RHS = ImpCastExprToType(RHS.get(), AtomicTy->getValueType(), Kind); Kind = CK_NonAtomicToAtomic; return Compatible; } // If the left-hand side is a reference type, then we are in a // (rare!) case where we've allowed the use of references in C, // e.g., as a parameter type in a built-in function. In this case, // just make sure that the type referenced is compatible with the // right-hand side type. The caller is responsible for adjusting // LHSType so that the resulting expression does not have reference // type. if (const ReferenceType *LHSTypeRef = LHSType->getAs()) { if (Context.typesAreCompatible(LHSTypeRef->getPointeeType(), RHSType)) { Kind = CK_LValueBitCast; return Compatible; } return Incompatible; } // Allow scalar to ExtVector assignments, and assignments of an ExtVector type // to the same ExtVector type. if (LHSType->isExtVectorType()) { if (RHSType->isExtVectorType()) return Incompatible; if (RHSType->isArithmeticType()) { // CK_VectorSplat does T -> vector T, so first cast to the element type. if (ConvertRHS) RHS = prepareVectorSplat(LHSType, RHS.get()); Kind = CK_VectorSplat; return Compatible; } } // Conversions to or from vector type. if (LHSType->isVectorType() || RHSType->isVectorType()) { if (LHSType->isVectorType() && RHSType->isVectorType()) { // Allow assignments of an AltiVec vector type to an equivalent GCC // vector type and vice versa if (Context.areCompatibleVectorTypes(LHSType, RHSType)) { Kind = CK_BitCast; return Compatible; } // If we are allowing lax vector conversions, and LHS and RHS are both // vectors, the total size only needs to be the same. This is a bitcast; // no bits are changed but the result type is different. if (isLaxVectorConversion(RHSType, LHSType)) { Kind = CK_BitCast; return IncompatibleVectors; } } // When the RHS comes from another lax conversion (e.g. binops between // scalars and vectors) the result is canonicalized as a vector. When the // LHS is also a vector, the lax is allowed by the condition above. Handle // the case where LHS is a scalar. if (LHSType->isScalarType()) { const VectorType *VecType = RHSType->getAs(); if (VecType && VecType->getNumElements() == 1 && isLaxVectorConversion(RHSType, LHSType)) { ExprResult *VecExpr = &RHS; *VecExpr = ImpCastExprToType(VecExpr->get(), LHSType, CK_BitCast); Kind = CK_BitCast; return Compatible; } } return Incompatible; } // Diagnose attempts to convert between __float128 and long double where // such conversions currently can't be handled. if (unsupportedTypeConversion(*this, LHSType, RHSType)) return Incompatible; // Disallow assigning a _Complex to a real type in C++ mode since it simply // discards the imaginary part. if (getLangOpts().CPlusPlus && RHSType->getAs() && !LHSType->getAs()) return Incompatible; // Arithmetic conversions. if (LHSType->isArithmeticType() && RHSType->isArithmeticType() && !(getLangOpts().CPlusPlus && LHSType->isEnumeralType())) { if (ConvertRHS) Kind = PrepareScalarCast(RHS, LHSType); return Compatible; } // Conversions to normal pointers. if (const PointerType *LHSPointer = dyn_cast(LHSType)) { // U* -> T* if (isa(RHSType)) { LangAS AddrSpaceL = LHSPointer->getPointeeType().getAddressSpace(); LangAS AddrSpaceR = RHSType->getPointeeType().getAddressSpace(); if (AddrSpaceL != AddrSpaceR) Kind = CK_AddressSpaceConversion; else if (Context.hasCvrSimilarType(RHSType, LHSType)) Kind = CK_NoOp; else Kind = CK_BitCast; return checkPointerTypesForAssignment(*this, LHSType, RHSType); } // int -> T* if (RHSType->isIntegerType()) { Kind = CK_IntegralToPointer; // FIXME: null? return IntToPointer; } // C pointers are not compatible with ObjC object pointers, // with two exceptions: if (isa(RHSType)) { // - conversions to void* if (LHSPointer->getPointeeType()->isVoidType()) { Kind = CK_BitCast; return Compatible; } // - conversions from 'Class' to the redefinition type if (RHSType->isObjCClassType() && Context.hasSameType(LHSType, Context.getObjCClassRedefinitionType())) { Kind = CK_BitCast; return Compatible; } Kind = CK_BitCast; return IncompatiblePointer; } // U^ -> void* if (RHSType->getAs()) { if (LHSPointer->getPointeeType()->isVoidType()) { LangAS AddrSpaceL = LHSPointer->getPointeeType().getAddressSpace(); LangAS AddrSpaceR = RHSType->getAs() ->getPointeeType() .getAddressSpace(); Kind = AddrSpaceL != AddrSpaceR ? CK_AddressSpaceConversion : CK_BitCast; return Compatible; } } return Incompatible; } // Conversions to block pointers. if (isa(LHSType)) { // U^ -> T^ if (RHSType->isBlockPointerType()) { LangAS AddrSpaceL = LHSType->getAs() ->getPointeeType() .getAddressSpace(); LangAS AddrSpaceR = RHSType->getAs() ->getPointeeType() .getAddressSpace(); Kind = AddrSpaceL != AddrSpaceR ? CK_AddressSpaceConversion : CK_BitCast; return checkBlockPointerTypesForAssignment(*this, LHSType, RHSType); } // int or null -> T^ if (RHSType->isIntegerType()) { Kind = CK_IntegralToPointer; // FIXME: null return IntToBlockPointer; } // id -> T^ if (getLangOpts().ObjC && RHSType->isObjCIdType()) { Kind = CK_AnyPointerToBlockPointerCast; return Compatible; } // void* -> T^ if (const PointerType *RHSPT = RHSType->getAs()) if (RHSPT->getPointeeType()->isVoidType()) { Kind = CK_AnyPointerToBlockPointerCast; return Compatible; } return Incompatible; } // Conversions to Objective-C pointers. if (isa(LHSType)) { // A* -> B* if (RHSType->isObjCObjectPointerType()) { Kind = CK_BitCast; Sema::AssignConvertType result = checkObjCPointerTypesForAssignment(*this, LHSType, RHSType); if (getLangOpts().allowsNonTrivialObjCLifetimeQualifiers() && result == Compatible && !CheckObjCARCUnavailableWeakConversion(OrigLHSType, RHSType)) result = IncompatibleObjCWeakRef; return result; } // int or null -> A* if (RHSType->isIntegerType()) { Kind = CK_IntegralToPointer; // FIXME: null return IntToPointer; } // In general, C pointers are not compatible with ObjC object pointers, // with two exceptions: if (isa(RHSType)) { Kind = CK_CPointerToObjCPointerCast; // - conversions from 'void*' if (RHSType->isVoidPointerType()) { return Compatible; } // - conversions to 'Class' from its redefinition type if (LHSType->isObjCClassType() && Context.hasSameType(RHSType, Context.getObjCClassRedefinitionType())) { return Compatible; } return IncompatiblePointer; } // Only under strict condition T^ is compatible with an Objective-C pointer. if (RHSType->isBlockPointerType() && LHSType->isBlockCompatibleObjCPointerType(Context)) { if (ConvertRHS) maybeExtendBlockObject(RHS); Kind = CK_BlockPointerToObjCPointerCast; return Compatible; } return Incompatible; } // Conversions from pointers that are not covered by the above. if (isa(RHSType)) { // T* -> _Bool if (LHSType == Context.BoolTy) { Kind = CK_PointerToBoolean; return Compatible; } // T* -> int if (LHSType->isIntegerType()) { Kind = CK_PointerToIntegral; return PointerToInt; } return Incompatible; } // Conversions from Objective-C pointers that are not covered by the above. if (isa(RHSType)) { // T* -> _Bool if (LHSType == Context.BoolTy) { Kind = CK_PointerToBoolean; return Compatible; } // T* -> int if (LHSType->isIntegerType()) { Kind = CK_PointerToIntegral; return PointerToInt; } return Incompatible; } // struct A -> struct B if (isa(LHSType) && isa(RHSType)) { if (Context.typesAreCompatible(LHSType, RHSType)) { Kind = CK_NoOp; return Compatible; } } if (LHSType->isSamplerT() && RHSType->isIntegerType()) { Kind = CK_IntToOCLSampler; return Compatible; } return Incompatible; } /// Constructs a transparent union from an expression that is /// used to initialize the transparent union. static void ConstructTransparentUnion(Sema &S, ASTContext &C, ExprResult &EResult, QualType UnionType, FieldDecl *Field) { // Build an initializer list that designates the appropriate member // of the transparent union. Expr *E = EResult.get(); InitListExpr *Initializer = new (C) InitListExpr(C, SourceLocation(), E, SourceLocation()); Initializer->setType(UnionType); Initializer->setInitializedFieldInUnion(Field); // Build a compound literal constructing a value of the transparent // union type from this initializer list. TypeSourceInfo *unionTInfo = C.getTrivialTypeSourceInfo(UnionType); EResult = new (C) CompoundLiteralExpr(SourceLocation(), unionTInfo, UnionType, VK_RValue, Initializer, false); } Sema::AssignConvertType Sema::CheckTransparentUnionArgumentConstraints(QualType ArgType, ExprResult &RHS) { QualType RHSType = RHS.get()->getType(); // If the ArgType is a Union type, we want to handle a potential // transparent_union GCC extension. const RecordType *UT = ArgType->getAsUnionType(); if (!UT || !UT->getDecl()->hasAttr()) return Incompatible; // The field to initialize within the transparent union. RecordDecl *UD = UT->getDecl(); FieldDecl *InitField = nullptr; // It's compatible if the expression matches any of the fields. for (auto *it : UD->fields()) { if (it->getType()->isPointerType()) { // If the transparent union contains a pointer type, we allow: // 1) void pointer // 2) null pointer constant if (RHSType->isPointerType()) if (RHSType->castAs()->getPointeeType()->isVoidType()) { RHS = ImpCastExprToType(RHS.get(), it->getType(), CK_BitCast); InitField = it; break; } if (RHS.get()->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) { RHS = ImpCastExprToType(RHS.get(), it->getType(), CK_NullToPointer); InitField = it; break; } } CastKind Kind; if (CheckAssignmentConstraints(it->getType(), RHS, Kind) == Compatible) { RHS = ImpCastExprToType(RHS.get(), it->getType(), Kind); InitField = it; break; } } if (!InitField) return Incompatible; ConstructTransparentUnion(*this, Context, RHS, ArgType, InitField); return Compatible; } Sema::AssignConvertType Sema::CheckSingleAssignmentConstraints(QualType LHSType, ExprResult &CallerRHS, bool Diagnose, bool DiagnoseCFAudited, bool ConvertRHS) { // We need to be able to tell the caller whether we diagnosed a problem, if // they ask us to issue diagnostics. assert((ConvertRHS || !Diagnose) && "can't indicate whether we diagnosed"); // If ConvertRHS is false, we want to leave the caller's RHS untouched. Sadly, // we can't avoid *all* modifications at the moment, so we need some somewhere // to put the updated value. ExprResult LocalRHS = CallerRHS; ExprResult &RHS = ConvertRHS ? CallerRHS : LocalRHS; if (const auto *LHSPtrType = LHSType->getAs()) { if (const auto *RHSPtrType = RHS.get()->getType()->getAs()) { if (RHSPtrType->getPointeeType()->hasAttr(attr::NoDeref) && !LHSPtrType->getPointeeType()->hasAttr(attr::NoDeref)) { Diag(RHS.get()->getExprLoc(), diag::warn_noderef_to_dereferenceable_pointer) << RHS.get()->getSourceRange(); } } } if (getLangOpts().CPlusPlus) { if (!LHSType->isRecordType() && !LHSType->isAtomicType()) { // C++ 5.17p3: If the left operand is not of class type, the // expression is implicitly converted (C++ 4) to the // cv-unqualified type of the left operand. QualType RHSType = RHS.get()->getType(); if (Diagnose) { RHS = PerformImplicitConversion(RHS.get(), LHSType.getUnqualifiedType(), AA_Assigning); } else { ImplicitConversionSequence ICS = TryImplicitConversion(RHS.get(), LHSType.getUnqualifiedType(), /*SuppressUserConversions=*/false, /*AllowExplicit=*/false, /*InOverloadResolution=*/false, /*CStyle=*/false, /*AllowObjCWritebackConversion=*/false); if (ICS.isFailure()) return Incompatible; RHS = PerformImplicitConversion(RHS.get(), LHSType.getUnqualifiedType(), ICS, AA_Assigning); } if (RHS.isInvalid()) return Incompatible; Sema::AssignConvertType result = Compatible; if (getLangOpts().allowsNonTrivialObjCLifetimeQualifiers() && !CheckObjCARCUnavailableWeakConversion(LHSType, RHSType)) result = IncompatibleObjCWeakRef; return result; } // FIXME: Currently, we fall through and treat C++ classes like C // structures. // FIXME: We also fall through for atomics; not sure what should // happen there, though. } else if (RHS.get()->getType() == Context.OverloadTy) { // As a set of extensions to C, we support overloading on functions. These // functions need to be resolved here. DeclAccessPair DAP; if (FunctionDecl *FD = ResolveAddressOfOverloadedFunction( RHS.get(), LHSType, /*Complain=*/false, DAP)) RHS = FixOverloadedFunctionReference(RHS.get(), DAP, FD); else return Incompatible; } // C99 6.5.16.1p1: the left operand is a pointer and the right is // a null pointer constant. if ((LHSType->isPointerType() || LHSType->isObjCObjectPointerType() || LHSType->isBlockPointerType()) && RHS.get()->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) { if (Diagnose || ConvertRHS) { CastKind Kind; CXXCastPath Path; CheckPointerConversion(RHS.get(), LHSType, Kind, Path, /*IgnoreBaseAccess=*/false, Diagnose); if (ConvertRHS) RHS = ImpCastExprToType(RHS.get(), LHSType, Kind, VK_RValue, &Path); } return Compatible; } // OpenCL queue_t type assignment. if (LHSType->isQueueT() && RHS.get()->isNullPointerConstant( Context, Expr::NPC_ValueDependentIsNull)) { RHS = ImpCastExprToType(RHS.get(), LHSType, CK_NullToPointer); return Compatible; } // This check seems unnatural, however it is necessary to ensure the proper // conversion of functions/arrays. If the conversion were done for all // DeclExpr's (created by ActOnIdExpression), it would mess up the unary // expressions that suppress this implicit conversion (&, sizeof). // // Suppress this for references: C++ 8.5.3p5. if (!LHSType->isReferenceType()) { // FIXME: We potentially allocate here even if ConvertRHS is false. RHS = DefaultFunctionArrayLvalueConversion(RHS.get(), Diagnose); if (RHS.isInvalid()) return Incompatible; } CastKind Kind; Sema::AssignConvertType result = CheckAssignmentConstraints(LHSType, RHS, Kind, ConvertRHS); // C99 6.5.16.1p2: The value of the right operand is converted to the // type of the assignment expression. // CheckAssignmentConstraints allows the left-hand side to be a reference, // so that we can use references in built-in functions even in C. // The getNonReferenceType() call makes sure that the resulting expression // does not have reference type. if (result != Incompatible && RHS.get()->getType() != LHSType) { QualType Ty = LHSType.getNonLValueExprType(Context); Expr *E = RHS.get(); // Check for various Objective-C errors. If we are not reporting // diagnostics and just checking for errors, e.g., during overload // resolution, return Incompatible to indicate the failure. if (getLangOpts().allowsNonTrivialObjCLifetimeQualifiers() && CheckObjCConversion(SourceRange(), Ty, E, CCK_ImplicitConversion, Diagnose, DiagnoseCFAudited) != ACR_okay) { if (!Diagnose) return Incompatible; } if (getLangOpts().ObjC && (CheckObjCBridgeRelatedConversions(E->getBeginLoc(), LHSType, E->getType(), E, Diagnose) || ConversionToObjCStringLiteralCheck(LHSType, E, Diagnose))) { if (!Diagnose) return Incompatible; // Replace the expression with a corrected version and continue so we // can find further errors. RHS = E; return Compatible; } if (ConvertRHS) RHS = ImpCastExprToType(E, Ty, Kind); } return result; } namespace { /// The original operand to an operator, prior to the application of the usual /// arithmetic conversions and converting the arguments of a builtin operator /// candidate. struct OriginalOperand { explicit OriginalOperand(Expr *Op) : Orig(Op), Conversion(nullptr) { if (auto *MTE = dyn_cast(Op)) Op = MTE->getSubExpr(); if (auto *BTE = dyn_cast(Op)) Op = BTE->getSubExpr(); if (auto *ICE = dyn_cast(Op)) { Orig = ICE->getSubExprAsWritten(); Conversion = ICE->getConversionFunction(); } } QualType getType() const { return Orig->getType(); } Expr *Orig; NamedDecl *Conversion; }; } QualType Sema::InvalidOperands(SourceLocation Loc, ExprResult &LHS, ExprResult &RHS) { OriginalOperand OrigLHS(LHS.get()), OrigRHS(RHS.get()); Diag(Loc, diag::err_typecheck_invalid_operands) << OrigLHS.getType() << OrigRHS.getType() << LHS.get()->getSourceRange() << RHS.get()->getSourceRange(); // If a user-defined conversion was applied to either of the operands prior // to applying the built-in operator rules, tell the user about it. if (OrigLHS.Conversion) { Diag(OrigLHS.Conversion->getLocation(), diag::note_typecheck_invalid_operands_converted) << 0 << LHS.get()->getType(); } if (OrigRHS.Conversion) { Diag(OrigRHS.Conversion->getLocation(), diag::note_typecheck_invalid_operands_converted) << 1 << RHS.get()->getType(); } return QualType(); } // Diagnose cases where a scalar was implicitly converted to a vector and // diagnose the underlying types. Otherwise, diagnose the error // as invalid vector logical operands for non-C++ cases. QualType Sema::InvalidLogicalVectorOperands(SourceLocation Loc, ExprResult &LHS, ExprResult &RHS) { QualType LHSType = LHS.get()->IgnoreImpCasts()->getType(); QualType RHSType = RHS.get()->IgnoreImpCasts()->getType(); bool LHSNatVec = LHSType->isVectorType(); bool RHSNatVec = RHSType->isVectorType(); if (!(LHSNatVec && RHSNatVec)) { Expr *Vector = LHSNatVec ? LHS.get() : RHS.get(); Expr *NonVector = !LHSNatVec ? LHS.get() : RHS.get(); Diag(Loc, diag::err_typecheck_logical_vector_expr_gnu_cpp_restrict) << 0 << Vector->getType() << NonVector->IgnoreImpCasts()->getType() << Vector->getSourceRange(); return QualType(); } Diag(Loc, diag::err_typecheck_logical_vector_expr_gnu_cpp_restrict) << 1 << LHSType << RHSType << LHS.get()->getSourceRange() << RHS.get()->getSourceRange(); return QualType(); } /// Try to convert a value of non-vector type to a vector type by converting /// the type to the element type of the vector and then performing a splat. /// If the language is OpenCL, we only use conversions that promote scalar /// rank; for C, Obj-C, and C++ we allow any real scalar conversion except /// for float->int. /// /// OpenCL V2.0 6.2.6.p2: /// An error shall occur if any scalar operand type has greater rank /// than the type of the vector element. /// /// \param scalar - if non-null, actually perform the conversions /// \return true if the operation fails (but without diagnosing the failure) static bool tryVectorConvertAndSplat(Sema &S, ExprResult *scalar, QualType scalarTy, QualType vectorEltTy, QualType vectorTy, unsigned &DiagID) { // The conversion to apply to the scalar before splatting it, // if necessary. CastKind scalarCast = CK_NoOp; if (vectorEltTy->isIntegralType(S.Context)) { if (S.getLangOpts().OpenCL && (scalarTy->isRealFloatingType() || (scalarTy->isIntegerType() && S.Context.getIntegerTypeOrder(vectorEltTy, scalarTy) < 0))) { DiagID = diag::err_opencl_scalar_type_rank_greater_than_vector_type; return true; } if (!scalarTy->isIntegralType(S.Context)) return true; scalarCast = CK_IntegralCast; } else if (vectorEltTy->isRealFloatingType()) { if (scalarTy->isRealFloatingType()) { if (S.getLangOpts().OpenCL && S.Context.getFloatingTypeOrder(vectorEltTy, scalarTy) < 0) { DiagID = diag::err_opencl_scalar_type_rank_greater_than_vector_type; return true; } scalarCast = CK_FloatingCast; } else if (scalarTy->isIntegralType(S.Context)) scalarCast = CK_IntegralToFloating; else return true; } else { return true; } // Adjust scalar if desired. if (scalar) { if (scalarCast != CK_NoOp) *scalar = S.ImpCastExprToType(scalar->get(), vectorEltTy, scalarCast); *scalar = S.ImpCastExprToType(scalar->get(), vectorTy, CK_VectorSplat); } return false; } /// Convert vector E to a vector with the same number of elements but different /// element type. static ExprResult convertVector(Expr *E, QualType ElementType, Sema &S) { const auto *VecTy = E->getType()->getAs(); assert(VecTy && "Expression E must be a vector"); QualType NewVecTy = S.Context.getVectorType(ElementType, VecTy->getNumElements(), VecTy->getVectorKind()); // Look through the implicit cast. Return the subexpression if its type is // NewVecTy. if (auto *ICE = dyn_cast(E)) if (ICE->getSubExpr()->getType() == NewVecTy) return ICE->getSubExpr(); auto Cast = ElementType->isIntegerType() ? CK_IntegralCast : CK_FloatingCast; return S.ImpCastExprToType(E, NewVecTy, Cast); } /// Test if a (constant) integer Int can be casted to another integer type /// IntTy without losing precision. static bool canConvertIntToOtherIntTy(Sema &S, ExprResult *Int, QualType OtherIntTy) { QualType IntTy = Int->get()->getType().getUnqualifiedType(); // Reject cases where the value of the Int is unknown as that would // possibly cause truncation, but accept cases where the scalar can be // demoted without loss of precision. Expr::EvalResult EVResult; bool CstInt = Int->get()->EvaluateAsInt(EVResult, S.Context); int Order = S.Context.getIntegerTypeOrder(OtherIntTy, IntTy); bool IntSigned = IntTy->hasSignedIntegerRepresentation(); bool OtherIntSigned = OtherIntTy->hasSignedIntegerRepresentation(); if (CstInt) { // If the scalar is constant and is of a higher order and has more active // bits that the vector element type, reject it. llvm::APSInt Result = EVResult.Val.getInt(); unsigned NumBits = IntSigned ? (Result.isNegative() ? Result.getMinSignedBits() : Result.getActiveBits()) : Result.getActiveBits(); if (Order < 0 && S.Context.getIntWidth(OtherIntTy) < NumBits) return true; // If the signedness of the scalar type and the vector element type // differs and the number of bits is greater than that of the vector // element reject it. return (IntSigned != OtherIntSigned && NumBits > S.Context.getIntWidth(OtherIntTy)); } // Reject cases where the value of the scalar is not constant and it's // order is greater than that of the vector element type. return (Order < 0); } /// Test if a (constant) integer Int can be casted to floating point type /// FloatTy without losing precision. static bool canConvertIntTyToFloatTy(Sema &S, ExprResult *Int, QualType FloatTy) { QualType IntTy = Int->get()->getType().getUnqualifiedType(); // Determine if the integer constant can be expressed as a floating point // number of the appropriate type. Expr::EvalResult EVResult; bool CstInt = Int->get()->EvaluateAsInt(EVResult, S.Context); uint64_t Bits = 0; if (CstInt) { // Reject constants that would be truncated if they were converted to // the floating point type. Test by simple to/from conversion. // FIXME: Ideally the conversion to an APFloat and from an APFloat // could be avoided if there was a convertFromAPInt method // which could signal back if implicit truncation occurred. llvm::APSInt Result = EVResult.Val.getInt(); llvm::APFloat Float(S.Context.getFloatTypeSemantics(FloatTy)); Float.convertFromAPInt(Result, IntTy->hasSignedIntegerRepresentation(), llvm::APFloat::rmTowardZero); llvm::APSInt ConvertBack(S.Context.getIntWidth(IntTy), !IntTy->hasSignedIntegerRepresentation()); bool Ignored = false; Float.convertToInteger(ConvertBack, llvm::APFloat::rmNearestTiesToEven, &Ignored); if (Result != ConvertBack) return true; } else { // Reject types that cannot be fully encoded into the mantissa of // the float. Bits = S.Context.getTypeSize(IntTy); unsigned FloatPrec = llvm::APFloat::semanticsPrecision( S.Context.getFloatTypeSemantics(FloatTy)); if (Bits > FloatPrec) return true; } return false; } /// Attempt to convert and splat Scalar into a vector whose types matches /// Vector following GCC conversion rules. The rule is that implicit /// conversion can occur when Scalar can be casted to match Vector's element /// type without causing truncation of Scalar. static bool tryGCCVectorConvertAndSplat(Sema &S, ExprResult *Scalar, ExprResult *Vector) { QualType ScalarTy = Scalar->get()->getType().getUnqualifiedType(); QualType VectorTy = Vector->get()->getType().getUnqualifiedType(); const VectorType *VT = VectorTy->getAs(); assert(!isa(VT) && "ExtVectorTypes should not be handled here!"); QualType VectorEltTy = VT->getElementType(); // Reject cases where the vector element type or the scalar element type are // not integral or floating point types. if (!VectorEltTy->isArithmeticType() || !ScalarTy->isArithmeticType()) return true; // The conversion to apply to the scalar before splatting it, // if necessary. CastKind ScalarCast = CK_NoOp; // Accept cases where the vector elements are integers and the scalar is // an integer. // FIXME: Notionally if the scalar was a floating point value with a precise // integral representation, we could cast it to an appropriate integer // type and then perform the rest of the checks here. GCC will perform // this conversion in some cases as determined by the input language. // We should accept it on a language independent basis. if (VectorEltTy->isIntegralType(S.Context) && ScalarTy->isIntegralType(S.Context) && S.Context.getIntegerTypeOrder(VectorEltTy, ScalarTy)) { if (canConvertIntToOtherIntTy(S, Scalar, VectorEltTy)) return true; ScalarCast = CK_IntegralCast; } else if (VectorEltTy->isIntegralType(S.Context) && ScalarTy->isRealFloatingType()) { if (S.Context.getTypeSize(VectorEltTy) == S.Context.getTypeSize(ScalarTy)) ScalarCast = CK_FloatingToIntegral; else return true; } else if (VectorEltTy->isRealFloatingType()) { if (ScalarTy->isRealFloatingType()) { // Reject cases where the scalar type is not a constant and has a higher // Order than the vector element type. llvm::APFloat Result(0.0); bool CstScalar = Scalar->get()->EvaluateAsFloat(Result, S.Context); int Order = S.Context.getFloatingTypeOrder(VectorEltTy, ScalarTy); if (!CstScalar && Order < 0) return true; // If the scalar cannot be safely casted to the vector element type, // reject it. if (CstScalar) { bool Truncated = false; Result.convert(S.Context.getFloatTypeSemantics(VectorEltTy), llvm::APFloat::rmNearestTiesToEven, &Truncated); if (Truncated) return true; } ScalarCast = CK_FloatingCast; } else if (ScalarTy->isIntegralType(S.Context)) { if (canConvertIntTyToFloatTy(S, Scalar, VectorEltTy)) return true; ScalarCast = CK_IntegralToFloating; } else return true; } // Adjust scalar if desired. if (Scalar) { if (ScalarCast != CK_NoOp) *Scalar = S.ImpCastExprToType(Scalar->get(), VectorEltTy, ScalarCast); *Scalar = S.ImpCastExprToType(Scalar->get(), VectorTy, CK_VectorSplat); } return false; } QualType Sema::CheckVectorOperands(ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, bool IsCompAssign, bool AllowBothBool, bool AllowBoolConversions) { if (!IsCompAssign) { LHS = DefaultFunctionArrayLvalueConversion(LHS.get()); if (LHS.isInvalid()) return QualType(); } RHS = DefaultFunctionArrayLvalueConversion(RHS.get()); if (RHS.isInvalid()) return QualType(); // For conversion purposes, we ignore any qualifiers. // For example, "const float" and "float" are equivalent. QualType LHSType = LHS.get()->getType().getUnqualifiedType(); QualType RHSType = RHS.get()->getType().getUnqualifiedType(); const VectorType *LHSVecType = LHSType->getAs(); const VectorType *RHSVecType = RHSType->getAs(); assert(LHSVecType || RHSVecType); // AltiVec-style "vector bool op vector bool" combinations are allowed // for some operators but not others. if (!AllowBothBool && LHSVecType && LHSVecType->getVectorKind() == VectorType::AltiVecBool && RHSVecType && RHSVecType->getVectorKind() == VectorType::AltiVecBool) return InvalidOperands(Loc, LHS, RHS); // If the vector types are identical, return. if (Context.hasSameType(LHSType, RHSType)) return LHSType; // If we have compatible AltiVec and GCC vector types, use the AltiVec type. if (LHSVecType && RHSVecType && Context.areCompatibleVectorTypes(LHSType, RHSType)) { if (isa(LHSVecType)) { RHS = ImpCastExprToType(RHS.get(), LHSType, CK_BitCast); return LHSType; } if (!IsCompAssign) LHS = ImpCastExprToType(LHS.get(), RHSType, CK_BitCast); return RHSType; } // AllowBoolConversions says that bool and non-bool AltiVec vectors // can be mixed, with the result being the non-bool type. The non-bool // operand must have integer element type. if (AllowBoolConversions && LHSVecType && RHSVecType && LHSVecType->getNumElements() == RHSVecType->getNumElements() && (Context.getTypeSize(LHSVecType->getElementType()) == Context.getTypeSize(RHSVecType->getElementType()))) { if (LHSVecType->getVectorKind() == VectorType::AltiVecVector && LHSVecType->getElementType()->isIntegerType() && RHSVecType->getVectorKind() == VectorType::AltiVecBool) { RHS = ImpCastExprToType(RHS.get(), LHSType, CK_BitCast); return LHSType; } if (!IsCompAssign && LHSVecType->getVectorKind() == VectorType::AltiVecBool && RHSVecType->getVectorKind() == VectorType::AltiVecVector && RHSVecType->getElementType()->isIntegerType()) { LHS = ImpCastExprToType(LHS.get(), RHSType, CK_BitCast); return RHSType; } } // If there's a vector type and a scalar, try to convert the scalar to // the vector element type and splat. unsigned DiagID = diag::err_typecheck_vector_not_convertable; if (!RHSVecType) { if (isa(LHSVecType)) { if (!tryVectorConvertAndSplat(*this, &RHS, RHSType, LHSVecType->getElementType(), LHSType, DiagID)) return LHSType; } else { if (!tryGCCVectorConvertAndSplat(*this, &RHS, &LHS)) return LHSType; } } if (!LHSVecType) { if (isa(RHSVecType)) { if (!tryVectorConvertAndSplat(*this, (IsCompAssign ? nullptr : &LHS), LHSType, RHSVecType->getElementType(), RHSType, DiagID)) return RHSType; } else { if (LHS.get()->getValueKind() == VK_LValue || !tryGCCVectorConvertAndSplat(*this, &LHS, &RHS)) return RHSType; } } // FIXME: The code below also handles conversion between vectors and // non-scalars, we should break this down into fine grained specific checks // and emit proper diagnostics. QualType VecType = LHSVecType ? LHSType : RHSType; const VectorType *VT = LHSVecType ? LHSVecType : RHSVecType; QualType OtherType = LHSVecType ? RHSType : LHSType; ExprResult *OtherExpr = LHSVecType ? &RHS : &LHS; if (isLaxVectorConversion(OtherType, VecType)) { // If we're allowing lax vector conversions, only the total (data) size // needs to be the same. For non compound assignment, if one of the types is // scalar, the result is always the vector type. if (!IsCompAssign) { *OtherExpr = ImpCastExprToType(OtherExpr->get(), VecType, CK_BitCast); return VecType; // In a compound assignment, lhs += rhs, 'lhs' is a lvalue src, forbidding // any implicit cast. Here, the 'rhs' should be implicit casted to 'lhs' // type. Note that this is already done by non-compound assignments in // CheckAssignmentConstraints. If it's a scalar type, only bitcast for // <1 x T> -> T. The result is also a vector type. } else if (OtherType->isExtVectorType() || OtherType->isVectorType() || (OtherType->isScalarType() && VT->getNumElements() == 1)) { ExprResult *RHSExpr = &RHS; *RHSExpr = ImpCastExprToType(RHSExpr->get(), LHSType, CK_BitCast); return VecType; } } // Okay, the expression is invalid. // If there's a non-vector, non-real operand, diagnose that. if ((!RHSVecType && !RHSType->isRealType()) || (!LHSVecType && !LHSType->isRealType())) { Diag(Loc, diag::err_typecheck_vector_not_convertable_non_scalar) << LHSType << RHSType << LHS.get()->getSourceRange() << RHS.get()->getSourceRange(); return QualType(); } // OpenCL V1.1 6.2.6.p1: // If the operands are of more than one vector type, then an error shall // occur. Implicit conversions between vector types are not permitted, per // section 6.2.1. if (getLangOpts().OpenCL && RHSVecType && isa(RHSVecType) && LHSVecType && isa(LHSVecType)) { Diag(Loc, diag::err_opencl_implicit_vector_conversion) << LHSType << RHSType; return QualType(); } // If there is a vector type that is not a ExtVector and a scalar, we reach // this point if scalar could not be converted to the vector's element type // without truncation. if ((RHSVecType && !isa(RHSVecType)) || (LHSVecType && !isa(LHSVecType))) { QualType Scalar = LHSVecType ? RHSType : LHSType; QualType Vector = LHSVecType ? LHSType : RHSType; unsigned ScalarOrVector = LHSVecType && RHSVecType ? 1 : 0; Diag(Loc, diag::err_typecheck_vector_not_convertable_implict_truncation) << ScalarOrVector << Scalar << Vector; return QualType(); } // Otherwise, use the generic diagnostic. Diag(Loc, DiagID) << LHSType << RHSType << LHS.get()->getSourceRange() << RHS.get()->getSourceRange(); return QualType(); } // checkArithmeticNull - Detect when a NULL constant is used improperly in an // expression. These are mainly cases where the null pointer is used as an // integer instead of a pointer. static void checkArithmeticNull(Sema &S, ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, bool IsCompare) { // The canonical way to check for a GNU null is with isNullPointerConstant, // but we use a bit of a hack here for speed; this is a relatively // hot path, and isNullPointerConstant is slow. bool LHSNull = isa(LHS.get()->IgnoreParenImpCasts()); bool RHSNull = isa(RHS.get()->IgnoreParenImpCasts()); QualType NonNullType = LHSNull ? RHS.get()->getType() : LHS.get()->getType(); // Avoid analyzing cases where the result will either be invalid (and // diagnosed as such) or entirely valid and not something to warn about. if ((!LHSNull && !RHSNull) || NonNullType->isBlockPointerType() || NonNullType->isMemberPointerType() || NonNullType->isFunctionType()) return; // Comparison operations would not make sense with a null pointer no matter // what the other expression is. if (!IsCompare) { S.Diag(Loc, diag::warn_null_in_arithmetic_operation) << (LHSNull ? LHS.get()->getSourceRange() : SourceRange()) << (RHSNull ? RHS.get()->getSourceRange() : SourceRange()); return; } // The rest of the operations only make sense with a null pointer // if the other expression is a pointer. if (LHSNull == RHSNull || NonNullType->isAnyPointerType() || NonNullType->canDecayToPointerType()) return; S.Diag(Loc, diag::warn_null_in_comparison_operation) << LHSNull /* LHS is NULL */ << NonNullType << LHS.get()->getSourceRange() << RHS.get()->getSourceRange(); } static void DiagnoseDivisionSizeofPointerOrArray(Sema &S, Expr *LHS, Expr *RHS, SourceLocation Loc) { const auto *LUE = dyn_cast(LHS); const auto *RUE = dyn_cast(RHS); if (!LUE || !RUE) return; if (LUE->getKind() != UETT_SizeOf || LUE->isArgumentType() || RUE->getKind() != UETT_SizeOf) return; const Expr *LHSArg = LUE->getArgumentExpr()->IgnoreParens(); QualType LHSTy = LHSArg->getType(); QualType RHSTy; if (RUE->isArgumentType()) RHSTy = RUE->getArgumentType(); else RHSTy = RUE->getArgumentExpr()->IgnoreParens()->getType(); if (LHSTy->isPointerType() && !RHSTy->isPointerType()) { if (!S.Context.hasSameUnqualifiedType(LHSTy->getPointeeType(), RHSTy)) return; S.Diag(Loc, diag::warn_division_sizeof_ptr) << LHS << LHS->getSourceRange(); if (const auto *DRE = dyn_cast(LHSArg)) { if (const ValueDecl *LHSArgDecl = DRE->getDecl()) S.Diag(LHSArgDecl->getLocation(), diag::note_pointer_declared_here) << LHSArgDecl; } } else if (const auto *ArrayTy = S.Context.getAsArrayType(LHSTy)) { QualType ArrayElemTy = ArrayTy->getElementType(); if (ArrayElemTy != S.Context.getBaseElementType(ArrayTy) || ArrayElemTy->isDependentType() || RHSTy->isDependentType() || ArrayElemTy->isCharType() || S.Context.getTypeSize(ArrayElemTy) == S.Context.getTypeSize(RHSTy)) return; S.Diag(Loc, diag::warn_division_sizeof_array) << LHSArg->getSourceRange() << ArrayElemTy << RHSTy; if (const auto *DRE = dyn_cast(LHSArg)) { if (const ValueDecl *LHSArgDecl = DRE->getDecl()) S.Diag(LHSArgDecl->getLocation(), diag::note_array_declared_here) << LHSArgDecl; } S.Diag(Loc, diag::note_precedence_silence) << RHS; } } static void DiagnoseBadDivideOrRemainderValues(Sema& S, ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, bool IsDiv) { // Check for division/remainder by zero. Expr::EvalResult RHSValue; if (!RHS.get()->isValueDependent() && RHS.get()->EvaluateAsInt(RHSValue, S.Context) && RHSValue.Val.getInt() == 0) S.DiagRuntimeBehavior(Loc, RHS.get(), S.PDiag(diag::warn_remainder_division_by_zero) << IsDiv << RHS.get()->getSourceRange()); } QualType Sema::CheckMultiplyDivideOperands(ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, bool IsCompAssign, bool IsDiv) { checkArithmeticNull(*this, LHS, RHS, Loc, /*IsCompare=*/false); if (LHS.get()->getType()->isVectorType() || RHS.get()->getType()->isVectorType()) return CheckVectorOperands(LHS, RHS, Loc, IsCompAssign, /*AllowBothBool*/getLangOpts().AltiVec, /*AllowBoolConversions*/false); QualType compType = UsualArithmeticConversions( LHS, RHS, Loc, IsCompAssign ? ACK_CompAssign : ACK_Arithmetic); if (LHS.isInvalid() || RHS.isInvalid()) return QualType(); if (compType.isNull() || !compType->isArithmeticType()) return InvalidOperands(Loc, LHS, RHS); if (IsDiv) { DiagnoseBadDivideOrRemainderValues(*this, LHS, RHS, Loc, IsDiv); DiagnoseDivisionSizeofPointerOrArray(*this, LHS.get(), RHS.get(), Loc); } return compType; } QualType Sema::CheckRemainderOperands( ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, bool IsCompAssign) { checkArithmeticNull(*this, LHS, RHS, Loc, /*IsCompare=*/false); if (LHS.get()->getType()->isVectorType() || RHS.get()->getType()->isVectorType()) { if (LHS.get()->getType()->hasIntegerRepresentation() && RHS.get()->getType()->hasIntegerRepresentation()) return CheckVectorOperands(LHS, RHS, Loc, IsCompAssign, /*AllowBothBool*/getLangOpts().AltiVec, /*AllowBoolConversions*/false); return InvalidOperands(Loc, LHS, RHS); } QualType compType = UsualArithmeticConversions( LHS, RHS, Loc, IsCompAssign ? ACK_CompAssign : ACK_Arithmetic); if (LHS.isInvalid() || RHS.isInvalid()) return QualType(); if (compType.isNull() || !compType->isIntegerType()) return InvalidOperands(Loc, LHS, RHS); DiagnoseBadDivideOrRemainderValues(*this, LHS, RHS, Loc, false /* IsDiv */); return compType; } /// Diagnose invalid arithmetic on two void pointers. static void diagnoseArithmeticOnTwoVoidPointers(Sema &S, SourceLocation Loc, Expr *LHSExpr, Expr *RHSExpr) { S.Diag(Loc, S.getLangOpts().CPlusPlus ? diag::err_typecheck_pointer_arith_void_type : diag::ext_gnu_void_ptr) << 1 /* two pointers */ << LHSExpr->getSourceRange() << RHSExpr->getSourceRange(); } /// Diagnose invalid arithmetic on a void pointer. static void diagnoseArithmeticOnVoidPointer(Sema &S, SourceLocation Loc, Expr *Pointer) { S.Diag(Loc, S.getLangOpts().CPlusPlus ? diag::err_typecheck_pointer_arith_void_type : diag::ext_gnu_void_ptr) << 0 /* one pointer */ << Pointer->getSourceRange(); } /// Diagnose invalid arithmetic on a null pointer. /// /// If \p IsGNUIdiom is true, the operation is using the 'p = (i8*)nullptr + n' /// idiom, which we recognize as a GNU extension. /// static void diagnoseArithmeticOnNullPointer(Sema &S, SourceLocation Loc, Expr *Pointer, bool IsGNUIdiom) { if (IsGNUIdiom) S.Diag(Loc, diag::warn_gnu_null_ptr_arith) << Pointer->getSourceRange(); else S.Diag(Loc, diag::warn_pointer_arith_null_ptr) << S.getLangOpts().CPlusPlus << Pointer->getSourceRange(); } /// Diagnose invalid arithmetic on two function pointers. static void diagnoseArithmeticOnTwoFunctionPointers(Sema &S, SourceLocation Loc, Expr *LHS, Expr *RHS) { assert(LHS->getType()->isAnyPointerType()); assert(RHS->getType()->isAnyPointerType()); S.Diag(Loc, S.getLangOpts().CPlusPlus ? diag::err_typecheck_pointer_arith_function_type : diag::ext_gnu_ptr_func_arith) << 1 /* two pointers */ << LHS->getType()->getPointeeType() // We only show the second type if it differs from the first. << (unsigned)!S.Context.hasSameUnqualifiedType(LHS->getType(), RHS->getType()) << RHS->getType()->getPointeeType() << LHS->getSourceRange() << RHS->getSourceRange(); } /// Diagnose invalid arithmetic on a function pointer. static void diagnoseArithmeticOnFunctionPointer(Sema &S, SourceLocation Loc, Expr *Pointer) { assert(Pointer->getType()->isAnyPointerType()); S.Diag(Loc, S.getLangOpts().CPlusPlus ? diag::err_typecheck_pointer_arith_function_type : diag::ext_gnu_ptr_func_arith) << 0 /* one pointer */ << Pointer->getType()->getPointeeType() << 0 /* one pointer, so only one type */ << Pointer->getSourceRange(); } /// Emit error if Operand is incomplete pointer type /// /// \returns True if pointer has incomplete type static bool checkArithmeticIncompletePointerType(Sema &S, SourceLocation Loc, Expr *Operand) { QualType ResType = Operand->getType(); if (const AtomicType *ResAtomicType = ResType->getAs()) ResType = ResAtomicType->getValueType(); assert(ResType->isAnyPointerType() && !ResType->isDependentType()); QualType PointeeTy = ResType->getPointeeType(); return S.RequireCompleteType(Loc, PointeeTy, diag::err_typecheck_arithmetic_incomplete_type, PointeeTy, Operand->getSourceRange()); } /// Check the validity of an arithmetic pointer operand. /// /// If the operand has pointer type, this code will check for pointer types /// which are invalid in arithmetic operations. These will be diagnosed /// appropriately, including whether or not the use is supported as an /// extension. /// /// \returns True when the operand is valid to use (even if as an extension). static bool checkArithmeticOpPointerOperand(Sema &S, SourceLocation Loc, Expr *Operand) { QualType ResType = Operand->getType(); if (const AtomicType *ResAtomicType = ResType->getAs()) ResType = ResAtomicType->getValueType(); if (!ResType->isAnyPointerType()) return true; QualType PointeeTy = ResType->getPointeeType(); if (PointeeTy->isVoidType()) { diagnoseArithmeticOnVoidPointer(S, Loc, Operand); return !S.getLangOpts().CPlusPlus; } if (PointeeTy->isFunctionType()) { diagnoseArithmeticOnFunctionPointer(S, Loc, Operand); return !S.getLangOpts().CPlusPlus; } if (checkArithmeticIncompletePointerType(S, Loc, Operand)) return false; return true; } /// Check the validity of a binary arithmetic operation w.r.t. pointer /// operands. /// /// This routine will diagnose any invalid arithmetic on pointer operands much /// like \see checkArithmeticOpPointerOperand. However, it has special logic /// for emitting a single diagnostic even for operations where both LHS and RHS /// are (potentially problematic) pointers. /// /// \returns True when the operand is valid to use (even if as an extension). static bool checkArithmeticBinOpPointerOperands(Sema &S, SourceLocation Loc, Expr *LHSExpr, Expr *RHSExpr) { bool isLHSPointer = LHSExpr->getType()->isAnyPointerType(); bool isRHSPointer = RHSExpr->getType()->isAnyPointerType(); if (!isLHSPointer && !isRHSPointer) return true; QualType LHSPointeeTy, RHSPointeeTy; if (isLHSPointer) LHSPointeeTy = LHSExpr->getType()->getPointeeType(); if (isRHSPointer) RHSPointeeTy = RHSExpr->getType()->getPointeeType(); // if both are pointers check if operation is valid wrt address spaces if (S.getLangOpts().OpenCL && isLHSPointer && isRHSPointer) { const PointerType *lhsPtr = LHSExpr->getType()->castAs(); const PointerType *rhsPtr = RHSExpr->getType()->castAs(); if (!lhsPtr->isAddressSpaceOverlapping(*rhsPtr)) { S.Diag(Loc, diag::err_typecheck_op_on_nonoverlapping_address_space_pointers) << LHSExpr->getType() << RHSExpr->getType() << 1 /*arithmetic op*/ << LHSExpr->getSourceRange() << RHSExpr->getSourceRange(); return false; } } // Check for arithmetic on pointers to incomplete types. bool isLHSVoidPtr = isLHSPointer && LHSPointeeTy->isVoidType(); bool isRHSVoidPtr = isRHSPointer && RHSPointeeTy->isVoidType(); if (isLHSVoidPtr || isRHSVoidPtr) { if (!isRHSVoidPtr) diagnoseArithmeticOnVoidPointer(S, Loc, LHSExpr); else if (!isLHSVoidPtr) diagnoseArithmeticOnVoidPointer(S, Loc, RHSExpr); else diagnoseArithmeticOnTwoVoidPointers(S, Loc, LHSExpr, RHSExpr); return !S.getLangOpts().CPlusPlus; } bool isLHSFuncPtr = isLHSPointer && LHSPointeeTy->isFunctionType(); bool isRHSFuncPtr = isRHSPointer && RHSPointeeTy->isFunctionType(); if (isLHSFuncPtr || isRHSFuncPtr) { if (!isRHSFuncPtr) diagnoseArithmeticOnFunctionPointer(S, Loc, LHSExpr); else if (!isLHSFuncPtr) diagnoseArithmeticOnFunctionPointer(S, Loc, RHSExpr); else diagnoseArithmeticOnTwoFunctionPointers(S, Loc, LHSExpr, RHSExpr); return !S.getLangOpts().CPlusPlus; } if (isLHSPointer && checkArithmeticIncompletePointerType(S, Loc, LHSExpr)) return false; if (isRHSPointer && checkArithmeticIncompletePointerType(S, Loc, RHSExpr)) return false; return true; } /// diagnoseStringPlusInt - Emit a warning when adding an integer to a string /// literal. static void diagnoseStringPlusInt(Sema &Self, SourceLocation OpLoc, Expr *LHSExpr, Expr *RHSExpr) { StringLiteral* StrExpr = dyn_cast(LHSExpr->IgnoreImpCasts()); Expr* IndexExpr = RHSExpr; if (!StrExpr) { StrExpr = dyn_cast(RHSExpr->IgnoreImpCasts()); IndexExpr = LHSExpr; } bool IsStringPlusInt = StrExpr && IndexExpr->getType()->isIntegralOrUnscopedEnumerationType(); if (!IsStringPlusInt || IndexExpr->isValueDependent()) return; SourceRange DiagRange(LHSExpr->getBeginLoc(), RHSExpr->getEndLoc()); Self.Diag(OpLoc, diag::warn_string_plus_int) << DiagRange << IndexExpr->IgnoreImpCasts()->getType(); // Only print a fixit for "str" + int, not for int + "str". if (IndexExpr == RHSExpr) { SourceLocation EndLoc = Self.getLocForEndOfToken(RHSExpr->getEndLoc()); Self.Diag(OpLoc, diag::note_string_plus_scalar_silence) << FixItHint::CreateInsertion(LHSExpr->getBeginLoc(), "&") << FixItHint::CreateReplacement(SourceRange(OpLoc), "[") << FixItHint::CreateInsertion(EndLoc, "]"); } else Self.Diag(OpLoc, diag::note_string_plus_scalar_silence); } /// Emit a warning when adding a char literal to a string. static void diagnoseStringPlusChar(Sema &Self, SourceLocation OpLoc, Expr *LHSExpr, Expr *RHSExpr) { const Expr *StringRefExpr = LHSExpr; const CharacterLiteral *CharExpr = dyn_cast(RHSExpr->IgnoreImpCasts()); if (!CharExpr) { CharExpr = dyn_cast(LHSExpr->IgnoreImpCasts()); StringRefExpr = RHSExpr; } if (!CharExpr || !StringRefExpr) return; const QualType StringType = StringRefExpr->getType(); // Return if not a PointerType. if (!StringType->isAnyPointerType()) return; // Return if not a CharacterType. if (!StringType->getPointeeType()->isAnyCharacterType()) return; ASTContext &Ctx = Self.getASTContext(); SourceRange DiagRange(LHSExpr->getBeginLoc(), RHSExpr->getEndLoc()); const QualType CharType = CharExpr->getType(); if (!CharType->isAnyCharacterType() && CharType->isIntegerType() && llvm::isUIntN(Ctx.getCharWidth(), CharExpr->getValue())) { Self.Diag(OpLoc, diag::warn_string_plus_char) << DiagRange << Ctx.CharTy; } else { Self.Diag(OpLoc, diag::warn_string_plus_char) << DiagRange << CharExpr->getType(); } // Only print a fixit for str + char, not for char + str. if (isa(RHSExpr->IgnoreImpCasts())) { SourceLocation EndLoc = Self.getLocForEndOfToken(RHSExpr->getEndLoc()); Self.Diag(OpLoc, diag::note_string_plus_scalar_silence) << FixItHint::CreateInsertion(LHSExpr->getBeginLoc(), "&") << FixItHint::CreateReplacement(SourceRange(OpLoc), "[") << FixItHint::CreateInsertion(EndLoc, "]"); } else { Self.Diag(OpLoc, diag::note_string_plus_scalar_silence); } } /// Emit error when two pointers are incompatible. static void diagnosePointerIncompatibility(Sema &S, SourceLocation Loc, Expr *LHSExpr, Expr *RHSExpr) { assert(LHSExpr->getType()->isAnyPointerType()); assert(RHSExpr->getType()->isAnyPointerType()); S.Diag(Loc, diag::err_typecheck_sub_ptr_compatible) << LHSExpr->getType() << RHSExpr->getType() << LHSExpr->getSourceRange() << RHSExpr->getSourceRange(); } // C99 6.5.6 QualType Sema::CheckAdditionOperands(ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, BinaryOperatorKind Opc, QualType* CompLHSTy) { checkArithmeticNull(*this, LHS, RHS, Loc, /*IsCompare=*/false); if (LHS.get()->getType()->isVectorType() || RHS.get()->getType()->isVectorType()) { QualType compType = CheckVectorOperands( LHS, RHS, Loc, CompLHSTy, /*AllowBothBool*/getLangOpts().AltiVec, /*AllowBoolConversions*/getLangOpts().ZVector); if (CompLHSTy) *CompLHSTy = compType; return compType; } QualType compType = UsualArithmeticConversions( LHS, RHS, Loc, CompLHSTy ? ACK_CompAssign : ACK_Arithmetic); if (LHS.isInvalid() || RHS.isInvalid()) return QualType(); // Diagnose "string literal" '+' int and string '+' "char literal". if (Opc == BO_Add) { diagnoseStringPlusInt(*this, Loc, LHS.get(), RHS.get()); diagnoseStringPlusChar(*this, Loc, LHS.get(), RHS.get()); } // handle the common case first (both operands are arithmetic). if (!compType.isNull() && compType->isArithmeticType()) { if (CompLHSTy) *CompLHSTy = compType; return compType; } // Type-checking. Ultimately the pointer's going to be in PExp; // note that we bias towards the LHS being the pointer. Expr *PExp = LHS.get(), *IExp = RHS.get(); bool isObjCPointer; if (PExp->getType()->isPointerType()) { isObjCPointer = false; } else if (PExp->getType()->isObjCObjectPointerType()) { isObjCPointer = true; } else { std::swap(PExp, IExp); if (PExp->getType()->isPointerType()) { isObjCPointer = false; } else if (PExp->getType()->isObjCObjectPointerType()) { isObjCPointer = true; } else { return InvalidOperands(Loc, LHS, RHS); } } assert(PExp->getType()->isAnyPointerType()); if (!IExp->getType()->isIntegerType()) return InvalidOperands(Loc, LHS, RHS); // Adding to a null pointer results in undefined behavior. if (PExp->IgnoreParenCasts()->isNullPointerConstant( Context, Expr::NPC_ValueDependentIsNotNull)) { // In C++ adding zero to a null pointer is defined. Expr::EvalResult KnownVal; if (!getLangOpts().CPlusPlus || (!IExp->isValueDependent() && (!IExp->EvaluateAsInt(KnownVal, Context) || KnownVal.Val.getInt() != 0))) { // Check the conditions to see if this is the 'p = nullptr + n' idiom. bool IsGNUIdiom = BinaryOperator::isNullPointerArithmeticExtension( Context, BO_Add, PExp, IExp); diagnoseArithmeticOnNullPointer(*this, Loc, PExp, IsGNUIdiom); } } if (!checkArithmeticOpPointerOperand(*this, Loc, PExp)) return QualType(); if (isObjCPointer && checkArithmeticOnObjCPointer(*this, Loc, PExp)) return QualType(); // Check array bounds for pointer arithemtic CheckArrayAccess(PExp, IExp); if (CompLHSTy) { QualType LHSTy = Context.isPromotableBitField(LHS.get()); if (LHSTy.isNull()) { LHSTy = LHS.get()->getType(); if (LHSTy->isPromotableIntegerType()) LHSTy = Context.getPromotedIntegerType(LHSTy); } *CompLHSTy = LHSTy; } return PExp->getType(); } // C99 6.5.6 QualType Sema::CheckSubtractionOperands(ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, QualType* CompLHSTy) { checkArithmeticNull(*this, LHS, RHS, Loc, /*IsCompare=*/false); if (LHS.get()->getType()->isVectorType() || RHS.get()->getType()->isVectorType()) { QualType compType = CheckVectorOperands( LHS, RHS, Loc, CompLHSTy, /*AllowBothBool*/getLangOpts().AltiVec, /*AllowBoolConversions*/getLangOpts().ZVector); if (CompLHSTy) *CompLHSTy = compType; return compType; } QualType compType = UsualArithmeticConversions( LHS, RHS, Loc, CompLHSTy ? ACK_CompAssign : ACK_Arithmetic); if (LHS.isInvalid() || RHS.isInvalid()) return QualType(); // Enforce type constraints: C99 6.5.6p3. // Handle the common case first (both operands are arithmetic). if (!compType.isNull() && compType->isArithmeticType()) { if (CompLHSTy) *CompLHSTy = compType; return compType; } // Either ptr - int or ptr - ptr. if (LHS.get()->getType()->isAnyPointerType()) { QualType lpointee = LHS.get()->getType()->getPointeeType(); // Diagnose bad cases where we step over interface counts. if (LHS.get()->getType()->isObjCObjectPointerType() && checkArithmeticOnObjCPointer(*this, Loc, LHS.get())) return QualType(); // The result type of a pointer-int computation is the pointer type. if (RHS.get()->getType()->isIntegerType()) { // Subtracting from a null pointer should produce a warning. // The last argument to the diagnose call says this doesn't match the // GNU int-to-pointer idiom. if (LHS.get()->IgnoreParenCasts()->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNotNull)) { // In C++ adding zero to a null pointer is defined. Expr::EvalResult KnownVal; if (!getLangOpts().CPlusPlus || (!RHS.get()->isValueDependent() && (!RHS.get()->EvaluateAsInt(KnownVal, Context) || KnownVal.Val.getInt() != 0))) { diagnoseArithmeticOnNullPointer(*this, Loc, LHS.get(), false); } } if (!checkArithmeticOpPointerOperand(*this, Loc, LHS.get())) return QualType(); // Check array bounds for pointer arithemtic CheckArrayAccess(LHS.get(), RHS.get(), /*ArraySubscriptExpr*/nullptr, /*AllowOnePastEnd*/true, /*IndexNegated*/true); if (CompLHSTy) *CompLHSTy = LHS.get()->getType(); return LHS.get()->getType(); } // Handle pointer-pointer subtractions. if (const PointerType *RHSPTy = RHS.get()->getType()->getAs()) { QualType rpointee = RHSPTy->getPointeeType(); if (getLangOpts().CPlusPlus) { // Pointee types must be the same: C++ [expr.add] if (!Context.hasSameUnqualifiedType(lpointee, rpointee)) { diagnosePointerIncompatibility(*this, Loc, LHS.get(), RHS.get()); } } else { // Pointee types must be compatible C99 6.5.6p3 if (!Context.typesAreCompatible( Context.getCanonicalType(lpointee).getUnqualifiedType(), Context.getCanonicalType(rpointee).getUnqualifiedType())) { diagnosePointerIncompatibility(*this, Loc, LHS.get(), RHS.get()); return QualType(); } } if (!checkArithmeticBinOpPointerOperands(*this, Loc, LHS.get(), RHS.get())) return QualType(); // FIXME: Add warnings for nullptr - ptr. // The pointee type may have zero size. As an extension, a structure or // union may have zero size or an array may have zero length. In this // case subtraction does not make sense. if (!rpointee->isVoidType() && !rpointee->isFunctionType()) { CharUnits ElementSize = Context.getTypeSizeInChars(rpointee); if (ElementSize.isZero()) { Diag(Loc,diag::warn_sub_ptr_zero_size_types) << rpointee.getUnqualifiedType() << LHS.get()->getSourceRange() << RHS.get()->getSourceRange(); } } if (CompLHSTy) *CompLHSTy = LHS.get()->getType(); return Context.getPointerDiffType(); } } return InvalidOperands(Loc, LHS, RHS); } static bool isScopedEnumerationType(QualType T) { if (const EnumType *ET = T->getAs()) return ET->getDecl()->isScoped(); return false; } static void DiagnoseBadShiftValues(Sema& S, ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, BinaryOperatorKind Opc, QualType LHSType) { // OpenCL 6.3j: shift values are effectively % word size of LHS (more defined), // so skip remaining warnings as we don't want to modify values within Sema. if (S.getLangOpts().OpenCL) return; // Check right/shifter operand Expr::EvalResult RHSResult; if (RHS.get()->isValueDependent() || !RHS.get()->EvaluateAsInt(RHSResult, S.Context)) return; llvm::APSInt Right = RHSResult.Val.getInt(); if (Right.isNegative()) { S.DiagRuntimeBehavior(Loc, RHS.get(), S.PDiag(diag::warn_shift_negative) << RHS.get()->getSourceRange()); return; } llvm::APInt LeftBits(Right.getBitWidth(), S.Context.getTypeSize(LHS.get()->getType())); if (Right.uge(LeftBits)) { S.DiagRuntimeBehavior(Loc, RHS.get(), S.PDiag(diag::warn_shift_gt_typewidth) << RHS.get()->getSourceRange()); return; } if (Opc != BO_Shl) return; // When left shifting an ICE which is signed, we can check for overflow which // according to C++ standards prior to C++2a has undefined behavior // ([expr.shift] 5.8/2). Unsigned integers have defined behavior modulo one // more than the maximum value representable in the result type, so never // warn for those. (FIXME: Unsigned left-shift overflow in a constant // expression is still probably a bug.) Expr::EvalResult LHSResult; if (LHS.get()->isValueDependent() || LHSType->hasUnsignedIntegerRepresentation() || !LHS.get()->EvaluateAsInt(LHSResult, S.Context)) return; llvm::APSInt Left = LHSResult.Val.getInt(); // If LHS does not have a signed type and non-negative value // then, the behavior is undefined before C++2a. Warn about it. if (Left.isNegative() && !S.getLangOpts().isSignedOverflowDefined() && !S.getLangOpts().CPlusPlus2a) { S.DiagRuntimeBehavior(Loc, LHS.get(), S.PDiag(diag::warn_shift_lhs_negative) << LHS.get()->getSourceRange()); return; } llvm::APInt ResultBits = static_cast(Right) + Left.getMinSignedBits(); if (LeftBits.uge(ResultBits)) return; llvm::APSInt Result = Left.extend(ResultBits.getLimitedValue()); Result = Result.shl(Right); // Print the bit representation of the signed integer as an unsigned // hexadecimal number. SmallString<40> HexResult; Result.toString(HexResult, 16, /*Signed =*/false, /*Literal =*/true); // If we are only missing a sign bit, this is less likely to result in actual // bugs -- if the result is cast back to an unsigned type, it will have the // expected value. Thus we place this behind a different warning that can be // turned off separately if needed. if (LeftBits == ResultBits - 1) { S.Diag(Loc, diag::warn_shift_result_sets_sign_bit) << HexResult << LHSType << LHS.get()->getSourceRange() << RHS.get()->getSourceRange(); return; } S.Diag(Loc, diag::warn_shift_result_gt_typewidth) << HexResult.str() << Result.getMinSignedBits() << LHSType << Left.getBitWidth() << LHS.get()->getSourceRange() << RHS.get()->getSourceRange(); } /// Return the resulting type when a vector is shifted /// by a scalar or vector shift amount. static QualType checkVectorShift(Sema &S, ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, bool IsCompAssign) { // OpenCL v1.1 s6.3.j says RHS can be a vector only if LHS is a vector. if ((S.LangOpts.OpenCL || S.LangOpts.ZVector) && !LHS.get()->getType()->isVectorType()) { S.Diag(Loc, diag::err_shift_rhs_only_vector) << RHS.get()->getType() << LHS.get()->getType() << LHS.get()->getSourceRange() << RHS.get()->getSourceRange(); return QualType(); } if (!IsCompAssign) { LHS = S.UsualUnaryConversions(LHS.get()); if (LHS.isInvalid()) return QualType(); } RHS = S.UsualUnaryConversions(RHS.get()); if (RHS.isInvalid()) return QualType(); QualType LHSType = LHS.get()->getType(); // Note that LHS might be a scalar because the routine calls not only in // OpenCL case. const VectorType *LHSVecTy = LHSType->getAs(); QualType LHSEleType = LHSVecTy ? LHSVecTy->getElementType() : LHSType; // Note that RHS might not be a vector. QualType RHSType = RHS.get()->getType(); const VectorType *RHSVecTy = RHSType->getAs(); QualType RHSEleType = RHSVecTy ? RHSVecTy->getElementType() : RHSType; // The operands need to be integers. if (!LHSEleType->isIntegerType()) { S.Diag(Loc, diag::err_typecheck_expect_int) << LHS.get()->getType() << LHS.get()->getSourceRange(); return QualType(); } if (!RHSEleType->isIntegerType()) { S.Diag(Loc, diag::err_typecheck_expect_int) << RHS.get()->getType() << RHS.get()->getSourceRange(); return QualType(); } if (!LHSVecTy) { assert(RHSVecTy); if (IsCompAssign) return RHSType; if (LHSEleType != RHSEleType) { LHS = S.ImpCastExprToType(LHS.get(),RHSEleType, CK_IntegralCast); LHSEleType = RHSEleType; } QualType VecTy = S.Context.getExtVectorType(LHSEleType, RHSVecTy->getNumElements()); LHS = S.ImpCastExprToType(LHS.get(), VecTy, CK_VectorSplat); LHSType = VecTy; } else if (RHSVecTy) { // OpenCL v1.1 s6.3.j says that for vector types, the operators // are applied component-wise. So if RHS is a vector, then ensure // that the number of elements is the same as LHS... if (RHSVecTy->getNumElements() != LHSVecTy->getNumElements()) { S.Diag(Loc, diag::err_typecheck_vector_lengths_not_equal) << LHS.get()->getType() << RHS.get()->getType() << LHS.get()->getSourceRange() << RHS.get()->getSourceRange(); return QualType(); } if (!S.LangOpts.OpenCL && !S.LangOpts.ZVector) { const BuiltinType *LHSBT = LHSEleType->getAs(); const BuiltinType *RHSBT = RHSEleType->getAs(); if (LHSBT != RHSBT && S.Context.getTypeSize(LHSBT) != S.Context.getTypeSize(RHSBT)) { S.Diag(Loc, diag::warn_typecheck_vector_element_sizes_not_equal) << LHS.get()->getType() << RHS.get()->getType() << LHS.get()->getSourceRange() << RHS.get()->getSourceRange(); } } } else { // ...else expand RHS to match the number of elements in LHS. QualType VecTy = S.Context.getExtVectorType(RHSEleType, LHSVecTy->getNumElements()); RHS = S.ImpCastExprToType(RHS.get(), VecTy, CK_VectorSplat); } return LHSType; } // C99 6.5.7 QualType Sema::CheckShiftOperands(ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, BinaryOperatorKind Opc, bool IsCompAssign) { checkArithmeticNull(*this, LHS, RHS, Loc, /*IsCompare=*/false); // Vector shifts promote their scalar inputs to vector type. if (LHS.get()->getType()->isVectorType() || RHS.get()->getType()->isVectorType()) { if (LangOpts.ZVector) { // The shift operators for the z vector extensions work basically // like general shifts, except that neither the LHS nor the RHS is // allowed to be a "vector bool". if (auto LHSVecType = LHS.get()->getType()->getAs()) if (LHSVecType->getVectorKind() == VectorType::AltiVecBool) return InvalidOperands(Loc, LHS, RHS); if (auto RHSVecType = RHS.get()->getType()->getAs()) if (RHSVecType->getVectorKind() == VectorType::AltiVecBool) return InvalidOperands(Loc, LHS, RHS); } return checkVectorShift(*this, LHS, RHS, Loc, IsCompAssign); } // Shifts don't perform usual arithmetic conversions, they just do integer // promotions on each operand. C99 6.5.7p3 // For the LHS, do usual unary conversions, but then reset them away // if this is a compound assignment. ExprResult OldLHS = LHS; LHS = UsualUnaryConversions(LHS.get()); if (LHS.isInvalid()) return QualType(); QualType LHSType = LHS.get()->getType(); if (IsCompAssign) LHS = OldLHS; // The RHS is simpler. RHS = UsualUnaryConversions(RHS.get()); if (RHS.isInvalid()) return QualType(); QualType RHSType = RHS.get()->getType(); // C99 6.5.7p2: Each of the operands shall have integer type. if (!LHSType->hasIntegerRepresentation() || !RHSType->hasIntegerRepresentation()) return InvalidOperands(Loc, LHS, RHS); // C++0x: Don't allow scoped enums. FIXME: Use something better than // hasIntegerRepresentation() above instead of this. if (isScopedEnumerationType(LHSType) || isScopedEnumerationType(RHSType)) { return InvalidOperands(Loc, LHS, RHS); } // Sanity-check shift operands DiagnoseBadShiftValues(*this, LHS, RHS, Loc, Opc, LHSType); // "The type of the result is that of the promoted left operand." return LHSType; } /// Diagnose bad pointer comparisons. static void diagnoseDistinctPointerComparison(Sema &S, SourceLocation Loc, ExprResult &LHS, ExprResult &RHS, bool IsError) { S.Diag(Loc, IsError ? diag::err_typecheck_comparison_of_distinct_pointers : diag::ext_typecheck_comparison_of_distinct_pointers) << LHS.get()->getType() << RHS.get()->getType() << LHS.get()->getSourceRange() << RHS.get()->getSourceRange(); } /// Returns false if the pointers are converted to a composite type, /// true otherwise. static bool convertPointersToCompositeType(Sema &S, SourceLocation Loc, ExprResult &LHS, ExprResult &RHS) { // C++ [expr.rel]p2: // [...] Pointer conversions (4.10) and qualification // conversions (4.4) are performed on pointer operands (or on // a pointer operand and a null pointer constant) to bring // them to their composite pointer type. [...] // // C++ [expr.eq]p1 uses the same notion for (in)equality // comparisons of pointers. QualType LHSType = LHS.get()->getType(); QualType RHSType = RHS.get()->getType(); assert(LHSType->isPointerType() || RHSType->isPointerType() || LHSType->isMemberPointerType() || RHSType->isMemberPointerType()); QualType T = S.FindCompositePointerType(Loc, LHS, RHS); if (T.isNull()) { if ((LHSType->isAnyPointerType() || LHSType->isMemberPointerType()) && (RHSType->isAnyPointerType() || RHSType->isMemberPointerType())) diagnoseDistinctPointerComparison(S, Loc, LHS, RHS, /*isError*/true); else S.InvalidOperands(Loc, LHS, RHS); return true; } return false; } static void diagnoseFunctionPointerToVoidComparison(Sema &S, SourceLocation Loc, ExprResult &LHS, ExprResult &RHS, bool IsError) { S.Diag(Loc, IsError ? diag::err_typecheck_comparison_of_fptr_to_void : diag::ext_typecheck_comparison_of_fptr_to_void) << LHS.get()->getType() << RHS.get()->getType() << LHS.get()->getSourceRange() << RHS.get()->getSourceRange(); } static bool isObjCObjectLiteral(ExprResult &E) { switch (E.get()->IgnoreParenImpCasts()->getStmtClass()) { case Stmt::ObjCArrayLiteralClass: case Stmt::ObjCDictionaryLiteralClass: case Stmt::ObjCStringLiteralClass: case Stmt::ObjCBoxedExprClass: return true; default: // Note that ObjCBoolLiteral is NOT an object literal! return false; } } static bool hasIsEqualMethod(Sema &S, const Expr *LHS, const Expr *RHS) { const ObjCObjectPointerType *Type = LHS->getType()->getAs(); // If this is not actually an Objective-C object, bail out. if (!Type) return false; // Get the LHS object's interface type. QualType InterfaceType = Type->getPointeeType(); // If the RHS isn't an Objective-C object, bail out. if (!RHS->getType()->isObjCObjectPointerType()) return false; // Try to find the -isEqual: method. Selector IsEqualSel = S.NSAPIObj->getIsEqualSelector(); ObjCMethodDecl *Method = S.LookupMethodInObjectType(IsEqualSel, InterfaceType, /*IsInstance=*/true); if (!Method) { if (Type->isObjCIdType()) { // For 'id', just check the global pool. Method = S.LookupInstanceMethodInGlobalPool(IsEqualSel, SourceRange(), /*receiverId=*/true); } else { // Check protocols. Method = S.LookupMethodInQualifiedType(IsEqualSel, Type, /*IsInstance=*/true); } } if (!Method) return false; QualType T = Method->parameters()[0]->getType(); if (!T->isObjCObjectPointerType()) return false; QualType R = Method->getReturnType(); if (!R->isScalarType()) return false; return true; } Sema::ObjCLiteralKind Sema::CheckLiteralKind(Expr *FromE) { FromE = FromE->IgnoreParenImpCasts(); switch (FromE->getStmtClass()) { default: break; case Stmt::ObjCStringLiteralClass: // "string literal" return LK_String; case Stmt::ObjCArrayLiteralClass: // "array literal" return LK_Array; case Stmt::ObjCDictionaryLiteralClass: // "dictionary literal" return LK_Dictionary; case Stmt::BlockExprClass: return LK_Block; case Stmt::ObjCBoxedExprClass: { Expr *Inner = cast(FromE)->getSubExpr()->IgnoreParens(); switch (Inner->getStmtClass()) { case Stmt::IntegerLiteralClass: case Stmt::FloatingLiteralClass: case Stmt::CharacterLiteralClass: case Stmt::ObjCBoolLiteralExprClass: case Stmt::CXXBoolLiteralExprClass: // "numeric literal" return LK_Numeric; case Stmt::ImplicitCastExprClass: { CastKind CK = cast(Inner)->getCastKind(); // Boolean literals can be represented by implicit casts. if (CK == CK_IntegralToBoolean || CK == CK_IntegralCast) return LK_Numeric; break; } default: break; } return LK_Boxed; } } return LK_None; } static void diagnoseObjCLiteralComparison(Sema &S, SourceLocation Loc, ExprResult &LHS, ExprResult &RHS, BinaryOperator::Opcode Opc){ Expr *Literal; Expr *Other; if (isObjCObjectLiteral(LHS)) { Literal = LHS.get(); Other = RHS.get(); } else { Literal = RHS.get(); Other = LHS.get(); } // Don't warn on comparisons against nil. Other = Other->IgnoreParenCasts(); if (Other->isNullPointerConstant(S.getASTContext(), Expr::NPC_ValueDependentIsNotNull)) return; // This should be kept in sync with warn_objc_literal_comparison. // LK_String should always be after the other literals, since it has its own // warning flag. Sema::ObjCLiteralKind LiteralKind = S.CheckLiteralKind(Literal); assert(LiteralKind != Sema::LK_Block); if (LiteralKind == Sema::LK_None) { llvm_unreachable("Unknown Objective-C object literal kind"); } if (LiteralKind == Sema::LK_String) S.Diag(Loc, diag::warn_objc_string_literal_comparison) << Literal->getSourceRange(); else S.Diag(Loc, diag::warn_objc_literal_comparison) << LiteralKind << Literal->getSourceRange(); if (BinaryOperator::isEqualityOp(Opc) && hasIsEqualMethod(S, LHS.get(), RHS.get())) { SourceLocation Start = LHS.get()->getBeginLoc(); SourceLocation End = S.getLocForEndOfToken(RHS.get()->getEndLoc()); CharSourceRange OpRange = CharSourceRange::getCharRange(Loc, S.getLocForEndOfToken(Loc)); S.Diag(Loc, diag::note_objc_literal_comparison_isequal) << FixItHint::CreateInsertion(Start, Opc == BO_EQ ? "[" : "![") << FixItHint::CreateReplacement(OpRange, " isEqual:") << FixItHint::CreateInsertion(End, "]"); } } /// Warns on !x < y, !x & y where !(x < y), !(x & y) was probably intended. static void diagnoseLogicalNotOnLHSofCheck(Sema &S, ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, BinaryOperatorKind Opc) { // Check that left hand side is !something. UnaryOperator *UO = dyn_cast(LHS.get()->IgnoreImpCasts()); if (!UO || UO->getOpcode() != UO_LNot) return; // Only check if the right hand side is non-bool arithmetic type. if (RHS.get()->isKnownToHaveBooleanValue()) return; // Make sure that the something in !something is not bool. Expr *SubExpr = UO->getSubExpr()->IgnoreImpCasts(); if (SubExpr->isKnownToHaveBooleanValue()) return; // Emit warning. bool IsBitwiseOp = Opc == BO_And || Opc == BO_Or || Opc == BO_Xor; S.Diag(UO->getOperatorLoc(), diag::warn_logical_not_on_lhs_of_check) << Loc << IsBitwiseOp; // First note suggest !(x < y) SourceLocation FirstOpen = SubExpr->getBeginLoc(); SourceLocation FirstClose = RHS.get()->getEndLoc(); FirstClose = S.getLocForEndOfToken(FirstClose); if (FirstClose.isInvalid()) FirstOpen = SourceLocation(); S.Diag(UO->getOperatorLoc(), diag::note_logical_not_fix) << IsBitwiseOp << FixItHint::CreateInsertion(FirstOpen, "(") << FixItHint::CreateInsertion(FirstClose, ")"); // Second note suggests (!x) < y SourceLocation SecondOpen = LHS.get()->getBeginLoc(); SourceLocation SecondClose = LHS.get()->getEndLoc(); SecondClose = S.getLocForEndOfToken(SecondClose); if (SecondClose.isInvalid()) SecondOpen = SourceLocation(); S.Diag(UO->getOperatorLoc(), diag::note_logical_not_silence_with_parens) << FixItHint::CreateInsertion(SecondOpen, "(") << FixItHint::CreateInsertion(SecondClose, ")"); } // Returns true if E refers to a non-weak array. static bool checkForArray(const Expr *E) { const ValueDecl *D = nullptr; if (const DeclRefExpr *DR = dyn_cast(E)) { D = DR->getDecl(); } else if (const MemberExpr *Mem = dyn_cast(E)) { if (Mem->isImplicitAccess()) D = Mem->getMemberDecl(); } if (!D) return false; return D->getType()->isArrayType() && !D->isWeak(); } /// Diagnose some forms of syntactically-obvious tautological comparison. static void diagnoseTautologicalComparison(Sema &S, SourceLocation Loc, Expr *LHS, Expr *RHS, BinaryOperatorKind Opc) { Expr *LHSStripped = LHS->IgnoreParenImpCasts(); Expr *RHSStripped = RHS->IgnoreParenImpCasts(); QualType LHSType = LHS->getType(); QualType RHSType = RHS->getType(); if (LHSType->hasFloatingRepresentation() || (LHSType->isBlockPointerType() && !BinaryOperator::isEqualityOp(Opc)) || S.inTemplateInstantiation()) return; // Comparisons between two array types are ill-formed for operator<=>, so // we shouldn't emit any additional warnings about it. if (Opc == BO_Cmp && LHSType->isArrayType() && RHSType->isArrayType()) return; // For non-floating point types, check for self-comparisons of the form // x == x, x != x, x < x, etc. These always evaluate to a constant, and // often indicate logic errors in the program. // // NOTE: Don't warn about comparison expressions resulting from macro // expansion. Also don't warn about comparisons which are only self // comparisons within a template instantiation. The warnings should catch // obvious cases in the definition of the template anyways. The idea is to // warn when the typed comparison operator will always evaluate to the same // result. // Used for indexing into %select in warn_comparison_always enum { AlwaysConstant, AlwaysTrue, AlwaysFalse, AlwaysEqual, // std::strong_ordering::equal from operator<=> }; // C++2a [depr.array.comp]: // Equality and relational comparisons ([expr.eq], [expr.rel]) between two // operands of array type are deprecated. if (S.getLangOpts().CPlusPlus2a && LHSStripped->getType()->isArrayType() && RHSStripped->getType()->isArrayType()) { S.Diag(Loc, diag::warn_depr_array_comparison) << LHS->getSourceRange() << RHS->getSourceRange() << LHSStripped->getType() << RHSStripped->getType(); // Carry on to produce the tautological comparison warning, if this // expression is potentially-evaluated, we can resolve the array to a // non-weak declaration, and so on. } if (!LHS->getBeginLoc().isMacroID() && !RHS->getBeginLoc().isMacroID()) { if (Expr::isSameComparisonOperand(LHS, RHS)) { unsigned Result; switch (Opc) { case BO_EQ: case BO_LE: case BO_GE: Result = AlwaysTrue; break; case BO_NE: case BO_LT: case BO_GT: Result = AlwaysFalse; break; case BO_Cmp: Result = AlwaysEqual; break; default: Result = AlwaysConstant; break; } S.DiagRuntimeBehavior(Loc, nullptr, S.PDiag(diag::warn_comparison_always) << 0 /*self-comparison*/ << Result); } else if (checkForArray(LHSStripped) && checkForArray(RHSStripped)) { // What is it always going to evaluate to? unsigned Result; switch (Opc) { case BO_EQ: // e.g. array1 == array2 Result = AlwaysFalse; break; case BO_NE: // e.g. array1 != array2 Result = AlwaysTrue; break; default: // e.g. array1 <= array2 // The best we can say is 'a constant' Result = AlwaysConstant; break; } S.DiagRuntimeBehavior(Loc, nullptr, S.PDiag(diag::warn_comparison_always) << 1 /*array comparison*/ << Result); } } if (isa(LHSStripped)) LHSStripped = LHSStripped->IgnoreParenCasts(); if (isa(RHSStripped)) RHSStripped = RHSStripped->IgnoreParenCasts(); // Warn about comparisons against a string constant (unless the other // operand is null); the user probably wants string comparison function. Expr *LiteralString = nullptr; Expr *LiteralStringStripped = nullptr; if ((isa(LHSStripped) || isa(LHSStripped)) && !RHSStripped->isNullPointerConstant(S.Context, Expr::NPC_ValueDependentIsNull)) { LiteralString = LHS; LiteralStringStripped = LHSStripped; } else if ((isa(RHSStripped) || isa(RHSStripped)) && !LHSStripped->isNullPointerConstant(S.Context, Expr::NPC_ValueDependentIsNull)) { LiteralString = RHS; LiteralStringStripped = RHSStripped; } if (LiteralString) { S.DiagRuntimeBehavior(Loc, nullptr, S.PDiag(diag::warn_stringcompare) << isa(LiteralStringStripped) << LiteralString->getSourceRange()); } } static ImplicitConversionKind castKindToImplicitConversionKind(CastKind CK) { switch (CK) { default: { #ifndef NDEBUG llvm::errs() << "unhandled cast kind: " << CastExpr::getCastKindName(CK) << "\n"; #endif llvm_unreachable("unhandled cast kind"); } case CK_UserDefinedConversion: return ICK_Identity; case CK_LValueToRValue: return ICK_Lvalue_To_Rvalue; case CK_ArrayToPointerDecay: return ICK_Array_To_Pointer; case CK_FunctionToPointerDecay: return ICK_Function_To_Pointer; case CK_IntegralCast: return ICK_Integral_Conversion; case CK_FloatingCast: return ICK_Floating_Conversion; case CK_IntegralToFloating: case CK_FloatingToIntegral: return ICK_Floating_Integral; case CK_IntegralComplexCast: case CK_FloatingComplexCast: case CK_FloatingComplexToIntegralComplex: case CK_IntegralComplexToFloatingComplex: return ICK_Complex_Conversion; case CK_FloatingComplexToReal: case CK_FloatingRealToComplex: case CK_IntegralComplexToReal: case CK_IntegralRealToComplex: return ICK_Complex_Real; } } static bool checkThreeWayNarrowingConversion(Sema &S, QualType ToType, Expr *E, QualType FromType, SourceLocation Loc) { // Check for a narrowing implicit conversion. StandardConversionSequence SCS; SCS.setAsIdentityConversion(); SCS.setToType(0, FromType); SCS.setToType(1, ToType); if (const auto *ICE = dyn_cast(E)) SCS.Second = castKindToImplicitConversionKind(ICE->getCastKind()); APValue PreNarrowingValue; QualType PreNarrowingType; switch (SCS.getNarrowingKind(S.Context, E, PreNarrowingValue, PreNarrowingType, /*IgnoreFloatToIntegralConversion*/ true)) { case NK_Dependent_Narrowing: // Implicit conversion to a narrower type, but the expression is // value-dependent so we can't tell whether it's actually narrowing. case NK_Not_Narrowing: return false; case NK_Constant_Narrowing: // Implicit conversion to a narrower type, and the value is not a constant // expression. S.Diag(E->getBeginLoc(), diag::err_spaceship_argument_narrowing) << /*Constant*/ 1 << PreNarrowingValue.getAsString(S.Context, PreNarrowingType) << ToType; return true; case NK_Variable_Narrowing: // Implicit conversion to a narrower type, and the value is not a constant // expression. case NK_Type_Narrowing: S.Diag(E->getBeginLoc(), diag::err_spaceship_argument_narrowing) << /*Constant*/ 0 << FromType << ToType; // TODO: It's not a constant expression, but what if the user intended it // to be? Can we produce notes to help them figure out why it isn't? return true; } llvm_unreachable("unhandled case in switch"); } static QualType checkArithmeticOrEnumeralThreeWayCompare(Sema &S, ExprResult &LHS, ExprResult &RHS, SourceLocation Loc) { QualType LHSType = LHS.get()->getType(); QualType RHSType = RHS.get()->getType(); // Dig out the original argument type and expression before implicit casts // were applied. These are the types/expressions we need to check the // [expr.spaceship] requirements against. ExprResult LHSStripped = LHS.get()->IgnoreParenImpCasts(); ExprResult RHSStripped = RHS.get()->IgnoreParenImpCasts(); QualType LHSStrippedType = LHSStripped.get()->getType(); QualType RHSStrippedType = RHSStripped.get()->getType(); // C++2a [expr.spaceship]p3: If one of the operands is of type bool and the // other is not, the program is ill-formed. if (LHSStrippedType->isBooleanType() != RHSStrippedType->isBooleanType()) { S.InvalidOperands(Loc, LHSStripped, RHSStripped); return QualType(); } // FIXME: Consider combining this with checkEnumArithmeticConversions. int NumEnumArgs = (int)LHSStrippedType->isEnumeralType() + RHSStrippedType->isEnumeralType(); if (NumEnumArgs == 1) { bool LHSIsEnum = LHSStrippedType->isEnumeralType(); QualType OtherTy = LHSIsEnum ? RHSStrippedType : LHSStrippedType; if (OtherTy->hasFloatingRepresentation()) { S.InvalidOperands(Loc, LHSStripped, RHSStripped); return QualType(); } } if (NumEnumArgs == 2) { // C++2a [expr.spaceship]p5: If both operands have the same enumeration // type E, the operator yields the result of converting the operands // to the underlying type of E and applying <=> to the converted operands. if (!S.Context.hasSameUnqualifiedType(LHSStrippedType, RHSStrippedType)) { S.InvalidOperands(Loc, LHS, RHS); return QualType(); } QualType IntType = LHSStrippedType->castAs()->getDecl()->getIntegerType(); assert(IntType->isArithmeticType()); // We can't use `CK_IntegralCast` when the underlying type is 'bool', so we // promote the boolean type, and all other promotable integer types, to // avoid this. if (IntType->isPromotableIntegerType()) IntType = S.Context.getPromotedIntegerType(IntType); LHS = S.ImpCastExprToType(LHS.get(), IntType, CK_IntegralCast); RHS = S.ImpCastExprToType(RHS.get(), IntType, CK_IntegralCast); LHSType = RHSType = IntType; } // C++2a [expr.spaceship]p4: If both operands have arithmetic types, the // usual arithmetic conversions are applied to the operands. QualType Type = S.UsualArithmeticConversions(LHS, RHS, Loc, Sema::ACK_Comparison); if (LHS.isInvalid() || RHS.isInvalid()) return QualType(); if (Type.isNull()) return S.InvalidOperands(Loc, LHS, RHS); Optional CCT = getComparisonCategoryForBuiltinCmp(Type); if (!CCT) return S.InvalidOperands(Loc, LHS, RHS); bool HasNarrowing = checkThreeWayNarrowingConversion( S, Type, LHS.get(), LHSType, LHS.get()->getBeginLoc()); HasNarrowing |= checkThreeWayNarrowingConversion(S, Type, RHS.get(), RHSType, RHS.get()->getBeginLoc()); if (HasNarrowing) return QualType(); assert(!Type.isNull() && "composite type for <=> has not been set"); return S.CheckComparisonCategoryType( *CCT, Loc, Sema::ComparisonCategoryUsage::OperatorInExpression); } static QualType checkArithmeticOrEnumeralCompare(Sema &S, ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, BinaryOperatorKind Opc) { if (Opc == BO_Cmp) return checkArithmeticOrEnumeralThreeWayCompare(S, LHS, RHS, Loc); // C99 6.5.8p3 / C99 6.5.9p4 QualType Type = S.UsualArithmeticConversions(LHS, RHS, Loc, Sema::ACK_Comparison); if (LHS.isInvalid() || RHS.isInvalid()) return QualType(); if (Type.isNull()) return S.InvalidOperands(Loc, LHS, RHS); assert(Type->isArithmeticType() || Type->isEnumeralType()); if (Type->isAnyComplexType() && BinaryOperator::isRelationalOp(Opc)) return S.InvalidOperands(Loc, LHS, RHS); // Check for comparisons of floating point operands using != and ==. if (Type->hasFloatingRepresentation() && BinaryOperator::isEqualityOp(Opc)) S.CheckFloatComparison(Loc, LHS.get(), RHS.get()); // The result of comparisons is 'bool' in C++, 'int' in C. return S.Context.getLogicalOperationType(); } void Sema::CheckPtrComparisonWithNullChar(ExprResult &E, ExprResult &NullE) { if (!NullE.get()->getType()->isAnyPointerType()) return; int NullValue = PP.isMacroDefined("NULL") ? 0 : 1; if (!E.get()->getType()->isAnyPointerType() && E.get()->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNotNull) == Expr::NPCK_ZeroExpression) { if (const auto *CL = dyn_cast(E.get())) { if (CL->getValue() == 0) Diag(E.get()->getExprLoc(), diag::warn_pointer_compare) << NullValue << FixItHint::CreateReplacement(E.get()->getExprLoc(), NullValue ? "NULL" : "(void *)0"); } else if (const auto *CE = dyn_cast(E.get())) { TypeSourceInfo *TI = CE->getTypeInfoAsWritten(); QualType T = Context.getCanonicalType(TI->getType()).getUnqualifiedType(); if (T == Context.CharTy) Diag(E.get()->getExprLoc(), diag::warn_pointer_compare) << NullValue << FixItHint::CreateReplacement(E.get()->getExprLoc(), NullValue ? "NULL" : "(void *)0"); } } } // C99 6.5.8, C++ [expr.rel] QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, BinaryOperatorKind Opc) { bool IsRelational = BinaryOperator::isRelationalOp(Opc); bool IsThreeWay = Opc == BO_Cmp; bool IsOrdered = IsRelational || IsThreeWay; auto IsAnyPointerType = [](ExprResult E) { QualType Ty = E.get()->getType(); return Ty->isPointerType() || Ty->isMemberPointerType(); }; // C++2a [expr.spaceship]p6: If at least one of the operands is of pointer // type, array-to-pointer, ..., conversions are performed on both operands to // bring them to their composite type. // Otherwise, all comparisons expect an rvalue, so convert to rvalue before // any type-related checks. if (!IsThreeWay || IsAnyPointerType(LHS) || IsAnyPointerType(RHS)) { LHS = DefaultFunctionArrayLvalueConversion(LHS.get()); if (LHS.isInvalid()) return QualType(); RHS = DefaultFunctionArrayLvalueConversion(RHS.get()); if (RHS.isInvalid()) return QualType(); } else { LHS = DefaultLvalueConversion(LHS.get()); if (LHS.isInvalid()) return QualType(); RHS = DefaultLvalueConversion(RHS.get()); if (RHS.isInvalid()) return QualType(); } checkArithmeticNull(*this, LHS, RHS, Loc, /*IsCompare=*/true); if (!getLangOpts().CPlusPlus && BinaryOperator::isEqualityOp(Opc)) { CheckPtrComparisonWithNullChar(LHS, RHS); CheckPtrComparisonWithNullChar(RHS, LHS); } // Handle vector comparisons separately. if (LHS.get()->getType()->isVectorType() || RHS.get()->getType()->isVectorType()) return CheckVectorCompareOperands(LHS, RHS, Loc, Opc); diagnoseLogicalNotOnLHSofCheck(*this, LHS, RHS, Loc, Opc); diagnoseTautologicalComparison(*this, Loc, LHS.get(), RHS.get(), Opc); QualType LHSType = LHS.get()->getType(); QualType RHSType = RHS.get()->getType(); if ((LHSType->isArithmeticType() || LHSType->isEnumeralType()) && (RHSType->isArithmeticType() || RHSType->isEnumeralType())) return checkArithmeticOrEnumeralCompare(*this, LHS, RHS, Loc, Opc); const Expr::NullPointerConstantKind LHSNullKind = LHS.get()->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull); const Expr::NullPointerConstantKind RHSNullKind = RHS.get()->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull); bool LHSIsNull = LHSNullKind != Expr::NPCK_NotNull; bool RHSIsNull = RHSNullKind != Expr::NPCK_NotNull; auto computeResultTy = [&]() { if (Opc != BO_Cmp) return Context.getLogicalOperationType(); assert(getLangOpts().CPlusPlus); assert(Context.hasSameType(LHS.get()->getType(), RHS.get()->getType())); QualType CompositeTy = LHS.get()->getType(); assert(!CompositeTy->isReferenceType()); Optional CCT = getComparisonCategoryForBuiltinCmp(CompositeTy); if (!CCT) return InvalidOperands(Loc, LHS, RHS); if (CompositeTy->isPointerType() && LHSIsNull != RHSIsNull) { // P0946R0: Comparisons between a null pointer constant and an object // pointer result in std::strong_equality, which is ill-formed under // P1959R0. Diag(Loc, diag::err_typecheck_three_way_comparison_of_pointer_and_zero) << (LHSIsNull ? LHS.get()->getSourceRange() : RHS.get()->getSourceRange()); return QualType(); } return CheckComparisonCategoryType( *CCT, Loc, ComparisonCategoryUsage::OperatorInExpression); }; if (!IsOrdered && LHSIsNull != RHSIsNull) { bool IsEquality = Opc == BO_EQ; if (RHSIsNull) DiagnoseAlwaysNonNullPointer(LHS.get(), RHSNullKind, IsEquality, RHS.get()->getSourceRange()); else DiagnoseAlwaysNonNullPointer(RHS.get(), LHSNullKind, IsEquality, LHS.get()->getSourceRange()); } if ((LHSType->isIntegerType() && !LHSIsNull) || (RHSType->isIntegerType() && !RHSIsNull)) { // Skip normal pointer conversion checks in this case; we have better // diagnostics for this below. } else if (getLangOpts().CPlusPlus) { // Equality comparison of a function pointer to a void pointer is invalid, // but we allow it as an extension. // FIXME: If we really want to allow this, should it be part of composite // pointer type computation so it works in conditionals too? if (!IsOrdered && ((LHSType->isFunctionPointerType() && RHSType->isVoidPointerType()) || (RHSType->isFunctionPointerType() && LHSType->isVoidPointerType()))) { // This is a gcc extension compatibility comparison. // In a SFINAE context, we treat this as a hard error to maintain // conformance with the C++ standard. diagnoseFunctionPointerToVoidComparison( *this, Loc, LHS, RHS, /*isError*/ (bool)isSFINAEContext()); if (isSFINAEContext()) return QualType(); RHS = ImpCastExprToType(RHS.get(), LHSType, CK_BitCast); return computeResultTy(); } // C++ [expr.eq]p2: // If at least one operand is a pointer [...] bring them to their // composite pointer type. // C++ [expr.spaceship]p6 // If at least one of the operands is of pointer type, [...] bring them // to their composite pointer type. // C++ [expr.rel]p2: // If both operands are pointers, [...] bring them to their composite // pointer type. // For <=>, the only valid non-pointer types are arrays and functions, and // we already decayed those, so this is really the same as the relational // comparison rule. if ((int)LHSType->isPointerType() + (int)RHSType->isPointerType() >= (IsOrdered ? 2 : 1) && (!LangOpts.ObjCAutoRefCount || !(LHSType->isObjCObjectPointerType() || RHSType->isObjCObjectPointerType()))) { if (convertPointersToCompositeType(*this, Loc, LHS, RHS)) return QualType(); return computeResultTy(); } } else if (LHSType->isPointerType() && RHSType->isPointerType()) { // C99 6.5.8p2 // All of the following pointer-related warnings are GCC extensions, except // when handling null pointer constants. QualType LCanPointeeTy = LHSType->castAs()->getPointeeType().getCanonicalType(); QualType RCanPointeeTy = RHSType->castAs()->getPointeeType().getCanonicalType(); // C99 6.5.9p2 and C99 6.5.8p2 if (Context.typesAreCompatible(LCanPointeeTy.getUnqualifiedType(), RCanPointeeTy.getUnqualifiedType())) { // Valid unless a relational comparison of function pointers if (IsRelational && LCanPointeeTy->isFunctionType()) { Diag(Loc, diag::ext_typecheck_ordered_comparison_of_function_pointers) << LHSType << RHSType << LHS.get()->getSourceRange() << RHS.get()->getSourceRange(); } } else if (!IsRelational && (LCanPointeeTy->isVoidType() || RCanPointeeTy->isVoidType())) { // Valid unless comparison between non-null pointer and function pointer if ((LCanPointeeTy->isFunctionType() || RCanPointeeTy->isFunctionType()) && !LHSIsNull && !RHSIsNull) diagnoseFunctionPointerToVoidComparison(*this, Loc, LHS, RHS, /*isError*/false); } else { // Invalid diagnoseDistinctPointerComparison(*this, Loc, LHS, RHS, /*isError*/false); } if (LCanPointeeTy != RCanPointeeTy) { // Treat NULL constant as a special case in OpenCL. if (getLangOpts().OpenCL && !LHSIsNull && !RHSIsNull) { const PointerType *LHSPtr = LHSType->castAs(); if (!LHSPtr->isAddressSpaceOverlapping(*RHSType->castAs())) { Diag(Loc, diag::err_typecheck_op_on_nonoverlapping_address_space_pointers) << LHSType << RHSType << 0 /* comparison */ << LHS.get()->getSourceRange() << RHS.get()->getSourceRange(); } } LangAS AddrSpaceL = LCanPointeeTy.getAddressSpace(); LangAS AddrSpaceR = RCanPointeeTy.getAddressSpace(); CastKind Kind = AddrSpaceL != AddrSpaceR ? CK_AddressSpaceConversion : CK_BitCast; if (LHSIsNull && !RHSIsNull) LHS = ImpCastExprToType(LHS.get(), RHSType, Kind); else RHS = ImpCastExprToType(RHS.get(), LHSType, Kind); } return computeResultTy(); } if (getLangOpts().CPlusPlus) { // C++ [expr.eq]p4: // Two operands of type std::nullptr_t or one operand of type // std::nullptr_t and the other a null pointer constant compare equal. if (!IsOrdered && LHSIsNull && RHSIsNull) { if (LHSType->isNullPtrType()) { RHS = ImpCastExprToType(RHS.get(), LHSType, CK_NullToPointer); return computeResultTy(); } if (RHSType->isNullPtrType()) { LHS = ImpCastExprToType(LHS.get(), RHSType, CK_NullToPointer); return computeResultTy(); } } // Comparison of Objective-C pointers and block pointers against nullptr_t. // These aren't covered by the composite pointer type rules. if (!IsOrdered && RHSType->isNullPtrType() && (LHSType->isObjCObjectPointerType() || LHSType->isBlockPointerType())) { RHS = ImpCastExprToType(RHS.get(), LHSType, CK_NullToPointer); return computeResultTy(); } if (!IsOrdered && LHSType->isNullPtrType() && (RHSType->isObjCObjectPointerType() || RHSType->isBlockPointerType())) { LHS = ImpCastExprToType(LHS.get(), RHSType, CK_NullToPointer); return computeResultTy(); } if (IsRelational && ((LHSType->isNullPtrType() && RHSType->isPointerType()) || (RHSType->isNullPtrType() && LHSType->isPointerType()))) { // HACK: Relational comparison of nullptr_t against a pointer type is // invalid per DR583, but we allow it within std::less<> and friends, // since otherwise common uses of it break. // FIXME: Consider removing this hack once LWG fixes std::less<> and // friends to have std::nullptr_t overload candidates. DeclContext *DC = CurContext; if (isa(DC)) DC = DC->getParent(); if (auto *CTSD = dyn_cast(DC)) { if (CTSD->isInStdNamespace() && llvm::StringSwitch(CTSD->getName()) .Cases("less", "less_equal", "greater", "greater_equal", true) .Default(false)) { if (RHSType->isNullPtrType()) RHS = ImpCastExprToType(RHS.get(), LHSType, CK_NullToPointer); else LHS = ImpCastExprToType(LHS.get(), RHSType, CK_NullToPointer); return computeResultTy(); } } } // C++ [expr.eq]p2: // If at least one operand is a pointer to member, [...] bring them to // their composite pointer type. if (!IsOrdered && (LHSType->isMemberPointerType() || RHSType->isMemberPointerType())) { if (convertPointersToCompositeType(*this, Loc, LHS, RHS)) return QualType(); else return computeResultTy(); } } // Handle block pointer types. if (!IsOrdered && LHSType->isBlockPointerType() && RHSType->isBlockPointerType()) { QualType lpointee = LHSType->castAs()->getPointeeType(); QualType rpointee = RHSType->castAs()->getPointeeType(); if (!LHSIsNull && !RHSIsNull && !Context.typesAreCompatible(lpointee, rpointee)) { Diag(Loc, diag::err_typecheck_comparison_of_distinct_blocks) << LHSType << RHSType << LHS.get()->getSourceRange() << RHS.get()->getSourceRange(); } RHS = ImpCastExprToType(RHS.get(), LHSType, CK_BitCast); return computeResultTy(); } // Allow block pointers to be compared with null pointer constants. if (!IsOrdered && ((LHSType->isBlockPointerType() && RHSType->isPointerType()) || (LHSType->isPointerType() && RHSType->isBlockPointerType()))) { if (!LHSIsNull && !RHSIsNull) { if (!((RHSType->isPointerType() && RHSType->castAs() ->getPointeeType()->isVoidType()) || (LHSType->isPointerType() && LHSType->castAs() ->getPointeeType()->isVoidType()))) Diag(Loc, diag::err_typecheck_comparison_of_distinct_blocks) << LHSType << RHSType << LHS.get()->getSourceRange() << RHS.get()->getSourceRange(); } if (LHSIsNull && !RHSIsNull) LHS = ImpCastExprToType(LHS.get(), RHSType, RHSType->isPointerType() ? CK_BitCast : CK_AnyPointerToBlockPointerCast); else RHS = ImpCastExprToType(RHS.get(), LHSType, LHSType->isPointerType() ? CK_BitCast : CK_AnyPointerToBlockPointerCast); return computeResultTy(); } if (LHSType->isObjCObjectPointerType() || RHSType->isObjCObjectPointerType()) { const PointerType *LPT = LHSType->getAs(); const PointerType *RPT = RHSType->getAs(); if (LPT || RPT) { bool LPtrToVoid = LPT ? LPT->getPointeeType()->isVoidType() : false; bool RPtrToVoid = RPT ? RPT->getPointeeType()->isVoidType() : false; if (!LPtrToVoid && !RPtrToVoid && !Context.typesAreCompatible(LHSType, RHSType)) { diagnoseDistinctPointerComparison(*this, Loc, LHS, RHS, /*isError*/false); } // FIXME: If LPtrToVoid, we should presumably convert the LHS rather than // the RHS, but we have test coverage for this behavior. // FIXME: Consider using convertPointersToCompositeType in C++. if (LHSIsNull && !RHSIsNull) { Expr *E = LHS.get(); if (getLangOpts().ObjCAutoRefCount) CheckObjCConversion(SourceRange(), RHSType, E, CCK_ImplicitConversion); LHS = ImpCastExprToType(E, RHSType, RPT ? CK_BitCast :CK_CPointerToObjCPointerCast); } else { Expr *E = RHS.get(); if (getLangOpts().ObjCAutoRefCount) CheckObjCConversion(SourceRange(), LHSType, E, CCK_ImplicitConversion, /*Diagnose=*/true, /*DiagnoseCFAudited=*/false, Opc); RHS = ImpCastExprToType(E, LHSType, LPT ? CK_BitCast :CK_CPointerToObjCPointerCast); } return computeResultTy(); } if (LHSType->isObjCObjectPointerType() && RHSType->isObjCObjectPointerType()) { if (!Context.areComparableObjCPointerTypes(LHSType, RHSType)) diagnoseDistinctPointerComparison(*this, Loc, LHS, RHS, /*isError*/false); if (isObjCObjectLiteral(LHS) || isObjCObjectLiteral(RHS)) diagnoseObjCLiteralComparison(*this, Loc, LHS, RHS, Opc); if (LHSIsNull && !RHSIsNull) LHS = ImpCastExprToType(LHS.get(), RHSType, CK_BitCast); else RHS = ImpCastExprToType(RHS.get(), LHSType, CK_BitCast); return computeResultTy(); } if (!IsOrdered && LHSType->isBlockPointerType() && RHSType->isBlockCompatibleObjCPointerType(Context)) { LHS = ImpCastExprToType(LHS.get(), RHSType, CK_BlockPointerToObjCPointerCast); return computeResultTy(); } else if (!IsOrdered && LHSType->isBlockCompatibleObjCPointerType(Context) && RHSType->isBlockPointerType()) { RHS = ImpCastExprToType(RHS.get(), LHSType, CK_BlockPointerToObjCPointerCast); return computeResultTy(); } } if ((LHSType->isAnyPointerType() && RHSType->isIntegerType()) || (LHSType->isIntegerType() && RHSType->isAnyPointerType())) { unsigned DiagID = 0; bool isError = false; if (LangOpts.DebuggerSupport) { // Under a debugger, allow the comparison of pointers to integers, // since users tend to want to compare addresses. } else if ((LHSIsNull && LHSType->isIntegerType()) || (RHSIsNull && RHSType->isIntegerType())) { if (IsOrdered) { isError = getLangOpts().CPlusPlus; DiagID = isError ? diag::err_typecheck_ordered_comparison_of_pointer_and_zero : diag::ext_typecheck_ordered_comparison_of_pointer_and_zero; } } else if (getLangOpts().CPlusPlus) { DiagID = diag::err_typecheck_comparison_of_pointer_integer; isError = true; } else if (IsOrdered) DiagID = diag::ext_typecheck_ordered_comparison_of_pointer_integer; else DiagID = diag::ext_typecheck_comparison_of_pointer_integer; if (DiagID) { Diag(Loc, DiagID) << LHSType << RHSType << LHS.get()->getSourceRange() << RHS.get()->getSourceRange(); if (isError) return QualType(); } if (LHSType->isIntegerType()) LHS = ImpCastExprToType(LHS.get(), RHSType, LHSIsNull ? CK_NullToPointer : CK_IntegralToPointer); else RHS = ImpCastExprToType(RHS.get(), LHSType, RHSIsNull ? CK_NullToPointer : CK_IntegralToPointer); return computeResultTy(); } // Handle block pointers. if (!IsOrdered && RHSIsNull && LHSType->isBlockPointerType() && RHSType->isIntegerType()) { RHS = ImpCastExprToType(RHS.get(), LHSType, CK_NullToPointer); return computeResultTy(); } if (!IsOrdered && LHSIsNull && LHSType->isIntegerType() && RHSType->isBlockPointerType()) { LHS = ImpCastExprToType(LHS.get(), RHSType, CK_NullToPointer); return computeResultTy(); } if (getLangOpts().OpenCLVersion >= 200 || getLangOpts().OpenCLCPlusPlus) { if (LHSType->isClkEventT() && RHSType->isClkEventT()) { return computeResultTy(); } if (LHSType->isQueueT() && RHSType->isQueueT()) { return computeResultTy(); } if (LHSIsNull && RHSType->isQueueT()) { LHS = ImpCastExprToType(LHS.get(), RHSType, CK_NullToPointer); return computeResultTy(); } if (LHSType->isQueueT() && RHSIsNull) { RHS = ImpCastExprToType(RHS.get(), LHSType, CK_NullToPointer); return computeResultTy(); } } return InvalidOperands(Loc, LHS, RHS); } // Return a signed ext_vector_type that is of identical size and number of // elements. For floating point vectors, return an integer type of identical // size and number of elements. In the non ext_vector_type case, search from // the largest type to the smallest type to avoid cases where long long == long, // where long gets picked over long long. QualType Sema::GetSignedVectorType(QualType V) { const VectorType *VTy = V->castAs(); unsigned TypeSize = Context.getTypeSize(VTy->getElementType()); if (isa(VTy)) { if (TypeSize == Context.getTypeSize(Context.CharTy)) return Context.getExtVectorType(Context.CharTy, VTy->getNumElements()); else if (TypeSize == Context.getTypeSize(Context.ShortTy)) return Context.getExtVectorType(Context.ShortTy, VTy->getNumElements()); else if (TypeSize == Context.getTypeSize(Context.IntTy)) return Context.getExtVectorType(Context.IntTy, VTy->getNumElements()); else if (TypeSize == Context.getTypeSize(Context.LongTy)) return Context.getExtVectorType(Context.LongTy, VTy->getNumElements()); assert(TypeSize == Context.getTypeSize(Context.LongLongTy) && "Unhandled vector element size in vector compare"); return Context.getExtVectorType(Context.LongLongTy, VTy->getNumElements()); } if (TypeSize == Context.getTypeSize(Context.LongLongTy)) return Context.getVectorType(Context.LongLongTy, VTy->getNumElements(), VectorType::GenericVector); else if (TypeSize == Context.getTypeSize(Context.LongTy)) return Context.getVectorType(Context.LongTy, VTy->getNumElements(), VectorType::GenericVector); else if (TypeSize == Context.getTypeSize(Context.IntTy)) return Context.getVectorType(Context.IntTy, VTy->getNumElements(), VectorType::GenericVector); else if (TypeSize == Context.getTypeSize(Context.ShortTy)) return Context.getVectorType(Context.ShortTy, VTy->getNumElements(), VectorType::GenericVector); assert(TypeSize == Context.getTypeSize(Context.CharTy) && "Unhandled vector element size in vector compare"); return Context.getVectorType(Context.CharTy, VTy->getNumElements(), VectorType::GenericVector); } /// CheckVectorCompareOperands - vector comparisons are a clang extension that /// operates on extended vector types. Instead of producing an IntTy result, /// like a scalar comparison, a vector comparison produces a vector of integer /// types. QualType Sema::CheckVectorCompareOperands(ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, BinaryOperatorKind Opc) { if (Opc == BO_Cmp) { Diag(Loc, diag::err_three_way_vector_comparison); return QualType(); } // Check to make sure we're operating on vectors of the same type and width, // Allowing one side to be a scalar of element type. QualType vType = CheckVectorOperands(LHS, RHS, Loc, /*isCompAssign*/false, /*AllowBothBool*/true, /*AllowBoolConversions*/getLangOpts().ZVector); if (vType.isNull()) return vType; QualType LHSType = LHS.get()->getType(); // If AltiVec, the comparison results in a numeric type, i.e. // bool for C++, int for C if (getLangOpts().AltiVec && vType->castAs()->getVectorKind() == VectorType::AltiVecVector) return Context.getLogicalOperationType(); // For non-floating point types, check for self-comparisons of the form // x == x, x != x, x < x, etc. These always evaluate to a constant, and // often indicate logic errors in the program. diagnoseTautologicalComparison(*this, Loc, LHS.get(), RHS.get(), Opc); // Check for comparisons of floating point operands using != and ==. if (BinaryOperator::isEqualityOp(Opc) && LHSType->hasFloatingRepresentation()) { assert(RHS.get()->getType()->hasFloatingRepresentation()); CheckFloatComparison(Loc, LHS.get(), RHS.get()); } // Return a signed type for the vector. return GetSignedVectorType(vType); } static void diagnoseXorMisusedAsPow(Sema &S, const ExprResult &XorLHS, const ExprResult &XorRHS, const SourceLocation Loc) { // Do not diagnose macros. if (Loc.isMacroID()) return; bool Negative = false; bool ExplicitPlus = false; const auto *LHSInt = dyn_cast(XorLHS.get()); const auto *RHSInt = dyn_cast(XorRHS.get()); if (!LHSInt) return; if (!RHSInt) { // Check negative literals. if (const auto *UO = dyn_cast(XorRHS.get())) { UnaryOperatorKind Opc = UO->getOpcode(); if (Opc != UO_Minus && Opc != UO_Plus) return; RHSInt = dyn_cast(UO->getSubExpr()); if (!RHSInt) return; Negative = (Opc == UO_Minus); ExplicitPlus = !Negative; } else { return; } } const llvm::APInt &LeftSideValue = LHSInt->getValue(); llvm::APInt RightSideValue = RHSInt->getValue(); if (LeftSideValue != 2 && LeftSideValue != 10) return; if (LeftSideValue.getBitWidth() != RightSideValue.getBitWidth()) return; CharSourceRange ExprRange = CharSourceRange::getCharRange( LHSInt->getBeginLoc(), S.getLocForEndOfToken(RHSInt->getLocation())); llvm::StringRef ExprStr = Lexer::getSourceText(ExprRange, S.getSourceManager(), S.getLangOpts()); CharSourceRange XorRange = CharSourceRange::getCharRange(Loc, S.getLocForEndOfToken(Loc)); llvm::StringRef XorStr = Lexer::getSourceText(XorRange, S.getSourceManager(), S.getLangOpts()); // Do not diagnose if xor keyword/macro is used. if (XorStr == "xor") return; std::string LHSStr = Lexer::getSourceText( CharSourceRange::getTokenRange(LHSInt->getSourceRange()), S.getSourceManager(), S.getLangOpts()); std::string RHSStr = Lexer::getSourceText( CharSourceRange::getTokenRange(RHSInt->getSourceRange()), S.getSourceManager(), S.getLangOpts()); if (Negative) { RightSideValue = -RightSideValue; RHSStr = "-" + RHSStr; } else if (ExplicitPlus) { RHSStr = "+" + RHSStr; } StringRef LHSStrRef = LHSStr; StringRef RHSStrRef = RHSStr; // Do not diagnose literals with digit separators, binary, hexadecimal, octal // literals. if (LHSStrRef.startswith("0b") || LHSStrRef.startswith("0B") || RHSStrRef.startswith("0b") || RHSStrRef.startswith("0B") || LHSStrRef.startswith("0x") || LHSStrRef.startswith("0X") || RHSStrRef.startswith("0x") || RHSStrRef.startswith("0X") || (LHSStrRef.size() > 1 && LHSStrRef.startswith("0")) || (RHSStrRef.size() > 1 && RHSStrRef.startswith("0")) || LHSStrRef.find('\'') != StringRef::npos || RHSStrRef.find('\'') != StringRef::npos) return; bool SuggestXor = S.getLangOpts().CPlusPlus || S.getPreprocessor().isMacroDefined("xor"); const llvm::APInt XorValue = LeftSideValue ^ RightSideValue; int64_t RightSideIntValue = RightSideValue.getSExtValue(); if (LeftSideValue == 2 && RightSideIntValue >= 0) { std::string SuggestedExpr = "1 << " + RHSStr; bool Overflow = false; llvm::APInt One = (LeftSideValue - 1); llvm::APInt PowValue = One.sshl_ov(RightSideValue, Overflow); if (Overflow) { if (RightSideIntValue < 64) S.Diag(Loc, diag::warn_xor_used_as_pow_base) << ExprStr << XorValue.toString(10, true) << ("1LL << " + RHSStr) << FixItHint::CreateReplacement(ExprRange, "1LL << " + RHSStr); else if (RightSideIntValue == 64) S.Diag(Loc, diag::warn_xor_used_as_pow) << ExprStr << XorValue.toString(10, true); else return; } else { S.Diag(Loc, diag::warn_xor_used_as_pow_base_extra) << ExprStr << XorValue.toString(10, true) << SuggestedExpr << PowValue.toString(10, true) << FixItHint::CreateReplacement( ExprRange, (RightSideIntValue == 0) ? "1" : SuggestedExpr); } S.Diag(Loc, diag::note_xor_used_as_pow_silence) << ("0x2 ^ " + RHSStr) << SuggestXor; } else if (LeftSideValue == 10) { std::string SuggestedValue = "1e" + std::to_string(RightSideIntValue); S.Diag(Loc, diag::warn_xor_used_as_pow_base) << ExprStr << XorValue.toString(10, true) << SuggestedValue << FixItHint::CreateReplacement(ExprRange, SuggestedValue); S.Diag(Loc, diag::note_xor_used_as_pow_silence) << ("0xA ^ " + RHSStr) << SuggestXor; } } QualType Sema::CheckVectorLogicalOperands(ExprResult &LHS, ExprResult &RHS, SourceLocation Loc) { // Ensure that either both operands are of the same vector type, or // one operand is of a vector type and the other is of its element type. QualType vType = CheckVectorOperands(LHS, RHS, Loc, false, /*AllowBothBool*/true, /*AllowBoolConversions*/false); if (vType.isNull()) return InvalidOperands(Loc, LHS, RHS); if (getLangOpts().OpenCL && getLangOpts().OpenCLVersion < 120 && !getLangOpts().OpenCLCPlusPlus && vType->hasFloatingRepresentation()) return InvalidOperands(Loc, LHS, RHS); // FIXME: The check for C++ here is for GCC compatibility. GCC rejects the // usage of the logical operators && and || with vectors in C. This // check could be notionally dropped. if (!getLangOpts().CPlusPlus && !(isa(vType->getAs()))) return InvalidLogicalVectorOperands(Loc, LHS, RHS); return GetSignedVectorType(LHS.get()->getType()); } inline QualType Sema::CheckBitwiseOperands(ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, BinaryOperatorKind Opc) { checkArithmeticNull(*this, LHS, RHS, Loc, /*IsCompare=*/false); bool IsCompAssign = Opc == BO_AndAssign || Opc == BO_OrAssign || Opc == BO_XorAssign; if (LHS.get()->getType()->isVectorType() || RHS.get()->getType()->isVectorType()) { if (LHS.get()->getType()->hasIntegerRepresentation() && RHS.get()->getType()->hasIntegerRepresentation()) return CheckVectorOperands(LHS, RHS, Loc, IsCompAssign, /*AllowBothBool*/true, /*AllowBoolConversions*/getLangOpts().ZVector); return InvalidOperands(Loc, LHS, RHS); } if (Opc == BO_And) diagnoseLogicalNotOnLHSofCheck(*this, LHS, RHS, Loc, Opc); if (LHS.get()->getType()->hasFloatingRepresentation() || RHS.get()->getType()->hasFloatingRepresentation()) return InvalidOperands(Loc, LHS, RHS); ExprResult LHSResult = LHS, RHSResult = RHS; QualType compType = UsualArithmeticConversions( LHSResult, RHSResult, Loc, IsCompAssign ? ACK_CompAssign : ACK_BitwiseOp); if (LHSResult.isInvalid() || RHSResult.isInvalid()) return QualType(); LHS = LHSResult.get(); RHS = RHSResult.get(); if (Opc == BO_Xor) diagnoseXorMisusedAsPow(*this, LHS, RHS, Loc); if (!compType.isNull() && compType->isIntegralOrUnscopedEnumerationType()) return compType; return InvalidOperands(Loc, LHS, RHS); } // C99 6.5.[13,14] inline QualType Sema::CheckLogicalOperands(ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, BinaryOperatorKind Opc) { // Check vector operands differently. if (LHS.get()->getType()->isVectorType() || RHS.get()->getType()->isVectorType()) return CheckVectorLogicalOperands(LHS, RHS, Loc); bool EnumConstantInBoolContext = false; for (const ExprResult &HS : {LHS, RHS}) { if (const auto *DREHS = dyn_cast(HS.get())) { const auto *ECDHS = dyn_cast(DREHS->getDecl()); if (ECDHS && ECDHS->getInitVal() != 0 && ECDHS->getInitVal() != 1) EnumConstantInBoolContext = true; } } if (EnumConstantInBoolContext) Diag(Loc, diag::warn_enum_constant_in_bool_context); // Diagnose cases where the user write a logical and/or but probably meant a // bitwise one. We do this when the LHS is a non-bool integer and the RHS // is a constant. if (!EnumConstantInBoolContext && LHS.get()->getType()->isIntegerType() && !LHS.get()->getType()->isBooleanType() && RHS.get()->getType()->isIntegerType() && !RHS.get()->isValueDependent() && // Don't warn in macros or template instantiations. !Loc.isMacroID() && !inTemplateInstantiation()) { // If the RHS can be constant folded, and if it constant folds to something // that isn't 0 or 1 (which indicate a potential logical operation that // happened to fold to true/false) then warn. // Parens on the RHS are ignored. Expr::EvalResult EVResult; if (RHS.get()->EvaluateAsInt(EVResult, Context)) { llvm::APSInt Result = EVResult.Val.getInt(); if ((getLangOpts().Bool && !RHS.get()->getType()->isBooleanType() && !RHS.get()->getExprLoc().isMacroID()) || (Result != 0 && Result != 1)) { Diag(Loc, diag::warn_logical_instead_of_bitwise) << RHS.get()->getSourceRange() << (Opc == BO_LAnd ? "&&" : "||"); // Suggest replacing the logical operator with the bitwise version Diag(Loc, diag::note_logical_instead_of_bitwise_change_operator) << (Opc == BO_LAnd ? "&" : "|") << FixItHint::CreateReplacement(SourceRange( Loc, getLocForEndOfToken(Loc)), Opc == BO_LAnd ? "&" : "|"); if (Opc == BO_LAnd) // Suggest replacing "Foo() && kNonZero" with "Foo()" Diag(Loc, diag::note_logical_instead_of_bitwise_remove_constant) << FixItHint::CreateRemoval( SourceRange(getLocForEndOfToken(LHS.get()->getEndLoc()), RHS.get()->getEndLoc())); } } } if (!Context.getLangOpts().CPlusPlus) { // OpenCL v1.1 s6.3.g: The logical operators and (&&), or (||) do // not operate on the built-in scalar and vector float types. if (Context.getLangOpts().OpenCL && Context.getLangOpts().OpenCLVersion < 120) { if (LHS.get()->getType()->isFloatingType() || RHS.get()->getType()->isFloatingType()) return InvalidOperands(Loc, LHS, RHS); } LHS = UsualUnaryConversions(LHS.get()); if (LHS.isInvalid()) return QualType(); RHS = UsualUnaryConversions(RHS.get()); if (RHS.isInvalid()) return QualType(); if (!LHS.get()->getType()->isScalarType() || !RHS.get()->getType()->isScalarType()) return InvalidOperands(Loc, LHS, RHS); return Context.IntTy; } // The following is safe because we only use this method for // non-overloadable operands. // C++ [expr.log.and]p1 // C++ [expr.log.or]p1 // The operands are both contextually converted to type bool. ExprResult LHSRes = PerformContextuallyConvertToBool(LHS.get()); if (LHSRes.isInvalid()) return InvalidOperands(Loc, LHS, RHS); LHS = LHSRes; ExprResult RHSRes = PerformContextuallyConvertToBool(RHS.get()); if (RHSRes.isInvalid()) return InvalidOperands(Loc, LHS, RHS); RHS = RHSRes; // C++ [expr.log.and]p2 // C++ [expr.log.or]p2 // The result is a bool. return Context.BoolTy; } static bool IsReadonlyMessage(Expr *E, Sema &S) { const MemberExpr *ME = dyn_cast(E); if (!ME) return false; if (!isa(ME->getMemberDecl())) return false; ObjCMessageExpr *Base = dyn_cast( ME->getBase()->IgnoreImplicit()->IgnoreParenImpCasts()); if (!Base) return false; return Base->getMethodDecl() != nullptr; } /// Is the given expression (which must be 'const') a reference to a /// variable which was originally non-const, but which has become /// 'const' due to being captured within a block? enum NonConstCaptureKind { NCCK_None, NCCK_Block, NCCK_Lambda }; static NonConstCaptureKind isReferenceToNonConstCapture(Sema &S, Expr *E) { assert(E->isLValue() && E->getType().isConstQualified()); E = E->IgnoreParens(); // Must be a reference to a declaration from an enclosing scope. DeclRefExpr *DRE = dyn_cast(E); if (!DRE) return NCCK_None; if (!DRE->refersToEnclosingVariableOrCapture()) return NCCK_None; // The declaration must be a variable which is not declared 'const'. VarDecl *var = dyn_cast(DRE->getDecl()); if (!var) return NCCK_None; if (var->getType().isConstQualified()) return NCCK_None; assert(var->hasLocalStorage() && "capture added 'const' to non-local?"); // Decide whether the first capture was for a block or a lambda. DeclContext *DC = S.CurContext, *Prev = nullptr; // Decide whether the first capture was for a block or a lambda. while (DC) { // For init-capture, it is possible that the variable belongs to the // template pattern of the current context. if (auto *FD = dyn_cast(DC)) if (var->isInitCapture() && FD->getTemplateInstantiationPattern() == var->getDeclContext()) break; if (DC == var->getDeclContext()) break; Prev = DC; DC = DC->getParent(); } // Unless we have an init-capture, we've gone one step too far. if (!var->isInitCapture()) DC = Prev; return (isa(DC) ? NCCK_Block : NCCK_Lambda); } static bool IsTypeModifiable(QualType Ty, bool IsDereference) { Ty = Ty.getNonReferenceType(); if (IsDereference && Ty->isPointerType()) Ty = Ty->getPointeeType(); return !Ty.isConstQualified(); } // Update err_typecheck_assign_const and note_typecheck_assign_const // when this enum is changed. enum { ConstFunction, ConstVariable, ConstMember, ConstMethod, NestedConstMember, ConstUnknown, // Keep as last element }; /// Emit the "read-only variable not assignable" error and print notes to give /// more information about why the variable is not assignable, such as pointing /// to the declaration of a const variable, showing that a method is const, or /// that the function is returning a const reference. static void DiagnoseConstAssignment(Sema &S, const Expr *E, SourceLocation Loc) { SourceRange ExprRange = E->getSourceRange(); // Only emit one error on the first const found. All other consts will emit // a note to the error. bool DiagnosticEmitted = false; // Track if the current expression is the result of a dereference, and if the // next checked expression is the result of a dereference. bool IsDereference = false; bool NextIsDereference = false; // Loop to process MemberExpr chains. while (true) { IsDereference = NextIsDereference; E = E->IgnoreImplicit()->IgnoreParenImpCasts(); if (const MemberExpr *ME = dyn_cast(E)) { NextIsDereference = ME->isArrow(); const ValueDecl *VD = ME->getMemberDecl(); if (const FieldDecl *Field = dyn_cast(VD)) { // Mutable fields can be modified even if the class is const. if (Field->isMutable()) { assert(DiagnosticEmitted && "Expected diagnostic not emitted."); break; } if (!IsTypeModifiable(Field->getType(), IsDereference)) { if (!DiagnosticEmitted) { S.Diag(Loc, diag::err_typecheck_assign_const) << ExprRange << ConstMember << false /*static*/ << Field << Field->getType(); DiagnosticEmitted = true; } S.Diag(VD->getLocation(), diag::note_typecheck_assign_const) << ConstMember << false /*static*/ << Field << Field->getType() << Field->getSourceRange(); } E = ME->getBase(); continue; } else if (const VarDecl *VDecl = dyn_cast(VD)) { if (VDecl->getType().isConstQualified()) { if (!DiagnosticEmitted) { S.Diag(Loc, diag::err_typecheck_assign_const) << ExprRange << ConstMember << true /*static*/ << VDecl << VDecl->getType(); DiagnosticEmitted = true; } S.Diag(VD->getLocation(), diag::note_typecheck_assign_const) << ConstMember << true /*static*/ << VDecl << VDecl->getType() << VDecl->getSourceRange(); } // Static fields do not inherit constness from parents. break; } break; // End MemberExpr } else if (const ArraySubscriptExpr *ASE = dyn_cast(E)) { E = ASE->getBase()->IgnoreParenImpCasts(); continue; } else if (const ExtVectorElementExpr *EVE = dyn_cast(E)) { E = EVE->getBase()->IgnoreParenImpCasts(); continue; } break; } if (const CallExpr *CE = dyn_cast(E)) { // Function calls const FunctionDecl *FD = CE->getDirectCallee(); if (FD && !IsTypeModifiable(FD->getReturnType(), IsDereference)) { if (!DiagnosticEmitted) { S.Diag(Loc, diag::err_typecheck_assign_const) << ExprRange << ConstFunction << FD; DiagnosticEmitted = true; } S.Diag(FD->getReturnTypeSourceRange().getBegin(), diag::note_typecheck_assign_const) << ConstFunction << FD << FD->getReturnType() << FD->getReturnTypeSourceRange(); } } else if (const DeclRefExpr *DRE = dyn_cast(E)) { // Point to variable declaration. if (const ValueDecl *VD = DRE->getDecl()) { if (!IsTypeModifiable(VD->getType(), IsDereference)) { if (!DiagnosticEmitted) { S.Diag(Loc, diag::err_typecheck_assign_const) << ExprRange << ConstVariable << VD << VD->getType(); DiagnosticEmitted = true; } S.Diag(VD->getLocation(), diag::note_typecheck_assign_const) << ConstVariable << VD << VD->getType() << VD->getSourceRange(); } } } else if (isa(E)) { if (const DeclContext *DC = S.getFunctionLevelDeclContext()) { if (const CXXMethodDecl *MD = dyn_cast(DC)) { if (MD->isConst()) { if (!DiagnosticEmitted) { S.Diag(Loc, diag::err_typecheck_assign_const) << ExprRange << ConstMethod << MD; DiagnosticEmitted = true; } S.Diag(MD->getLocation(), diag::note_typecheck_assign_const) << ConstMethod << MD << MD->getSourceRange(); } } } } if (DiagnosticEmitted) return; // Can't determine a more specific message, so display the generic error. S.Diag(Loc, diag::err_typecheck_assign_const) << ExprRange << ConstUnknown; } enum OriginalExprKind { OEK_Variable, OEK_Member, OEK_LValue }; static void DiagnoseRecursiveConstFields(Sema &S, const ValueDecl *VD, const RecordType *Ty, SourceLocation Loc, SourceRange Range, OriginalExprKind OEK, bool &DiagnosticEmitted) { std::vector RecordTypeList; RecordTypeList.push_back(Ty); unsigned NextToCheckIndex = 0; // We walk the record hierarchy breadth-first to ensure that we print // diagnostics in field nesting order. while (RecordTypeList.size() > NextToCheckIndex) { bool IsNested = NextToCheckIndex > 0; for (const FieldDecl *Field : RecordTypeList[NextToCheckIndex]->getDecl()->fields()) { // First, check every field for constness. QualType FieldTy = Field->getType(); if (FieldTy.isConstQualified()) { if (!DiagnosticEmitted) { S.Diag(Loc, diag::err_typecheck_assign_const) << Range << NestedConstMember << OEK << VD << IsNested << Field; DiagnosticEmitted = true; } S.Diag(Field->getLocation(), diag::note_typecheck_assign_const) << NestedConstMember << IsNested << Field << FieldTy << Field->getSourceRange(); } // Then we append it to the list to check next in order. FieldTy = FieldTy.getCanonicalType(); if (const auto *FieldRecTy = FieldTy->getAs()) { if (llvm::find(RecordTypeList, FieldRecTy) == RecordTypeList.end()) RecordTypeList.push_back(FieldRecTy); } } ++NextToCheckIndex; } } /// Emit an error for the case where a record we are trying to assign to has a /// const-qualified field somewhere in its hierarchy. static void DiagnoseRecursiveConstFields(Sema &S, const Expr *E, SourceLocation Loc) { QualType Ty = E->getType(); assert(Ty->isRecordType() && "lvalue was not record?"); SourceRange Range = E->getSourceRange(); const RecordType *RTy = Ty.getCanonicalType()->getAs(); bool DiagEmitted = false; if (const MemberExpr *ME = dyn_cast(E)) DiagnoseRecursiveConstFields(S, ME->getMemberDecl(), RTy, Loc, Range, OEK_Member, DiagEmitted); else if (const DeclRefExpr *DRE = dyn_cast(E)) DiagnoseRecursiveConstFields(S, DRE->getDecl(), RTy, Loc, Range, OEK_Variable, DiagEmitted); else DiagnoseRecursiveConstFields(S, nullptr, RTy, Loc, Range, OEK_LValue, DiagEmitted); if (!DiagEmitted) DiagnoseConstAssignment(S, E, Loc); } /// CheckForModifiableLvalue - Verify that E is a modifiable lvalue. If not, /// emit an error and return true. If so, return false. static bool CheckForModifiableLvalue(Expr *E, SourceLocation Loc, Sema &S) { assert(!E->hasPlaceholderType(BuiltinType::PseudoObject)); S.CheckShadowingDeclModification(E, Loc); SourceLocation OrigLoc = Loc; Expr::isModifiableLvalueResult IsLV = E->isModifiableLvalue(S.Context, &Loc); if (IsLV == Expr::MLV_ClassTemporary && IsReadonlyMessage(E, S)) IsLV = Expr::MLV_InvalidMessageExpression; if (IsLV == Expr::MLV_Valid) return false; unsigned DiagID = 0; bool NeedType = false; switch (IsLV) { // C99 6.5.16p2 case Expr::MLV_ConstQualified: // Use a specialized diagnostic when we're assigning to an object // from an enclosing function or block. if (NonConstCaptureKind NCCK = isReferenceToNonConstCapture(S, E)) { if (NCCK == NCCK_Block) DiagID = diag::err_block_decl_ref_not_modifiable_lvalue; else DiagID = diag::err_lambda_decl_ref_not_modifiable_lvalue; break; } // In ARC, use some specialized diagnostics for occasions where we // infer 'const'. These are always pseudo-strong variables. if (S.getLangOpts().ObjCAutoRefCount) { DeclRefExpr *declRef = dyn_cast(E->IgnoreParenCasts()); if (declRef && isa(declRef->getDecl())) { VarDecl *var = cast(declRef->getDecl()); // Use the normal diagnostic if it's pseudo-__strong but the // user actually wrote 'const'. if (var->isARCPseudoStrong() && (!var->getTypeSourceInfo() || !var->getTypeSourceInfo()->getType().isConstQualified())) { // There are three pseudo-strong cases: // - self ObjCMethodDecl *method = S.getCurMethodDecl(); if (method && var == method->getSelfDecl()) { DiagID = method->isClassMethod() ? diag::err_typecheck_arc_assign_self_class_method : diag::err_typecheck_arc_assign_self; // - Objective-C externally_retained attribute. } else if (var->hasAttr() || isa(var)) { DiagID = diag::err_typecheck_arc_assign_externally_retained; // - fast enumeration variables } else { DiagID = diag::err_typecheck_arr_assign_enumeration; } SourceRange Assign; if (Loc != OrigLoc) Assign = SourceRange(OrigLoc, OrigLoc); S.Diag(Loc, DiagID) << E->getSourceRange() << Assign; // We need to preserve the AST regardless, so migration tool // can do its job. return false; } } } // If none of the special cases above are triggered, then this is a // simple const assignment. if (DiagID == 0) { DiagnoseConstAssignment(S, E, Loc); return true; } break; case Expr::MLV_ConstAddrSpace: DiagnoseConstAssignment(S, E, Loc); return true; case Expr::MLV_ConstQualifiedField: DiagnoseRecursiveConstFields(S, E, Loc); return true; case Expr::MLV_ArrayType: case Expr::MLV_ArrayTemporary: DiagID = diag::err_typecheck_array_not_modifiable_lvalue; NeedType = true; break; case Expr::MLV_NotObjectType: DiagID = diag::err_typecheck_non_object_not_modifiable_lvalue; NeedType = true; break; case Expr::MLV_LValueCast: DiagID = diag::err_typecheck_lvalue_casts_not_supported; break; case Expr::MLV_Valid: llvm_unreachable("did not take early return for MLV_Valid"); case Expr::MLV_InvalidExpression: case Expr::MLV_MemberFunction: case Expr::MLV_ClassTemporary: DiagID = diag::err_typecheck_expression_not_modifiable_lvalue; break; case Expr::MLV_IncompleteType: case Expr::MLV_IncompleteVoidType: return S.RequireCompleteType(Loc, E->getType(), diag::err_typecheck_incomplete_type_not_modifiable_lvalue, E); case Expr::MLV_DuplicateVectorComponents: DiagID = diag::err_typecheck_duplicate_vector_components_not_mlvalue; break; case Expr::MLV_NoSetterProperty: llvm_unreachable("readonly properties should be processed differently"); case Expr::MLV_InvalidMessageExpression: DiagID = diag::err_readonly_message_assignment; break; case Expr::MLV_SubObjCPropertySetting: DiagID = diag::err_no_subobject_property_setting; break; } SourceRange Assign; if (Loc != OrigLoc) Assign = SourceRange(OrigLoc, OrigLoc); if (NeedType) S.Diag(Loc, DiagID) << E->getType() << E->getSourceRange() << Assign; else S.Diag(Loc, DiagID) << E->getSourceRange() << Assign; return true; } static void CheckIdentityFieldAssignment(Expr *LHSExpr, Expr *RHSExpr, SourceLocation Loc, Sema &Sema) { if (Sema.inTemplateInstantiation()) return; if (Sema.isUnevaluatedContext()) return; if (Loc.isInvalid() || Loc.isMacroID()) return; if (LHSExpr->getExprLoc().isMacroID() || RHSExpr->getExprLoc().isMacroID()) return; // C / C++ fields MemberExpr *ML = dyn_cast(LHSExpr); MemberExpr *MR = dyn_cast(RHSExpr); if (ML && MR) { if (!(isa(ML->getBase()) && isa(MR->getBase()))) return; const ValueDecl *LHSDecl = cast(ML->getMemberDecl()->getCanonicalDecl()); const ValueDecl *RHSDecl = cast(MR->getMemberDecl()->getCanonicalDecl()); if (LHSDecl != RHSDecl) return; if (LHSDecl->getType().isVolatileQualified()) return; if (const ReferenceType *RefTy = LHSDecl->getType()->getAs()) if (RefTy->getPointeeType().isVolatileQualified()) return; Sema.Diag(Loc, diag::warn_identity_field_assign) << 0; } // Objective-C instance variables ObjCIvarRefExpr *OL = dyn_cast(LHSExpr); ObjCIvarRefExpr *OR = dyn_cast(RHSExpr); if (OL && OR && OL->getDecl() == OR->getDecl()) { DeclRefExpr *RL = dyn_cast(OL->getBase()->IgnoreImpCasts()); DeclRefExpr *RR = dyn_cast(OR->getBase()->IgnoreImpCasts()); if (RL && RR && RL->getDecl() == RR->getDecl()) Sema.Diag(Loc, diag::warn_identity_field_assign) << 1; } } // C99 6.5.16.1 QualType Sema::CheckAssignmentOperands(Expr *LHSExpr, ExprResult &RHS, SourceLocation Loc, QualType CompoundType) { assert(!LHSExpr->hasPlaceholderType(BuiltinType::PseudoObject)); // Verify that LHS is a modifiable lvalue, and emit error if not. if (CheckForModifiableLvalue(LHSExpr, Loc, *this)) return QualType(); QualType LHSType = LHSExpr->getType(); QualType RHSType = CompoundType.isNull() ? RHS.get()->getType() : CompoundType; // OpenCL v1.2 s6.1.1.1 p2: // The half data type can only be used to declare a pointer to a buffer that // contains half values if (getLangOpts().OpenCL && !getOpenCLOptions().isEnabled("cl_khr_fp16") && LHSType->isHalfType()) { Diag(Loc, diag::err_opencl_half_load_store) << 1 << LHSType.getUnqualifiedType(); return QualType(); } AssignConvertType ConvTy; if (CompoundType.isNull()) { Expr *RHSCheck = RHS.get(); CheckIdentityFieldAssignment(LHSExpr, RHSCheck, Loc, *this); QualType LHSTy(LHSType); ConvTy = CheckSingleAssignmentConstraints(LHSTy, RHS); if (RHS.isInvalid()) return QualType(); // Special case of NSObject attributes on c-style pointer types. if (ConvTy == IncompatiblePointer && ((Context.isObjCNSObjectType(LHSType) && RHSType->isObjCObjectPointerType()) || (Context.isObjCNSObjectType(RHSType) && LHSType->isObjCObjectPointerType()))) ConvTy = Compatible; if (ConvTy == Compatible && LHSType->isObjCObjectType()) Diag(Loc, diag::err_objc_object_assignment) << LHSType; // If the RHS is a unary plus or minus, check to see if they = and + are // right next to each other. If so, the user may have typo'd "x =+ 4" // instead of "x += 4". if (ImplicitCastExpr *ICE = dyn_cast(RHSCheck)) RHSCheck = ICE->getSubExpr(); if (UnaryOperator *UO = dyn_cast(RHSCheck)) { if ((UO->getOpcode() == UO_Plus || UO->getOpcode() == UO_Minus) && Loc.isFileID() && UO->getOperatorLoc().isFileID() && // Only if the two operators are exactly adjacent. Loc.getLocWithOffset(1) == UO->getOperatorLoc() && // And there is a space or other character before the subexpr of the // unary +/-. We don't want to warn on "x=-1". Loc.getLocWithOffset(2) != UO->getSubExpr()->getBeginLoc() && UO->getSubExpr()->getBeginLoc().isFileID()) { Diag(Loc, diag::warn_not_compound_assign) << (UO->getOpcode() == UO_Plus ? "+" : "-") << SourceRange(UO->getOperatorLoc(), UO->getOperatorLoc()); } } if (ConvTy == Compatible) { if (LHSType.getObjCLifetime() == Qualifiers::OCL_Strong) { // Warn about retain cycles where a block captures the LHS, but // not if the LHS is a simple variable into which the block is // being stored...unless that variable can be captured by reference! const Expr *InnerLHS = LHSExpr->IgnoreParenCasts(); const DeclRefExpr *DRE = dyn_cast(InnerLHS); if (!DRE || DRE->getDecl()->hasAttr()) checkRetainCycles(LHSExpr, RHS.get()); } if (LHSType.getObjCLifetime() == Qualifiers::OCL_Strong || LHSType.isNonWeakInMRRWithObjCWeak(Context)) { // It is safe to assign a weak reference into a strong variable. // Although this code can still have problems: // id x = self.weakProp; // id y = self.weakProp; // we do not warn to warn spuriously when 'x' and 'y' are on separate // paths through the function. This should be revisited if // -Wrepeated-use-of-weak is made flow-sensitive. // For ObjCWeak only, we do not warn if the assign is to a non-weak // variable, which will be valid for the current autorelease scope. if (!Diags.isIgnored(diag::warn_arc_repeated_use_of_weak, RHS.get()->getBeginLoc())) getCurFunction()->markSafeWeakUse(RHS.get()); } else if (getLangOpts().ObjCAutoRefCount || getLangOpts().ObjCWeak) { checkUnsafeExprAssigns(Loc, LHSExpr, RHS.get()); } } } else { // Compound assignment "x += y" ConvTy = CheckAssignmentConstraints(Loc, LHSType, RHSType); } if (DiagnoseAssignmentResult(ConvTy, Loc, LHSType, RHSType, RHS.get(), AA_Assigning)) return QualType(); CheckForNullPointerDereference(*this, LHSExpr); if (getLangOpts().CPlusPlus2a && LHSType.isVolatileQualified()) { if (CompoundType.isNull()) { // C++2a [expr.ass]p5: // A simple-assignment whose left operand is of a volatile-qualified // type is deprecated unless the assignment is either a discarded-value // expression or an unevaluated operand ExprEvalContexts.back().VolatileAssignmentLHSs.push_back(LHSExpr); } else { // C++2a [expr.ass]p6: // [Compound-assignment] expressions are deprecated if E1 has // volatile-qualified type Diag(Loc, diag::warn_deprecated_compound_assign_volatile) << LHSType; } } // C99 6.5.16p3: The type of an assignment expression is the type of the // left operand unless the left operand has qualified type, in which case // it is the unqualified version of the type of the left operand. // C99 6.5.16.1p2: In simple assignment, the value of the right operand // is converted to the type of the assignment expression (above). // C++ 5.17p1: the type of the assignment expression is that of its left // operand. return (getLangOpts().CPlusPlus ? LHSType : LHSType.getUnqualifiedType()); } // Only ignore explicit casts to void. static bool IgnoreCommaOperand(const Expr *E) { E = E->IgnoreParens(); if (const CastExpr *CE = dyn_cast(E)) { if (CE->getCastKind() == CK_ToVoid) { return true; } // static_cast on a dependent type will not show up as CK_ToVoid. if (CE->getCastKind() == CK_Dependent && E->getType()->isVoidType() && CE->getSubExpr()->getType()->isDependentType()) { return true; } } return false; } // Look for instances where it is likely the comma operator is confused with // another operator. There is a whitelist of acceptable expressions for the // left hand side of the comma operator, otherwise emit a warning. void Sema::DiagnoseCommaOperator(const Expr *LHS, SourceLocation Loc) { // No warnings in macros if (Loc.isMacroID()) return; // Don't warn in template instantiations. if (inTemplateInstantiation()) return; // Scope isn't fine-grained enough to whitelist the specific cases, so // instead, skip more than needed, then call back into here with the // CommaVisitor in SemaStmt.cpp. // The whitelisted locations are the initialization and increment portions // of a for loop. The additional checks are on the condition of // if statements, do/while loops, and for loops. // Differences in scope flags for C89 mode requires the extra logic. const unsigned ForIncrementFlags = getLangOpts().C99 || getLangOpts().CPlusPlus ? Scope::ControlScope | Scope::ContinueScope | Scope::BreakScope : Scope::ContinueScope | Scope::BreakScope; const unsigned ForInitFlags = Scope::ControlScope | Scope::DeclScope; const unsigned ScopeFlags = getCurScope()->getFlags(); if ((ScopeFlags & ForIncrementFlags) == ForIncrementFlags || (ScopeFlags & ForInitFlags) == ForInitFlags) return; // If there are multiple comma operators used together, get the RHS of the // of the comma operator as the LHS. while (const BinaryOperator *BO = dyn_cast(LHS)) { if (BO->getOpcode() != BO_Comma) break; LHS = BO->getRHS(); } // Only allow some expressions on LHS to not warn. if (IgnoreCommaOperand(LHS)) return; Diag(Loc, diag::warn_comma_operator); Diag(LHS->getBeginLoc(), diag::note_cast_to_void) << LHS->getSourceRange() << FixItHint::CreateInsertion(LHS->getBeginLoc(), LangOpts.CPlusPlus ? "static_cast(" : "(void)(") << FixItHint::CreateInsertion(PP.getLocForEndOfToken(LHS->getEndLoc()), ")"); } // C99 6.5.17 static QualType CheckCommaOperands(Sema &S, ExprResult &LHS, ExprResult &RHS, SourceLocation Loc) { LHS = S.CheckPlaceholderExpr(LHS.get()); RHS = S.CheckPlaceholderExpr(RHS.get()); if (LHS.isInvalid() || RHS.isInvalid()) return QualType(); // C's comma performs lvalue conversion (C99 6.3.2.1) on both its // operands, but not unary promotions. // C++'s comma does not do any conversions at all (C++ [expr.comma]p1). // So we treat the LHS as a ignored value, and in C++ we allow the // containing site to determine what should be done with the RHS. LHS = S.IgnoredValueConversions(LHS.get()); if (LHS.isInvalid()) return QualType(); S.DiagnoseUnusedExprResult(LHS.get()); if (!S.getLangOpts().CPlusPlus) { RHS = S.DefaultFunctionArrayLvalueConversion(RHS.get()); if (RHS.isInvalid()) return QualType(); if (!RHS.get()->getType()->isVoidType()) S.RequireCompleteType(Loc, RHS.get()->getType(), diag::err_incomplete_type); } if (!S.getDiagnostics().isIgnored(diag::warn_comma_operator, Loc)) S.DiagnoseCommaOperator(LHS.get(), Loc); return RHS.get()->getType(); } /// CheckIncrementDecrementOperand - unlike most "Check" methods, this routine /// doesn't need to call UsualUnaryConversions or UsualArithmeticConversions. static QualType CheckIncrementDecrementOperand(Sema &S, Expr *Op, ExprValueKind &VK, ExprObjectKind &OK, SourceLocation OpLoc, bool IsInc, bool IsPrefix) { if (Op->isTypeDependent()) return S.Context.DependentTy; QualType ResType = Op->getType(); // Atomic types can be used for increment / decrement where the non-atomic // versions can, so ignore the _Atomic() specifier for the purpose of // checking. if (const AtomicType *ResAtomicType = ResType->getAs()) ResType = ResAtomicType->getValueType(); assert(!ResType.isNull() && "no type for increment/decrement expression"); if (S.getLangOpts().CPlusPlus && ResType->isBooleanType()) { // Decrement of bool is not allowed. if (!IsInc) { S.Diag(OpLoc, diag::err_decrement_bool) << Op->getSourceRange(); return QualType(); } // Increment of bool sets it to true, but is deprecated. S.Diag(OpLoc, S.getLangOpts().CPlusPlus17 ? diag::ext_increment_bool : diag::warn_increment_bool) << Op->getSourceRange(); } else if (S.getLangOpts().CPlusPlus && ResType->isEnumeralType()) { // Error on enum increments and decrements in C++ mode S.Diag(OpLoc, diag::err_increment_decrement_enum) << IsInc << ResType; return QualType(); } else if (ResType->isRealType()) { // OK! } else if (ResType->isPointerType()) { // C99 6.5.2.4p2, 6.5.6p2 if (!checkArithmeticOpPointerOperand(S, OpLoc, Op)) return QualType(); } else if (ResType->isObjCObjectPointerType()) { // On modern runtimes, ObjC pointer arithmetic is forbidden. // Otherwise, we just need a complete type. if (checkArithmeticIncompletePointerType(S, OpLoc, Op) || checkArithmeticOnObjCPointer(S, OpLoc, Op)) return QualType(); } else if (ResType->isAnyComplexType()) { // C99 does not support ++/-- on complex types, we allow as an extension. S.Diag(OpLoc, diag::ext_integer_increment_complex) << ResType << Op->getSourceRange(); } else if (ResType->isPlaceholderType()) { ExprResult PR = S.CheckPlaceholderExpr(Op); if (PR.isInvalid()) return QualType(); return CheckIncrementDecrementOperand(S, PR.get(), VK, OK, OpLoc, IsInc, IsPrefix); } else if (S.getLangOpts().AltiVec && ResType->isVectorType()) { // OK! ( C/C++ Language Extensions for CBEA(Version 2.6) 10.3 ) } else if (S.getLangOpts().ZVector && ResType->isVectorType() && (ResType->castAs()->getVectorKind() != VectorType::AltiVecBool)) { // The z vector extensions allow ++ and -- for non-bool vectors. } else if(S.getLangOpts().OpenCL && ResType->isVectorType() && ResType->castAs()->getElementType()->isIntegerType()) { // OpenCL V1.2 6.3 says dec/inc ops operate on integer vector types. } else { S.Diag(OpLoc, diag::err_typecheck_illegal_increment_decrement) << ResType << int(IsInc) << Op->getSourceRange(); return QualType(); } // At this point, we know we have a real, complex or pointer type. // Now make sure the operand is a modifiable lvalue. if (CheckForModifiableLvalue(Op, OpLoc, S)) return QualType(); if (S.getLangOpts().CPlusPlus2a && ResType.isVolatileQualified()) { // C++2a [expr.pre.inc]p1, [expr.post.inc]p1: // An operand with volatile-qualified type is deprecated S.Diag(OpLoc, diag::warn_deprecated_increment_decrement_volatile) << IsInc << ResType; } // In C++, a prefix increment is the same type as the operand. Otherwise // (in C or with postfix), the increment is the unqualified type of the // operand. if (IsPrefix && S.getLangOpts().CPlusPlus) { VK = VK_LValue; OK = Op->getObjectKind(); return ResType; } else { VK = VK_RValue; return ResType.getUnqualifiedType(); } } /// getPrimaryDecl - Helper function for CheckAddressOfOperand(). /// This routine allows us to typecheck complex/recursive expressions /// where the declaration is needed for type checking. We only need to /// handle cases when the expression references a function designator /// or is an lvalue. Here are some examples: /// - &(x) => x /// - &*****f => f for f a function designator. /// - &s.xx => s /// - &s.zz[1].yy -> s, if zz is an array /// - *(x + 1) -> x, if x is an array /// - &"123"[2] -> 0 /// - & __real__ x -> x static ValueDecl *getPrimaryDecl(Expr *E) { switch (E->getStmtClass()) { case Stmt::DeclRefExprClass: return cast(E)->getDecl(); case Stmt::MemberExprClass: // If this is an arrow operator, the address is an offset from // the base's value, so the object the base refers to is // irrelevant. if (cast(E)->isArrow()) return nullptr; // Otherwise, the expression refers to a part of the base return getPrimaryDecl(cast(E)->getBase()); case Stmt::ArraySubscriptExprClass: { // FIXME: This code shouldn't be necessary! We should catch the implicit // promotion of register arrays earlier. Expr* Base = cast(E)->getBase(); if (ImplicitCastExpr* ICE = dyn_cast(Base)) { if (ICE->getSubExpr()->getType()->isArrayType()) return getPrimaryDecl(ICE->getSubExpr()); } return nullptr; } case Stmt::UnaryOperatorClass: { UnaryOperator *UO = cast(E); switch(UO->getOpcode()) { case UO_Real: case UO_Imag: case UO_Extension: return getPrimaryDecl(UO->getSubExpr()); default: return nullptr; } } case Stmt::ParenExprClass: return getPrimaryDecl(cast(E)->getSubExpr()); case Stmt::ImplicitCastExprClass: // If the result of an implicit cast is an l-value, we care about // the sub-expression; otherwise, the result here doesn't matter. return getPrimaryDecl(cast(E)->getSubExpr()); default: return nullptr; } } namespace { enum { AO_Bit_Field = 0, AO_Vector_Element = 1, AO_Property_Expansion = 2, AO_Register_Variable = 3, AO_No_Error = 4 }; } /// Diagnose invalid operand for address of operations. /// /// \param Type The type of operand which cannot have its address taken. static void diagnoseAddressOfInvalidType(Sema &S, SourceLocation Loc, Expr *E, unsigned Type) { S.Diag(Loc, diag::err_typecheck_address_of) << Type << E->getSourceRange(); } /// CheckAddressOfOperand - The operand of & must be either a function /// designator or an lvalue designating an object. If it is an lvalue, the /// object cannot be declared with storage class register or be a bit field. /// Note: The usual conversions are *not* applied to the operand of the & /// operator (C99 6.3.2.1p[2-4]), and its result is never an lvalue. /// In C++, the operand might be an overloaded function name, in which case /// we allow the '&' but retain the overloaded-function type. QualType Sema::CheckAddressOfOperand(ExprResult &OrigOp, SourceLocation OpLoc) { if (const BuiltinType *PTy = OrigOp.get()->getType()->getAsPlaceholderType()){ if (PTy->getKind() == BuiltinType::Overload) { Expr *E = OrigOp.get()->IgnoreParens(); if (!isa(E)) { assert(cast(E)->getOpcode() == UO_AddrOf); Diag(OpLoc, diag::err_typecheck_invalid_lvalue_addrof_addrof_function) << OrigOp.get()->getSourceRange(); return QualType(); } OverloadExpr *Ovl = cast(E); if (isa(Ovl)) if (!ResolveSingleFunctionTemplateSpecialization(Ovl)) { Diag(OpLoc, diag::err_invalid_form_pointer_member_function) << OrigOp.get()->getSourceRange(); return QualType(); } return Context.OverloadTy; } if (PTy->getKind() == BuiltinType::UnknownAny) return Context.UnknownAnyTy; if (PTy->getKind() == BuiltinType::BoundMember) { Diag(OpLoc, diag::err_invalid_form_pointer_member_function) << OrigOp.get()->getSourceRange(); return QualType(); } OrigOp = CheckPlaceholderExpr(OrigOp.get()); if (OrigOp.isInvalid()) return QualType(); } if (OrigOp.get()->isTypeDependent()) return Context.DependentTy; assert(!OrigOp.get()->getType()->isPlaceholderType()); // Make sure to ignore parentheses in subsequent checks Expr *op = OrigOp.get()->IgnoreParens(); // In OpenCL captures for blocks called as lambda functions // are located in the private address space. Blocks used in // enqueue_kernel can be located in a different address space // depending on a vendor implementation. Thus preventing // taking an address of the capture to avoid invalid AS casts. if (LangOpts.OpenCL) { auto* VarRef = dyn_cast(op); if (VarRef && VarRef->refersToEnclosingVariableOrCapture()) { Diag(op->getExprLoc(), diag::err_opencl_taking_address_capture); return QualType(); } } if (getLangOpts().C99) { // Implement C99-only parts of addressof rules. if (UnaryOperator* uOp = dyn_cast(op)) { if (uOp->getOpcode() == UO_Deref) // Per C99 6.5.3.2, the address of a deref always returns a valid result // (assuming the deref expression is valid). return uOp->getSubExpr()->getType(); } // Technically, there should be a check for array subscript // expressions here, but the result of one is always an lvalue anyway. } ValueDecl *dcl = getPrimaryDecl(op); if (auto *FD = dyn_cast_or_null(dcl)) if (!checkAddressOfFunctionIsAvailable(FD, /*Complain=*/true, op->getBeginLoc())) return QualType(); Expr::LValueClassification lval = op->ClassifyLValue(Context); unsigned AddressOfError = AO_No_Error; if (lval == Expr::LV_ClassTemporary || lval == Expr::LV_ArrayTemporary) { bool sfinae = (bool)isSFINAEContext(); Diag(OpLoc, isSFINAEContext() ? diag::err_typecheck_addrof_temporary : diag::ext_typecheck_addrof_temporary) << op->getType() << op->getSourceRange(); if (sfinae) return QualType(); // Materialize the temporary as an lvalue so that we can take its address. OrigOp = op = CreateMaterializeTemporaryExpr(op->getType(), OrigOp.get(), true); } else if (isa(op)) { return Context.getPointerType(op->getType()); } else if (lval == Expr::LV_MemberFunction) { // If it's an instance method, make a member pointer. // The expression must have exactly the form &A::foo. // If the underlying expression isn't a decl ref, give up. if (!isa(op)) { Diag(OpLoc, diag::err_invalid_form_pointer_member_function) << OrigOp.get()->getSourceRange(); return QualType(); } DeclRefExpr *DRE = cast(op); CXXMethodDecl *MD = cast(DRE->getDecl()); // The id-expression was parenthesized. if (OrigOp.get() != DRE) { Diag(OpLoc, diag::err_parens_pointer_member_function) << OrigOp.get()->getSourceRange(); // The method was named without a qualifier. } else if (!DRE->getQualifier()) { if (MD->getParent()->getName().empty()) Diag(OpLoc, diag::err_unqualified_pointer_member_function) << op->getSourceRange(); else { SmallString<32> Str; StringRef Qual = (MD->getParent()->getName() + "::").toStringRef(Str); Diag(OpLoc, diag::err_unqualified_pointer_member_function) << op->getSourceRange() << FixItHint::CreateInsertion(op->getSourceRange().getBegin(), Qual); } } // Taking the address of a dtor is illegal per C++ [class.dtor]p2. if (isa(MD)) Diag(OpLoc, diag::err_typecheck_addrof_dtor) << op->getSourceRange(); QualType MPTy = Context.getMemberPointerType( op->getType(), Context.getTypeDeclType(MD->getParent()).getTypePtr()); // Under the MS ABI, lock down the inheritance model now. if (Context.getTargetInfo().getCXXABI().isMicrosoft()) (void)isCompleteType(OpLoc, MPTy); return MPTy; } else if (lval != Expr::LV_Valid && lval != Expr::LV_IncompleteVoidType) { // C99 6.5.3.2p1 // The operand must be either an l-value or a function designator if (!op->getType()->isFunctionType()) { // Use a special diagnostic for loads from property references. if (isa(op)) { AddressOfError = AO_Property_Expansion; } else { Diag(OpLoc, diag::err_typecheck_invalid_lvalue_addrof) << op->getType() << op->getSourceRange(); return QualType(); } } } else if (op->getObjectKind() == OK_BitField) { // C99 6.5.3.2p1 // The operand cannot be a bit-field AddressOfError = AO_Bit_Field; } else if (op->getObjectKind() == OK_VectorComponent) { // The operand cannot be an element of a vector AddressOfError = AO_Vector_Element; } else if (dcl) { // C99 6.5.3.2p1 // We have an lvalue with a decl. Make sure the decl is not declared // with the register storage-class specifier. if (const VarDecl *vd = dyn_cast(dcl)) { // in C++ it is not error to take address of a register // variable (c++03 7.1.1P3) if (vd->getStorageClass() == SC_Register && !getLangOpts().CPlusPlus) { AddressOfError = AO_Register_Variable; } } else if (isa(dcl)) { AddressOfError = AO_Property_Expansion; } else if (isa(dcl)) { return Context.OverloadTy; } else if (isa(dcl) || isa(dcl)) { // Okay: we can take the address of a field. // Could be a pointer to member, though, if there is an explicit // scope qualifier for the class. if (isa(op) && cast(op)->getQualifier()) { DeclContext *Ctx = dcl->getDeclContext(); if (Ctx && Ctx->isRecord()) { if (dcl->getType()->isReferenceType()) { Diag(OpLoc, diag::err_cannot_form_pointer_to_member_of_reference_type) << dcl->getDeclName() << dcl->getType(); return QualType(); } while (cast(Ctx)->isAnonymousStructOrUnion()) Ctx = Ctx->getParent(); QualType MPTy = Context.getMemberPointerType( op->getType(), Context.getTypeDeclType(cast(Ctx)).getTypePtr()); // Under the MS ABI, lock down the inheritance model now. if (Context.getTargetInfo().getCXXABI().isMicrosoft()) (void)isCompleteType(OpLoc, MPTy); return MPTy; } } } else if (!isa(dcl) && !isa(dcl) && !isa(dcl)) llvm_unreachable("Unknown/unexpected decl type"); } if (AddressOfError != AO_No_Error) { diagnoseAddressOfInvalidType(*this, OpLoc, op, AddressOfError); return QualType(); } if (lval == Expr::LV_IncompleteVoidType) { // Taking the address of a void variable is technically illegal, but we // allow it in cases which are otherwise valid. // Example: "extern void x; void* y = &x;". Diag(OpLoc, diag::ext_typecheck_addrof_void) << op->getSourceRange(); } // If the operand has type "type", the result has type "pointer to type". if (op->getType()->isObjCObjectType()) return Context.getObjCObjectPointerType(op->getType()); CheckAddressOfPackedMember(op); return Context.getPointerType(op->getType()); } static void RecordModifiableNonNullParam(Sema &S, const Expr *Exp) { const DeclRefExpr *DRE = dyn_cast(Exp); if (!DRE) return; const Decl *D = DRE->getDecl(); if (!D) return; const ParmVarDecl *Param = dyn_cast(D); if (!Param) return; if (const FunctionDecl* FD = dyn_cast(Param->getDeclContext())) if (!FD->hasAttr() && !Param->hasAttr()) return; if (FunctionScopeInfo *FD = S.getCurFunction()) if (!FD->ModifiedNonNullParams.count(Param)) FD->ModifiedNonNullParams.insert(Param); } /// CheckIndirectionOperand - Type check unary indirection (prefix '*'). static QualType CheckIndirectionOperand(Sema &S, Expr *Op, ExprValueKind &VK, SourceLocation OpLoc) { if (Op->isTypeDependent()) return S.Context.DependentTy; ExprResult ConvResult = S.UsualUnaryConversions(Op); if (ConvResult.isInvalid()) return QualType(); Op = ConvResult.get(); QualType OpTy = Op->getType(); QualType Result; if (isa(Op)) { QualType OpOrigType = Op->IgnoreParenCasts()->getType(); S.CheckCompatibleReinterpretCast(OpOrigType, OpTy, /*IsDereference*/true, Op->getSourceRange()); } if (const PointerType *PT = OpTy->getAs()) { Result = PT->getPointeeType(); } else if (const ObjCObjectPointerType *OPT = OpTy->getAs()) Result = OPT->getPointeeType(); else { ExprResult PR = S.CheckPlaceholderExpr(Op); if (PR.isInvalid()) return QualType(); if (PR.get() != Op) return CheckIndirectionOperand(S, PR.get(), VK, OpLoc); } if (Result.isNull()) { S.Diag(OpLoc, diag::err_typecheck_indirection_requires_pointer) << OpTy << Op->getSourceRange(); return QualType(); } // Note that per both C89 and C99, indirection is always legal, even if Result // is an incomplete type or void. It would be possible to warn about // dereferencing a void pointer, but it's completely well-defined, and such a // warning is unlikely to catch any mistakes. In C++, indirection is not valid // for pointers to 'void' but is fine for any other pointer type: // // C++ [expr.unary.op]p1: // [...] the expression to which [the unary * operator] is applied shall // be a pointer to an object type, or a pointer to a function type if (S.getLangOpts().CPlusPlus && Result->isVoidType()) S.Diag(OpLoc, diag::ext_typecheck_indirection_through_void_pointer) << OpTy << Op->getSourceRange(); // Dereferences are usually l-values... VK = VK_LValue; // ...except that certain expressions are never l-values in C. if (!S.getLangOpts().CPlusPlus && Result.isCForbiddenLValueType()) VK = VK_RValue; return Result; } BinaryOperatorKind Sema::ConvertTokenKindToBinaryOpcode(tok::TokenKind Kind) { BinaryOperatorKind Opc; switch (Kind) { default: llvm_unreachable("Unknown binop!"); case tok::periodstar: Opc = BO_PtrMemD; break; case tok::arrowstar: Opc = BO_PtrMemI; break; case tok::star: Opc = BO_Mul; break; case tok::slash: Opc = BO_Div; break; case tok::percent: Opc = BO_Rem; break; case tok::plus: Opc = BO_Add; break; case tok::minus: Opc = BO_Sub; break; case tok::lessless: Opc = BO_Shl; break; case tok::greatergreater: Opc = BO_Shr; break; case tok::lessequal: Opc = BO_LE; break; case tok::less: Opc = BO_LT; break; case tok::greaterequal: Opc = BO_GE; break; case tok::greater: Opc = BO_GT; break; case tok::exclaimequal: Opc = BO_NE; break; case tok::equalequal: Opc = BO_EQ; break; case tok::spaceship: Opc = BO_Cmp; break; case tok::amp: Opc = BO_And; break; case tok::caret: Opc = BO_Xor; break; case tok::pipe: Opc = BO_Or; break; case tok::ampamp: Opc = BO_LAnd; break; case tok::pipepipe: Opc = BO_LOr; break; case tok::equal: Opc = BO_Assign; break; case tok::starequal: Opc = BO_MulAssign; break; case tok::slashequal: Opc = BO_DivAssign; break; case tok::percentequal: Opc = BO_RemAssign; break; case tok::plusequal: Opc = BO_AddAssign; break; case tok::minusequal: Opc = BO_SubAssign; break; case tok::lesslessequal: Opc = BO_ShlAssign; break; case tok::greatergreaterequal: Opc = BO_ShrAssign; break; case tok::ampequal: Opc = BO_AndAssign; break; case tok::caretequal: Opc = BO_XorAssign; break; case tok::pipeequal: Opc = BO_OrAssign; break; case tok::comma: Opc = BO_Comma; break; } return Opc; } static inline UnaryOperatorKind ConvertTokenKindToUnaryOpcode( tok::TokenKind Kind) { UnaryOperatorKind Opc; switch (Kind) { default: llvm_unreachable("Unknown unary op!"); case tok::plusplus: Opc = UO_PreInc; break; case tok::minusminus: Opc = UO_PreDec; break; case tok::amp: Opc = UO_AddrOf; break; case tok::star: Opc = UO_Deref; break; case tok::plus: Opc = UO_Plus; break; case tok::minus: Opc = UO_Minus; break; case tok::tilde: Opc = UO_Not; break; case tok::exclaim: Opc = UO_LNot; break; case tok::kw___real: Opc = UO_Real; break; case tok::kw___imag: Opc = UO_Imag; break; case tok::kw___extension__: Opc = UO_Extension; break; } return Opc; } /// DiagnoseSelfAssignment - Emits a warning if a value is assigned to itself. /// This warning suppressed in the event of macro expansions. static void DiagnoseSelfAssignment(Sema &S, Expr *LHSExpr, Expr *RHSExpr, SourceLocation OpLoc, bool IsBuiltin) { if (S.inTemplateInstantiation()) return; if (S.isUnevaluatedContext()) return; if (OpLoc.isInvalid() || OpLoc.isMacroID()) return; LHSExpr = LHSExpr->IgnoreParenImpCasts(); RHSExpr = RHSExpr->IgnoreParenImpCasts(); const DeclRefExpr *LHSDeclRef = dyn_cast(LHSExpr); const DeclRefExpr *RHSDeclRef = dyn_cast(RHSExpr); if (!LHSDeclRef || !RHSDeclRef || LHSDeclRef->getLocation().isMacroID() || RHSDeclRef->getLocation().isMacroID()) return; const ValueDecl *LHSDecl = cast(LHSDeclRef->getDecl()->getCanonicalDecl()); const ValueDecl *RHSDecl = cast(RHSDeclRef->getDecl()->getCanonicalDecl()); if (LHSDecl != RHSDecl) return; if (LHSDecl->getType().isVolatileQualified()) return; if (const ReferenceType *RefTy = LHSDecl->getType()->getAs()) if (RefTy->getPointeeType().isVolatileQualified()) return; S.Diag(OpLoc, IsBuiltin ? diag::warn_self_assignment_builtin : diag::warn_self_assignment_overloaded) << LHSDeclRef->getType() << LHSExpr->getSourceRange() << RHSExpr->getSourceRange(); } /// Check if a bitwise-& is performed on an Objective-C pointer. This /// is usually indicative of introspection within the Objective-C pointer. static void checkObjCPointerIntrospection(Sema &S, ExprResult &L, ExprResult &R, SourceLocation OpLoc) { if (!S.getLangOpts().ObjC) return; const Expr *ObjCPointerExpr = nullptr, *OtherExpr = nullptr; const Expr *LHS = L.get(); const Expr *RHS = R.get(); if (LHS->IgnoreParenCasts()->getType()->isObjCObjectPointerType()) { ObjCPointerExpr = LHS; OtherExpr = RHS; } else if (RHS->IgnoreParenCasts()->getType()->isObjCObjectPointerType()) { ObjCPointerExpr = RHS; OtherExpr = LHS; } // This warning is deliberately made very specific to reduce false // positives with logic that uses '&' for hashing. This logic mainly // looks for code trying to introspect into tagged pointers, which // code should generally never do. if (ObjCPointerExpr && isa(OtherExpr->IgnoreParenCasts())) { unsigned Diag = diag::warn_objc_pointer_masking; // Determine if we are introspecting the result of performSelectorXXX. const Expr *Ex = ObjCPointerExpr->IgnoreParenCasts(); // Special case messages to -performSelector and friends, which // can return non-pointer values boxed in a pointer value. // Some clients may wish to silence warnings in this subcase. if (const ObjCMessageExpr *ME = dyn_cast(Ex)) { Selector S = ME->getSelector(); StringRef SelArg0 = S.getNameForSlot(0); if (SelArg0.startswith("performSelector")) Diag = diag::warn_objc_pointer_masking_performSelector; } S.Diag(OpLoc, Diag) << ObjCPointerExpr->getSourceRange(); } } static NamedDecl *getDeclFromExpr(Expr *E) { if (!E) return nullptr; if (auto *DRE = dyn_cast(E)) return DRE->getDecl(); if (auto *ME = dyn_cast(E)) return ME->getMemberDecl(); if (auto *IRE = dyn_cast(E)) return IRE->getDecl(); return nullptr; } // This helper function promotes a binary operator's operands (which are of a // half vector type) to a vector of floats and then truncates the result to // a vector of either half or short. static ExprResult convertHalfVecBinOp(Sema &S, ExprResult LHS, ExprResult RHS, BinaryOperatorKind Opc, QualType ResultTy, ExprValueKind VK, ExprObjectKind OK, bool IsCompAssign, SourceLocation OpLoc, FPOptions FPFeatures) { auto &Context = S.getASTContext(); assert((isVector(ResultTy, Context.HalfTy) || isVector(ResultTy, Context.ShortTy)) && "Result must be a vector of half or short"); assert(isVector(LHS.get()->getType(), Context.HalfTy) && isVector(RHS.get()->getType(), Context.HalfTy) && "both operands expected to be a half vector"); RHS = convertVector(RHS.get(), Context.FloatTy, S); QualType BinOpResTy = RHS.get()->getType(); // If Opc is a comparison, ResultType is a vector of shorts. In that case, // change BinOpResTy to a vector of ints. if (isVector(ResultTy, Context.ShortTy)) BinOpResTy = S.GetSignedVectorType(BinOpResTy); if (IsCompAssign) return new (Context) CompoundAssignOperator( LHS.get(), RHS.get(), Opc, ResultTy, VK, OK, BinOpResTy, BinOpResTy, OpLoc, FPFeatures); LHS = convertVector(LHS.get(), Context.FloatTy, S); auto *BO = new (Context) BinaryOperator(LHS.get(), RHS.get(), Opc, BinOpResTy, VK, OK, OpLoc, FPFeatures); return convertVector(BO, ResultTy->castAs()->getElementType(), S); } static std::pair CorrectDelayedTyposInBinOp(Sema &S, BinaryOperatorKind Opc, Expr *LHSExpr, Expr *RHSExpr) { ExprResult LHS = LHSExpr, RHS = RHSExpr; if (!S.getLangOpts().CPlusPlus) { // C cannot handle TypoExpr nodes on either side of a binop because it // doesn't handle dependent types properly, so make sure any TypoExprs have // been dealt with before checking the operands. LHS = S.CorrectDelayedTyposInExpr(LHS); RHS = S.CorrectDelayedTyposInExpr(RHS, [Opc, LHS](Expr *E) { if (Opc != BO_Assign) return ExprResult(E); // Avoid correcting the RHS to the same Expr as the LHS. Decl *D = getDeclFromExpr(E); return (D && D == getDeclFromExpr(LHS.get())) ? ExprError() : E; }); } return std::make_pair(LHS, RHS); } /// Returns true if conversion between vectors of halfs and vectors of floats /// is needed. static bool needsConversionOfHalfVec(bool OpRequiresConversion, ASTContext &Ctx, QualType SrcType) { return OpRequiresConversion && !Ctx.getLangOpts().NativeHalfType && !Ctx.getTargetInfo().useFP16ConversionIntrinsics() && isVector(SrcType, Ctx.HalfTy); } /// CreateBuiltinBinOp - Creates a new built-in binary operation with /// operator @p Opc at location @c TokLoc. This routine only supports /// built-in operations; ActOnBinOp handles overloaded operators. ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc, BinaryOperatorKind Opc, Expr *LHSExpr, Expr *RHSExpr) { if (getLangOpts().CPlusPlus11 && isa(RHSExpr)) { // The syntax only allows initializer lists on the RHS of assignment, // so we don't need to worry about accepting invalid code for // non-assignment operators. // C++11 5.17p9: // The meaning of x = {v} [...] is that of x = T(v) [...]. The meaning // of x = {} is x = T(). InitializationKind Kind = InitializationKind::CreateDirectList( RHSExpr->getBeginLoc(), RHSExpr->getBeginLoc(), RHSExpr->getEndLoc()); InitializedEntity Entity = InitializedEntity::InitializeTemporary(LHSExpr->getType()); InitializationSequence InitSeq(*this, Entity, Kind, RHSExpr); ExprResult Init = InitSeq.Perform(*this, Entity, Kind, RHSExpr); if (Init.isInvalid()) return Init; RHSExpr = Init.get(); } ExprResult LHS = LHSExpr, RHS = RHSExpr; QualType ResultTy; // Result type of the binary operator. // The following two variables are used for compound assignment operators QualType CompLHSTy; // Type of LHS after promotions for computation QualType CompResultTy; // Type of computation result ExprValueKind VK = VK_RValue; ExprObjectKind OK = OK_Ordinary; bool ConvertHalfVec = false; std::tie(LHS, RHS) = CorrectDelayedTyposInBinOp(*this, Opc, LHSExpr, RHSExpr); if (!LHS.isUsable() || !RHS.isUsable()) return ExprError(); if (getLangOpts().OpenCL) { QualType LHSTy = LHSExpr->getType(); QualType RHSTy = RHSExpr->getType(); // OpenCLC v2.0 s6.13.11.1 allows atomic variables to be initialized by // the ATOMIC_VAR_INIT macro. if (LHSTy->isAtomicType() || RHSTy->isAtomicType()) { SourceRange SR(LHSExpr->getBeginLoc(), RHSExpr->getEndLoc()); if (BO_Assign == Opc) Diag(OpLoc, diag::err_opencl_atomic_init) << 0 << SR; else ResultTy = InvalidOperands(OpLoc, LHS, RHS); return ExprError(); } // OpenCL special types - image, sampler, pipe, and blocks are to be used // only with a builtin functions and therefore should be disallowed here. if (LHSTy->isImageType() || RHSTy->isImageType() || LHSTy->isSamplerT() || RHSTy->isSamplerT() || LHSTy->isPipeType() || RHSTy->isPipeType() || LHSTy->isBlockPointerType() || RHSTy->isBlockPointerType()) { ResultTy = InvalidOperands(OpLoc, LHS, RHS); return ExprError(); } } // Diagnose operations on the unsupported types for OpenMP device compilation. if (getLangOpts().OpenMP && getLangOpts().OpenMPIsDevice) { if (Opc != BO_Assign && Opc != BO_Comma) { checkOpenMPDeviceExpr(LHSExpr); checkOpenMPDeviceExpr(RHSExpr); } } switch (Opc) { case BO_Assign: ResultTy = CheckAssignmentOperands(LHS.get(), RHS, OpLoc, QualType()); if (getLangOpts().CPlusPlus && LHS.get()->getObjectKind() != OK_ObjCProperty) { VK = LHS.get()->getValueKind(); OK = LHS.get()->getObjectKind(); } if (!ResultTy.isNull()) { DiagnoseSelfAssignment(*this, LHS.get(), RHS.get(), OpLoc, true); DiagnoseSelfMove(LHS.get(), RHS.get(), OpLoc); // Avoid copying a block to the heap if the block is assigned to a local // auto variable that is declared in the same scope as the block. This // optimization is unsafe if the local variable is declared in an outer // scope. For example: // // BlockTy b; // { // b = ^{...}; // } // // It is unsafe to invoke the block here if it wasn't copied to the // // heap. // b(); if (auto *BE = dyn_cast(RHS.get()->IgnoreParens())) if (auto *DRE = dyn_cast(LHS.get()->IgnoreParens())) if (auto *VD = dyn_cast(DRE->getDecl())) if (VD->hasLocalStorage() && getCurScope()->isDeclScope(VD)) BE->getBlockDecl()->setCanAvoidCopyToHeap(); if (LHS.get()->getType().hasNonTrivialToPrimitiveCopyCUnion()) checkNonTrivialCUnion(LHS.get()->getType(), LHS.get()->getExprLoc(), NTCUC_Assignment, NTCUK_Copy); } RecordModifiableNonNullParam(*this, LHS.get()); break; case BO_PtrMemD: case BO_PtrMemI: ResultTy = CheckPointerToMemberOperands(LHS, RHS, VK, OpLoc, Opc == BO_PtrMemI); break; case BO_Mul: case BO_Div: ConvertHalfVec = true; ResultTy = CheckMultiplyDivideOperands(LHS, RHS, OpLoc, false, Opc == BO_Div); break; case BO_Rem: ResultTy = CheckRemainderOperands(LHS, RHS, OpLoc); break; case BO_Add: ConvertHalfVec = true; ResultTy = CheckAdditionOperands(LHS, RHS, OpLoc, Opc); break; case BO_Sub: ConvertHalfVec = true; ResultTy = CheckSubtractionOperands(LHS, RHS, OpLoc); break; case BO_Shl: case BO_Shr: ResultTy = CheckShiftOperands(LHS, RHS, OpLoc, Opc); break; case BO_LE: case BO_LT: case BO_GE: case BO_GT: ConvertHalfVec = true; ResultTy = CheckCompareOperands(LHS, RHS, OpLoc, Opc); break; case BO_EQ: case BO_NE: ConvertHalfVec = true; ResultTy = CheckCompareOperands(LHS, RHS, OpLoc, Opc); break; case BO_Cmp: ConvertHalfVec = true; ResultTy = CheckCompareOperands(LHS, RHS, OpLoc, Opc); assert(ResultTy.isNull() || ResultTy->getAsCXXRecordDecl()); break; case BO_And: checkObjCPointerIntrospection(*this, LHS, RHS, OpLoc); LLVM_FALLTHROUGH; case BO_Xor: case BO_Or: ResultTy = CheckBitwiseOperands(LHS, RHS, OpLoc, Opc); break; case BO_LAnd: case BO_LOr: ConvertHalfVec = true; ResultTy = CheckLogicalOperands(LHS, RHS, OpLoc, Opc); break; case BO_MulAssign: case BO_DivAssign: ConvertHalfVec = true; CompResultTy = CheckMultiplyDivideOperands(LHS, RHS, OpLoc, true, Opc == BO_DivAssign); CompLHSTy = CompResultTy; if (!CompResultTy.isNull() && !LHS.isInvalid() && !RHS.isInvalid()) ResultTy = CheckAssignmentOperands(LHS.get(), RHS, OpLoc, CompResultTy); break; case BO_RemAssign: CompResultTy = CheckRemainderOperands(LHS, RHS, OpLoc, true); CompLHSTy = CompResultTy; if (!CompResultTy.isNull() && !LHS.isInvalid() && !RHS.isInvalid()) ResultTy = CheckAssignmentOperands(LHS.get(), RHS, OpLoc, CompResultTy); break; case BO_AddAssign: ConvertHalfVec = true; CompResultTy = CheckAdditionOperands(LHS, RHS, OpLoc, Opc, &CompLHSTy); if (!CompResultTy.isNull() && !LHS.isInvalid() && !RHS.isInvalid()) ResultTy = CheckAssignmentOperands(LHS.get(), RHS, OpLoc, CompResultTy); break; case BO_SubAssign: ConvertHalfVec = true; CompResultTy = CheckSubtractionOperands(LHS, RHS, OpLoc, &CompLHSTy); if (!CompResultTy.isNull() && !LHS.isInvalid() && !RHS.isInvalid()) ResultTy = CheckAssignmentOperands(LHS.get(), RHS, OpLoc, CompResultTy); break; case BO_ShlAssign: case BO_ShrAssign: CompResultTy = CheckShiftOperands(LHS, RHS, OpLoc, Opc, true); CompLHSTy = CompResultTy; if (!CompResultTy.isNull() && !LHS.isInvalid() && !RHS.isInvalid()) ResultTy = CheckAssignmentOperands(LHS.get(), RHS, OpLoc, CompResultTy); break; case BO_AndAssign: case BO_OrAssign: // fallthrough DiagnoseSelfAssignment(*this, LHS.get(), RHS.get(), OpLoc, true); LLVM_FALLTHROUGH; case BO_XorAssign: CompResultTy = CheckBitwiseOperands(LHS, RHS, OpLoc, Opc); CompLHSTy = CompResultTy; if (!CompResultTy.isNull() && !LHS.isInvalid() && !RHS.isInvalid()) ResultTy = CheckAssignmentOperands(LHS.get(), RHS, OpLoc, CompResultTy); break; case BO_Comma: ResultTy = CheckCommaOperands(*this, LHS, RHS, OpLoc); if (getLangOpts().CPlusPlus && !RHS.isInvalid()) { VK = RHS.get()->getValueKind(); OK = RHS.get()->getObjectKind(); } break; } if (ResultTy.isNull() || LHS.isInvalid() || RHS.isInvalid()) return ExprError(); if (ResultTy->isRealFloatingType() && (getLangOpts().getFPRoundingMode() != LangOptions::FPR_ToNearest || getLangOpts().getFPExceptionMode() != LangOptions::FPE_Ignore)) // Mark the current function as usng floating point constrained intrinsics if (FunctionDecl *F = dyn_cast(CurContext)) { F->setUsesFPIntrin(true); } // Some of the binary operations require promoting operands of half vector to // float vectors and truncating the result back to half vector. For now, we do // this only when HalfArgsAndReturn is set (that is, when the target is arm or // arm64). assert(isVector(RHS.get()->getType(), Context.HalfTy) == isVector(LHS.get()->getType(), Context.HalfTy) && "both sides are half vectors or neither sides are"); ConvertHalfVec = needsConversionOfHalfVec(ConvertHalfVec, Context, LHS.get()->getType()); // Check for array bounds violations for both sides of the BinaryOperator CheckArrayAccess(LHS.get()); CheckArrayAccess(RHS.get()); if (const ObjCIsaExpr *OISA = dyn_cast(LHS.get()->IgnoreParenCasts())) { NamedDecl *ObjectSetClass = LookupSingleName(TUScope, &Context.Idents.get("object_setClass"), SourceLocation(), LookupOrdinaryName); if (ObjectSetClass && isa(LHS.get())) { SourceLocation RHSLocEnd = getLocForEndOfToken(RHS.get()->getEndLoc()); Diag(LHS.get()->getExprLoc(), diag::warn_objc_isa_assign) << FixItHint::CreateInsertion(LHS.get()->getBeginLoc(), "object_setClass(") << FixItHint::CreateReplacement(SourceRange(OISA->getOpLoc(), OpLoc), ",") << FixItHint::CreateInsertion(RHSLocEnd, ")"); } else Diag(LHS.get()->getExprLoc(), diag::warn_objc_isa_assign); } else if (const ObjCIvarRefExpr *OIRE = dyn_cast(LHS.get()->IgnoreParenCasts())) DiagnoseDirectIsaAccess(*this, OIRE, OpLoc, RHS.get()); // Opc is not a compound assignment if CompResultTy is null. if (CompResultTy.isNull()) { if (ConvertHalfVec) return convertHalfVecBinOp(*this, LHS, RHS, Opc, ResultTy, VK, OK, false, OpLoc, FPFeatures); return new (Context) BinaryOperator(LHS.get(), RHS.get(), Opc, ResultTy, VK, OK, OpLoc, FPFeatures); } // Handle compound assignments. if (getLangOpts().CPlusPlus && LHS.get()->getObjectKind() != OK_ObjCProperty) { VK = VK_LValue; OK = LHS.get()->getObjectKind(); } if (ConvertHalfVec) return convertHalfVecBinOp(*this, LHS, RHS, Opc, ResultTy, VK, OK, true, OpLoc, FPFeatures); return new (Context) CompoundAssignOperator( LHS.get(), RHS.get(), Opc, ResultTy, VK, OK, CompLHSTy, CompResultTy, OpLoc, FPFeatures); } /// DiagnoseBitwisePrecedence - Emit a warning when bitwise and comparison /// operators are mixed in a way that suggests that the programmer forgot that /// comparison operators have higher precedence. The most typical example of /// such code is "flags & 0x0020 != 0", which is equivalent to "flags & 1". static void DiagnoseBitwisePrecedence(Sema &Self, BinaryOperatorKind Opc, SourceLocation OpLoc, Expr *LHSExpr, Expr *RHSExpr) { BinaryOperator *LHSBO = dyn_cast(LHSExpr); BinaryOperator *RHSBO = dyn_cast(RHSExpr); // Check that one of the sides is a comparison operator and the other isn't. bool isLeftComp = LHSBO && LHSBO->isComparisonOp(); bool isRightComp = RHSBO && RHSBO->isComparisonOp(); if (isLeftComp == isRightComp) return; // Bitwise operations are sometimes used as eager logical ops. // Don't diagnose this. bool isLeftBitwise = LHSBO && LHSBO->isBitwiseOp(); bool isRightBitwise = RHSBO && RHSBO->isBitwiseOp(); if (isLeftBitwise || isRightBitwise) return; SourceRange DiagRange = isLeftComp ? SourceRange(LHSExpr->getBeginLoc(), OpLoc) : SourceRange(OpLoc, RHSExpr->getEndLoc()); StringRef OpStr = isLeftComp ? LHSBO->getOpcodeStr() : RHSBO->getOpcodeStr(); SourceRange ParensRange = isLeftComp ? SourceRange(LHSBO->getRHS()->getBeginLoc(), RHSExpr->getEndLoc()) : SourceRange(LHSExpr->getBeginLoc(), RHSBO->getLHS()->getEndLoc()); Self.Diag(OpLoc, diag::warn_precedence_bitwise_rel) << DiagRange << BinaryOperator::getOpcodeStr(Opc) << OpStr; SuggestParentheses(Self, OpLoc, Self.PDiag(diag::note_precedence_silence) << OpStr, (isLeftComp ? LHSExpr : RHSExpr)->getSourceRange()); SuggestParentheses(Self, OpLoc, Self.PDiag(diag::note_precedence_bitwise_first) << BinaryOperator::getOpcodeStr(Opc), ParensRange); } /// It accepts a '&&' expr that is inside a '||' one. /// Emit a diagnostic together with a fixit hint that wraps the '&&' expression /// in parentheses. static void EmitDiagnosticForLogicalAndInLogicalOr(Sema &Self, SourceLocation OpLoc, BinaryOperator *Bop) { assert(Bop->getOpcode() == BO_LAnd); Self.Diag(Bop->getOperatorLoc(), diag::warn_logical_and_in_logical_or) << Bop->getSourceRange() << OpLoc; SuggestParentheses(Self, Bop->getOperatorLoc(), Self.PDiag(diag::note_precedence_silence) << Bop->getOpcodeStr(), Bop->getSourceRange()); } /// Returns true if the given expression can be evaluated as a constant /// 'true'. static bool EvaluatesAsTrue(Sema &S, Expr *E) { bool Res; return !E->isValueDependent() && E->EvaluateAsBooleanCondition(Res, S.getASTContext()) && Res; } /// Returns true if the given expression can be evaluated as a constant /// 'false'. static bool EvaluatesAsFalse(Sema &S, Expr *E) { bool Res; return !E->isValueDependent() && E->EvaluateAsBooleanCondition(Res, S.getASTContext()) && !Res; } /// Look for '&&' in the left hand of a '||' expr. static void DiagnoseLogicalAndInLogicalOrLHS(Sema &S, SourceLocation OpLoc, Expr *LHSExpr, Expr *RHSExpr) { if (BinaryOperator *Bop = dyn_cast(LHSExpr)) { if (Bop->getOpcode() == BO_LAnd) { // If it's "a && b || 0" don't warn since the precedence doesn't matter. if (EvaluatesAsFalse(S, RHSExpr)) return; // If it's "1 && a || b" don't warn since the precedence doesn't matter. if (!EvaluatesAsTrue(S, Bop->getLHS())) return EmitDiagnosticForLogicalAndInLogicalOr(S, OpLoc, Bop); } else if (Bop->getOpcode() == BO_LOr) { if (BinaryOperator *RBop = dyn_cast(Bop->getRHS())) { // If it's "a || b && 1 || c" we didn't warn earlier for // "a || b && 1", but warn now. if (RBop->getOpcode() == BO_LAnd && EvaluatesAsTrue(S, RBop->getRHS())) return EmitDiagnosticForLogicalAndInLogicalOr(S, OpLoc, RBop); } } } } /// Look for '&&' in the right hand of a '||' expr. static void DiagnoseLogicalAndInLogicalOrRHS(Sema &S, SourceLocation OpLoc, Expr *LHSExpr, Expr *RHSExpr) { if (BinaryOperator *Bop = dyn_cast(RHSExpr)) { if (Bop->getOpcode() == BO_LAnd) { // If it's "0 || a && b" don't warn since the precedence doesn't matter. if (EvaluatesAsFalse(S, LHSExpr)) return; // If it's "a || b && 1" don't warn since the precedence doesn't matter. if (!EvaluatesAsTrue(S, Bop->getRHS())) return EmitDiagnosticForLogicalAndInLogicalOr(S, OpLoc, Bop); } } } /// Look for bitwise op in the left or right hand of a bitwise op with /// lower precedence and emit a diagnostic together with a fixit hint that wraps /// the '&' expression in parentheses. static void DiagnoseBitwiseOpInBitwiseOp(Sema &S, BinaryOperatorKind Opc, SourceLocation OpLoc, Expr *SubExpr) { if (BinaryOperator *Bop = dyn_cast(SubExpr)) { if (Bop->isBitwiseOp() && Bop->getOpcode() < Opc) { S.Diag(Bop->getOperatorLoc(), diag::warn_bitwise_op_in_bitwise_op) << Bop->getOpcodeStr() << BinaryOperator::getOpcodeStr(Opc) << Bop->getSourceRange() << OpLoc; SuggestParentheses(S, Bop->getOperatorLoc(), S.PDiag(diag::note_precedence_silence) << Bop->getOpcodeStr(), Bop->getSourceRange()); } } } static void DiagnoseAdditionInShift(Sema &S, SourceLocation OpLoc, Expr *SubExpr, StringRef Shift) { if (BinaryOperator *Bop = dyn_cast(SubExpr)) { if (Bop->getOpcode() == BO_Add || Bop->getOpcode() == BO_Sub) { StringRef Op = Bop->getOpcodeStr(); S.Diag(Bop->getOperatorLoc(), diag::warn_addition_in_bitshift) << Bop->getSourceRange() << OpLoc << Shift << Op; SuggestParentheses(S, Bop->getOperatorLoc(), S.PDiag(diag::note_precedence_silence) << Op, Bop->getSourceRange()); } } } static void DiagnoseShiftCompare(Sema &S, SourceLocation OpLoc, Expr *LHSExpr, Expr *RHSExpr) { CXXOperatorCallExpr *OCE = dyn_cast(LHSExpr); if (!OCE) return; FunctionDecl *FD = OCE->getDirectCallee(); if (!FD || !FD->isOverloadedOperator()) return; OverloadedOperatorKind Kind = FD->getOverloadedOperator(); if (Kind != OO_LessLess && Kind != OO_GreaterGreater) return; S.Diag(OpLoc, diag::warn_overloaded_shift_in_comparison) << LHSExpr->getSourceRange() << RHSExpr->getSourceRange() << (Kind == OO_LessLess); SuggestParentheses(S, OCE->getOperatorLoc(), S.PDiag(diag::note_precedence_silence) << (Kind == OO_LessLess ? "<<" : ">>"), OCE->getSourceRange()); SuggestParentheses( S, OpLoc, S.PDiag(diag::note_evaluate_comparison_first), SourceRange(OCE->getArg(1)->getBeginLoc(), RHSExpr->getEndLoc())); } /// DiagnoseBinOpPrecedence - Emit warnings for expressions with tricky /// precedence. static void DiagnoseBinOpPrecedence(Sema &Self, BinaryOperatorKind Opc, SourceLocation OpLoc, Expr *LHSExpr, Expr *RHSExpr){ // Diagnose "arg1 'bitwise' arg2 'eq' arg3". if (BinaryOperator::isBitwiseOp(Opc)) DiagnoseBitwisePrecedence(Self, Opc, OpLoc, LHSExpr, RHSExpr); // Diagnose "arg1 & arg2 | arg3" if ((Opc == BO_Or || Opc == BO_Xor) && !OpLoc.isMacroID()/* Don't warn in macros. */) { DiagnoseBitwiseOpInBitwiseOp(Self, Opc, OpLoc, LHSExpr); DiagnoseBitwiseOpInBitwiseOp(Self, Opc, OpLoc, RHSExpr); } // Warn about arg1 || arg2 && arg3, as GCC 4.3+ does. // We don't warn for 'assert(a || b && "bad")' since this is safe. if (Opc == BO_LOr && !OpLoc.isMacroID()/* Don't warn in macros. */) { DiagnoseLogicalAndInLogicalOrLHS(Self, OpLoc, LHSExpr, RHSExpr); DiagnoseLogicalAndInLogicalOrRHS(Self, OpLoc, LHSExpr, RHSExpr); } if ((Opc == BO_Shl && LHSExpr->getType()->isIntegralType(Self.getASTContext())) || Opc == BO_Shr) { StringRef Shift = BinaryOperator::getOpcodeStr(Opc); DiagnoseAdditionInShift(Self, OpLoc, LHSExpr, Shift); DiagnoseAdditionInShift(Self, OpLoc, RHSExpr, Shift); } // Warn on overloaded shift operators and comparisons, such as: // cout << 5 == 4; if (BinaryOperator::isComparisonOp(Opc)) DiagnoseShiftCompare(Self, OpLoc, LHSExpr, RHSExpr); } // Binary Operators. 'Tok' is the token for the operator. ExprResult Sema::ActOnBinOp(Scope *S, SourceLocation TokLoc, tok::TokenKind Kind, Expr *LHSExpr, Expr *RHSExpr) { BinaryOperatorKind Opc = ConvertTokenKindToBinaryOpcode(Kind); assert(LHSExpr && "ActOnBinOp(): missing left expression"); assert(RHSExpr && "ActOnBinOp(): missing right expression"); // Emit warnings for tricky precedence issues, e.g. "bitfield & 0x4 == 0" DiagnoseBinOpPrecedence(*this, Opc, TokLoc, LHSExpr, RHSExpr); return BuildBinOp(S, TokLoc, Opc, LHSExpr, RHSExpr); } /// Build an overloaded binary operator expression in the given scope. static ExprResult BuildOverloadedBinOp(Sema &S, Scope *Sc, SourceLocation OpLoc, BinaryOperatorKind Opc, Expr *LHS, Expr *RHS) { switch (Opc) { case BO_Assign: case BO_DivAssign: case BO_RemAssign: case BO_SubAssign: case BO_AndAssign: case BO_OrAssign: case BO_XorAssign: DiagnoseSelfAssignment(S, LHS, RHS, OpLoc, false); CheckIdentityFieldAssignment(LHS, RHS, OpLoc, S); break; default: break; } // Find all of the overloaded operators visible from this // point. We perform both an operator-name lookup from the local // scope and an argument-dependent lookup based on the types of // the arguments. UnresolvedSet<16> Functions; OverloadedOperatorKind OverOp = BinaryOperator::getOverloadedOperator(Opc); if (Sc && OverOp != OO_None && OverOp != OO_Equal) S.LookupOverloadedOperatorName(OverOp, Sc, LHS->getType(), RHS->getType(), Functions); // In C++20 onwards, we may have a second operator to look up. if (S.getLangOpts().CPlusPlus2a) { if (OverloadedOperatorKind ExtraOp = getRewrittenOverloadedOperator(OverOp)) S.LookupOverloadedOperatorName(ExtraOp, Sc, LHS->getType(), RHS->getType(), Functions); } // Build the (potentially-overloaded, potentially-dependent) // binary operation. return S.CreateOverloadedBinOp(OpLoc, Opc, Functions, LHS, RHS); } ExprResult Sema::BuildBinOp(Scope *S, SourceLocation OpLoc, BinaryOperatorKind Opc, Expr *LHSExpr, Expr *RHSExpr) { ExprResult LHS, RHS; std::tie(LHS, RHS) = CorrectDelayedTyposInBinOp(*this, Opc, LHSExpr, RHSExpr); if (!LHS.isUsable() || !RHS.isUsable()) return ExprError(); LHSExpr = LHS.get(); RHSExpr = RHS.get(); // We want to end up calling one of checkPseudoObjectAssignment // (if the LHS is a pseudo-object), BuildOverloadedBinOp (if // both expressions are overloadable or either is type-dependent), // or CreateBuiltinBinOp (in any other case). We also want to get // any placeholder types out of the way. // Handle pseudo-objects in the LHS. if (const BuiltinType *pty = LHSExpr->getType()->getAsPlaceholderType()) { // Assignments with a pseudo-object l-value need special analysis. if (pty->getKind() == BuiltinType::PseudoObject && BinaryOperator::isAssignmentOp(Opc)) return checkPseudoObjectAssignment(S, OpLoc, Opc, LHSExpr, RHSExpr); // Don't resolve overloads if the other type is overloadable. if (getLangOpts().CPlusPlus && pty->getKind() == BuiltinType::Overload) { // We can't actually test that if we still have a placeholder, // though. Fortunately, none of the exceptions we see in that // code below are valid when the LHS is an overload set. Note // that an overload set can be dependently-typed, but it never // instantiates to having an overloadable type. ExprResult resolvedRHS = CheckPlaceholderExpr(RHSExpr); if (resolvedRHS.isInvalid()) return ExprError(); RHSExpr = resolvedRHS.get(); if (RHSExpr->isTypeDependent() || RHSExpr->getType()->isOverloadableType()) return BuildOverloadedBinOp(*this, S, OpLoc, Opc, LHSExpr, RHSExpr); } // If we're instantiating "a.x < b" or "A::x < b" and 'x' names a function // template, diagnose the missing 'template' keyword instead of diagnosing // an invalid use of a bound member function. // // Note that "A::x < b" might be valid if 'b' has an overloadable type due // to C++1z [over.over]/1.4, but we already checked for that case above. if (Opc == BO_LT && inTemplateInstantiation() && (pty->getKind() == BuiltinType::BoundMember || pty->getKind() == BuiltinType::Overload)) { auto *OE = dyn_cast(LHSExpr); if (OE && !OE->hasTemplateKeyword() && !OE->hasExplicitTemplateArgs() && std::any_of(OE->decls_begin(), OE->decls_end(), [](NamedDecl *ND) { return isa(ND); })) { Diag(OE->getQualifier() ? OE->getQualifierLoc().getBeginLoc() : OE->getNameLoc(), diag::err_template_kw_missing) << OE->getName().getAsString() << ""; return ExprError(); } } ExprResult LHS = CheckPlaceholderExpr(LHSExpr); if (LHS.isInvalid()) return ExprError(); LHSExpr = LHS.get(); } // Handle pseudo-objects in the RHS. if (const BuiltinType *pty = RHSExpr->getType()->getAsPlaceholderType()) { // An overload in the RHS can potentially be resolved by the type // being assigned to. if (Opc == BO_Assign && pty->getKind() == BuiltinType::Overload) { if (getLangOpts().CPlusPlus && (LHSExpr->isTypeDependent() || RHSExpr->isTypeDependent() || LHSExpr->getType()->isOverloadableType())) return BuildOverloadedBinOp(*this, S, OpLoc, Opc, LHSExpr, RHSExpr); return CreateBuiltinBinOp(OpLoc, Opc, LHSExpr, RHSExpr); } // Don't resolve overloads if the other type is overloadable. if (getLangOpts().CPlusPlus && pty->getKind() == BuiltinType::Overload && LHSExpr->getType()->isOverloadableType()) return BuildOverloadedBinOp(*this, S, OpLoc, Opc, LHSExpr, RHSExpr); ExprResult resolvedRHS = CheckPlaceholderExpr(RHSExpr); if (!resolvedRHS.isUsable()) return ExprError(); RHSExpr = resolvedRHS.get(); } if (getLangOpts().CPlusPlus) { // If either expression is type-dependent, always build an // overloaded op. if (LHSExpr->isTypeDependent() || RHSExpr->isTypeDependent()) return BuildOverloadedBinOp(*this, S, OpLoc, Opc, LHSExpr, RHSExpr); // Otherwise, build an overloaded op if either expression has an // overloadable type. if (LHSExpr->getType()->isOverloadableType() || RHSExpr->getType()->isOverloadableType()) return BuildOverloadedBinOp(*this, S, OpLoc, Opc, LHSExpr, RHSExpr); } // Build a built-in binary operation. return CreateBuiltinBinOp(OpLoc, Opc, LHSExpr, RHSExpr); } static bool isOverflowingIntegerType(ASTContext &Ctx, QualType T) { if (T.isNull() || T->isDependentType()) return false; if (!T->isPromotableIntegerType()) return true; return Ctx.getIntWidth(T) >= Ctx.getIntWidth(Ctx.IntTy); } ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc, UnaryOperatorKind Opc, Expr *InputExpr) { ExprResult Input = InputExpr; ExprValueKind VK = VK_RValue; ExprObjectKind OK = OK_Ordinary; QualType resultType; bool CanOverflow = false; bool ConvertHalfVec = false; if (getLangOpts().OpenCL) { QualType Ty = InputExpr->getType(); // The only legal unary operation for atomics is '&'. if ((Opc != UO_AddrOf && Ty->isAtomicType()) || // OpenCL special types - image, sampler, pipe, and blocks are to be used // only with a builtin functions and therefore should be disallowed here. (Ty->isImageType() || Ty->isSamplerT() || Ty->isPipeType() || Ty->isBlockPointerType())) { return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr) << InputExpr->getType() << Input.get()->getSourceRange()); } } // Diagnose operations on the unsupported types for OpenMP device compilation. if (getLangOpts().OpenMP && getLangOpts().OpenMPIsDevice) { if (UnaryOperator::isIncrementDecrementOp(Opc) || UnaryOperator::isArithmeticOp(Opc)) checkOpenMPDeviceExpr(InputExpr); } switch (Opc) { case UO_PreInc: case UO_PreDec: case UO_PostInc: case UO_PostDec: resultType = CheckIncrementDecrementOperand(*this, Input.get(), VK, OK, OpLoc, Opc == UO_PreInc || Opc == UO_PostInc, Opc == UO_PreInc || Opc == UO_PreDec); CanOverflow = isOverflowingIntegerType(Context, resultType); break; case UO_AddrOf: resultType = CheckAddressOfOperand(Input, OpLoc); CheckAddressOfNoDeref(InputExpr); RecordModifiableNonNullParam(*this, InputExpr); break; case UO_Deref: { Input = DefaultFunctionArrayLvalueConversion(Input.get()); if (Input.isInvalid()) return ExprError(); resultType = CheckIndirectionOperand(*this, Input.get(), VK, OpLoc); break; } case UO_Plus: case UO_Minus: CanOverflow = Opc == UO_Minus && isOverflowingIntegerType(Context, Input.get()->getType()); Input = UsualUnaryConversions(Input.get()); if (Input.isInvalid()) return ExprError(); // Unary plus and minus require promoting an operand of half vector to a // float vector and truncating the result back to a half vector. For now, we // do this only when HalfArgsAndReturns is set (that is, when the target is // arm or arm64). ConvertHalfVec = needsConversionOfHalfVec(true, Context, Input.get()->getType()); // If the operand is a half vector, promote it to a float vector. if (ConvertHalfVec) Input = convertVector(Input.get(), Context.FloatTy, *this); resultType = Input.get()->getType(); if (resultType->isDependentType()) break; if (resultType->isArithmeticType()) // C99 6.5.3.3p1 break; else if (resultType->isVectorType() && // The z vector extensions don't allow + or - with bool vectors. (!Context.getLangOpts().ZVector || resultType->castAs()->getVectorKind() != VectorType::AltiVecBool)) break; else if (getLangOpts().CPlusPlus && // C++ [expr.unary.op]p6 Opc == UO_Plus && resultType->isPointerType()) break; return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr) << resultType << Input.get()->getSourceRange()); case UO_Not: // bitwise complement Input = UsualUnaryConversions(Input.get()); if (Input.isInvalid()) return ExprError(); resultType = Input.get()->getType(); if (resultType->isDependentType()) break; // C99 6.5.3.3p1. We allow complex int and float as a GCC extension. if (resultType->isComplexType() || resultType->isComplexIntegerType()) // C99 does not support '~' for complex conjugation. Diag(OpLoc, diag::ext_integer_complement_complex) << resultType << Input.get()->getSourceRange(); else if (resultType->hasIntegerRepresentation()) break; else if (resultType->isExtVectorType() && Context.getLangOpts().OpenCL) { // OpenCL v1.1 s6.3.f: The bitwise operator not (~) does not operate // on vector float types. QualType T = resultType->castAs()->getElementType(); if (!T->isIntegerType()) return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr) << resultType << Input.get()->getSourceRange()); } else { return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr) << resultType << Input.get()->getSourceRange()); } break; case UO_LNot: // logical negation // Unlike +/-/~, integer promotions aren't done here (C99 6.5.3.3p5). Input = DefaultFunctionArrayLvalueConversion(Input.get()); if (Input.isInvalid()) return ExprError(); resultType = Input.get()->getType(); // Though we still have to promote half FP to float... if (resultType->isHalfType() && !Context.getLangOpts().NativeHalfType) { Input = ImpCastExprToType(Input.get(), Context.FloatTy, CK_FloatingCast).get(); resultType = Context.FloatTy; } if (resultType->isDependentType()) break; if (resultType->isScalarType() && !isScopedEnumerationType(resultType)) { // C99 6.5.3.3p1: ok, fallthrough; if (Context.getLangOpts().CPlusPlus) { // C++03 [expr.unary.op]p8, C++0x [expr.unary.op]p9: // operand contextually converted to bool. Input = ImpCastExprToType(Input.get(), Context.BoolTy, ScalarTypeToBooleanCastKind(resultType)); } else if (Context.getLangOpts().OpenCL && Context.getLangOpts().OpenCLVersion < 120) { // OpenCL v1.1 6.3.h: The logical operator not (!) does not // operate on scalar float types. if (!resultType->isIntegerType() && !resultType->isPointerType()) return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr) << resultType << Input.get()->getSourceRange()); } } else if (resultType->isExtVectorType()) { if (Context.getLangOpts().OpenCL && Context.getLangOpts().OpenCLVersion < 120 && !Context.getLangOpts().OpenCLCPlusPlus) { // OpenCL v1.1 6.3.h: The logical operator not (!) does not // operate on vector float types. QualType T = resultType->castAs()->getElementType(); if (!T->isIntegerType()) return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr) << resultType << Input.get()->getSourceRange()); } // Vector logical not returns the signed variant of the operand type. resultType = GetSignedVectorType(resultType); break; } else { // FIXME: GCC's vector extension permits the usage of '!' with a vector // type in C++. We should allow that here too. return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr) << resultType << Input.get()->getSourceRange()); } // LNot always has type int. C99 6.5.3.3p5. // In C++, it's bool. C++ 5.3.1p8 resultType = Context.getLogicalOperationType(); break; case UO_Real: case UO_Imag: resultType = CheckRealImagOperand(*this, Input, OpLoc, Opc == UO_Real); // _Real maps ordinary l-values into ordinary l-values. _Imag maps ordinary // complex l-values to ordinary l-values and all other values to r-values. if (Input.isInvalid()) return ExprError(); if (Opc == UO_Real || Input.get()->getType()->isAnyComplexType()) { if (Input.get()->getValueKind() != VK_RValue && Input.get()->getObjectKind() == OK_Ordinary) VK = Input.get()->getValueKind(); } else if (!getLangOpts().CPlusPlus) { // In C, a volatile scalar is read by __imag. In C++, it is not. Input = DefaultLvalueConversion(Input.get()); } break; case UO_Extension: resultType = Input.get()->getType(); VK = Input.get()->getValueKind(); OK = Input.get()->getObjectKind(); break; case UO_Coawait: // It's unnecessary to represent the pass-through operator co_await in the // AST; just return the input expression instead. assert(!Input.get()->getType()->isDependentType() && "the co_await expression must be non-dependant before " "building operator co_await"); return Input; } if (resultType.isNull() || Input.isInvalid()) return ExprError(); // Check for array bounds violations in the operand of the UnaryOperator, // except for the '*' and '&' operators that have to be handled specially // by CheckArrayAccess (as there are special cases like &array[arraysize] // that are explicitly defined as valid by the standard). if (Opc != UO_AddrOf && Opc != UO_Deref) CheckArrayAccess(Input.get()); auto *UO = new (Context) UnaryOperator(Input.get(), Opc, resultType, VK, OK, OpLoc, CanOverflow); if (Opc == UO_Deref && UO->getType()->hasAttr(attr::NoDeref) && !isa(UO->getType().getDesugaredType(Context))) ExprEvalContexts.back().PossibleDerefs.insert(UO); // Convert the result back to a half vector. if (ConvertHalfVec) return convertVector(UO, Context.HalfTy, *this); return UO; } /// Determine whether the given expression is a qualified member /// access expression, of a form that could be turned into a pointer to member /// with the address-of operator. bool Sema::isQualifiedMemberAccess(Expr *E) { if (DeclRefExpr *DRE = dyn_cast(E)) { if (!DRE->getQualifier()) return false; ValueDecl *VD = DRE->getDecl(); if (!VD->isCXXClassMember()) return false; if (isa(VD) || isa(VD)) return true; if (CXXMethodDecl *Method = dyn_cast(VD)) return Method->isInstance(); return false; } if (UnresolvedLookupExpr *ULE = dyn_cast(E)) { if (!ULE->getQualifier()) return false; for (NamedDecl *D : ULE->decls()) { if (CXXMethodDecl *Method = dyn_cast(D)) { if (Method->isInstance()) return true; } else { // Overload set does not contain methods. break; } } return false; } return false; } ExprResult Sema::BuildUnaryOp(Scope *S, SourceLocation OpLoc, UnaryOperatorKind Opc, Expr *Input) { // First things first: handle placeholders so that the // overloaded-operator check considers the right type. if (const BuiltinType *pty = Input->getType()->getAsPlaceholderType()) { // Increment and decrement of pseudo-object references. if (pty->getKind() == BuiltinType::PseudoObject && UnaryOperator::isIncrementDecrementOp(Opc)) return checkPseudoObjectIncDec(S, OpLoc, Opc, Input); // extension is always a builtin operator. if (Opc == UO_Extension) return CreateBuiltinUnaryOp(OpLoc, Opc, Input); // & gets special logic for several kinds of placeholder. // The builtin code knows what to do. if (Opc == UO_AddrOf && (pty->getKind() == BuiltinType::Overload || pty->getKind() == BuiltinType::UnknownAny || pty->getKind() == BuiltinType::BoundMember)) return CreateBuiltinUnaryOp(OpLoc, Opc, Input); // Anything else needs to be handled now. ExprResult Result = CheckPlaceholderExpr(Input); if (Result.isInvalid()) return ExprError(); Input = Result.get(); } if (getLangOpts().CPlusPlus && Input->getType()->isOverloadableType() && UnaryOperator::getOverloadedOperator(Opc) != OO_None && !(Opc == UO_AddrOf && isQualifiedMemberAccess(Input))) { // Find all of the overloaded operators visible from this // point. We perform both an operator-name lookup from the local // scope and an argument-dependent lookup based on the types of // the arguments. UnresolvedSet<16> Functions; OverloadedOperatorKind OverOp = UnaryOperator::getOverloadedOperator(Opc); if (S && OverOp != OO_None) LookupOverloadedOperatorName(OverOp, S, Input->getType(), QualType(), Functions); return CreateOverloadedUnaryOp(OpLoc, Opc, Functions, Input); } return CreateBuiltinUnaryOp(OpLoc, Opc, Input); } // Unary Operators. 'Tok' is the token for the operator. ExprResult Sema::ActOnUnaryOp(Scope *S, SourceLocation OpLoc, tok::TokenKind Op, Expr *Input) { return BuildUnaryOp(S, OpLoc, ConvertTokenKindToUnaryOpcode(Op), Input); } /// ActOnAddrLabel - Parse the GNU address of label extension: "&&foo". ExprResult Sema::ActOnAddrLabel(SourceLocation OpLoc, SourceLocation LabLoc, LabelDecl *TheDecl) { TheDecl->markUsed(Context); // Create the AST node. The address of a label always has type 'void*'. return new (Context) AddrLabelExpr(OpLoc, LabLoc, TheDecl, Context.getPointerType(Context.VoidTy)); } void Sema::ActOnStartStmtExpr() { PushExpressionEvaluationContext(ExprEvalContexts.back().Context); } void Sema::ActOnStmtExprError() { // Note that function is also called by TreeTransform when leaving a // StmtExpr scope without rebuilding anything. DiscardCleanupsInEvaluationContext(); PopExpressionEvaluationContext(); } ExprResult Sema::ActOnStmtExpr(Scope *S, SourceLocation LPLoc, Stmt *SubStmt, - SourceLocation RPLoc) { // "({..})" + SourceLocation RPLoc) { + return BuildStmtExpr(LPLoc, SubStmt, RPLoc, getTemplateDepth(S)); +} + +ExprResult Sema::BuildStmtExpr(SourceLocation LPLoc, Stmt *SubStmt, + SourceLocation RPLoc, unsigned TemplateDepth) { assert(SubStmt && isa(SubStmt) && "Invalid action invocation!"); CompoundStmt *Compound = cast(SubStmt); if (hasAnyUnrecoverableErrorsInThisFunction()) DiscardCleanupsInEvaluationContext(); assert(!Cleanup.exprNeedsCleanups() && "cleanups within StmtExpr not correctly bound!"); PopExpressionEvaluationContext(); // FIXME: there are a variety of strange constraints to enforce here, for // example, it is not possible to goto into a stmt expression apparently. // More semantic analysis is needed. // If there are sub-stmts in the compound stmt, take the type of the last one // as the type of the stmtexpr. QualType Ty = Context.VoidTy; bool StmtExprMayBindToTemp = false; if (!Compound->body_empty()) { // For GCC compatibility we get the last Stmt excluding trailing NullStmts. if (const auto *LastStmt = dyn_cast(Compound->getStmtExprResult())) { if (const Expr *Value = LastStmt->getExprStmt()) { StmtExprMayBindToTemp = true; Ty = Value->getType(); } } } - bool IsDependentContext = false; - if (S) - IsDependentContext = S->getTemplateParamParent() != nullptr; - else - // FIXME: This is not correct when substituting inside a templated - // context that isn't a DeclContext (such as a variable template). - IsDependentContext = CurContext->isDependentContext(); - // FIXME: Check that expression type is complete/non-abstract; statement // expressions are not lvalues. Expr *ResStmtExpr = - new (Context) StmtExpr(Compound, Ty, LPLoc, RPLoc, IsDependentContext); + new (Context) StmtExpr(Compound, Ty, LPLoc, RPLoc, TemplateDepth); if (StmtExprMayBindToTemp) return MaybeBindToTemporary(ResStmtExpr); return ResStmtExpr; } ExprResult Sema::ActOnStmtExprResult(ExprResult ER) { if (ER.isInvalid()) return ExprError(); // Do function/array conversion on the last expression, but not // lvalue-to-rvalue. However, initialize an unqualified type. ER = DefaultFunctionArrayConversion(ER.get()); if (ER.isInvalid()) return ExprError(); Expr *E = ER.get(); if (E->isTypeDependent()) return E; // In ARC, if the final expression ends in a consume, splice // the consume out and bind it later. In the alternate case // (when dealing with a retainable type), the result // initialization will create a produce. In both cases the // result will be +1, and we'll need to balance that out with // a bind. auto *Cast = dyn_cast(E); if (Cast && Cast->getCastKind() == CK_ARCConsumeObject) return Cast->getSubExpr(); // FIXME: Provide a better location for the initialization. return PerformCopyInitialization( InitializedEntity::InitializeStmtExprResult( E->getBeginLoc(), E->getType().getUnqualifiedType()), SourceLocation(), E); } ExprResult Sema::BuildBuiltinOffsetOf(SourceLocation BuiltinLoc, TypeSourceInfo *TInfo, ArrayRef Components, SourceLocation RParenLoc) { QualType ArgTy = TInfo->getType(); bool Dependent = ArgTy->isDependentType(); SourceRange TypeRange = TInfo->getTypeLoc().getLocalSourceRange(); // We must have at least one component that refers to the type, and the first // one is known to be a field designator. Verify that the ArgTy represents // a struct/union/class. if (!Dependent && !ArgTy->isRecordType()) return ExprError(Diag(BuiltinLoc, diag::err_offsetof_record_type) << ArgTy << TypeRange); // Type must be complete per C99 7.17p3 because a declaring a variable // with an incomplete type would be ill-formed. if (!Dependent && RequireCompleteType(BuiltinLoc, ArgTy, diag::err_offsetof_incomplete_type, TypeRange)) return ExprError(); bool DidWarnAboutNonPOD = false; QualType CurrentType = ArgTy; SmallVector Comps; SmallVector Exprs; for (const OffsetOfComponent &OC : Components) { if (OC.isBrackets) { // Offset of an array sub-field. TODO: Should we allow vector elements? if (!CurrentType->isDependentType()) { const ArrayType *AT = Context.getAsArrayType(CurrentType); if(!AT) return ExprError(Diag(OC.LocEnd, diag::err_offsetof_array_type) << CurrentType); CurrentType = AT->getElementType(); } else CurrentType = Context.DependentTy; ExprResult IdxRval = DefaultLvalueConversion(static_cast(OC.U.E)); if (IdxRval.isInvalid()) return ExprError(); Expr *Idx = IdxRval.get(); // The expression must be an integral expression. // FIXME: An integral constant expression? if (!Idx->isTypeDependent() && !Idx->isValueDependent() && !Idx->getType()->isIntegerType()) return ExprError( Diag(Idx->getBeginLoc(), diag::err_typecheck_subscript_not_integer) << Idx->getSourceRange()); // Record this array index. Comps.push_back(OffsetOfNode(OC.LocStart, Exprs.size(), OC.LocEnd)); Exprs.push_back(Idx); continue; } // Offset of a field. if (CurrentType->isDependentType()) { // We have the offset of a field, but we can't look into the dependent // type. Just record the identifier of the field. Comps.push_back(OffsetOfNode(OC.LocStart, OC.U.IdentInfo, OC.LocEnd)); CurrentType = Context.DependentTy; continue; } // We need to have a complete type to look into. if (RequireCompleteType(OC.LocStart, CurrentType, diag::err_offsetof_incomplete_type)) return ExprError(); // Look for the designated field. const RecordType *RC = CurrentType->getAs(); if (!RC) return ExprError(Diag(OC.LocEnd, diag::err_offsetof_record_type) << CurrentType); RecordDecl *RD = RC->getDecl(); // C++ [lib.support.types]p5: // The macro offsetof accepts a restricted set of type arguments in this // International Standard. type shall be a POD structure or a POD union // (clause 9). // C++11 [support.types]p4: // If type is not a standard-layout class (Clause 9), the results are // undefined. if (CXXRecordDecl *CRD = dyn_cast(RD)) { bool IsSafe = LangOpts.CPlusPlus11? CRD->isStandardLayout() : CRD->isPOD(); unsigned DiagID = LangOpts.CPlusPlus11? diag::ext_offsetof_non_standardlayout_type : diag::ext_offsetof_non_pod_type; if (!IsSafe && !DidWarnAboutNonPOD && DiagRuntimeBehavior(BuiltinLoc, nullptr, PDiag(DiagID) << SourceRange(Components[0].LocStart, OC.LocEnd) << CurrentType)) DidWarnAboutNonPOD = true; } // Look for the field. LookupResult R(*this, OC.U.IdentInfo, OC.LocStart, LookupMemberName); LookupQualifiedName(R, RD); FieldDecl *MemberDecl = R.getAsSingle(); IndirectFieldDecl *IndirectMemberDecl = nullptr; if (!MemberDecl) { if ((IndirectMemberDecl = R.getAsSingle())) MemberDecl = IndirectMemberDecl->getAnonField(); } if (!MemberDecl) return ExprError(Diag(BuiltinLoc, diag::err_no_member) << OC.U.IdentInfo << RD << SourceRange(OC.LocStart, OC.LocEnd)); // C99 7.17p3: // (If the specified member is a bit-field, the behavior is undefined.) // // We diagnose this as an error. if (MemberDecl->isBitField()) { Diag(OC.LocEnd, diag::err_offsetof_bitfield) << MemberDecl->getDeclName() << SourceRange(BuiltinLoc, RParenLoc); Diag(MemberDecl->getLocation(), diag::note_bitfield_decl); return ExprError(); } RecordDecl *Parent = MemberDecl->getParent(); if (IndirectMemberDecl) Parent = cast(IndirectMemberDecl->getDeclContext()); // If the member was found in a base class, introduce OffsetOfNodes for // the base class indirections. CXXBasePaths Paths; if (IsDerivedFrom(OC.LocStart, CurrentType, Context.getTypeDeclType(Parent), Paths)) { if (Paths.getDetectedVirtual()) { Diag(OC.LocEnd, diag::err_offsetof_field_of_virtual_base) << MemberDecl->getDeclName() << SourceRange(BuiltinLoc, RParenLoc); return ExprError(); } CXXBasePath &Path = Paths.front(); for (const CXXBasePathElement &B : Path) Comps.push_back(OffsetOfNode(B.Base)); } if (IndirectMemberDecl) { for (auto *FI : IndirectMemberDecl->chain()) { assert(isa(FI)); Comps.push_back(OffsetOfNode(OC.LocStart, cast(FI), OC.LocEnd)); } } else Comps.push_back(OffsetOfNode(OC.LocStart, MemberDecl, OC.LocEnd)); CurrentType = MemberDecl->getType().getNonReferenceType(); } return OffsetOfExpr::Create(Context, Context.getSizeType(), BuiltinLoc, TInfo, Comps, Exprs, RParenLoc); } ExprResult Sema::ActOnBuiltinOffsetOf(Scope *S, SourceLocation BuiltinLoc, SourceLocation TypeLoc, ParsedType ParsedArgTy, ArrayRef Components, SourceLocation RParenLoc) { TypeSourceInfo *ArgTInfo; QualType ArgTy = GetTypeFromParser(ParsedArgTy, &ArgTInfo); if (ArgTy.isNull()) return ExprError(); if (!ArgTInfo) ArgTInfo = Context.getTrivialTypeSourceInfo(ArgTy, TypeLoc); return BuildBuiltinOffsetOf(BuiltinLoc, ArgTInfo, Components, RParenLoc); } ExprResult Sema::ActOnChooseExpr(SourceLocation BuiltinLoc, Expr *CondExpr, Expr *LHSExpr, Expr *RHSExpr, SourceLocation RPLoc) { assert((CondExpr && LHSExpr && RHSExpr) && "Missing type argument(s)"); ExprValueKind VK = VK_RValue; ExprObjectKind OK = OK_Ordinary; QualType resType; bool ValueDependent = false; bool CondIsTrue = false; if (CondExpr->isTypeDependent() || CondExpr->isValueDependent()) { resType = Context.DependentTy; ValueDependent = true; } else { // The conditional expression is required to be a constant expression. llvm::APSInt condEval(32); ExprResult CondICE = VerifyIntegerConstantExpression(CondExpr, &condEval, diag::err_typecheck_choose_expr_requires_constant, false); if (CondICE.isInvalid()) return ExprError(); CondExpr = CondICE.get(); CondIsTrue = condEval.getZExtValue(); // If the condition is > zero, then the AST type is the same as the LHSExpr. Expr *ActiveExpr = CondIsTrue ? LHSExpr : RHSExpr; resType = ActiveExpr->getType(); ValueDependent = ActiveExpr->isValueDependent(); VK = ActiveExpr->getValueKind(); OK = ActiveExpr->getObjectKind(); } return new (Context) ChooseExpr(BuiltinLoc, CondExpr, LHSExpr, RHSExpr, resType, VK, OK, RPLoc, CondIsTrue, resType->isDependentType(), ValueDependent); } //===----------------------------------------------------------------------===// // Clang Extensions. //===----------------------------------------------------------------------===// /// ActOnBlockStart - This callback is invoked when a block literal is started. void Sema::ActOnBlockStart(SourceLocation CaretLoc, Scope *CurScope) { BlockDecl *Block = BlockDecl::Create(Context, CurContext, CaretLoc); if (LangOpts.CPlusPlus) { MangleNumberingContext *MCtx; Decl *ManglingContextDecl; std::tie(MCtx, ManglingContextDecl) = getCurrentMangleNumberContext(Block->getDeclContext()); if (MCtx) { unsigned ManglingNumber = MCtx->getManglingNumber(Block); Block->setBlockMangling(ManglingNumber, ManglingContextDecl); } } PushBlockScope(CurScope, Block); CurContext->addDecl(Block); if (CurScope) PushDeclContext(CurScope, Block); else CurContext = Block; getCurBlock()->HasImplicitReturnType = true; // Enter a new evaluation context to insulate the block from any // cleanups from the enclosing full-expression. PushExpressionEvaluationContext( ExpressionEvaluationContext::PotentiallyEvaluated); } void Sema::ActOnBlockArguments(SourceLocation CaretLoc, Declarator &ParamInfo, Scope *CurScope) { assert(ParamInfo.getIdentifier() == nullptr && "block-id should have no identifier!"); assert(ParamInfo.getContext() == DeclaratorContext::BlockLiteralContext); BlockScopeInfo *CurBlock = getCurBlock(); TypeSourceInfo *Sig = GetTypeForDeclarator(ParamInfo, CurScope); QualType T = Sig->getType(); // FIXME: We should allow unexpanded parameter packs here, but that would, // in turn, make the block expression contain unexpanded parameter packs. if (DiagnoseUnexpandedParameterPack(CaretLoc, Sig, UPPC_Block)) { // Drop the parameters. FunctionProtoType::ExtProtoInfo EPI; EPI.HasTrailingReturn = false; EPI.TypeQuals.addConst(); T = Context.getFunctionType(Context.DependentTy, None, EPI); Sig = Context.getTrivialTypeSourceInfo(T); } // GetTypeForDeclarator always produces a function type for a block // literal signature. Furthermore, it is always a FunctionProtoType // unless the function was written with a typedef. assert(T->isFunctionType() && "GetTypeForDeclarator made a non-function block signature"); // Look for an explicit signature in that function type. FunctionProtoTypeLoc ExplicitSignature; if ((ExplicitSignature = Sig->getTypeLoc() .getAsAdjusted())) { // Check whether that explicit signature was synthesized by // GetTypeForDeclarator. If so, don't save that as part of the // written signature. if (ExplicitSignature.getLocalRangeBegin() == ExplicitSignature.getLocalRangeEnd()) { // This would be much cheaper if we stored TypeLocs instead of // TypeSourceInfos. TypeLoc Result = ExplicitSignature.getReturnLoc(); unsigned Size = Result.getFullDataSize(); Sig = Context.CreateTypeSourceInfo(Result.getType(), Size); Sig->getTypeLoc().initializeFullCopy(Result, Size); ExplicitSignature = FunctionProtoTypeLoc(); } } CurBlock->TheDecl->setSignatureAsWritten(Sig); CurBlock->FunctionType = T; const FunctionType *Fn = T->getAs(); QualType RetTy = Fn->getReturnType(); bool isVariadic = (isa(Fn) && cast(Fn)->isVariadic()); CurBlock->TheDecl->setIsVariadic(isVariadic); // Context.DependentTy is used as a placeholder for a missing block // return type. TODO: what should we do with declarators like: // ^ * { ... } // If the answer is "apply template argument deduction".... if (RetTy != Context.DependentTy) { CurBlock->ReturnType = RetTy; CurBlock->TheDecl->setBlockMissingReturnType(false); CurBlock->HasImplicitReturnType = false; } // Push block parameters from the declarator if we had them. SmallVector Params; if (ExplicitSignature) { for (unsigned I = 0, E = ExplicitSignature.getNumParams(); I != E; ++I) { ParmVarDecl *Param = ExplicitSignature.getParam(I); if (Param->getIdentifier() == nullptr && !Param->isImplicit() && !Param->isInvalidDecl() && !getLangOpts().CPlusPlus) Diag(Param->getLocation(), diag::err_parameter_name_omitted); Params.push_back(Param); } // Fake up parameter variables if we have a typedef, like // ^ fntype { ... } } else if (const FunctionProtoType *Fn = T->getAs()) { for (const auto &I : Fn->param_types()) { ParmVarDecl *Param = BuildParmVarDeclForTypedef( CurBlock->TheDecl, ParamInfo.getBeginLoc(), I); Params.push_back(Param); } } // Set the parameters on the block decl. if (!Params.empty()) { CurBlock->TheDecl->setParams(Params); CheckParmsForFunctionDef(CurBlock->TheDecl->parameters(), /*CheckParameterNames=*/false); } // Finally we can process decl attributes. ProcessDeclAttributes(CurScope, CurBlock->TheDecl, ParamInfo); // Put the parameter variables in scope. for (auto AI : CurBlock->TheDecl->parameters()) { AI->setOwningFunction(CurBlock->TheDecl); // If this has an identifier, add it to the scope stack. if (AI->getIdentifier()) { CheckShadow(CurBlock->TheScope, AI); PushOnScopeChains(AI, CurBlock->TheScope); } } } /// ActOnBlockError - If there is an error parsing a block, this callback /// is invoked to pop the information about the block from the action impl. void Sema::ActOnBlockError(SourceLocation CaretLoc, Scope *CurScope) { // Leave the expression-evaluation context. DiscardCleanupsInEvaluationContext(); PopExpressionEvaluationContext(); // Pop off CurBlock, handle nested blocks. PopDeclContext(); PopFunctionScopeInfo(); } /// ActOnBlockStmtExpr - This is called when the body of a block statement /// literal was successfully completed. ^(int x){...} ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc, Stmt *Body, Scope *CurScope) { // If blocks are disabled, emit an error. if (!LangOpts.Blocks) Diag(CaretLoc, diag::err_blocks_disable) << LangOpts.OpenCL; // Leave the expression-evaluation context. if (hasAnyUnrecoverableErrorsInThisFunction()) DiscardCleanupsInEvaluationContext(); assert(!Cleanup.exprNeedsCleanups() && "cleanups within block not correctly bound!"); PopExpressionEvaluationContext(); BlockScopeInfo *BSI = cast(FunctionScopes.back()); BlockDecl *BD = BSI->TheDecl; if (BSI->HasImplicitReturnType) deduceClosureReturnType(*BSI); QualType RetTy = Context.VoidTy; if (!BSI->ReturnType.isNull()) RetTy = BSI->ReturnType; bool NoReturn = BD->hasAttr(); QualType BlockTy; // If the user wrote a function type in some form, try to use that. if (!BSI->FunctionType.isNull()) { const FunctionType *FTy = BSI->FunctionType->castAs(); FunctionType::ExtInfo Ext = FTy->getExtInfo(); if (NoReturn && !Ext.getNoReturn()) Ext = Ext.withNoReturn(true); // Turn protoless block types into nullary block types. if (isa(FTy)) { FunctionProtoType::ExtProtoInfo EPI; EPI.ExtInfo = Ext; BlockTy = Context.getFunctionType(RetTy, None, EPI); // Otherwise, if we don't need to change anything about the function type, // preserve its sugar structure. } else if (FTy->getReturnType() == RetTy && (!NoReturn || FTy->getNoReturnAttr())) { BlockTy = BSI->FunctionType; // Otherwise, make the minimal modifications to the function type. } else { const FunctionProtoType *FPT = cast(FTy); FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo(); EPI.TypeQuals = Qualifiers(); EPI.ExtInfo = Ext; BlockTy = Context.getFunctionType(RetTy, FPT->getParamTypes(), EPI); } // If we don't have a function type, just build one from nothing. } else { FunctionProtoType::ExtProtoInfo EPI; EPI.ExtInfo = FunctionType::ExtInfo().withNoReturn(NoReturn); BlockTy = Context.getFunctionType(RetTy, None, EPI); } DiagnoseUnusedParameters(BD->parameters()); BlockTy = Context.getBlockPointerType(BlockTy); // If needed, diagnose invalid gotos and switches in the block. if (getCurFunction()->NeedsScopeChecking() && !PP.isCodeCompletionEnabled()) DiagnoseInvalidJumps(cast(Body)); BD->setBody(cast(Body)); if (Body && getCurFunction()->HasPotentialAvailabilityViolations) DiagnoseUnguardedAvailabilityViolations(BD); // Try to apply the named return value optimization. We have to check again // if we can do this, though, because blocks keep return statements around // to deduce an implicit return type. if (getLangOpts().CPlusPlus && RetTy->isRecordType() && !BD->isDependentContext()) computeNRVO(Body, BSI); if (RetTy.hasNonTrivialToPrimitiveDestructCUnion() || RetTy.hasNonTrivialToPrimitiveCopyCUnion()) checkNonTrivialCUnion(RetTy, BD->getCaretLocation(), NTCUC_FunctionReturn, NTCUK_Destruct|NTCUK_Copy); PopDeclContext(); // Pop the block scope now but keep it alive to the end of this function. AnalysisBasedWarnings::Policy WP = AnalysisWarnings.getDefaultPolicy(); PoppedFunctionScopePtr ScopeRAII = PopFunctionScopeInfo(&WP, BD, BlockTy); // Set the captured variables on the block. SmallVector Captures; for (Capture &Cap : BSI->Captures) { if (Cap.isInvalid() || Cap.isThisCapture()) continue; VarDecl *Var = Cap.getVariable(); Expr *CopyExpr = nullptr; if (getLangOpts().CPlusPlus && Cap.isCopyCapture()) { if (const RecordType *Record = Cap.getCaptureType()->getAs()) { // The capture logic needs the destructor, so make sure we mark it. // Usually this is unnecessary because most local variables have // their destructors marked at declaration time, but parameters are // an exception because it's technically only the call site that // actually requires the destructor. if (isa(Var)) FinalizeVarWithDestructor(Var, Record); // Enter a separate potentially-evaluated context while building block // initializers to isolate their cleanups from those of the block // itself. // FIXME: Is this appropriate even when the block itself occurs in an // unevaluated operand? EnterExpressionEvaluationContext EvalContext( *this, ExpressionEvaluationContext::PotentiallyEvaluated); SourceLocation Loc = Cap.getLocation(); ExprResult Result = BuildDeclarationNameExpr( CXXScopeSpec(), DeclarationNameInfo(Var->getDeclName(), Loc), Var); // According to the blocks spec, the capture of a variable from // the stack requires a const copy constructor. This is not true // of the copy/move done to move a __block variable to the heap. if (!Result.isInvalid() && !Result.get()->getType().isConstQualified()) { Result = ImpCastExprToType(Result.get(), Result.get()->getType().withConst(), CK_NoOp, VK_LValue); } if (!Result.isInvalid()) { Result = PerformCopyInitialization( InitializedEntity::InitializeBlock(Var->getLocation(), Cap.getCaptureType(), false), Loc, Result.get()); } // Build a full-expression copy expression if initialization // succeeded and used a non-trivial constructor. Recover from // errors by pretending that the copy isn't necessary. if (!Result.isInvalid() && !cast(Result.get())->getConstructor() ->isTrivial()) { Result = MaybeCreateExprWithCleanups(Result); CopyExpr = Result.get(); } } } BlockDecl::Capture NewCap(Var, Cap.isBlockCapture(), Cap.isNested(), CopyExpr); Captures.push_back(NewCap); } BD->setCaptures(Context, Captures, BSI->CXXThisCaptureIndex != 0); BlockExpr *Result = new (Context) BlockExpr(BD, BlockTy); // If the block isn't obviously global, i.e. it captures anything at // all, then we need to do a few things in the surrounding context: if (Result->getBlockDecl()->hasCaptures()) { // First, this expression has a new cleanup object. ExprCleanupObjects.push_back(Result->getBlockDecl()); Cleanup.setExprNeedsCleanups(true); // It also gets a branch-protected scope if any of the captured // variables needs destruction. for (const auto &CI : Result->getBlockDecl()->captures()) { const VarDecl *var = CI.getVariable(); if (var->getType().isDestructedType() != QualType::DK_none) { setFunctionHasBranchProtectedScope(); break; } } } if (getCurFunction()) getCurFunction()->addBlock(BD); return Result; } ExprResult Sema::ActOnVAArg(SourceLocation BuiltinLoc, Expr *E, ParsedType Ty, SourceLocation RPLoc) { TypeSourceInfo *TInfo; GetTypeFromParser(Ty, &TInfo); return BuildVAArgExpr(BuiltinLoc, E, TInfo, RPLoc); } ExprResult Sema::BuildVAArgExpr(SourceLocation BuiltinLoc, Expr *E, TypeSourceInfo *TInfo, SourceLocation RPLoc) { Expr *OrigExpr = E; bool IsMS = false; // CUDA device code does not support varargs. if (getLangOpts().CUDA && getLangOpts().CUDAIsDevice) { if (const FunctionDecl *F = dyn_cast(CurContext)) { CUDAFunctionTarget T = IdentifyCUDATarget(F); if (T == CFT_Global || T == CFT_Device || T == CFT_HostDevice) return ExprError(Diag(E->getBeginLoc(), diag::err_va_arg_in_device)); } } // NVPTX does not support va_arg expression. if (getLangOpts().OpenMP && getLangOpts().OpenMPIsDevice && Context.getTargetInfo().getTriple().isNVPTX()) targetDiag(E->getBeginLoc(), diag::err_va_arg_in_device); // It might be a __builtin_ms_va_list. (But don't ever mark a va_arg() // as Microsoft ABI on an actual Microsoft platform, where // __builtin_ms_va_list and __builtin_va_list are the same.) if (!E->isTypeDependent() && Context.getTargetInfo().hasBuiltinMSVaList() && Context.getTargetInfo().getBuiltinVaListKind() != TargetInfo::CharPtrBuiltinVaList) { QualType MSVaListType = Context.getBuiltinMSVaListType(); if (Context.hasSameType(MSVaListType, E->getType())) { if (CheckForModifiableLvalue(E, BuiltinLoc, *this)) return ExprError(); IsMS = true; } } // Get the va_list type QualType VaListType = Context.getBuiltinVaListType(); if (!IsMS) { if (VaListType->isArrayType()) { // Deal with implicit array decay; for example, on x86-64, // va_list is an array, but it's supposed to decay to // a pointer for va_arg. VaListType = Context.getArrayDecayedType(VaListType); // Make sure the input expression also decays appropriately. ExprResult Result = UsualUnaryConversions(E); if (Result.isInvalid()) return ExprError(); E = Result.get(); } else if (VaListType->isRecordType() && getLangOpts().CPlusPlus) { // If va_list is a record type and we are compiling in C++ mode, // check the argument using reference binding. InitializedEntity Entity = InitializedEntity::InitializeParameter( Context, Context.getLValueReferenceType(VaListType), false); ExprResult Init = PerformCopyInitialization(Entity, SourceLocation(), E); if (Init.isInvalid()) return ExprError(); E = Init.getAs(); } else { // Otherwise, the va_list argument must be an l-value because // it is modified by va_arg. if (!E->isTypeDependent() && CheckForModifiableLvalue(E, BuiltinLoc, *this)) return ExprError(); } } if (!IsMS && !E->isTypeDependent() && !Context.hasSameType(VaListType, E->getType())) return ExprError( Diag(E->getBeginLoc(), diag::err_first_argument_to_va_arg_not_of_type_va_list) << OrigExpr->getType() << E->getSourceRange()); if (!TInfo->getType()->isDependentType()) { if (RequireCompleteType(TInfo->getTypeLoc().getBeginLoc(), TInfo->getType(), diag::err_second_parameter_to_va_arg_incomplete, TInfo->getTypeLoc())) return ExprError(); if (RequireNonAbstractType(TInfo->getTypeLoc().getBeginLoc(), TInfo->getType(), diag::err_second_parameter_to_va_arg_abstract, TInfo->getTypeLoc())) return ExprError(); if (!TInfo->getType().isPODType(Context)) { Diag(TInfo->getTypeLoc().getBeginLoc(), TInfo->getType()->isObjCLifetimeType() ? diag::warn_second_parameter_to_va_arg_ownership_qualified : diag::warn_second_parameter_to_va_arg_not_pod) << TInfo->getType() << TInfo->getTypeLoc().getSourceRange(); } // Check for va_arg where arguments of the given type will be promoted // (i.e. this va_arg is guaranteed to have undefined behavior). QualType PromoteType; if (TInfo->getType()->isPromotableIntegerType()) { PromoteType = Context.getPromotedIntegerType(TInfo->getType()); if (Context.typesAreCompatible(PromoteType, TInfo->getType())) PromoteType = QualType(); } if (TInfo->getType()->isSpecificBuiltinType(BuiltinType::Float)) PromoteType = Context.DoubleTy; if (!PromoteType.isNull()) DiagRuntimeBehavior(TInfo->getTypeLoc().getBeginLoc(), E, PDiag(diag::warn_second_parameter_to_va_arg_never_compatible) << TInfo->getType() << PromoteType << TInfo->getTypeLoc().getSourceRange()); } QualType T = TInfo->getType().getNonLValueExprType(Context); return new (Context) VAArgExpr(BuiltinLoc, E, TInfo, RPLoc, T, IsMS); } ExprResult Sema::ActOnGNUNullExpr(SourceLocation TokenLoc) { // The type of __null will be int or long, depending on the size of // pointers on the target. QualType Ty; unsigned pw = Context.getTargetInfo().getPointerWidth(0); if (pw == Context.getTargetInfo().getIntWidth()) Ty = Context.IntTy; else if (pw == Context.getTargetInfo().getLongWidth()) Ty = Context.LongTy; else if (pw == Context.getTargetInfo().getLongLongWidth()) Ty = Context.LongLongTy; else { llvm_unreachable("I don't know size of pointer!"); } return new (Context) GNUNullExpr(Ty, TokenLoc); } ExprResult Sema::ActOnSourceLocExpr(SourceLocExpr::IdentKind Kind, SourceLocation BuiltinLoc, SourceLocation RPLoc) { return BuildSourceLocExpr(Kind, BuiltinLoc, RPLoc, CurContext); } ExprResult Sema::BuildSourceLocExpr(SourceLocExpr::IdentKind Kind, SourceLocation BuiltinLoc, SourceLocation RPLoc, DeclContext *ParentContext) { return new (Context) SourceLocExpr(Context, Kind, BuiltinLoc, RPLoc, ParentContext); } bool Sema::ConversionToObjCStringLiteralCheck(QualType DstType, Expr *&Exp, bool Diagnose) { if (!getLangOpts().ObjC) return false; const ObjCObjectPointerType *PT = DstType->getAs(); if (!PT) return false; if (!PT->isObjCIdType()) { // Check if the destination is the 'NSString' interface. const ObjCInterfaceDecl *ID = PT->getInterfaceDecl(); if (!ID || !ID->getIdentifier()->isStr("NSString")) return false; } // Ignore any parens, implicit casts (should only be // array-to-pointer decays), and not-so-opaque values. The last is // important for making this trigger for property assignments. Expr *SrcExpr = Exp->IgnoreParenImpCasts(); if (OpaqueValueExpr *OV = dyn_cast(SrcExpr)) if (OV->getSourceExpr()) SrcExpr = OV->getSourceExpr()->IgnoreParenImpCasts(); StringLiteral *SL = dyn_cast(SrcExpr); if (!SL || !SL->isAscii()) return false; if (Diagnose) { Diag(SL->getBeginLoc(), diag::err_missing_atsign_prefix) << FixItHint::CreateInsertion(SL->getBeginLoc(), "@"); Exp = BuildObjCStringLiteral(SL->getBeginLoc(), SL).get(); } return true; } static bool maybeDiagnoseAssignmentToFunction(Sema &S, QualType DstType, const Expr *SrcExpr) { if (!DstType->isFunctionPointerType() || !SrcExpr->getType()->isFunctionType()) return false; auto *DRE = dyn_cast(SrcExpr->IgnoreParenImpCasts()); if (!DRE) return false; auto *FD = dyn_cast(DRE->getDecl()); if (!FD) return false; return !S.checkAddressOfFunctionIsAvailable(FD, /*Complain=*/true, SrcExpr->getBeginLoc()); } bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy, SourceLocation Loc, QualType DstType, QualType SrcType, Expr *SrcExpr, AssignmentAction Action, bool *Complained) { if (Complained) *Complained = false; // Decode the result (notice that AST's are still created for extensions). bool CheckInferredResultType = false; bool isInvalid = false; unsigned DiagKind = 0; FixItHint Hint; ConversionFixItGenerator ConvHints; bool MayHaveConvFixit = false; bool MayHaveFunctionDiff = false; const ObjCInterfaceDecl *IFace = nullptr; const ObjCProtocolDecl *PDecl = nullptr; switch (ConvTy) { case Compatible: DiagnoseAssignmentEnum(DstType, SrcType, SrcExpr); return false; case PointerToInt: DiagKind = diag::ext_typecheck_convert_pointer_int; ConvHints.tryToFixConversion(SrcExpr, SrcType, DstType, *this); MayHaveConvFixit = true; break; case IntToPointer: DiagKind = diag::ext_typecheck_convert_int_pointer; ConvHints.tryToFixConversion(SrcExpr, SrcType, DstType, *this); MayHaveConvFixit = true; break; case IncompatiblePointer: if (Action == AA_Passing_CFAudited) DiagKind = diag::err_arc_typecheck_convert_incompatible_pointer; else if (SrcType->isFunctionPointerType() && DstType->isFunctionPointerType()) DiagKind = diag::ext_typecheck_convert_incompatible_function_pointer; else DiagKind = diag::ext_typecheck_convert_incompatible_pointer; CheckInferredResultType = DstType->isObjCObjectPointerType() && SrcType->isObjCObjectPointerType(); if (Hint.isNull() && !CheckInferredResultType) { ConvHints.tryToFixConversion(SrcExpr, SrcType, DstType, *this); } else if (CheckInferredResultType) { SrcType = SrcType.getUnqualifiedType(); DstType = DstType.getUnqualifiedType(); } MayHaveConvFixit = true; break; case IncompatiblePointerSign: DiagKind = diag::ext_typecheck_convert_incompatible_pointer_sign; break; case FunctionVoidPointer: DiagKind = diag::ext_typecheck_convert_pointer_void_func; break; case IncompatiblePointerDiscardsQualifiers: { // Perform array-to-pointer decay if necessary. if (SrcType->isArrayType()) SrcType = Context.getArrayDecayedType(SrcType); Qualifiers lhq = SrcType->getPointeeType().getQualifiers(); Qualifiers rhq = DstType->getPointeeType().getQualifiers(); if (lhq.getAddressSpace() != rhq.getAddressSpace()) { DiagKind = diag::err_typecheck_incompatible_address_space; break; } else if (lhq.getObjCLifetime() != rhq.getObjCLifetime()) { DiagKind = diag::err_typecheck_incompatible_ownership; break; } llvm_unreachable("unknown error case for discarding qualifiers!"); // fallthrough } case CompatiblePointerDiscardsQualifiers: // If the qualifiers lost were because we were applying the // (deprecated) C++ conversion from a string literal to a char* // (or wchar_t*), then there was no error (C++ 4.2p2). FIXME: // Ideally, this check would be performed in // checkPointerTypesForAssignment. However, that would require a // bit of refactoring (so that the second argument is an // expression, rather than a type), which should be done as part // of a larger effort to fix checkPointerTypesForAssignment for // C++ semantics. if (getLangOpts().CPlusPlus && IsStringLiteralToNonConstPointerConversion(SrcExpr, DstType)) return false; DiagKind = diag::ext_typecheck_convert_discards_qualifiers; break; case IncompatibleNestedPointerQualifiers: DiagKind = diag::ext_nested_pointer_qualifier_mismatch; break; case IncompatibleNestedPointerAddressSpaceMismatch: DiagKind = diag::err_typecheck_incompatible_nested_address_space; break; case IntToBlockPointer: DiagKind = diag::err_int_to_block_pointer; break; case IncompatibleBlockPointer: DiagKind = diag::err_typecheck_convert_incompatible_block_pointer; break; case IncompatibleObjCQualifiedId: { if (SrcType->isObjCQualifiedIdType()) { const ObjCObjectPointerType *srcOPT = SrcType->castAs(); for (auto *srcProto : srcOPT->quals()) { PDecl = srcProto; break; } if (const ObjCInterfaceType *IFaceT = DstType->castAs()->getInterfaceType()) IFace = IFaceT->getDecl(); } else if (DstType->isObjCQualifiedIdType()) { const ObjCObjectPointerType *dstOPT = DstType->castAs(); for (auto *dstProto : dstOPT->quals()) { PDecl = dstProto; break; } if (const ObjCInterfaceType *IFaceT = SrcType->castAs()->getInterfaceType()) IFace = IFaceT->getDecl(); } DiagKind = diag::warn_incompatible_qualified_id; break; } case IncompatibleVectors: DiagKind = diag::warn_incompatible_vectors; break; case IncompatibleObjCWeakRef: DiagKind = diag::err_arc_weak_unavailable_assign; break; case Incompatible: if (maybeDiagnoseAssignmentToFunction(*this, DstType, SrcExpr)) { if (Complained) *Complained = true; return true; } DiagKind = diag::err_typecheck_convert_incompatible; ConvHints.tryToFixConversion(SrcExpr, SrcType, DstType, *this); MayHaveConvFixit = true; isInvalid = true; MayHaveFunctionDiff = true; break; } QualType FirstType, SecondType; switch (Action) { case AA_Assigning: case AA_Initializing: // The destination type comes first. FirstType = DstType; SecondType = SrcType; break; case AA_Returning: case AA_Passing: case AA_Passing_CFAudited: case AA_Converting: case AA_Sending: case AA_Casting: // The source type comes first. FirstType = SrcType; SecondType = DstType; break; } PartialDiagnostic FDiag = PDiag(DiagKind); if (Action == AA_Passing_CFAudited) FDiag << FirstType << SecondType << AA_Passing << SrcExpr->getSourceRange(); else FDiag << FirstType << SecondType << Action << SrcExpr->getSourceRange(); // If we can fix the conversion, suggest the FixIts. assert(ConvHints.isNull() || Hint.isNull()); if (!ConvHints.isNull()) { for (FixItHint &H : ConvHints.Hints) FDiag << H; } else { FDiag << Hint; } if (MayHaveConvFixit) { FDiag << (unsigned) (ConvHints.Kind); } if (MayHaveFunctionDiff) HandleFunctionTypeMismatch(FDiag, SecondType, FirstType); Diag(Loc, FDiag); if (DiagKind == diag::warn_incompatible_qualified_id && PDecl && IFace && !IFace->hasDefinition()) Diag(IFace->getLocation(), diag::note_incomplete_class_and_qualified_id) << IFace << PDecl; if (SecondType == Context.OverloadTy) NoteAllOverloadCandidates(OverloadExpr::find(SrcExpr).Expression, FirstType, /*TakingAddress=*/true); if (CheckInferredResultType) EmitRelatedResultTypeNote(SrcExpr); if (Action == AA_Returning && ConvTy == IncompatiblePointer) EmitRelatedResultTypeNoteForReturn(DstType); if (Complained) *Complained = true; return isInvalid; } ExprResult Sema::VerifyIntegerConstantExpression(Expr *E, llvm::APSInt *Result) { class SimpleICEDiagnoser : public VerifyICEDiagnoser { public: void diagnoseNotICE(Sema &S, SourceLocation Loc, SourceRange SR) override { S.Diag(Loc, diag::err_expr_not_ice) << S.LangOpts.CPlusPlus << SR; } } Diagnoser; return VerifyIntegerConstantExpression(E, Result, Diagnoser); } ExprResult Sema::VerifyIntegerConstantExpression(Expr *E, llvm::APSInt *Result, unsigned DiagID, bool AllowFold) { class IDDiagnoser : public VerifyICEDiagnoser { unsigned DiagID; public: IDDiagnoser(unsigned DiagID) : VerifyICEDiagnoser(DiagID == 0), DiagID(DiagID) { } void diagnoseNotICE(Sema &S, SourceLocation Loc, SourceRange SR) override { S.Diag(Loc, DiagID) << SR; } } Diagnoser(DiagID); return VerifyIntegerConstantExpression(E, Result, Diagnoser, AllowFold); } void Sema::VerifyICEDiagnoser::diagnoseFold(Sema &S, SourceLocation Loc, SourceRange SR) { S.Diag(Loc, diag::ext_expr_not_ice) << SR << S.LangOpts.CPlusPlus; } ExprResult Sema::VerifyIntegerConstantExpression(Expr *E, llvm::APSInt *Result, VerifyICEDiagnoser &Diagnoser, bool AllowFold) { SourceLocation DiagLoc = E->getBeginLoc(); if (getLangOpts().CPlusPlus11) { // C++11 [expr.const]p5: // If an expression of literal class type is used in a context where an // integral constant expression is required, then that class type shall // have a single non-explicit conversion function to an integral or // unscoped enumeration type ExprResult Converted; class CXX11ConvertDiagnoser : public ICEConvertDiagnoser { public: CXX11ConvertDiagnoser(bool Silent) : ICEConvertDiagnoser(/*AllowScopedEnumerations*/false, Silent, true) {} SemaDiagnosticBuilder diagnoseNotInt(Sema &S, SourceLocation Loc, QualType T) override { return S.Diag(Loc, diag::err_ice_not_integral) << T; } SemaDiagnosticBuilder diagnoseIncomplete( Sema &S, SourceLocation Loc, QualType T) override { return S.Diag(Loc, diag::err_ice_incomplete_type) << T; } SemaDiagnosticBuilder diagnoseExplicitConv( Sema &S, SourceLocation Loc, QualType T, QualType ConvTy) override { return S.Diag(Loc, diag::err_ice_explicit_conversion) << T << ConvTy; } SemaDiagnosticBuilder noteExplicitConv( Sema &S, CXXConversionDecl *Conv, QualType ConvTy) override { return S.Diag(Conv->getLocation(), diag::note_ice_conversion_here) << ConvTy->isEnumeralType() << ConvTy; } SemaDiagnosticBuilder diagnoseAmbiguous( Sema &S, SourceLocation Loc, QualType T) override { return S.Diag(Loc, diag::err_ice_ambiguous_conversion) << T; } SemaDiagnosticBuilder noteAmbiguous( Sema &S, CXXConversionDecl *Conv, QualType ConvTy) override { return S.Diag(Conv->getLocation(), diag::note_ice_conversion_here) << ConvTy->isEnumeralType() << ConvTy; } SemaDiagnosticBuilder diagnoseConversion( Sema &S, SourceLocation Loc, QualType T, QualType ConvTy) override { llvm_unreachable("conversion functions are permitted"); } } ConvertDiagnoser(Diagnoser.Suppress); Converted = PerformContextualImplicitConversion(DiagLoc, E, ConvertDiagnoser); if (Converted.isInvalid()) return Converted; E = Converted.get(); if (!E->getType()->isIntegralOrUnscopedEnumerationType()) return ExprError(); } else if (!E->getType()->isIntegralOrUnscopedEnumerationType()) { // An ICE must be of integral or unscoped enumeration type. if (!Diagnoser.Suppress) Diagnoser.diagnoseNotICE(*this, DiagLoc, E->getSourceRange()); return ExprError(); } // Circumvent ICE checking in C++11 to avoid evaluating the expression twice // in the non-ICE case. if (!getLangOpts().CPlusPlus11 && E->isIntegerConstantExpr(Context)) { if (Result) *Result = E->EvaluateKnownConstIntCheckOverflow(Context); if (!isa(E)) E = ConstantExpr::Create(Context, E); return E; } Expr::EvalResult EvalResult; SmallVector Notes; EvalResult.Diag = &Notes; // Try to evaluate the expression, and produce diagnostics explaining why it's // not a constant expression as a side-effect. bool Folded = E->EvaluateAsRValue(EvalResult, Context, /*isConstantContext*/ true) && EvalResult.Val.isInt() && !EvalResult.HasSideEffects; if (!isa(E)) E = ConstantExpr::Create(Context, E, EvalResult.Val); // In C++11, we can rely on diagnostics being produced for any expression // which is not a constant expression. If no diagnostics were produced, then // this is a constant expression. if (Folded && getLangOpts().CPlusPlus11 && Notes.empty()) { if (Result) *Result = EvalResult.Val.getInt(); return E; } // If our only note is the usual "invalid subexpression" note, just point // the caret at its location rather than producing an essentially // redundant note. if (Notes.size() == 1 && Notes[0].second.getDiagID() == diag::note_invalid_subexpr_in_const_expr) { DiagLoc = Notes[0].first; Notes.clear(); } if (!Folded || !AllowFold) { if (!Diagnoser.Suppress) { Diagnoser.diagnoseNotICE(*this, DiagLoc, E->getSourceRange()); for (const PartialDiagnosticAt &Note : Notes) Diag(Note.first, Note.second); } return ExprError(); } Diagnoser.diagnoseFold(*this, DiagLoc, E->getSourceRange()); for (const PartialDiagnosticAt &Note : Notes) Diag(Note.first, Note.second); if (Result) *Result = EvalResult.Val.getInt(); return E; } namespace { // Handle the case where we conclude a expression which we speculatively // considered to be unevaluated is actually evaluated. class TransformToPE : public TreeTransform { typedef TreeTransform BaseTransform; public: TransformToPE(Sema &SemaRef) : BaseTransform(SemaRef) { } // Make sure we redo semantic analysis bool AlwaysRebuild() { return true; } bool ReplacingOriginal() { return true; } // We need to special-case DeclRefExprs referring to FieldDecls which // are not part of a member pointer formation; normal TreeTransforming // doesn't catch this case because of the way we represent them in the AST. // FIXME: This is a bit ugly; is it really the best way to handle this // case? // // Error on DeclRefExprs referring to FieldDecls. ExprResult TransformDeclRefExpr(DeclRefExpr *E) { if (isa(E->getDecl()) && !SemaRef.isUnevaluatedContext()) return SemaRef.Diag(E->getLocation(), diag::err_invalid_non_static_member_use) << E->getDecl() << E->getSourceRange(); return BaseTransform::TransformDeclRefExpr(E); } // Exception: filter out member pointer formation ExprResult TransformUnaryOperator(UnaryOperator *E) { if (E->getOpcode() == UO_AddrOf && E->getType()->isMemberPointerType()) return E; return BaseTransform::TransformUnaryOperator(E); } // The body of a lambda-expression is in a separate expression evaluation // context so never needs to be transformed. // FIXME: Ideally we wouldn't transform the closure type either, and would // just recreate the capture expressions and lambda expression. StmtResult TransformLambdaBody(LambdaExpr *E, Stmt *Body) { return SkipLambdaBody(E, Body); } }; } ExprResult Sema::TransformToPotentiallyEvaluated(Expr *E) { assert(isUnevaluatedContext() && "Should only transform unevaluated expressions"); ExprEvalContexts.back().Context = ExprEvalContexts[ExprEvalContexts.size()-2].Context; if (isUnevaluatedContext()) return E; return TransformToPE(*this).TransformExpr(E); } void Sema::PushExpressionEvaluationContext( ExpressionEvaluationContext NewContext, Decl *LambdaContextDecl, ExpressionEvaluationContextRecord::ExpressionKind ExprContext) { ExprEvalContexts.emplace_back(NewContext, ExprCleanupObjects.size(), Cleanup, LambdaContextDecl, ExprContext); Cleanup.reset(); if (!MaybeODRUseExprs.empty()) std::swap(MaybeODRUseExprs, ExprEvalContexts.back().SavedMaybeODRUseExprs); } void Sema::PushExpressionEvaluationContext( ExpressionEvaluationContext NewContext, ReuseLambdaContextDecl_t, ExpressionEvaluationContextRecord::ExpressionKind ExprContext) { Decl *ClosureContextDecl = ExprEvalContexts.back().ManglingContextDecl; PushExpressionEvaluationContext(NewContext, ClosureContextDecl, ExprContext); } namespace { const DeclRefExpr *CheckPossibleDeref(Sema &S, const Expr *PossibleDeref) { PossibleDeref = PossibleDeref->IgnoreParenImpCasts(); if (const auto *E = dyn_cast(PossibleDeref)) { if (E->getOpcode() == UO_Deref) return CheckPossibleDeref(S, E->getSubExpr()); } else if (const auto *E = dyn_cast(PossibleDeref)) { return CheckPossibleDeref(S, E->getBase()); } else if (const auto *E = dyn_cast(PossibleDeref)) { return CheckPossibleDeref(S, E->getBase()); } else if (const auto E = dyn_cast(PossibleDeref)) { QualType Inner; QualType Ty = E->getType(); if (const auto *Ptr = Ty->getAs()) Inner = Ptr->getPointeeType(); else if (const auto *Arr = S.Context.getAsArrayType(Ty)) Inner = Arr->getElementType(); else return nullptr; if (Inner->hasAttr(attr::NoDeref)) return E; } return nullptr; } } // namespace void Sema::WarnOnPendingNoDerefs(ExpressionEvaluationContextRecord &Rec) { for (const Expr *E : Rec.PossibleDerefs) { const DeclRefExpr *DeclRef = CheckPossibleDeref(*this, E); if (DeclRef) { const ValueDecl *Decl = DeclRef->getDecl(); Diag(E->getExprLoc(), diag::warn_dereference_of_noderef_type) << Decl->getName() << E->getSourceRange(); Diag(Decl->getLocation(), diag::note_previous_decl) << Decl->getName(); } else { Diag(E->getExprLoc(), diag::warn_dereference_of_noderef_type_no_decl) << E->getSourceRange(); } } Rec.PossibleDerefs.clear(); } /// Check whether E, which is either a discarded-value expression or an /// unevaluated operand, is a simple-assignment to a volatlie-qualified lvalue, /// and if so, remove it from the list of volatile-qualified assignments that /// we are going to warn are deprecated. void Sema::CheckUnusedVolatileAssignment(Expr *E) { if (!E->getType().isVolatileQualified() || !getLangOpts().CPlusPlus2a) return; // Note: ignoring parens here is not justified by the standard rules, but // ignoring parentheses seems like a more reasonable approach, and this only // drives a deprecation warning so doesn't affect conformance. if (auto *BO = dyn_cast(E->IgnoreParenImpCasts())) { if (BO->getOpcode() == BO_Assign) { auto &LHSs = ExprEvalContexts.back().VolatileAssignmentLHSs; LHSs.erase(std::remove(LHSs.begin(), LHSs.end(), BO->getLHS()), LHSs.end()); } } } void Sema::PopExpressionEvaluationContext() { ExpressionEvaluationContextRecord& Rec = ExprEvalContexts.back(); unsigned NumTypos = Rec.NumTypos; if (!Rec.Lambdas.empty()) { using ExpressionKind = ExpressionEvaluationContextRecord::ExpressionKind; if (Rec.ExprContext == ExpressionKind::EK_TemplateArgument || Rec.isUnevaluated() || (Rec.isConstantEvaluated() && !getLangOpts().CPlusPlus17)) { unsigned D; if (Rec.isUnevaluated()) { // C++11 [expr.prim.lambda]p2: // A lambda-expression shall not appear in an unevaluated operand // (Clause 5). D = diag::err_lambda_unevaluated_operand; } else if (Rec.isConstantEvaluated() && !getLangOpts().CPlusPlus17) { // C++1y [expr.const]p2: // A conditional-expression e is a core constant expression unless the // evaluation of e, following the rules of the abstract machine, would // evaluate [...] a lambda-expression. D = diag::err_lambda_in_constant_expression; } else if (Rec.ExprContext == ExpressionKind::EK_TemplateArgument) { // C++17 [expr.prim.lamda]p2: // A lambda-expression shall not appear [...] in a template-argument. D = diag::err_lambda_in_invalid_context; } else llvm_unreachable("Couldn't infer lambda error message."); for (const auto *L : Rec.Lambdas) Diag(L->getBeginLoc(), D); } } WarnOnPendingNoDerefs(Rec); // Warn on any volatile-qualified simple-assignments that are not discarded- // value expressions nor unevaluated operands (those cases get removed from // this list by CheckUnusedVolatileAssignment). for (auto *BO : Rec.VolatileAssignmentLHSs) Diag(BO->getBeginLoc(), diag::warn_deprecated_simple_assign_volatile) << BO->getType(); // When are coming out of an unevaluated context, clear out any // temporaries that we may have created as part of the evaluation of // the expression in that context: they aren't relevant because they // will never be constructed. if (Rec.isUnevaluated() || Rec.isConstantEvaluated()) { ExprCleanupObjects.erase(ExprCleanupObjects.begin() + Rec.NumCleanupObjects, ExprCleanupObjects.end()); Cleanup = Rec.ParentCleanup; CleanupVarDeclMarking(); std::swap(MaybeODRUseExprs, Rec.SavedMaybeODRUseExprs); // Otherwise, merge the contexts together. } else { Cleanup.mergeFrom(Rec.ParentCleanup); MaybeODRUseExprs.insert(Rec.SavedMaybeODRUseExprs.begin(), Rec.SavedMaybeODRUseExprs.end()); } // Pop the current expression evaluation context off the stack. ExprEvalContexts.pop_back(); // The global expression evaluation context record is never popped. ExprEvalContexts.back().NumTypos += NumTypos; } void Sema::DiscardCleanupsInEvaluationContext() { ExprCleanupObjects.erase( ExprCleanupObjects.begin() + ExprEvalContexts.back().NumCleanupObjects, ExprCleanupObjects.end()); Cleanup.reset(); MaybeODRUseExprs.clear(); } ExprResult Sema::HandleExprEvaluationContextForTypeof(Expr *E) { ExprResult Result = CheckPlaceholderExpr(E); if (Result.isInvalid()) return ExprError(); E = Result.get(); if (!E->getType()->isVariablyModifiedType()) return E; return TransformToPotentiallyEvaluated(E); } /// Are we in a context that is potentially constant evaluated per C++20 /// [expr.const]p12? static bool isPotentiallyConstantEvaluatedContext(Sema &SemaRef) { /// C++2a [expr.const]p12: // An expression or conversion is potentially constant evaluated if it is switch (SemaRef.ExprEvalContexts.back().Context) { case Sema::ExpressionEvaluationContext::ConstantEvaluated: // -- a manifestly constant-evaluated expression, case Sema::ExpressionEvaluationContext::PotentiallyEvaluated: case Sema::ExpressionEvaluationContext::PotentiallyEvaluatedIfUsed: case Sema::ExpressionEvaluationContext::DiscardedStatement: // -- a potentially-evaluated expression, case Sema::ExpressionEvaluationContext::UnevaluatedList: // -- an immediate subexpression of a braced-init-list, // -- [FIXME] an expression of the form & cast-expression that occurs // within a templated entity // -- a subexpression of one of the above that is not a subexpression of // a nested unevaluated operand. return true; case Sema::ExpressionEvaluationContext::Unevaluated: case Sema::ExpressionEvaluationContext::UnevaluatedAbstract: // Expressions in this context are never evaluated. return false; } llvm_unreachable("Invalid context"); } /// Return true if this function has a calling convention that requires mangling /// in the size of the parameter pack. static bool funcHasParameterSizeMangling(Sema &S, FunctionDecl *FD) { // These manglings don't do anything on non-Windows or non-x86 platforms, so // we don't need parameter type sizes. const llvm::Triple &TT = S.Context.getTargetInfo().getTriple(); if (!TT.isOSWindows() || !TT.isX86()) return false; // If this is C++ and this isn't an extern "C" function, parameters do not // need to be complete. In this case, C++ mangling will apply, which doesn't // use the size of the parameters. if (S.getLangOpts().CPlusPlus && !FD->isExternC()) return false; // Stdcall, fastcall, and vectorcall need this special treatment. CallingConv CC = FD->getType()->castAs()->getCallConv(); switch (CC) { case CC_X86StdCall: case CC_X86FastCall: case CC_X86VectorCall: return true; default: break; } return false; } /// Require that all of the parameter types of function be complete. Normally, /// parameter types are only required to be complete when a function is called /// or defined, but to mangle functions with certain calling conventions, the /// mangler needs to know the size of the parameter list. In this situation, /// MSVC doesn't emit an error or instantiate templates. Instead, MSVC mangles /// the function as _foo@0, i.e. zero bytes of parameters, which will usually /// result in a linker error. Clang doesn't implement this behavior, and instead /// attempts to error at compile time. static void CheckCompleteParameterTypesForMangler(Sema &S, FunctionDecl *FD, SourceLocation Loc) { class ParamIncompleteTypeDiagnoser : public Sema::TypeDiagnoser { FunctionDecl *FD; ParmVarDecl *Param; public: ParamIncompleteTypeDiagnoser(FunctionDecl *FD, ParmVarDecl *Param) : FD(FD), Param(Param) {} void diagnose(Sema &S, SourceLocation Loc, QualType T) override { CallingConv CC = FD->getType()->castAs()->getCallConv(); StringRef CCName; switch (CC) { case CC_X86StdCall: CCName = "stdcall"; break; case CC_X86FastCall: CCName = "fastcall"; break; case CC_X86VectorCall: CCName = "vectorcall"; break; default: llvm_unreachable("CC does not need mangling"); } S.Diag(Loc, diag::err_cconv_incomplete_param_type) << Param->getDeclName() << FD->getDeclName() << CCName; } }; for (ParmVarDecl *Param : FD->parameters()) { ParamIncompleteTypeDiagnoser Diagnoser(FD, Param); S.RequireCompleteType(Loc, Param->getType(), Diagnoser); } } namespace { enum class OdrUseContext { /// Declarations in this context are not odr-used. None, /// Declarations in this context are formally odr-used, but this is a /// dependent context. Dependent, /// Declarations in this context are odr-used but not actually used (yet). FormallyOdrUsed, /// Declarations in this context are used. Used }; } /// Are we within a context in which references to resolved functions or to /// variables result in odr-use? static OdrUseContext isOdrUseContext(Sema &SemaRef) { OdrUseContext Result; switch (SemaRef.ExprEvalContexts.back().Context) { case Sema::ExpressionEvaluationContext::Unevaluated: case Sema::ExpressionEvaluationContext::UnevaluatedList: case Sema::ExpressionEvaluationContext::UnevaluatedAbstract: return OdrUseContext::None; case Sema::ExpressionEvaluationContext::ConstantEvaluated: case Sema::ExpressionEvaluationContext::PotentiallyEvaluated: Result = OdrUseContext::Used; break; case Sema::ExpressionEvaluationContext::DiscardedStatement: Result = OdrUseContext::FormallyOdrUsed; break; case Sema::ExpressionEvaluationContext::PotentiallyEvaluatedIfUsed: // A default argument formally results in odr-use, but doesn't actually // result in a use in any real sense until it itself is used. Result = OdrUseContext::FormallyOdrUsed; break; } if (SemaRef.CurContext->isDependentContext()) return OdrUseContext::Dependent; return Result; } static bool isImplicitlyDefinableConstexprFunction(FunctionDecl *Func) { return Func->isConstexpr() && (Func->isImplicitlyInstantiable() || !Func->isUserProvided()); } /// Mark a function referenced, and check whether it is odr-used /// (C++ [basic.def.odr]p2, C99 6.9p3) void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func, bool MightBeOdrUse) { assert(Func && "No function?"); Func->setReferenced(); // Recursive functions aren't really used until they're used from some other // context. bool IsRecursiveCall = CurContext == Func; // C++11 [basic.def.odr]p3: // A function whose name appears as a potentially-evaluated expression is // odr-used if it is the unique lookup result or the selected member of a // set of overloaded functions [...]. // // We (incorrectly) mark overload resolution as an unevaluated context, so we // can just check that here. OdrUseContext OdrUse = MightBeOdrUse ? isOdrUseContext(*this) : OdrUseContext::None; if (IsRecursiveCall && OdrUse == OdrUseContext::Used) OdrUse = OdrUseContext::FormallyOdrUsed; // Trivial default constructors and destructors are never actually used. // FIXME: What about other special members? if (Func->isTrivial() && !Func->hasAttr() && OdrUse == OdrUseContext::Used) { if (auto *Constructor = dyn_cast(Func)) if (Constructor->isDefaultConstructor()) OdrUse = OdrUseContext::FormallyOdrUsed; if (isa(Func)) OdrUse = OdrUseContext::FormallyOdrUsed; } // C++20 [expr.const]p12: // A function [...] is needed for constant evaluation if it is [...] a // constexpr function that is named by an expression that is potentially // constant evaluated bool NeededForConstantEvaluation = isPotentiallyConstantEvaluatedContext(*this) && isImplicitlyDefinableConstexprFunction(Func); // Determine whether we require a function definition to exist, per // C++11 [temp.inst]p3: // Unless a function template specialization has been explicitly // instantiated or explicitly specialized, the function template // specialization is implicitly instantiated when the specialization is // referenced in a context that requires a function definition to exist. // C++20 [temp.inst]p7: // The existence of a definition of a [...] function is considered to // affect the semantics of the program if the [...] function is needed for // constant evaluation by an expression // C++20 [basic.def.odr]p10: // Every program shall contain exactly one definition of every non-inline // function or variable that is odr-used in that program outside of a // discarded statement // C++20 [special]p1: // The implementation will implicitly define [defaulted special members] // if they are odr-used or needed for constant evaluation. // // Note that we skip the implicit instantiation of templates that are only // used in unused default arguments or by recursive calls to themselves. // This is formally non-conforming, but seems reasonable in practice. bool NeedDefinition = !IsRecursiveCall && (OdrUse == OdrUseContext::Used || NeededForConstantEvaluation); // C++14 [temp.expl.spec]p6: // If a template [...] is explicitly specialized then that specialization // shall be declared before the first use of that specialization that would // cause an implicit instantiation to take place, in every translation unit // in which such a use occurs if (NeedDefinition && (Func->getTemplateSpecializationKind() != TSK_Undeclared || Func->getMemberSpecializationInfo())) checkSpecializationVisibility(Loc, Func); if (getLangOpts().CUDA) CheckCUDACall(Loc, Func); // If we need a definition, try to create one. if (NeedDefinition && !Func->getBody()) { runWithSufficientStackSpace(Loc, [&] { if (CXXConstructorDecl *Constructor = dyn_cast(Func)) { Constructor = cast(Constructor->getFirstDecl()); if (Constructor->isDefaulted() && !Constructor->isDeleted()) { if (Constructor->isDefaultConstructor()) { if (Constructor->isTrivial() && !Constructor->hasAttr()) return; DefineImplicitDefaultConstructor(Loc, Constructor); } else if (Constructor->isCopyConstructor()) { DefineImplicitCopyConstructor(Loc, Constructor); } else if (Constructor->isMoveConstructor()) { DefineImplicitMoveConstructor(Loc, Constructor); } } else if (Constructor->getInheritedConstructor()) { DefineInheritingConstructor(Loc, Constructor); } } else if (CXXDestructorDecl *Destructor = dyn_cast(Func)) { Destructor = cast(Destructor->getFirstDecl()); if (Destructor->isDefaulted() && !Destructor->isDeleted()) { if (Destructor->isTrivial() && !Destructor->hasAttr()) return; DefineImplicitDestructor(Loc, Destructor); } if (Destructor->isVirtual() && getLangOpts().AppleKext) MarkVTableUsed(Loc, Destructor->getParent()); } else if (CXXMethodDecl *MethodDecl = dyn_cast(Func)) { if (MethodDecl->isOverloadedOperator() && MethodDecl->getOverloadedOperator() == OO_Equal) { MethodDecl = cast(MethodDecl->getFirstDecl()); if (MethodDecl->isDefaulted() && !MethodDecl->isDeleted()) { if (MethodDecl->isCopyAssignmentOperator()) DefineImplicitCopyAssignment(Loc, MethodDecl); else if (MethodDecl->isMoveAssignmentOperator()) DefineImplicitMoveAssignment(Loc, MethodDecl); } } else if (isa(MethodDecl) && MethodDecl->getParent()->isLambda()) { CXXConversionDecl *Conversion = cast(MethodDecl->getFirstDecl()); if (Conversion->isLambdaToBlockPointerConversion()) DefineImplicitLambdaToBlockPointerConversion(Loc, Conversion); else DefineImplicitLambdaToFunctionPointerConversion(Loc, Conversion); } else if (MethodDecl->isVirtual() && getLangOpts().AppleKext) MarkVTableUsed(Loc, MethodDecl->getParent()); } if (Func->isDefaulted() && !Func->isDeleted()) { DefaultedComparisonKind DCK = getDefaultedComparisonKind(Func); if (DCK != DefaultedComparisonKind::None) DefineDefaultedComparison(Loc, Func, DCK); } // Implicit instantiation of function templates and member functions of // class templates. if (Func->isImplicitlyInstantiable()) { TemplateSpecializationKind TSK = Func->getTemplateSpecializationKindForInstantiation(); SourceLocation PointOfInstantiation = Func->getPointOfInstantiation(); bool FirstInstantiation = PointOfInstantiation.isInvalid(); if (FirstInstantiation) { PointOfInstantiation = Loc; Func->setTemplateSpecializationKind(TSK, PointOfInstantiation); } else if (TSK != TSK_ImplicitInstantiation) { // Use the point of use as the point of instantiation, instead of the // point of explicit instantiation (which we track as the actual point // of instantiation). This gives better backtraces in diagnostics. PointOfInstantiation = Loc; } if (FirstInstantiation || TSK != TSK_ImplicitInstantiation || Func->isConstexpr()) { if (isa(Func->getDeclContext()) && cast(Func->getDeclContext())->isLocalClass() && CodeSynthesisContexts.size()) PendingLocalImplicitInstantiations.push_back( std::make_pair(Func, PointOfInstantiation)); else if (Func->isConstexpr()) // Do not defer instantiations of constexpr functions, to avoid the // expression evaluator needing to call back into Sema if it sees a // call to such a function. InstantiateFunctionDefinition(PointOfInstantiation, Func); else { Func->setInstantiationIsPending(true); PendingInstantiations.push_back( std::make_pair(Func, PointOfInstantiation)); // Notify the consumer that a function was implicitly instantiated. Consumer.HandleCXXImplicitFunctionInstantiation(Func); } } } else { // Walk redefinitions, as some of them may be instantiable. for (auto i : Func->redecls()) { if (!i->isUsed(false) && i->isImplicitlyInstantiable()) MarkFunctionReferenced(Loc, i, MightBeOdrUse); } } }); } // C++14 [except.spec]p17: // An exception-specification is considered to be needed when: // - the function is odr-used or, if it appears in an unevaluated operand, // would be odr-used if the expression were potentially-evaluated; // // Note, we do this even if MightBeOdrUse is false. That indicates that the // function is a pure virtual function we're calling, and in that case the // function was selected by overload resolution and we need to resolve its // exception specification for a different reason. const FunctionProtoType *FPT = Func->getType()->getAs(); if (FPT && isUnresolvedExceptionSpec(FPT->getExceptionSpecType())) ResolveExceptionSpec(Loc, FPT); // If this is the first "real" use, act on that. if (OdrUse == OdrUseContext::Used && !Func->isUsed(/*CheckUsedAttr=*/false)) { // Keep track of used but undefined functions. if (!Func->isDefined()) { if (mightHaveNonExternalLinkage(Func)) UndefinedButUsed.insert(std::make_pair(Func->getCanonicalDecl(), Loc)); else if (Func->getMostRecentDecl()->isInlined() && !LangOpts.GNUInline && !Func->getMostRecentDecl()->hasAttr()) UndefinedButUsed.insert(std::make_pair(Func->getCanonicalDecl(), Loc)); else if (isExternalWithNoLinkageType(Func)) UndefinedButUsed.insert(std::make_pair(Func->getCanonicalDecl(), Loc)); } // Some x86 Windows calling conventions mangle the size of the parameter // pack into the name. Computing the size of the parameters requires the // parameter types to be complete. Check that now. if (funcHasParameterSizeMangling(*this, Func)) CheckCompleteParameterTypesForMangler(*this, Func, Loc); Func->markUsed(Context); } if (LangOpts.OpenMP) { markOpenMPDeclareVariantFuncsReferenced(Loc, Func, MightBeOdrUse); if (LangOpts.OpenMPIsDevice) checkOpenMPDeviceFunction(Loc, Func); else checkOpenMPHostFunction(Loc, Func); } } /// Directly mark a variable odr-used. Given a choice, prefer to use /// MarkVariableReferenced since it does additional checks and then /// calls MarkVarDeclODRUsed. /// If the variable must be captured: /// - if FunctionScopeIndexToStopAt is null, capture it in the CurContext /// - else capture it in the DeclContext that maps to the /// *FunctionScopeIndexToStopAt on the FunctionScopeInfo stack. static void MarkVarDeclODRUsed(VarDecl *Var, SourceLocation Loc, Sema &SemaRef, const unsigned *const FunctionScopeIndexToStopAt = nullptr) { // Keep track of used but undefined variables. // FIXME: We shouldn't suppress this warning for static data members. if (Var->hasDefinition(SemaRef.Context) == VarDecl::DeclarationOnly && (!Var->isExternallyVisible() || Var->isInline() || SemaRef.isExternalWithNoLinkageType(Var)) && !(Var->isStaticDataMember() && Var->hasInit())) { SourceLocation &old = SemaRef.UndefinedButUsed[Var->getCanonicalDecl()]; if (old.isInvalid()) old = Loc; } QualType CaptureType, DeclRefType; if (SemaRef.LangOpts.OpenMP) SemaRef.tryCaptureOpenMPLambdas(Var); SemaRef.tryCaptureVariable(Var, Loc, Sema::TryCapture_Implicit, /*EllipsisLoc*/ SourceLocation(), /*BuildAndDiagnose*/ true, CaptureType, DeclRefType, FunctionScopeIndexToStopAt); Var->markUsed(SemaRef.Context); } void Sema::MarkCaptureUsedInEnclosingContext(VarDecl *Capture, SourceLocation Loc, unsigned CapturingScopeIndex) { MarkVarDeclODRUsed(Capture, Loc, *this, &CapturingScopeIndex); } static void diagnoseUncapturableValueReference(Sema &S, SourceLocation loc, ValueDecl *var, DeclContext *DC) { DeclContext *VarDC = var->getDeclContext(); // If the parameter still belongs to the translation unit, then // we're actually just using one parameter in the declaration of // the next. if (isa(var) && isa(VarDC)) return; // For C code, don't diagnose about capture if we're not actually in code // right now; it's impossible to write a non-constant expression outside of // function context, so we'll get other (more useful) diagnostics later. // // For C++, things get a bit more nasty... it would be nice to suppress this // diagnostic for certain cases like using a local variable in an array bound // for a member of a local class, but the correct predicate is not obvious. if (!S.getLangOpts().CPlusPlus && !S.CurContext->isFunctionOrMethod()) return; unsigned ValueKind = isa(var) ? 1 : 0; unsigned ContextKind = 3; // unknown if (isa(VarDC) && cast(VarDC->getParent())->isLambda()) { ContextKind = 2; } else if (isa(VarDC)) { ContextKind = 0; } else if (isa(VarDC)) { ContextKind = 1; } S.Diag(loc, diag::err_reference_to_local_in_enclosing_context) << var << ValueKind << ContextKind << VarDC; S.Diag(var->getLocation(), diag::note_entity_declared_at) << var; // FIXME: Add additional diagnostic info about class etc. which prevents // capture. } static bool isVariableAlreadyCapturedInScopeInfo(CapturingScopeInfo *CSI, VarDecl *Var, bool &SubCapturesAreNested, QualType &CaptureType, QualType &DeclRefType) { // Check whether we've already captured it. if (CSI->CaptureMap.count(Var)) { // If we found a capture, any subcaptures are nested. SubCapturesAreNested = true; // Retrieve the capture type for this variable. CaptureType = CSI->getCapture(Var).getCaptureType(); // Compute the type of an expression that refers to this variable. DeclRefType = CaptureType.getNonReferenceType(); // Similarly to mutable captures in lambda, all the OpenMP captures by copy // are mutable in the sense that user can change their value - they are // private instances of the captured declarations. const Capture &Cap = CSI->getCapture(Var); if (Cap.isCopyCapture() && !(isa(CSI) && cast(CSI)->Mutable) && !(isa(CSI) && cast(CSI)->CapRegionKind == CR_OpenMP)) DeclRefType.addConst(); return true; } return false; } // Only block literals, captured statements, and lambda expressions can // capture; other scopes don't work. static DeclContext *getParentOfCapturingContextOrNull(DeclContext *DC, VarDecl *Var, SourceLocation Loc, const bool Diagnose, Sema &S) { if (isa(DC) || isa(DC) || isLambdaCallOperator(DC)) return getLambdaAwareParentOfDeclContext(DC); else if (Var->hasLocalStorage()) { if (Diagnose) diagnoseUncapturableValueReference(S, Loc, Var, DC); } return nullptr; } // Certain capturing entities (lambdas, blocks etc.) are not allowed to capture // certain types of variables (unnamed, variably modified types etc.) // so check for eligibility. static bool isVariableCapturable(CapturingScopeInfo *CSI, VarDecl *Var, SourceLocation Loc, const bool Diagnose, Sema &S) { bool IsBlock = isa(CSI); bool IsLambda = isa(CSI); // Lambdas are not allowed to capture unnamed variables // (e.g. anonymous unions). // FIXME: The C++11 rule don't actually state this explicitly, but I'm // assuming that's the intent. if (IsLambda && !Var->getDeclName()) { if (Diagnose) { S.Diag(Loc, diag::err_lambda_capture_anonymous_var); S.Diag(Var->getLocation(), diag::note_declared_at); } return false; } // Prohibit variably-modified types in blocks; they're difficult to deal with. if (Var->getType()->isVariablyModifiedType() && IsBlock) { if (Diagnose) { S.Diag(Loc, diag::err_ref_vm_type); S.Diag(Var->getLocation(), diag::note_previous_decl) << Var->getDeclName(); } return false; } // Prohibit structs with flexible array members too. // We cannot capture what is in the tail end of the struct. if (const RecordType *VTTy = Var->getType()->getAs()) { if (VTTy->getDecl()->hasFlexibleArrayMember()) { if (Diagnose) { if (IsBlock) S.Diag(Loc, diag::err_ref_flexarray_type); else S.Diag(Loc, diag::err_lambda_capture_flexarray_type) << Var->getDeclName(); S.Diag(Var->getLocation(), diag::note_previous_decl) << Var->getDeclName(); } return false; } } const bool HasBlocksAttr = Var->hasAttr(); // Lambdas and captured statements are not allowed to capture __block // variables; they don't support the expected semantics. if (HasBlocksAttr && (IsLambda || isa(CSI))) { if (Diagnose) { S.Diag(Loc, diag::err_capture_block_variable) << Var->getDeclName() << !IsLambda; S.Diag(Var->getLocation(), diag::note_previous_decl) << Var->getDeclName(); } return false; } // OpenCL v2.0 s6.12.5: Blocks cannot reference/capture other blocks if (S.getLangOpts().OpenCL && IsBlock && Var->getType()->isBlockPointerType()) { if (Diagnose) S.Diag(Loc, diag::err_opencl_block_ref_block); return false; } return true; } // Returns true if the capture by block was successful. static bool captureInBlock(BlockScopeInfo *BSI, VarDecl *Var, SourceLocation Loc, const bool BuildAndDiagnose, QualType &CaptureType, QualType &DeclRefType, const bool Nested, Sema &S, bool Invalid) { bool ByRef = false; // Blocks are not allowed to capture arrays, excepting OpenCL. // OpenCL v2.0 s1.12.5 (revision 40): arrays are captured by reference // (decayed to pointers). if (!Invalid && !S.getLangOpts().OpenCL && CaptureType->isArrayType()) { if (BuildAndDiagnose) { S.Diag(Loc, diag::err_ref_array_type); S.Diag(Var->getLocation(), diag::note_previous_decl) << Var->getDeclName(); Invalid = true; } else { return false; } } // Forbid the block-capture of autoreleasing variables. if (!Invalid && CaptureType.getObjCLifetime() == Qualifiers::OCL_Autoreleasing) { if (BuildAndDiagnose) { S.Diag(Loc, diag::err_arc_autoreleasing_capture) << /*block*/ 0; S.Diag(Var->getLocation(), diag::note_previous_decl) << Var->getDeclName(); Invalid = true; } else { return false; } } // Warn about implicitly autoreleasing indirect parameters captured by blocks. if (const auto *PT = CaptureType->getAs()) { QualType PointeeTy = PT->getPointeeType(); if (!Invalid && PointeeTy->getAs() && PointeeTy.getObjCLifetime() == Qualifiers::OCL_Autoreleasing && !S.Context.hasDirectOwnershipQualifier(PointeeTy)) { if (BuildAndDiagnose) { SourceLocation VarLoc = Var->getLocation(); S.Diag(Loc, diag::warn_block_capture_autoreleasing); S.Diag(VarLoc, diag::note_declare_parameter_strong); } } } const bool HasBlocksAttr = Var->hasAttr(); if (HasBlocksAttr || CaptureType->isReferenceType() || (S.getLangOpts().OpenMP && S.isOpenMPCapturedDecl(Var))) { // Block capture by reference does not change the capture or // declaration reference types. ByRef = true; } else { // Block capture by copy introduces 'const'. CaptureType = CaptureType.getNonReferenceType().withConst(); DeclRefType = CaptureType; } // Actually capture the variable. if (BuildAndDiagnose) BSI->addCapture(Var, HasBlocksAttr, ByRef, Nested, Loc, SourceLocation(), CaptureType, Invalid); return !Invalid; } /// Capture the given variable in the captured region. static bool captureInCapturedRegion(CapturedRegionScopeInfo *RSI, VarDecl *Var, SourceLocation Loc, const bool BuildAndDiagnose, QualType &CaptureType, QualType &DeclRefType, const bool RefersToCapturedVariable, Sema &S, bool Invalid) { // By default, capture variables by reference. bool ByRef = true; // Using an LValue reference type is consistent with Lambdas (see below). if (S.getLangOpts().OpenMP && RSI->CapRegionKind == CR_OpenMP) { if (S.isOpenMPCapturedDecl(Var)) { bool HasConst = DeclRefType.isConstQualified(); DeclRefType = DeclRefType.getUnqualifiedType(); // Don't lose diagnostics about assignments to const. if (HasConst) DeclRefType.addConst(); } ByRef = S.isOpenMPCapturedByRef(Var, RSI->OpenMPLevel, RSI->OpenMPCaptureLevel); } if (ByRef) CaptureType = S.Context.getLValueReferenceType(DeclRefType); else CaptureType = DeclRefType; // Actually capture the variable. if (BuildAndDiagnose) RSI->addCapture(Var, /*isBlock*/ false, ByRef, RefersToCapturedVariable, Loc, SourceLocation(), CaptureType, Invalid); return !Invalid; } /// Capture the given variable in the lambda. static bool captureInLambda(LambdaScopeInfo *LSI, VarDecl *Var, SourceLocation Loc, const bool BuildAndDiagnose, QualType &CaptureType, QualType &DeclRefType, const bool RefersToCapturedVariable, const Sema::TryCaptureKind Kind, SourceLocation EllipsisLoc, const bool IsTopScope, Sema &S, bool Invalid) { // Determine whether we are capturing by reference or by value. bool ByRef = false; if (IsTopScope && Kind != Sema::TryCapture_Implicit) { ByRef = (Kind == Sema::TryCapture_ExplicitByRef); } else { ByRef = (LSI->ImpCaptureStyle == LambdaScopeInfo::ImpCap_LambdaByref); } // Compute the type of the field that will capture this variable. if (ByRef) { // C++11 [expr.prim.lambda]p15: // An entity is captured by reference if it is implicitly or // explicitly captured but not captured by copy. It is // unspecified whether additional unnamed non-static data // members are declared in the closure type for entities // captured by reference. // // FIXME: It is not clear whether we want to build an lvalue reference // to the DeclRefType or to CaptureType.getNonReferenceType(). GCC appears // to do the former, while EDG does the latter. Core issue 1249 will // clarify, but for now we follow GCC because it's a more permissive and // easily defensible position. CaptureType = S.Context.getLValueReferenceType(DeclRefType); } else { // C++11 [expr.prim.lambda]p14: // For each entity captured by copy, an unnamed non-static // data member is declared in the closure type. The // declaration order of these members is unspecified. The type // of such a data member is the type of the corresponding // captured entity if the entity is not a reference to an // object, or the referenced type otherwise. [Note: If the // captured entity is a reference to a function, the // corresponding data member is also a reference to a // function. - end note ] if (const ReferenceType *RefType = CaptureType->getAs()){ if (!RefType->getPointeeType()->isFunctionType()) CaptureType = RefType->getPointeeType(); } // Forbid the lambda copy-capture of autoreleasing variables. if (!Invalid && CaptureType.getObjCLifetime() == Qualifiers::OCL_Autoreleasing) { if (BuildAndDiagnose) { S.Diag(Loc, diag::err_arc_autoreleasing_capture) << /*lambda*/ 1; S.Diag(Var->getLocation(), diag::note_previous_decl) << Var->getDeclName(); Invalid = true; } else { return false; } } // Make sure that by-copy captures are of a complete and non-abstract type. if (!Invalid && BuildAndDiagnose) { if (!CaptureType->isDependentType() && S.RequireCompleteType(Loc, CaptureType, diag::err_capture_of_incomplete_type, Var->getDeclName())) Invalid = true; else if (S.RequireNonAbstractType(Loc, CaptureType, diag::err_capture_of_abstract_type)) Invalid = true; } } // Compute the type of a reference to this captured variable. if (ByRef) DeclRefType = CaptureType.getNonReferenceType(); else { // C++ [expr.prim.lambda]p5: // The closure type for a lambda-expression has a public inline // function call operator [...]. This function call operator is // declared const (9.3.1) if and only if the lambda-expression's // parameter-declaration-clause is not followed by mutable. DeclRefType = CaptureType.getNonReferenceType(); if (!LSI->Mutable && !CaptureType->isReferenceType()) DeclRefType.addConst(); } // Add the capture. if (BuildAndDiagnose) LSI->addCapture(Var, /*isBlock=*/false, ByRef, RefersToCapturedVariable, Loc, EllipsisLoc, CaptureType, Invalid); return !Invalid; } bool Sema::tryCaptureVariable( VarDecl *Var, SourceLocation ExprLoc, TryCaptureKind Kind, SourceLocation EllipsisLoc, bool BuildAndDiagnose, QualType &CaptureType, QualType &DeclRefType, const unsigned *const FunctionScopeIndexToStopAt) { // An init-capture is notionally from the context surrounding its // declaration, but its parent DC is the lambda class. DeclContext *VarDC = Var->getDeclContext(); if (Var->isInitCapture()) VarDC = VarDC->getParent(); DeclContext *DC = CurContext; const unsigned MaxFunctionScopesIndex = FunctionScopeIndexToStopAt ? *FunctionScopeIndexToStopAt : FunctionScopes.size() - 1; // We need to sync up the Declaration Context with the // FunctionScopeIndexToStopAt if (FunctionScopeIndexToStopAt) { unsigned FSIndex = FunctionScopes.size() - 1; while (FSIndex != MaxFunctionScopesIndex) { DC = getLambdaAwareParentOfDeclContext(DC); --FSIndex; } } // If the variable is declared in the current context, there is no need to // capture it. if (VarDC == DC) return true; // Capture global variables if it is required to use private copy of this // variable. bool IsGlobal = !Var->hasLocalStorage(); if (IsGlobal && !(LangOpts.OpenMP && isOpenMPCapturedDecl(Var, /*CheckScopeInfo=*/true, MaxFunctionScopesIndex))) return true; Var = Var->getCanonicalDecl(); // Walk up the stack to determine whether we can capture the variable, // performing the "simple" checks that don't depend on type. We stop when // we've either hit the declared scope of the variable or find an existing // capture of that variable. We start from the innermost capturing-entity // (the DC) and ensure that all intervening capturing-entities // (blocks/lambdas etc.) between the innermost capturer and the variable`s // declcontext can either capture the variable or have already captured // the variable. CaptureType = Var->getType(); DeclRefType = CaptureType.getNonReferenceType(); bool Nested = false; bool Explicit = (Kind != TryCapture_Implicit); unsigned FunctionScopesIndex = MaxFunctionScopesIndex; do { // Only block literals, captured statements, and lambda expressions can // capture; other scopes don't work. DeclContext *ParentDC = getParentOfCapturingContextOrNull(DC, Var, ExprLoc, BuildAndDiagnose, *this); // We need to check for the parent *first* because, if we *have* // private-captured a global variable, we need to recursively capture it in // intermediate blocks, lambdas, etc. if (!ParentDC) { if (IsGlobal) { FunctionScopesIndex = MaxFunctionScopesIndex - 1; break; } return true; } FunctionScopeInfo *FSI = FunctionScopes[FunctionScopesIndex]; CapturingScopeInfo *CSI = cast(FSI); // Check whether we've already captured it. if (isVariableAlreadyCapturedInScopeInfo(CSI, Var, Nested, CaptureType, DeclRefType)) { CSI->getCapture(Var).markUsed(BuildAndDiagnose); break; } // If we are instantiating a generic lambda call operator body, // we do not want to capture new variables. What was captured // during either a lambdas transformation or initial parsing // should be used. if (isGenericLambdaCallOperatorSpecialization(DC)) { if (BuildAndDiagnose) { LambdaScopeInfo *LSI = cast(CSI); if (LSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_None) { Diag(ExprLoc, diag::err_lambda_impcap) << Var->getDeclName(); Diag(Var->getLocation(), diag::note_previous_decl) << Var->getDeclName(); Diag(LSI->Lambda->getBeginLoc(), diag::note_lambda_decl); } else diagnoseUncapturableValueReference(*this, ExprLoc, Var, DC); } return true; } // Try to capture variable-length arrays types. if (Var->getType()->isVariablyModifiedType()) { // We're going to walk down into the type and look for VLA // expressions. QualType QTy = Var->getType(); if (ParmVarDecl *PVD = dyn_cast_or_null(Var)) QTy = PVD->getOriginalType(); captureVariablyModifiedType(Context, QTy, CSI); } if (getLangOpts().OpenMP) { if (auto *RSI = dyn_cast(CSI)) { // OpenMP private variables should not be captured in outer scope, so // just break here. Similarly, global variables that are captured in a // target region should not be captured outside the scope of the region. if (RSI->CapRegionKind == CR_OpenMP) { bool IsOpenMPPrivateDecl = isOpenMPPrivateDecl(Var, RSI->OpenMPLevel); // If the variable is private (i.e. not captured) and has variably // modified type, we still need to capture the type for correct // codegen in all regions, associated with the construct. Currently, // it is captured in the innermost captured region only. if (IsOpenMPPrivateDecl && Var->getType()->isVariablyModifiedType()) { QualType QTy = Var->getType(); if (ParmVarDecl *PVD = dyn_cast_or_null(Var)) QTy = PVD->getOriginalType(); for (int I = 1, E = getNumberOfConstructScopes(RSI->OpenMPLevel); I < E; ++I) { auto *OuterRSI = cast( FunctionScopes[FunctionScopesIndex - I]); assert(RSI->OpenMPLevel == OuterRSI->OpenMPLevel && "Wrong number of captured regions associated with the " "OpenMP construct."); captureVariablyModifiedType(Context, QTy, OuterRSI); } } bool IsTargetCap = !IsOpenMPPrivateDecl && isOpenMPTargetCapturedDecl(Var, RSI->OpenMPLevel); // When we detect target captures we are looking from inside the // target region, therefore we need to propagate the capture from the // enclosing region. Therefore, the capture is not initially nested. if (IsTargetCap) adjustOpenMPTargetScopeIndex(FunctionScopesIndex, RSI->OpenMPLevel); if (IsTargetCap || IsOpenMPPrivateDecl) { Nested = !IsTargetCap; DeclRefType = DeclRefType.getUnqualifiedType(); CaptureType = Context.getLValueReferenceType(DeclRefType); break; } } } } if (CSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_None && !Explicit) { // No capture-default, and this is not an explicit capture // so cannot capture this variable. if (BuildAndDiagnose) { Diag(ExprLoc, diag::err_lambda_impcap) << Var->getDeclName(); Diag(Var->getLocation(), diag::note_previous_decl) << Var->getDeclName(); if (cast(CSI)->Lambda) Diag(cast(CSI)->Lambda->getBeginLoc(), diag::note_lambda_decl); // FIXME: If we error out because an outer lambda can not implicitly // capture a variable that an inner lambda explicitly captures, we // should have the inner lambda do the explicit capture - because // it makes for cleaner diagnostics later. This would purely be done // so that the diagnostic does not misleadingly claim that a variable // can not be captured by a lambda implicitly even though it is captured // explicitly. Suggestion: // - create const bool VariableCaptureWasInitiallyExplicit = Explicit // at the function head // - cache the StartingDeclContext - this must be a lambda // - captureInLambda in the innermost lambda the variable. } return true; } FunctionScopesIndex--; DC = ParentDC; Explicit = false; } while (!VarDC->Equals(DC)); // Walk back down the scope stack, (e.g. from outer lambda to inner lambda) // computing the type of the capture at each step, checking type-specific // requirements, and adding captures if requested. // If the variable had already been captured previously, we start capturing // at the lambda nested within that one. bool Invalid = false; for (unsigned I = ++FunctionScopesIndex, N = MaxFunctionScopesIndex + 1; I != N; ++I) { CapturingScopeInfo *CSI = cast(FunctionScopes[I]); // Certain capturing entities (lambdas, blocks etc.) are not allowed to capture // certain types of variables (unnamed, variably modified types etc.) // so check for eligibility. if (!Invalid) Invalid = !isVariableCapturable(CSI, Var, ExprLoc, BuildAndDiagnose, *this); // After encountering an error, if we're actually supposed to capture, keep // capturing in nested contexts to suppress any follow-on diagnostics. if (Invalid && !BuildAndDiagnose) return true; if (BlockScopeInfo *BSI = dyn_cast(CSI)) { Invalid = !captureInBlock(BSI, Var, ExprLoc, BuildAndDiagnose, CaptureType, DeclRefType, Nested, *this, Invalid); Nested = true; } else if (CapturedRegionScopeInfo *RSI = dyn_cast(CSI)) { Invalid = !captureInCapturedRegion(RSI, Var, ExprLoc, BuildAndDiagnose, CaptureType, DeclRefType, Nested, *this, Invalid); Nested = true; } else { LambdaScopeInfo *LSI = cast(CSI); Invalid = !captureInLambda(LSI, Var, ExprLoc, BuildAndDiagnose, CaptureType, DeclRefType, Nested, Kind, EllipsisLoc, /*IsTopScope*/ I == N - 1, *this, Invalid); Nested = true; } if (Invalid && !BuildAndDiagnose) return true; } return Invalid; } bool Sema::tryCaptureVariable(VarDecl *Var, SourceLocation Loc, TryCaptureKind Kind, SourceLocation EllipsisLoc) { QualType CaptureType; QualType DeclRefType; return tryCaptureVariable(Var, Loc, Kind, EllipsisLoc, /*BuildAndDiagnose=*/true, CaptureType, DeclRefType, nullptr); } bool Sema::NeedToCaptureVariable(VarDecl *Var, SourceLocation Loc) { QualType CaptureType; QualType DeclRefType; return !tryCaptureVariable(Var, Loc, TryCapture_Implicit, SourceLocation(), /*BuildAndDiagnose=*/false, CaptureType, DeclRefType, nullptr); } QualType Sema::getCapturedDeclRefType(VarDecl *Var, SourceLocation Loc) { QualType CaptureType; QualType DeclRefType; // Determine whether we can capture this variable. if (tryCaptureVariable(Var, Loc, TryCapture_Implicit, SourceLocation(), /*BuildAndDiagnose=*/false, CaptureType, DeclRefType, nullptr)) return QualType(); return DeclRefType; } namespace { // Helper to copy the template arguments from a DeclRefExpr or MemberExpr. // The produced TemplateArgumentListInfo* points to data stored within this // object, so should only be used in contexts where the pointer will not be // used after the CopiedTemplateArgs object is destroyed. class CopiedTemplateArgs { bool HasArgs; TemplateArgumentListInfo TemplateArgStorage; public: template CopiedTemplateArgs(RefExpr *E) : HasArgs(E->hasExplicitTemplateArgs()) { if (HasArgs) E->copyTemplateArgumentsInto(TemplateArgStorage); } operator TemplateArgumentListInfo*() #ifdef __has_cpp_attribute #if __has_cpp_attribute(clang::lifetimebound) [[clang::lifetimebound]] #endif #endif { return HasArgs ? &TemplateArgStorage : nullptr; } }; } /// Walk the set of potential results of an expression and mark them all as /// non-odr-uses if they satisfy the side-conditions of the NonOdrUseReason. /// /// \return A new expression if we found any potential results, ExprEmpty() if /// not, and ExprError() if we diagnosed an error. static ExprResult rebuildPotentialResultsAsNonOdrUsed(Sema &S, Expr *E, NonOdrUseReason NOUR) { // Per C++11 [basic.def.odr], a variable is odr-used "unless it is // an object that satisfies the requirements for appearing in a // constant expression (5.19) and the lvalue-to-rvalue conversion (4.1) // is immediately applied." This function handles the lvalue-to-rvalue // conversion part. // // If we encounter a node that claims to be an odr-use but shouldn't be, we // transform it into the relevant kind of non-odr-use node and rebuild the // tree of nodes leading to it. // // This is a mini-TreeTransform that only transforms a restricted subset of // nodes (and only certain operands of them). // Rebuild a subexpression. auto Rebuild = [&](Expr *Sub) { return rebuildPotentialResultsAsNonOdrUsed(S, Sub, NOUR); }; // Check whether a potential result satisfies the requirements of NOUR. auto IsPotentialResultOdrUsed = [&](NamedDecl *D) { // Any entity other than a VarDecl is always odr-used whenever it's named // in a potentially-evaluated expression. auto *VD = dyn_cast(D); if (!VD) return true; // C++2a [basic.def.odr]p4: // A variable x whose name appears as a potentially-evalauted expression // e is odr-used by e unless // -- x is a reference that is usable in constant expressions, or // -- x is a variable of non-reference type that is usable in constant // expressions and has no mutable subobjects, and e is an element of // the set of potential results of an expression of // non-volatile-qualified non-class type to which the lvalue-to-rvalue // conversion is applied, or // -- x is a variable of non-reference type, and e is an element of the // set of potential results of a discarded-value expression to which // the lvalue-to-rvalue conversion is not applied // // We check the first bullet and the "potentially-evaluated" condition in // BuildDeclRefExpr. We check the type requirements in the second bullet // in CheckLValueToRValueConversionOperand below. switch (NOUR) { case NOUR_None: case NOUR_Unevaluated: llvm_unreachable("unexpected non-odr-use-reason"); case NOUR_Constant: // Constant references were handled when they were built. if (VD->getType()->isReferenceType()) return true; if (auto *RD = VD->getType()->getAsCXXRecordDecl()) if (RD->hasMutableFields()) return true; if (!VD->isUsableInConstantExpressions(S.Context)) return true; break; case NOUR_Discarded: if (VD->getType()->isReferenceType()) return true; break; } return false; }; // Mark that this expression does not constitute an odr-use. auto MarkNotOdrUsed = [&] { S.MaybeODRUseExprs.erase(E); if (LambdaScopeInfo *LSI = S.getCurLambda()) LSI->markVariableExprAsNonODRUsed(E); }; // C++2a [basic.def.odr]p2: // The set of potential results of an expression e is defined as follows: switch (E->getStmtClass()) { // -- If e is an id-expression, ... case Expr::DeclRefExprClass: { auto *DRE = cast(E); if (DRE->isNonOdrUse() || IsPotentialResultOdrUsed(DRE->getDecl())) break; // Rebuild as a non-odr-use DeclRefExpr. MarkNotOdrUsed(); return DeclRefExpr::Create( S.Context, DRE->getQualifierLoc(), DRE->getTemplateKeywordLoc(), DRE->getDecl(), DRE->refersToEnclosingVariableOrCapture(), DRE->getNameInfo(), DRE->getType(), DRE->getValueKind(), DRE->getFoundDecl(), CopiedTemplateArgs(DRE), NOUR); } case Expr::FunctionParmPackExprClass: { auto *FPPE = cast(E); // If any of the declarations in the pack is odr-used, then the expression // as a whole constitutes an odr-use. for (VarDecl *D : *FPPE) if (IsPotentialResultOdrUsed(D)) return ExprEmpty(); // FIXME: Rebuild as a non-odr-use FunctionParmPackExpr? In practice, // nothing cares about whether we marked this as an odr-use, but it might // be useful for non-compiler tools. MarkNotOdrUsed(); break; } // -- If e is a subscripting operation with an array operand... case Expr::ArraySubscriptExprClass: { auto *ASE = cast(E); Expr *OldBase = ASE->getBase()->IgnoreImplicit(); if (!OldBase->getType()->isArrayType()) break; ExprResult Base = Rebuild(OldBase); if (!Base.isUsable()) return Base; Expr *LHS = ASE->getBase() == ASE->getLHS() ? Base.get() : ASE->getLHS(); Expr *RHS = ASE->getBase() == ASE->getRHS() ? Base.get() : ASE->getRHS(); SourceLocation LBracketLoc = ASE->getBeginLoc(); // FIXME: Not stored. return S.ActOnArraySubscriptExpr(nullptr, LHS, LBracketLoc, RHS, ASE->getRBracketLoc()); } case Expr::MemberExprClass: { auto *ME = cast(E); // -- If e is a class member access expression [...] naming a non-static // data member... if (isa(ME->getMemberDecl())) { ExprResult Base = Rebuild(ME->getBase()); if (!Base.isUsable()) return Base; return MemberExpr::Create( S.Context, Base.get(), ME->isArrow(), ME->getOperatorLoc(), ME->getQualifierLoc(), ME->getTemplateKeywordLoc(), ME->getMemberDecl(), ME->getFoundDecl(), ME->getMemberNameInfo(), CopiedTemplateArgs(ME), ME->getType(), ME->getValueKind(), ME->getObjectKind(), ME->isNonOdrUse()); } if (ME->getMemberDecl()->isCXXInstanceMember()) break; // -- If e is a class member access expression naming a static data member, // ... if (ME->isNonOdrUse() || IsPotentialResultOdrUsed(ME->getMemberDecl())) break; // Rebuild as a non-odr-use MemberExpr. MarkNotOdrUsed(); return MemberExpr::Create( S.Context, ME->getBase(), ME->isArrow(), ME->getOperatorLoc(), ME->getQualifierLoc(), ME->getTemplateKeywordLoc(), ME->getMemberDecl(), ME->getFoundDecl(), ME->getMemberNameInfo(), CopiedTemplateArgs(ME), ME->getType(), ME->getValueKind(), ME->getObjectKind(), NOUR); return ExprEmpty(); } case Expr::BinaryOperatorClass: { auto *BO = cast(E); Expr *LHS = BO->getLHS(); Expr *RHS = BO->getRHS(); // -- If e is a pointer-to-member expression of the form e1 .* e2 ... if (BO->getOpcode() == BO_PtrMemD) { ExprResult Sub = Rebuild(LHS); if (!Sub.isUsable()) return Sub; LHS = Sub.get(); // -- If e is a comma expression, ... } else if (BO->getOpcode() == BO_Comma) { ExprResult Sub = Rebuild(RHS); if (!Sub.isUsable()) return Sub; RHS = Sub.get(); } else { break; } return S.BuildBinOp(nullptr, BO->getOperatorLoc(), BO->getOpcode(), LHS, RHS); } // -- If e has the form (e1)... case Expr::ParenExprClass: { auto *PE = cast(E); ExprResult Sub = Rebuild(PE->getSubExpr()); if (!Sub.isUsable()) return Sub; return S.ActOnParenExpr(PE->getLParen(), PE->getRParen(), Sub.get()); } // -- If e is a glvalue conditional expression, ... // We don't apply this to a binary conditional operator. FIXME: Should we? case Expr::ConditionalOperatorClass: { auto *CO = cast(E); ExprResult LHS = Rebuild(CO->getLHS()); if (LHS.isInvalid()) return ExprError(); ExprResult RHS = Rebuild(CO->getRHS()); if (RHS.isInvalid()) return ExprError(); if (!LHS.isUsable() && !RHS.isUsable()) return ExprEmpty(); if (!LHS.isUsable()) LHS = CO->getLHS(); if (!RHS.isUsable()) RHS = CO->getRHS(); return S.ActOnConditionalOp(CO->getQuestionLoc(), CO->getColonLoc(), CO->getCond(), LHS.get(), RHS.get()); } // [Clang extension] // -- If e has the form __extension__ e1... case Expr::UnaryOperatorClass: { auto *UO = cast(E); if (UO->getOpcode() != UO_Extension) break; ExprResult Sub = Rebuild(UO->getSubExpr()); if (!Sub.isUsable()) return Sub; return S.BuildUnaryOp(nullptr, UO->getOperatorLoc(), UO_Extension, Sub.get()); } // [Clang extension] // -- If e has the form _Generic(...), the set of potential results is the // union of the sets of potential results of the associated expressions. case Expr::GenericSelectionExprClass: { auto *GSE = cast(E); SmallVector AssocExprs; bool AnyChanged = false; for (Expr *OrigAssocExpr : GSE->getAssocExprs()) { ExprResult AssocExpr = Rebuild(OrigAssocExpr); if (AssocExpr.isInvalid()) return ExprError(); if (AssocExpr.isUsable()) { AssocExprs.push_back(AssocExpr.get()); AnyChanged = true; } else { AssocExprs.push_back(OrigAssocExpr); } } return AnyChanged ? S.CreateGenericSelectionExpr( GSE->getGenericLoc(), GSE->getDefaultLoc(), GSE->getRParenLoc(), GSE->getControllingExpr(), GSE->getAssocTypeSourceInfos(), AssocExprs) : ExprEmpty(); } // [Clang extension] // -- If e has the form __builtin_choose_expr(...), the set of potential // results is the union of the sets of potential results of the // second and third subexpressions. case Expr::ChooseExprClass: { auto *CE = cast(E); ExprResult LHS = Rebuild(CE->getLHS()); if (LHS.isInvalid()) return ExprError(); ExprResult RHS = Rebuild(CE->getLHS()); if (RHS.isInvalid()) return ExprError(); if (!LHS.get() && !RHS.get()) return ExprEmpty(); if (!LHS.isUsable()) LHS = CE->getLHS(); if (!RHS.isUsable()) RHS = CE->getRHS(); return S.ActOnChooseExpr(CE->getBuiltinLoc(), CE->getCond(), LHS.get(), RHS.get(), CE->getRParenLoc()); } // Step through non-syntactic nodes. case Expr::ConstantExprClass: { auto *CE = cast(E); ExprResult Sub = Rebuild(CE->getSubExpr()); if (!Sub.isUsable()) return Sub; return ConstantExpr::Create(S.Context, Sub.get()); } // We could mostly rely on the recursive rebuilding to rebuild implicit // casts, but not at the top level, so rebuild them here. case Expr::ImplicitCastExprClass: { auto *ICE = cast(E); // Only step through the narrow set of cast kinds we expect to encounter. // Anything else suggests we've left the region in which potential results // can be found. switch (ICE->getCastKind()) { case CK_NoOp: case CK_DerivedToBase: case CK_UncheckedDerivedToBase: { ExprResult Sub = Rebuild(ICE->getSubExpr()); if (!Sub.isUsable()) return Sub; CXXCastPath Path(ICE->path()); return S.ImpCastExprToType(Sub.get(), ICE->getType(), ICE->getCastKind(), ICE->getValueKind(), &Path); } default: break; } break; } default: break; } // Can't traverse through this node. Nothing to do. return ExprEmpty(); } ExprResult Sema::CheckLValueToRValueConversionOperand(Expr *E) { // Check whether the operand is or contains an object of non-trivial C union // type. if (E->getType().isVolatileQualified() && (E->getType().hasNonTrivialToPrimitiveDestructCUnion() || E->getType().hasNonTrivialToPrimitiveCopyCUnion())) checkNonTrivialCUnion(E->getType(), E->getExprLoc(), Sema::NTCUC_LValueToRValueVolatile, NTCUK_Destruct|NTCUK_Copy); // C++2a [basic.def.odr]p4: // [...] an expression of non-volatile-qualified non-class type to which // the lvalue-to-rvalue conversion is applied [...] if (E->getType().isVolatileQualified() || E->getType()->getAs()) return E; ExprResult Result = rebuildPotentialResultsAsNonOdrUsed(*this, E, NOUR_Constant); if (Result.isInvalid()) return ExprError(); return Result.get() ? Result : E; } ExprResult Sema::ActOnConstantExpression(ExprResult Res) { Res = CorrectDelayedTyposInExpr(Res); if (!Res.isUsable()) return Res; // If a constant-expression is a reference to a variable where we delay // deciding whether it is an odr-use, just assume we will apply the // lvalue-to-rvalue conversion. In the one case where this doesn't happen // (a non-type template argument), we have special handling anyway. return CheckLValueToRValueConversionOperand(Res.get()); } void Sema::CleanupVarDeclMarking() { // Iterate through a local copy in case MarkVarDeclODRUsed makes a recursive // call. MaybeODRUseExprSet LocalMaybeODRUseExprs; std::swap(LocalMaybeODRUseExprs, MaybeODRUseExprs); for (Expr *E : LocalMaybeODRUseExprs) { if (auto *DRE = dyn_cast(E)) { MarkVarDeclODRUsed(cast(DRE->getDecl()), DRE->getLocation(), *this); } else if (auto *ME = dyn_cast(E)) { MarkVarDeclODRUsed(cast(ME->getMemberDecl()), ME->getMemberLoc(), *this); } else if (auto *FP = dyn_cast(E)) { for (VarDecl *VD : *FP) MarkVarDeclODRUsed(VD, FP->getParameterPackLocation(), *this); } else { llvm_unreachable("Unexpected expression"); } } assert(MaybeODRUseExprs.empty() && "MarkVarDeclODRUsed failed to cleanup MaybeODRUseExprs?"); } static void DoMarkVarDeclReferenced(Sema &SemaRef, SourceLocation Loc, VarDecl *Var, Expr *E) { assert((!E || isa(E) || isa(E) || isa(E)) && "Invalid Expr argument to DoMarkVarDeclReferenced"); Var->setReferenced(); if (Var->isInvalidDecl()) return; auto *MSI = Var->getMemberSpecializationInfo(); TemplateSpecializationKind TSK = MSI ? MSI->getTemplateSpecializationKind() : Var->getTemplateSpecializationKind(); OdrUseContext OdrUse = isOdrUseContext(SemaRef); bool UsableInConstantExpr = Var->mightBeUsableInConstantExpressions(SemaRef.Context); // C++20 [expr.const]p12: // A variable [...] is needed for constant evaluation if it is [...] a // variable whose name appears as a potentially constant evaluated // expression that is either a contexpr variable or is of non-volatile // const-qualified integral type or of reference type bool NeededForConstantEvaluation = isPotentiallyConstantEvaluatedContext(SemaRef) && UsableInConstantExpr; bool NeedDefinition = OdrUse == OdrUseContext::Used || NeededForConstantEvaluation; VarTemplateSpecializationDecl *VarSpec = dyn_cast(Var); assert(!isa(Var) && "Can't instantiate a partial template specialization."); // If this might be a member specialization of a static data member, check // the specialization is visible. We already did the checks for variable // template specializations when we created them. if (NeedDefinition && TSK != TSK_Undeclared && !isa(Var)) SemaRef.checkSpecializationVisibility(Loc, Var); // Perform implicit instantiation of static data members, static data member // templates of class templates, and variable template specializations. Delay // instantiations of variable templates, except for those that could be used // in a constant expression. if (NeedDefinition && isTemplateInstantiation(TSK)) { // Per C++17 [temp.explicit]p10, we may instantiate despite an explicit // instantiation declaration if a variable is usable in a constant // expression (among other cases). bool TryInstantiating = TSK == TSK_ImplicitInstantiation || (TSK == TSK_ExplicitInstantiationDeclaration && UsableInConstantExpr); if (TryInstantiating) { SourceLocation PointOfInstantiation = MSI ? MSI->getPointOfInstantiation() : Var->getPointOfInstantiation(); bool FirstInstantiation = PointOfInstantiation.isInvalid(); if (FirstInstantiation) { PointOfInstantiation = Loc; if (MSI) MSI->setPointOfInstantiation(PointOfInstantiation); else Var->setTemplateSpecializationKind(TSK, PointOfInstantiation); } bool InstantiationDependent = false; bool IsNonDependent = VarSpec ? !TemplateSpecializationType::anyDependentTemplateArguments( VarSpec->getTemplateArgsInfo(), InstantiationDependent) : true; // Do not instantiate specializations that are still type-dependent. if (IsNonDependent) { if (UsableInConstantExpr) { // Do not defer instantiations of variables that could be used in a // constant expression. SemaRef.runWithSufficientStackSpace(PointOfInstantiation, [&] { SemaRef.InstantiateVariableDefinition(PointOfInstantiation, Var); }); } else if (FirstInstantiation || isa(Var)) { // FIXME: For a specialization of a variable template, we don't // distinguish between "declaration and type implicitly instantiated" // and "implicit instantiation of definition requested", so we have // no direct way to avoid enqueueing the pending instantiation // multiple times. SemaRef.PendingInstantiations .push_back(std::make_pair(Var, PointOfInstantiation)); } } } } // C++2a [basic.def.odr]p4: // A variable x whose name appears as a potentially-evaluated expression e // is odr-used by e unless // -- x is a reference that is usable in constant expressions // -- x is a variable of non-reference type that is usable in constant // expressions and has no mutable subobjects [FIXME], and e is an // element of the set of potential results of an expression of // non-volatile-qualified non-class type to which the lvalue-to-rvalue // conversion is applied // -- x is a variable of non-reference type, and e is an element of the set // of potential results of a discarded-value expression to which the // lvalue-to-rvalue conversion is not applied [FIXME] // // We check the first part of the second bullet here, and // Sema::CheckLValueToRValueConversionOperand deals with the second part. // FIXME: To get the third bullet right, we need to delay this even for // variables that are not usable in constant expressions. // If we already know this isn't an odr-use, there's nothing more to do. if (DeclRefExpr *DRE = dyn_cast_or_null(E)) if (DRE->isNonOdrUse()) return; if (MemberExpr *ME = dyn_cast_or_null(E)) if (ME->isNonOdrUse()) return; switch (OdrUse) { case OdrUseContext::None: assert((!E || isa(E)) && "missing non-odr-use marking for unevaluated decl ref"); break; case OdrUseContext::FormallyOdrUsed: // FIXME: Ignoring formal odr-uses results in incorrect lambda capture // behavior. break; case OdrUseContext::Used: // If we might later find that this expression isn't actually an odr-use, // delay the marking. if (E && Var->isUsableInConstantExpressions(SemaRef.Context)) SemaRef.MaybeODRUseExprs.insert(E); else MarkVarDeclODRUsed(Var, Loc, SemaRef); break; case OdrUseContext::Dependent: // If this is a dependent context, we don't need to mark variables as // odr-used, but we may still need to track them for lambda capture. // FIXME: Do we also need to do this inside dependent typeid expressions // (which are modeled as unevaluated at this point)? const bool RefersToEnclosingScope = (SemaRef.CurContext != Var->getDeclContext() && Var->getDeclContext()->isFunctionOrMethod() && Var->hasLocalStorage()); if (RefersToEnclosingScope) { LambdaScopeInfo *const LSI = SemaRef.getCurLambda(/*IgnoreNonLambdaCapturingScope=*/true); if (LSI && (!LSI->CallOperator || !LSI->CallOperator->Encloses(Var->getDeclContext()))) { // If a variable could potentially be odr-used, defer marking it so // until we finish analyzing the full expression for any // lvalue-to-rvalue // or discarded value conversions that would obviate odr-use. // Add it to the list of potential captures that will be analyzed // later (ActOnFinishFullExpr) for eventual capture and odr-use marking // unless the variable is a reference that was initialized by a constant // expression (this will never need to be captured or odr-used). // // FIXME: We can simplify this a lot after implementing P0588R1. assert(E && "Capture variable should be used in an expression."); if (!Var->getType()->isReferenceType() || !Var->isUsableInConstantExpressions(SemaRef.Context)) LSI->addPotentialCapture(E->IgnoreParens()); } } break; } } /// Mark a variable referenced, and check whether it is odr-used /// (C++ [basic.def.odr]p2, C99 6.9p3). Note that this should not be /// used directly for normal expressions referring to VarDecl. void Sema::MarkVariableReferenced(SourceLocation Loc, VarDecl *Var) { DoMarkVarDeclReferenced(*this, Loc, Var, nullptr); } static void MarkExprReferenced(Sema &SemaRef, SourceLocation Loc, Decl *D, Expr *E, bool MightBeOdrUse) { if (SemaRef.isInOpenMPDeclareTargetContext()) SemaRef.checkDeclIsAllowedInOpenMPTarget(E, D); if (VarDecl *Var = dyn_cast(D)) { DoMarkVarDeclReferenced(SemaRef, Loc, Var, E); return; } SemaRef.MarkAnyDeclReferenced(Loc, D, MightBeOdrUse); // If this is a call to a method via a cast, also mark the method in the // derived class used in case codegen can devirtualize the call. const MemberExpr *ME = dyn_cast(E); if (!ME) return; CXXMethodDecl *MD = dyn_cast(ME->getMemberDecl()); if (!MD) return; // Only attempt to devirtualize if this is truly a virtual call. bool IsVirtualCall = MD->isVirtual() && ME->performsVirtualDispatch(SemaRef.getLangOpts()); if (!IsVirtualCall) return; // If it's possible to devirtualize the call, mark the called function // referenced. CXXMethodDecl *DM = MD->getDevirtualizedMethod( ME->getBase(), SemaRef.getLangOpts().AppleKext); if (DM) SemaRef.MarkAnyDeclReferenced(Loc, DM, MightBeOdrUse); } /// Perform reference-marking and odr-use handling for a DeclRefExpr. void Sema::MarkDeclRefReferenced(DeclRefExpr *E, const Expr *Base) { // TODO: update this with DR# once a defect report is filed. // C++11 defect. The address of a pure member should not be an ODR use, even // if it's a qualified reference. bool OdrUse = true; if (const CXXMethodDecl *Method = dyn_cast(E->getDecl())) if (Method->isVirtual() && !Method->getDevirtualizedMethod(Base, getLangOpts().AppleKext)) OdrUse = false; MarkExprReferenced(*this, E->getLocation(), E->getDecl(), E, OdrUse); } /// Perform reference-marking and odr-use handling for a MemberExpr. void Sema::MarkMemberReferenced(MemberExpr *E) { // C++11 [basic.def.odr]p2: // A non-overloaded function whose name appears as a potentially-evaluated // expression or a member of a set of candidate functions, if selected by // overload resolution when referred to from a potentially-evaluated // expression, is odr-used, unless it is a pure virtual function and its // name is not explicitly qualified. bool MightBeOdrUse = true; if (E->performsVirtualDispatch(getLangOpts())) { if (CXXMethodDecl *Method = dyn_cast(E->getMemberDecl())) if (Method->isPure()) MightBeOdrUse = false; } SourceLocation Loc = E->getMemberLoc().isValid() ? E->getMemberLoc() : E->getBeginLoc(); MarkExprReferenced(*this, Loc, E->getMemberDecl(), E, MightBeOdrUse); } /// Perform reference-marking and odr-use handling for a FunctionParmPackExpr. void Sema::MarkFunctionParmPackReferenced(FunctionParmPackExpr *E) { for (VarDecl *VD : *E) MarkExprReferenced(*this, E->getParameterPackLocation(), VD, E, true); } /// Perform marking for a reference to an arbitrary declaration. It /// marks the declaration referenced, and performs odr-use checking for /// functions and variables. This method should not be used when building a /// normal expression which refers to a variable. void Sema::MarkAnyDeclReferenced(SourceLocation Loc, Decl *D, bool MightBeOdrUse) { if (MightBeOdrUse) { if (auto *VD = dyn_cast(D)) { MarkVariableReferenced(Loc, VD); return; } } if (auto *FD = dyn_cast(D)) { MarkFunctionReferenced(Loc, FD, MightBeOdrUse); return; } D->setReferenced(); } namespace { // Mark all of the declarations used by a type as referenced. // FIXME: Not fully implemented yet! We need to have a better understanding // of when we're entering a context we should not recurse into. // FIXME: This is and EvaluatedExprMarker are more-or-less equivalent to // TreeTransforms rebuilding the type in a new context. Rather than // duplicating the TreeTransform logic, we should consider reusing it here. // Currently that causes problems when rebuilding LambdaExprs. class MarkReferencedDecls : public RecursiveASTVisitor { Sema &S; SourceLocation Loc; public: typedef RecursiveASTVisitor Inherited; MarkReferencedDecls(Sema &S, SourceLocation Loc) : S(S), Loc(Loc) { } bool TraverseTemplateArgument(const TemplateArgument &Arg); }; } bool MarkReferencedDecls::TraverseTemplateArgument( const TemplateArgument &Arg) { { // A non-type template argument is a constant-evaluated context. EnterExpressionEvaluationContext Evaluated( S, Sema::ExpressionEvaluationContext::ConstantEvaluated); if (Arg.getKind() == TemplateArgument::Declaration) { if (Decl *D = Arg.getAsDecl()) S.MarkAnyDeclReferenced(Loc, D, true); } else if (Arg.getKind() == TemplateArgument::Expression) { S.MarkDeclarationsReferencedInExpr(Arg.getAsExpr(), false); } } return Inherited::TraverseTemplateArgument(Arg); } void Sema::MarkDeclarationsReferencedInType(SourceLocation Loc, QualType T) { MarkReferencedDecls Marker(*this, Loc); Marker.TraverseType(T); } namespace { /// Helper class that marks all of the declarations referenced by /// potentially-evaluated subexpressions as "referenced". class EvaluatedExprMarker : public EvaluatedExprVisitor { Sema &S; bool SkipLocalVariables; public: typedef EvaluatedExprVisitor Inherited; EvaluatedExprMarker(Sema &S, bool SkipLocalVariables) : Inherited(S.Context), S(S), SkipLocalVariables(SkipLocalVariables) { } void VisitDeclRefExpr(DeclRefExpr *E) { // If we were asked not to visit local variables, don't. if (SkipLocalVariables) { if (VarDecl *VD = dyn_cast(E->getDecl())) if (VD->hasLocalStorage()) return; } S.MarkDeclRefReferenced(E); } void VisitMemberExpr(MemberExpr *E) { S.MarkMemberReferenced(E); Inherited::VisitMemberExpr(E); } void VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E) { S.MarkFunctionReferenced( E->getBeginLoc(), const_cast(E->getTemporary()->getDestructor())); Visit(E->getSubExpr()); } void VisitCXXNewExpr(CXXNewExpr *E) { if (E->getOperatorNew()) S.MarkFunctionReferenced(E->getBeginLoc(), E->getOperatorNew()); if (E->getOperatorDelete()) S.MarkFunctionReferenced(E->getBeginLoc(), E->getOperatorDelete()); Inherited::VisitCXXNewExpr(E); } void VisitCXXDeleteExpr(CXXDeleteExpr *E) { if (E->getOperatorDelete()) S.MarkFunctionReferenced(E->getBeginLoc(), E->getOperatorDelete()); QualType Destroyed = S.Context.getBaseElementType(E->getDestroyedType()); if (const RecordType *DestroyedRec = Destroyed->getAs()) { CXXRecordDecl *Record = cast(DestroyedRec->getDecl()); S.MarkFunctionReferenced(E->getBeginLoc(), S.LookupDestructor(Record)); } Inherited::VisitCXXDeleteExpr(E); } void VisitCXXConstructExpr(CXXConstructExpr *E) { S.MarkFunctionReferenced(E->getBeginLoc(), E->getConstructor()); Inherited::VisitCXXConstructExpr(E); } void VisitCXXDefaultArgExpr(CXXDefaultArgExpr *E) { Visit(E->getExpr()); } }; } /// Mark any declarations that appear within this expression or any /// potentially-evaluated subexpressions as "referenced". /// /// \param SkipLocalVariables If true, don't mark local variables as /// 'referenced'. void Sema::MarkDeclarationsReferencedInExpr(Expr *E, bool SkipLocalVariables) { EvaluatedExprMarker(*this, SkipLocalVariables).Visit(E); } /// Emit a diagnostic that describes an effect on the run-time behavior /// of the program being compiled. /// /// This routine emits the given diagnostic when the code currently being /// type-checked is "potentially evaluated", meaning that there is a /// possibility that the code will actually be executable. Code in sizeof() /// expressions, code used only during overload resolution, etc., are not /// potentially evaluated. This routine will suppress such diagnostics or, /// in the absolutely nutty case of potentially potentially evaluated /// expressions (C++ typeid), queue the diagnostic to potentially emit it /// later. /// /// This routine should be used for all diagnostics that describe the run-time /// behavior of a program, such as passing a non-POD value through an ellipsis. /// Failure to do so will likely result in spurious diagnostics or failures /// during overload resolution or within sizeof/alignof/typeof/typeid. bool Sema::DiagRuntimeBehavior(SourceLocation Loc, ArrayRef Stmts, const PartialDiagnostic &PD) { switch (ExprEvalContexts.back().Context) { case ExpressionEvaluationContext::Unevaluated: case ExpressionEvaluationContext::UnevaluatedList: case ExpressionEvaluationContext::UnevaluatedAbstract: case ExpressionEvaluationContext::DiscardedStatement: // The argument will never be evaluated, so don't complain. break; case ExpressionEvaluationContext::ConstantEvaluated: // Relevant diagnostics should be produced by constant evaluation. break; case ExpressionEvaluationContext::PotentiallyEvaluated: case ExpressionEvaluationContext::PotentiallyEvaluatedIfUsed: if (!Stmts.empty() && getCurFunctionOrMethodDecl()) { FunctionScopes.back()->PossiblyUnreachableDiags. push_back(sema::PossiblyUnreachableDiag(PD, Loc, Stmts)); return true; } // The initializer of a constexpr variable or of the first declaration of a // static data member is not syntactically a constant evaluated constant, // but nonetheless is always required to be a constant expression, so we // can skip diagnosing. // FIXME: Using the mangling context here is a hack. if (auto *VD = dyn_cast_or_null( ExprEvalContexts.back().ManglingContextDecl)) { if (VD->isConstexpr() || (VD->isStaticDataMember() && VD->isFirstDecl() && !VD->isInline())) break; // FIXME: For any other kind of variable, we should build a CFG for its // initializer and check whether the context in question is reachable. } Diag(Loc, PD); return true; } return false; } bool Sema::DiagRuntimeBehavior(SourceLocation Loc, const Stmt *Statement, const PartialDiagnostic &PD) { return DiagRuntimeBehavior( Loc, Statement ? llvm::makeArrayRef(Statement) : llvm::None, PD); } bool Sema::CheckCallReturnType(QualType ReturnType, SourceLocation Loc, CallExpr *CE, FunctionDecl *FD) { if (ReturnType->isVoidType() || !ReturnType->isIncompleteType()) return false; // If we're inside a decltype's expression, don't check for a valid return // type or construct temporaries until we know whether this is the last call. if (ExprEvalContexts.back().ExprContext == ExpressionEvaluationContextRecord::EK_Decltype) { ExprEvalContexts.back().DelayedDecltypeCalls.push_back(CE); return false; } class CallReturnIncompleteDiagnoser : public TypeDiagnoser { FunctionDecl *FD; CallExpr *CE; public: CallReturnIncompleteDiagnoser(FunctionDecl *FD, CallExpr *CE) : FD(FD), CE(CE) { } void diagnose(Sema &S, SourceLocation Loc, QualType T) override { if (!FD) { S.Diag(Loc, diag::err_call_incomplete_return) << T << CE->getSourceRange(); return; } S.Diag(Loc, diag::err_call_function_incomplete_return) << CE->getSourceRange() << FD->getDeclName() << T; S.Diag(FD->getLocation(), diag::note_entity_declared_at) << FD->getDeclName(); } } Diagnoser(FD, CE); if (RequireCompleteType(Loc, ReturnType, Diagnoser)) return true; return false; } // Diagnose the s/=/==/ and s/\|=/!=/ typos. Note that adding parentheses // will prevent this condition from triggering, which is what we want. void Sema::DiagnoseAssignmentAsCondition(Expr *E) { SourceLocation Loc; unsigned diagnostic = diag::warn_condition_is_assignment; bool IsOrAssign = false; if (BinaryOperator *Op = dyn_cast(E)) { if (Op->getOpcode() != BO_Assign && Op->getOpcode() != BO_OrAssign) return; IsOrAssign = Op->getOpcode() == BO_OrAssign; // Greylist some idioms by putting them into a warning subcategory. if (ObjCMessageExpr *ME = dyn_cast(Op->getRHS()->IgnoreParenCasts())) { Selector Sel = ME->getSelector(); // self = [ init...] if (isSelfExpr(Op->getLHS()) && ME->getMethodFamily() == OMF_init) diagnostic = diag::warn_condition_is_idiomatic_assignment; // = [ nextObject] else if (Sel.isUnarySelector() && Sel.getNameForSlot(0) == "nextObject") diagnostic = diag::warn_condition_is_idiomatic_assignment; } Loc = Op->getOperatorLoc(); } else if (CXXOperatorCallExpr *Op = dyn_cast(E)) { if (Op->getOperator() != OO_Equal && Op->getOperator() != OO_PipeEqual) return; IsOrAssign = Op->getOperator() == OO_PipeEqual; Loc = Op->getOperatorLoc(); } else if (PseudoObjectExpr *POE = dyn_cast(E)) return DiagnoseAssignmentAsCondition(POE->getSyntacticForm()); else { // Not an assignment. return; } Diag(Loc, diagnostic) << E->getSourceRange(); SourceLocation Open = E->getBeginLoc(); SourceLocation Close = getLocForEndOfToken(E->getSourceRange().getEnd()); Diag(Loc, diag::note_condition_assign_silence) << FixItHint::CreateInsertion(Open, "(") << FixItHint::CreateInsertion(Close, ")"); if (IsOrAssign) Diag(Loc, diag::note_condition_or_assign_to_comparison) << FixItHint::CreateReplacement(Loc, "!="); else Diag(Loc, diag::note_condition_assign_to_comparison) << FixItHint::CreateReplacement(Loc, "=="); } /// Redundant parentheses over an equality comparison can indicate /// that the user intended an assignment used as condition. void Sema::DiagnoseEqualityWithExtraParens(ParenExpr *ParenE) { // Don't warn if the parens came from a macro. SourceLocation parenLoc = ParenE->getBeginLoc(); if (parenLoc.isInvalid() || parenLoc.isMacroID()) return; // Don't warn for dependent expressions. if (ParenE->isTypeDependent()) return; Expr *E = ParenE->IgnoreParens(); if (BinaryOperator *opE = dyn_cast(E)) if (opE->getOpcode() == BO_EQ && opE->getLHS()->IgnoreParenImpCasts()->isModifiableLvalue(Context) == Expr::MLV_Valid) { SourceLocation Loc = opE->getOperatorLoc(); Diag(Loc, diag::warn_equality_with_extra_parens) << E->getSourceRange(); SourceRange ParenERange = ParenE->getSourceRange(); Diag(Loc, diag::note_equality_comparison_silence) << FixItHint::CreateRemoval(ParenERange.getBegin()) << FixItHint::CreateRemoval(ParenERange.getEnd()); Diag(Loc, diag::note_equality_comparison_to_assign) << FixItHint::CreateReplacement(Loc, "="); } } ExprResult Sema::CheckBooleanCondition(SourceLocation Loc, Expr *E, bool IsConstexpr) { DiagnoseAssignmentAsCondition(E); if (ParenExpr *parenE = dyn_cast(E)) DiagnoseEqualityWithExtraParens(parenE); ExprResult result = CheckPlaceholderExpr(E); if (result.isInvalid()) return ExprError(); E = result.get(); if (!E->isTypeDependent()) { if (getLangOpts().CPlusPlus) return CheckCXXBooleanCondition(E, IsConstexpr); // C++ 6.4p4 ExprResult ERes = DefaultFunctionArrayLvalueConversion(E); if (ERes.isInvalid()) return ExprError(); E = ERes.get(); QualType T = E->getType(); if (!T->isScalarType()) { // C99 6.8.4.1p1 Diag(Loc, diag::err_typecheck_statement_requires_scalar) << T << E->getSourceRange(); return ExprError(); } CheckBoolLikeConversion(E, Loc); } return E; } Sema::ConditionResult Sema::ActOnCondition(Scope *S, SourceLocation Loc, Expr *SubExpr, ConditionKind CK) { // Empty conditions are valid in for-statements. if (!SubExpr) return ConditionResult(); ExprResult Cond; switch (CK) { case ConditionKind::Boolean: Cond = CheckBooleanCondition(Loc, SubExpr); break; case ConditionKind::ConstexprIf: Cond = CheckBooleanCondition(Loc, SubExpr, true); break; case ConditionKind::Switch: Cond = CheckSwitchCondition(Loc, SubExpr); break; } if (Cond.isInvalid()) return ConditionError(); // FIXME: FullExprArg doesn't have an invalid bit, so check nullness instead. FullExprArg FullExpr = MakeFullExpr(Cond.get(), Loc); if (!FullExpr.get()) return ConditionError(); return ConditionResult(*this, nullptr, FullExpr, CK == ConditionKind::ConstexprIf); } namespace { /// A visitor for rebuilding a call to an __unknown_any expression /// to have an appropriate type. struct RebuildUnknownAnyFunction : StmtVisitor { Sema &S; RebuildUnknownAnyFunction(Sema &S) : S(S) {} ExprResult VisitStmt(Stmt *S) { llvm_unreachable("unexpected statement!"); } ExprResult VisitExpr(Expr *E) { S.Diag(E->getExprLoc(), diag::err_unsupported_unknown_any_call) << E->getSourceRange(); return ExprError(); } /// Rebuild an expression which simply semantically wraps another /// expression which it shares the type and value kind of. template ExprResult rebuildSugarExpr(T *E) { ExprResult SubResult = Visit(E->getSubExpr()); if (SubResult.isInvalid()) return ExprError(); Expr *SubExpr = SubResult.get(); E->setSubExpr(SubExpr); E->setType(SubExpr->getType()); E->setValueKind(SubExpr->getValueKind()); assert(E->getObjectKind() == OK_Ordinary); return E; } ExprResult VisitParenExpr(ParenExpr *E) { return rebuildSugarExpr(E); } ExprResult VisitUnaryExtension(UnaryOperator *E) { return rebuildSugarExpr(E); } ExprResult VisitUnaryAddrOf(UnaryOperator *E) { ExprResult SubResult = Visit(E->getSubExpr()); if (SubResult.isInvalid()) return ExprError(); Expr *SubExpr = SubResult.get(); E->setSubExpr(SubExpr); E->setType(S.Context.getPointerType(SubExpr->getType())); assert(E->getValueKind() == VK_RValue); assert(E->getObjectKind() == OK_Ordinary); return E; } ExprResult resolveDecl(Expr *E, ValueDecl *VD) { if (!isa(VD)) return VisitExpr(E); E->setType(VD->getType()); assert(E->getValueKind() == VK_RValue); if (S.getLangOpts().CPlusPlus && !(isa(VD) && cast(VD)->isInstance())) E->setValueKind(VK_LValue); return E; } ExprResult VisitMemberExpr(MemberExpr *E) { return resolveDecl(E, E->getMemberDecl()); } ExprResult VisitDeclRefExpr(DeclRefExpr *E) { return resolveDecl(E, E->getDecl()); } }; } /// Given a function expression of unknown-any type, try to rebuild it /// to have a function type. static ExprResult rebuildUnknownAnyFunction(Sema &S, Expr *FunctionExpr) { ExprResult Result = RebuildUnknownAnyFunction(S).Visit(FunctionExpr); if (Result.isInvalid()) return ExprError(); return S.DefaultFunctionArrayConversion(Result.get()); } namespace { /// A visitor for rebuilding an expression of type __unknown_anytype /// into one which resolves the type directly on the referring /// expression. Strict preservation of the original source /// structure is not a goal. struct RebuildUnknownAnyExpr : StmtVisitor { Sema &S; /// The current destination type. QualType DestType; RebuildUnknownAnyExpr(Sema &S, QualType CastType) : S(S), DestType(CastType) {} ExprResult VisitStmt(Stmt *S) { llvm_unreachable("unexpected statement!"); } ExprResult VisitExpr(Expr *E) { S.Diag(E->getExprLoc(), diag::err_unsupported_unknown_any_expr) << E->getSourceRange(); return ExprError(); } ExprResult VisitCallExpr(CallExpr *E); ExprResult VisitObjCMessageExpr(ObjCMessageExpr *E); /// Rebuild an expression which simply semantically wraps another /// expression which it shares the type and value kind of. template ExprResult rebuildSugarExpr(T *E) { ExprResult SubResult = Visit(E->getSubExpr()); if (SubResult.isInvalid()) return ExprError(); Expr *SubExpr = SubResult.get(); E->setSubExpr(SubExpr); E->setType(SubExpr->getType()); E->setValueKind(SubExpr->getValueKind()); assert(E->getObjectKind() == OK_Ordinary); return E; } ExprResult VisitParenExpr(ParenExpr *E) { return rebuildSugarExpr(E); } ExprResult VisitUnaryExtension(UnaryOperator *E) { return rebuildSugarExpr(E); } ExprResult VisitUnaryAddrOf(UnaryOperator *E) { const PointerType *Ptr = DestType->getAs(); if (!Ptr) { S.Diag(E->getOperatorLoc(), diag::err_unknown_any_addrof) << E->getSourceRange(); return ExprError(); } if (isa(E->getSubExpr())) { S.Diag(E->getOperatorLoc(), diag::err_unknown_any_addrof_call) << E->getSourceRange(); return ExprError(); } assert(E->getValueKind() == VK_RValue); assert(E->getObjectKind() == OK_Ordinary); E->setType(DestType); // Build the sub-expression as if it were an object of the pointee type. DestType = Ptr->getPointeeType(); ExprResult SubResult = Visit(E->getSubExpr()); if (SubResult.isInvalid()) return ExprError(); E->setSubExpr(SubResult.get()); return E; } ExprResult VisitImplicitCastExpr(ImplicitCastExpr *E); ExprResult resolveDecl(Expr *E, ValueDecl *VD); ExprResult VisitMemberExpr(MemberExpr *E) { return resolveDecl(E, E->getMemberDecl()); } ExprResult VisitDeclRefExpr(DeclRefExpr *E) { return resolveDecl(E, E->getDecl()); } }; } /// Rebuilds a call expression which yielded __unknown_anytype. ExprResult RebuildUnknownAnyExpr::VisitCallExpr(CallExpr *E) { Expr *CalleeExpr = E->getCallee(); enum FnKind { FK_MemberFunction, FK_FunctionPointer, FK_BlockPointer }; FnKind Kind; QualType CalleeType = CalleeExpr->getType(); if (CalleeType == S.Context.BoundMemberTy) { assert(isa(E) || isa(E)); Kind = FK_MemberFunction; CalleeType = Expr::findBoundMemberType(CalleeExpr); } else if (const PointerType *Ptr = CalleeType->getAs()) { CalleeType = Ptr->getPointeeType(); Kind = FK_FunctionPointer; } else { CalleeType = CalleeType->castAs()->getPointeeType(); Kind = FK_BlockPointer; } const FunctionType *FnType = CalleeType->castAs(); // Verify that this is a legal result type of a function. if (DestType->isArrayType() || DestType->isFunctionType()) { unsigned diagID = diag::err_func_returning_array_function; if (Kind == FK_BlockPointer) diagID = diag::err_block_returning_array_function; S.Diag(E->getExprLoc(), diagID) << DestType->isFunctionType() << DestType; return ExprError(); } // Otherwise, go ahead and set DestType as the call's result. E->setType(DestType.getNonLValueExprType(S.Context)); E->setValueKind(Expr::getValueKindForType(DestType)); assert(E->getObjectKind() == OK_Ordinary); // Rebuild the function type, replacing the result type with DestType. const FunctionProtoType *Proto = dyn_cast(FnType); if (Proto) { // __unknown_anytype(...) is a special case used by the debugger when // it has no idea what a function's signature is. // // We want to build this call essentially under the K&R // unprototyped rules, but making a FunctionNoProtoType in C++ // would foul up all sorts of assumptions. However, we cannot // simply pass all arguments as variadic arguments, nor can we // portably just call the function under a non-variadic type; see // the comment on IR-gen's TargetInfo::isNoProtoCallVariadic. // However, it turns out that in practice it is generally safe to // call a function declared as "A foo(B,C,D);" under the prototype // "A foo(B,C,D,...);". The only known exception is with the // Windows ABI, where any variadic function is implicitly cdecl // regardless of its normal CC. Therefore we change the parameter // types to match the types of the arguments. // // This is a hack, but it is far superior to moving the // corresponding target-specific code from IR-gen to Sema/AST. ArrayRef ParamTypes = Proto->getParamTypes(); SmallVector ArgTypes; if (ParamTypes.empty() && Proto->isVariadic()) { // the special case ArgTypes.reserve(E->getNumArgs()); for (unsigned i = 0, e = E->getNumArgs(); i != e; ++i) { Expr *Arg = E->getArg(i); QualType ArgType = Arg->getType(); if (E->isLValue()) { ArgType = S.Context.getLValueReferenceType(ArgType); } else if (E->isXValue()) { ArgType = S.Context.getRValueReferenceType(ArgType); } ArgTypes.push_back(ArgType); } ParamTypes = ArgTypes; } DestType = S.Context.getFunctionType(DestType, ParamTypes, Proto->getExtProtoInfo()); } else { DestType = S.Context.getFunctionNoProtoType(DestType, FnType->getExtInfo()); } // Rebuild the appropriate pointer-to-function type. switch (Kind) { case FK_MemberFunction: // Nothing to do. break; case FK_FunctionPointer: DestType = S.Context.getPointerType(DestType); break; case FK_BlockPointer: DestType = S.Context.getBlockPointerType(DestType); break; } // Finally, we can recurse. ExprResult CalleeResult = Visit(CalleeExpr); if (!CalleeResult.isUsable()) return ExprError(); E->setCallee(CalleeResult.get()); // Bind a temporary if necessary. return S.MaybeBindToTemporary(E); } ExprResult RebuildUnknownAnyExpr::VisitObjCMessageExpr(ObjCMessageExpr *E) { // Verify that this is a legal result type of a call. if (DestType->isArrayType() || DestType->isFunctionType()) { S.Diag(E->getExprLoc(), diag::err_func_returning_array_function) << DestType->isFunctionType() << DestType; return ExprError(); } // Rewrite the method result type if available. if (ObjCMethodDecl *Method = E->getMethodDecl()) { assert(Method->getReturnType() == S.Context.UnknownAnyTy); Method->setReturnType(DestType); } // Change the type of the message. E->setType(DestType.getNonReferenceType()); E->setValueKind(Expr::getValueKindForType(DestType)); return S.MaybeBindToTemporary(E); } ExprResult RebuildUnknownAnyExpr::VisitImplicitCastExpr(ImplicitCastExpr *E) { // The only case we should ever see here is a function-to-pointer decay. if (E->getCastKind() == CK_FunctionToPointerDecay) { assert(E->getValueKind() == VK_RValue); assert(E->getObjectKind() == OK_Ordinary); E->setType(DestType); // Rebuild the sub-expression as the pointee (function) type. DestType = DestType->castAs()->getPointeeType(); ExprResult Result = Visit(E->getSubExpr()); if (!Result.isUsable()) return ExprError(); E->setSubExpr(Result.get()); return E; } else if (E->getCastKind() == CK_LValueToRValue) { assert(E->getValueKind() == VK_RValue); assert(E->getObjectKind() == OK_Ordinary); assert(isa(E->getType())); E->setType(DestType); // The sub-expression has to be a lvalue reference, so rebuild it as such. DestType = S.Context.getLValueReferenceType(DestType); ExprResult Result = Visit(E->getSubExpr()); if (!Result.isUsable()) return ExprError(); E->setSubExpr(Result.get()); return E; } else { llvm_unreachable("Unhandled cast type!"); } } ExprResult RebuildUnknownAnyExpr::resolveDecl(Expr *E, ValueDecl *VD) { ExprValueKind ValueKind = VK_LValue; QualType Type = DestType; // We know how to make this work for certain kinds of decls: // - functions if (FunctionDecl *FD = dyn_cast(VD)) { if (const PointerType *Ptr = Type->getAs()) { DestType = Ptr->getPointeeType(); ExprResult Result = resolveDecl(E, VD); if (Result.isInvalid()) return ExprError(); return S.ImpCastExprToType(Result.get(), Type, CK_FunctionToPointerDecay, VK_RValue); } if (!Type->isFunctionType()) { S.Diag(E->getExprLoc(), diag::err_unknown_any_function) << VD << E->getSourceRange(); return ExprError(); } if (const FunctionProtoType *FT = Type->getAs()) { // We must match the FunctionDecl's type to the hack introduced in // RebuildUnknownAnyExpr::VisitCallExpr to vararg functions of unknown // type. See the lengthy commentary in that routine. QualType FDT = FD->getType(); const FunctionType *FnType = FDT->castAs(); const FunctionProtoType *Proto = dyn_cast_or_null(FnType); DeclRefExpr *DRE = dyn_cast(E); if (DRE && Proto && Proto->getParamTypes().empty() && Proto->isVariadic()) { SourceLocation Loc = FD->getLocation(); FunctionDecl *NewFD = FunctionDecl::Create( S.Context, FD->getDeclContext(), Loc, Loc, FD->getNameInfo().getName(), DestType, FD->getTypeSourceInfo(), SC_None, false /*isInlineSpecified*/, FD->hasPrototype(), /*ConstexprKind*/ CSK_unspecified); if (FD->getQualifier()) NewFD->setQualifierInfo(FD->getQualifierLoc()); SmallVector Params; for (const auto &AI : FT->param_types()) { ParmVarDecl *Param = S.BuildParmVarDeclForTypedef(FD, Loc, AI); Param->setScopeInfo(0, Params.size()); Params.push_back(Param); } NewFD->setParams(Params); DRE->setDecl(NewFD); VD = DRE->getDecl(); } } if (CXXMethodDecl *MD = dyn_cast(FD)) if (MD->isInstance()) { ValueKind = VK_RValue; Type = S.Context.BoundMemberTy; } // Function references aren't l-values in C. if (!S.getLangOpts().CPlusPlus) ValueKind = VK_RValue; // - variables } else if (isa(VD)) { if (const ReferenceType *RefTy = Type->getAs()) { Type = RefTy->getPointeeType(); } else if (Type->isFunctionType()) { S.Diag(E->getExprLoc(), diag::err_unknown_any_var_function_type) << VD << E->getSourceRange(); return ExprError(); } // - nothing else } else { S.Diag(E->getExprLoc(), diag::err_unsupported_unknown_any_decl) << VD << E->getSourceRange(); return ExprError(); } // Modifying the declaration like this is friendly to IR-gen but // also really dangerous. VD->setType(DestType); E->setType(Type); E->setValueKind(ValueKind); return E; } /// Check a cast of an unknown-any type. We intentionally only /// trigger this for C-style casts. ExprResult Sema::checkUnknownAnyCast(SourceRange TypeRange, QualType CastType, Expr *CastExpr, CastKind &CastKind, ExprValueKind &VK, CXXCastPath &Path) { // The type we're casting to must be either void or complete. if (!CastType->isVoidType() && RequireCompleteType(TypeRange.getBegin(), CastType, diag::err_typecheck_cast_to_incomplete)) return ExprError(); // Rewrite the casted expression from scratch. ExprResult result = RebuildUnknownAnyExpr(*this, CastType).Visit(CastExpr); if (!result.isUsable()) return ExprError(); CastExpr = result.get(); VK = CastExpr->getValueKind(); CastKind = CK_NoOp; return CastExpr; } ExprResult Sema::forceUnknownAnyToType(Expr *E, QualType ToType) { return RebuildUnknownAnyExpr(*this, ToType).Visit(E); } ExprResult Sema::checkUnknownAnyArg(SourceLocation callLoc, Expr *arg, QualType ¶mType) { // If the syntactic form of the argument is not an explicit cast of // any sort, just do default argument promotion. ExplicitCastExpr *castArg = dyn_cast(arg->IgnoreParens()); if (!castArg) { ExprResult result = DefaultArgumentPromotion(arg); if (result.isInvalid()) return ExprError(); paramType = result.get()->getType(); return result; } // Otherwise, use the type that was written in the explicit cast. assert(!arg->hasPlaceholderType()); paramType = castArg->getTypeAsWritten(); // Copy-initialize a parameter of that type. InitializedEntity entity = InitializedEntity::InitializeParameter(Context, paramType, /*consumed*/ false); return PerformCopyInitialization(entity, callLoc, arg); } static ExprResult diagnoseUnknownAnyExpr(Sema &S, Expr *E) { Expr *orig = E; unsigned diagID = diag::err_uncasted_use_of_unknown_any; while (true) { E = E->IgnoreParenImpCasts(); if (CallExpr *call = dyn_cast(E)) { E = call->getCallee(); diagID = diag::err_uncasted_call_of_unknown_any; } else { break; } } SourceLocation loc; NamedDecl *d; if (DeclRefExpr *ref = dyn_cast(E)) { loc = ref->getLocation(); d = ref->getDecl(); } else if (MemberExpr *mem = dyn_cast(E)) { loc = mem->getMemberLoc(); d = mem->getMemberDecl(); } else if (ObjCMessageExpr *msg = dyn_cast(E)) { diagID = diag::err_uncasted_call_of_unknown_any; loc = msg->getSelectorStartLoc(); d = msg->getMethodDecl(); if (!d) { S.Diag(loc, diag::err_uncasted_send_to_unknown_any_method) << static_cast(msg->isClassMessage()) << msg->getSelector() << orig->getSourceRange(); return ExprError(); } } else { S.Diag(E->getExprLoc(), diag::err_unsupported_unknown_any_expr) << E->getSourceRange(); return ExprError(); } S.Diag(loc, diagID) << d << orig->getSourceRange(); // Never recoverable. return ExprError(); } /// Check for operands with placeholder types and complain if found. /// Returns ExprError() if there was an error and no recovery was possible. ExprResult Sema::CheckPlaceholderExpr(Expr *E) { if (!getLangOpts().CPlusPlus) { // C cannot handle TypoExpr nodes on either side of a binop because it // doesn't handle dependent types properly, so make sure any TypoExprs have // been dealt with before checking the operands. ExprResult Result = CorrectDelayedTyposInExpr(E); if (!Result.isUsable()) return ExprError(); E = Result.get(); } const BuiltinType *placeholderType = E->getType()->getAsPlaceholderType(); if (!placeholderType) return E; switch (placeholderType->getKind()) { // Overloaded expressions. case BuiltinType::Overload: { // Try to resolve a single function template specialization. // This is obligatory. ExprResult Result = E; if (ResolveAndFixSingleFunctionTemplateSpecialization(Result, false)) return Result; // No guarantees that ResolveAndFixSingleFunctionTemplateSpecialization // leaves Result unchanged on failure. Result = E; if (resolveAndFixAddressOfSingleOverloadCandidate(Result)) return Result; // If that failed, try to recover with a call. tryToRecoverWithCall(Result, PDiag(diag::err_ovl_unresolvable), /*complain*/ true); return Result; } // Bound member functions. case BuiltinType::BoundMember: { ExprResult result = E; const Expr *BME = E->IgnoreParens(); PartialDiagnostic PD = PDiag(diag::err_bound_member_function); // Try to give a nicer diagnostic if it is a bound member that we recognize. if (isa(BME)) { PD = PDiag(diag::err_dtor_expr_without_call) << /*pseudo-destructor*/ 1; } else if (const auto *ME = dyn_cast(BME)) { if (ME->getMemberNameInfo().getName().getNameKind() == DeclarationName::CXXDestructorName) PD = PDiag(diag::err_dtor_expr_without_call) << /*destructor*/ 0; } tryToRecoverWithCall(result, PD, /*complain*/ true); return result; } // ARC unbridged casts. case BuiltinType::ARCUnbridgedCast: { Expr *realCast = stripARCUnbridgedCast(E); diagnoseARCUnbridgedCast(realCast); return realCast; } // Expressions of unknown type. case BuiltinType::UnknownAny: return diagnoseUnknownAnyExpr(*this, E); // Pseudo-objects. case BuiltinType::PseudoObject: return checkPseudoObjectRValue(E); case BuiltinType::BuiltinFn: { // Accept __noop without parens by implicitly converting it to a call expr. auto *DRE = dyn_cast(E->IgnoreParenImpCasts()); if (DRE) { auto *FD = cast(DRE->getDecl()); if (FD->getBuiltinID() == Builtin::BI__noop) { E = ImpCastExprToType(E, Context.getPointerType(FD->getType()), CK_BuiltinFnToFnPtr) .get(); return CallExpr::Create(Context, E, /*Args=*/{}, Context.IntTy, VK_RValue, SourceLocation()); } } Diag(E->getBeginLoc(), diag::err_builtin_fn_use); return ExprError(); } // Expressions of unknown type. case BuiltinType::OMPArraySection: Diag(E->getBeginLoc(), diag::err_omp_array_section_use); return ExprError(); // Everything else should be impossible. #define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \ case BuiltinType::Id: #include "clang/Basic/OpenCLImageTypes.def" #define EXT_OPAQUE_TYPE(ExtType, Id, Ext) \ case BuiltinType::Id: #include "clang/Basic/OpenCLExtensionTypes.def" #define SVE_TYPE(Name, Id, SingletonId) \ case BuiltinType::Id: #include "clang/Basic/AArch64SVEACLETypes.def" #define BUILTIN_TYPE(Id, SingletonId) case BuiltinType::Id: #define PLACEHOLDER_TYPE(Id, SingletonId) #include "clang/AST/BuiltinTypes.def" break; } llvm_unreachable("invalid placeholder type!"); } bool Sema::CheckCaseExpression(Expr *E) { if (E->isTypeDependent()) return true; if (E->isValueDependent() || E->isIntegerConstantExpr(Context)) return E->getType()->isIntegralOrEnumerationType(); return false; } /// ActOnObjCBoolLiteral - Parse {__objc_yes,__objc_no} literals. ExprResult Sema::ActOnObjCBoolLiteral(SourceLocation OpLoc, tok::TokenKind Kind) { assert((Kind == tok::kw___objc_yes || Kind == tok::kw___objc_no) && "Unknown Objective-C Boolean value!"); QualType BoolT = Context.ObjCBuiltinBoolTy; if (!Context.getBOOLDecl()) { LookupResult Result(*this, &Context.Idents.get("BOOL"), OpLoc, Sema::LookupOrdinaryName); if (LookupName(Result, getCurScope()) && Result.isSingleResult()) { NamedDecl *ND = Result.getFoundDecl(); if (TypedefDecl *TD = dyn_cast(ND)) Context.setBOOLDecl(TD); } } if (Context.getBOOLDecl()) BoolT = Context.getBOOLType(); return new (Context) ObjCBoolLiteralExpr(Kind == tok::kw___objc_yes, BoolT, OpLoc); } ExprResult Sema::ActOnObjCAvailabilityCheckExpr( llvm::ArrayRef AvailSpecs, SourceLocation AtLoc, SourceLocation RParen) { StringRef Platform = getASTContext().getTargetInfo().getPlatformName(); auto Spec = llvm::find_if(AvailSpecs, [&](const AvailabilitySpec &Spec) { return Spec.getPlatform() == Platform; }); VersionTuple Version; if (Spec != AvailSpecs.end()) Version = Spec->getVersion(); // The use of `@available` in the enclosing function should be analyzed to // warn when it's used inappropriately (i.e. not if(@available)). if (getCurFunctionOrMethodDecl()) getEnclosingFunction()->HasPotentialAvailabilityViolations = true; else if (getCurBlock() || getCurLambda()) getCurFunction()->HasPotentialAvailabilityViolations = true; return new (Context) ObjCAvailabilityCheckExpr(Version, AtLoc, RParen, Context.BoolTy); } bool Sema::IsDependentFunctionNameExpr(Expr *E) { assert(E->isTypeDependent()); return isa(E); } Index: vendor/llvm-project/release-10.x/clang/lib/Sema/SemaExprCXX.cpp =================================================================== --- vendor/llvm-project/release-10.x/clang/lib/Sema/SemaExprCXX.cpp (revision 359078) +++ vendor/llvm-project/release-10.x/clang/lib/Sema/SemaExprCXX.cpp (revision 359079) @@ -1,8548 +1,8548 @@ //===--- SemaExprCXX.cpp - Semantic Analysis for Expressions --------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// /// /// \file /// Implements semantic analysis for C++ expressions. /// //===----------------------------------------------------------------------===// #include "clang/Sema/Template.h" #include "clang/Sema/SemaInternal.h" #include "TreeTransform.h" #include "TypeLocBuilder.h" #include "clang/AST/ASTContext.h" #include "clang/AST/ASTLambda.h" #include "clang/AST/CXXInheritance.h" #include "clang/AST/CharUnits.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/ExprObjC.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/TypeLoc.h" #include "clang/Basic/AlignedAllocation.h" #include "clang/Basic/PartialDiagnostic.h" #include "clang/Basic/TargetInfo.h" #include "clang/Lex/Preprocessor.h" #include "clang/Sema/DeclSpec.h" #include "clang/Sema/Initialization.h" #include "clang/Sema/Lookup.h" #include "clang/Sema/ParsedTemplate.h" #include "clang/Sema/Scope.h" #include "clang/Sema/ScopeInfo.h" #include "clang/Sema/SemaLambda.h" #include "clang/Sema/TemplateDeduction.h" #include "llvm/ADT/APInt.h" #include "llvm/ADT/STLExtras.h" #include "llvm/Support/ErrorHandling.h" using namespace clang; using namespace sema; /// Handle the result of the special case name lookup for inheriting /// constructor declarations. 'NS::X::X' and 'NS::X<...>::X' are treated as /// constructor names in member using declarations, even if 'X' is not the /// name of the corresponding type. ParsedType Sema::getInheritingConstructorName(CXXScopeSpec &SS, SourceLocation NameLoc, IdentifierInfo &Name) { NestedNameSpecifier *NNS = SS.getScopeRep(); // Convert the nested-name-specifier into a type. QualType Type; switch (NNS->getKind()) { case NestedNameSpecifier::TypeSpec: case NestedNameSpecifier::TypeSpecWithTemplate: Type = QualType(NNS->getAsType(), 0); break; case NestedNameSpecifier::Identifier: // Strip off the last layer of the nested-name-specifier and build a // typename type for it. assert(NNS->getAsIdentifier() == &Name && "not a constructor name"); Type = Context.getDependentNameType(ETK_None, NNS->getPrefix(), NNS->getAsIdentifier()); break; case NestedNameSpecifier::Global: case NestedNameSpecifier::Super: case NestedNameSpecifier::Namespace: case NestedNameSpecifier::NamespaceAlias: llvm_unreachable("Nested name specifier is not a type for inheriting ctor"); } // This reference to the type is located entirely at the location of the // final identifier in the qualified-id. return CreateParsedType(Type, Context.getTrivialTypeSourceInfo(Type, NameLoc)); } ParsedType Sema::getConstructorName(IdentifierInfo &II, SourceLocation NameLoc, Scope *S, CXXScopeSpec &SS, bool EnteringContext) { CXXRecordDecl *CurClass = getCurrentClass(S, &SS); assert(CurClass && &II == CurClass->getIdentifier() && "not a constructor name"); // When naming a constructor as a member of a dependent context (eg, in a // friend declaration or an inherited constructor declaration), form an // unresolved "typename" type. if (CurClass->isDependentContext() && !EnteringContext && SS.getScopeRep()) { QualType T = Context.getDependentNameType(ETK_None, SS.getScopeRep(), &II); return ParsedType::make(T); } if (SS.isNotEmpty() && RequireCompleteDeclContext(SS, CurClass)) return ParsedType(); // Find the injected-class-name declaration. Note that we make no attempt to // diagnose cases where the injected-class-name is shadowed: the only // declaration that can validly shadow the injected-class-name is a // non-static data member, and if the class contains both a non-static data // member and a constructor then it is ill-formed (we check that in // CheckCompletedCXXClass). CXXRecordDecl *InjectedClassName = nullptr; for (NamedDecl *ND : CurClass->lookup(&II)) { auto *RD = dyn_cast(ND); if (RD && RD->isInjectedClassName()) { InjectedClassName = RD; break; } } if (!InjectedClassName) { if (!CurClass->isInvalidDecl()) { // FIXME: RequireCompleteDeclContext doesn't check dependent contexts // properly. Work around it here for now. Diag(SS.getLastQualifierNameLoc(), diag::err_incomplete_nested_name_spec) << CurClass << SS.getRange(); } return ParsedType(); } QualType T = Context.getTypeDeclType(InjectedClassName); DiagnoseUseOfDecl(InjectedClassName, NameLoc); MarkAnyDeclReferenced(NameLoc, InjectedClassName, /*OdrUse=*/false); return ParsedType::make(T); } ParsedType Sema::getDestructorName(SourceLocation TildeLoc, IdentifierInfo &II, SourceLocation NameLoc, Scope *S, CXXScopeSpec &SS, ParsedType ObjectTypePtr, bool EnteringContext) { // Determine where to perform name lookup. // FIXME: This area of the standard is very messy, and the current // wording is rather unclear about which scopes we search for the // destructor name; see core issues 399 and 555. Issue 399 in // particular shows where the current description of destructor name // lookup is completely out of line with existing practice, e.g., // this appears to be ill-formed: // // namespace N { // template struct S { // ~S(); // }; // } // // void f(N::S* s) { // s->N::S::~S(); // } // // See also PR6358 and PR6359. // For this reason, we're currently only doing the C++03 version of this // code; the C++0x version has to wait until we get a proper spec. QualType SearchType; DeclContext *LookupCtx = nullptr; bool isDependent = false; bool LookInScope = false; if (SS.isInvalid()) return nullptr; // If we have an object type, it's because we are in a // pseudo-destructor-expression or a member access expression, and // we know what type we're looking for. if (ObjectTypePtr) SearchType = GetTypeFromParser(ObjectTypePtr); if (SS.isSet()) { NestedNameSpecifier *NNS = SS.getScopeRep(); bool AlreadySearched = false; bool LookAtPrefix = true; // C++11 [basic.lookup.qual]p6: // If a pseudo-destructor-name (5.2.4) contains a nested-name-specifier, // the type-names are looked up as types in the scope designated by the // nested-name-specifier. Similarly, in a qualified-id of the form: // // nested-name-specifier[opt] class-name :: ~ class-name // // the second class-name is looked up in the same scope as the first. // // Here, we determine whether the code below is permitted to look at the // prefix of the nested-name-specifier. DeclContext *DC = computeDeclContext(SS, EnteringContext); if (DC && DC->isFileContext()) { AlreadySearched = true; LookupCtx = DC; isDependent = false; } else if (DC && isa(DC)) { LookAtPrefix = false; LookInScope = true; } // The second case from the C++03 rules quoted further above. NestedNameSpecifier *Prefix = nullptr; if (AlreadySearched) { // Nothing left to do. } else if (LookAtPrefix && (Prefix = NNS->getPrefix())) { CXXScopeSpec PrefixSS; PrefixSS.Adopt(NestedNameSpecifierLoc(Prefix, SS.location_data())); LookupCtx = computeDeclContext(PrefixSS, EnteringContext); isDependent = isDependentScopeSpecifier(PrefixSS); } else if (ObjectTypePtr) { LookupCtx = computeDeclContext(SearchType); isDependent = SearchType->isDependentType(); } else { LookupCtx = computeDeclContext(SS, EnteringContext); isDependent = LookupCtx && LookupCtx->isDependentContext(); } } else if (ObjectTypePtr) { // C++ [basic.lookup.classref]p3: // If the unqualified-id is ~type-name, the type-name is looked up // in the context of the entire postfix-expression. If the type T // of the object expression is of a class type C, the type-name is // also looked up in the scope of class C. At least one of the // lookups shall find a name that refers to (possibly // cv-qualified) T. LookupCtx = computeDeclContext(SearchType); isDependent = SearchType->isDependentType(); assert((isDependent || !SearchType->isIncompleteType()) && "Caller should have completed object type"); LookInScope = true; } else { // Perform lookup into the current scope (only). LookInScope = true; } TypeDecl *NonMatchingTypeDecl = nullptr; LookupResult Found(*this, &II, NameLoc, LookupOrdinaryName); for (unsigned Step = 0; Step != 2; ++Step) { // Look for the name first in the computed lookup context (if we // have one) and, if that fails to find a match, in the scope (if // we're allowed to look there). Found.clear(); if (Step == 0 && LookupCtx) { if (RequireCompleteDeclContext(SS, LookupCtx)) return nullptr; LookupQualifiedName(Found, LookupCtx); } else if (Step == 1 && LookInScope && S) { LookupName(Found, S); } else { continue; } // FIXME: Should we be suppressing ambiguities here? if (Found.isAmbiguous()) return nullptr; if (TypeDecl *Type = Found.getAsSingle()) { QualType T = Context.getTypeDeclType(Type); MarkAnyDeclReferenced(Type->getLocation(), Type, /*OdrUse=*/false); if (SearchType.isNull() || SearchType->isDependentType() || Context.hasSameUnqualifiedType(T, SearchType)) { // We found our type! return CreateParsedType(T, Context.getTrivialTypeSourceInfo(T, NameLoc)); } if (!SearchType.isNull()) NonMatchingTypeDecl = Type; } // If the name that we found is a class template name, and it is // the same name as the template name in the last part of the // nested-name-specifier (if present) or the object type, then // this is the destructor for that class. // FIXME: This is a workaround until we get real drafting for core // issue 399, for which there isn't even an obvious direction. if (ClassTemplateDecl *Template = Found.getAsSingle()) { QualType MemberOfType; if (SS.isSet()) { if (DeclContext *Ctx = computeDeclContext(SS, EnteringContext)) { // Figure out the type of the context, if it has one. if (CXXRecordDecl *Record = dyn_cast(Ctx)) MemberOfType = Context.getTypeDeclType(Record); } } if (MemberOfType.isNull()) MemberOfType = SearchType; if (MemberOfType.isNull()) continue; // We're referring into a class template specialization. If the // class template we found is the same as the template being // specialized, we found what we are looking for. if (const RecordType *Record = MemberOfType->getAs()) { if (ClassTemplateSpecializationDecl *Spec = dyn_cast(Record->getDecl())) { if (Spec->getSpecializedTemplate()->getCanonicalDecl() == Template->getCanonicalDecl()) return CreateParsedType( MemberOfType, Context.getTrivialTypeSourceInfo(MemberOfType, NameLoc)); } continue; } // We're referring to an unresolved class template // specialization. Determine whether we class template we found // is the same as the template being specialized or, if we don't // know which template is being specialized, that it at least // has the same name. if (const TemplateSpecializationType *SpecType = MemberOfType->getAs()) { TemplateName SpecName = SpecType->getTemplateName(); // The class template we found is the same template being // specialized. if (TemplateDecl *SpecTemplate = SpecName.getAsTemplateDecl()) { if (SpecTemplate->getCanonicalDecl() == Template->getCanonicalDecl()) return CreateParsedType( MemberOfType, Context.getTrivialTypeSourceInfo(MemberOfType, NameLoc)); continue; } // The class template we found has the same name as the // (dependent) template name being specialized. if (DependentTemplateName *DepTemplate = SpecName.getAsDependentTemplateName()) { if (DepTemplate->isIdentifier() && DepTemplate->getIdentifier() == Template->getIdentifier()) return CreateParsedType( MemberOfType, Context.getTrivialTypeSourceInfo(MemberOfType, NameLoc)); continue; } } } } if (isDependent) { // We didn't find our type, but that's okay: it's dependent // anyway. // FIXME: What if we have no nested-name-specifier? QualType T = CheckTypenameType(ETK_None, SourceLocation(), SS.getWithLocInContext(Context), II, NameLoc); return ParsedType::make(T); } if (NonMatchingTypeDecl) { QualType T = Context.getTypeDeclType(NonMatchingTypeDecl); Diag(NameLoc, diag::err_destructor_expr_type_mismatch) << T << SearchType; Diag(NonMatchingTypeDecl->getLocation(), diag::note_destructor_type_here) << T; } else if (ObjectTypePtr) Diag(NameLoc, diag::err_ident_in_dtor_not_a_type) << &II; else { SemaDiagnosticBuilder DtorDiag = Diag(NameLoc, diag::err_destructor_class_name); if (S) { const DeclContext *Ctx = S->getEntity(); if (const CXXRecordDecl *Class = dyn_cast_or_null(Ctx)) DtorDiag << FixItHint::CreateReplacement(SourceRange(NameLoc), Class->getNameAsString()); } } return nullptr; } ParsedType Sema::getDestructorTypeForDecltype(const DeclSpec &DS, ParsedType ObjectType) { if (DS.getTypeSpecType() == DeclSpec::TST_error) return nullptr; if (DS.getTypeSpecType() == DeclSpec::TST_decltype_auto) { Diag(DS.getTypeSpecTypeLoc(), diag::err_decltype_auto_invalid); return nullptr; } assert(DS.getTypeSpecType() == DeclSpec::TST_decltype && "unexpected type in getDestructorType"); QualType T = BuildDecltypeType(DS.getRepAsExpr(), DS.getTypeSpecTypeLoc()); // If we know the type of the object, check that the correct destructor // type was named now; we can give better diagnostics this way. QualType SearchType = GetTypeFromParser(ObjectType); if (!SearchType.isNull() && !SearchType->isDependentType() && !Context.hasSameUnqualifiedType(T, SearchType)) { Diag(DS.getTypeSpecTypeLoc(), diag::err_destructor_expr_type_mismatch) << T << SearchType; return nullptr; } return ParsedType::make(T); } bool Sema::checkLiteralOperatorId(const CXXScopeSpec &SS, const UnqualifiedId &Name) { assert(Name.getKind() == UnqualifiedIdKind::IK_LiteralOperatorId); if (!SS.isValid()) return false; switch (SS.getScopeRep()->getKind()) { case NestedNameSpecifier::Identifier: case NestedNameSpecifier::TypeSpec: case NestedNameSpecifier::TypeSpecWithTemplate: // Per C++11 [over.literal]p2, literal operators can only be declared at // namespace scope. Therefore, this unqualified-id cannot name anything. // Reject it early, because we have no AST representation for this in the // case where the scope is dependent. Diag(Name.getBeginLoc(), diag::err_literal_operator_id_outside_namespace) << SS.getScopeRep(); return true; case NestedNameSpecifier::Global: case NestedNameSpecifier::Super: case NestedNameSpecifier::Namespace: case NestedNameSpecifier::NamespaceAlias: return false; } llvm_unreachable("unknown nested name specifier kind"); } /// Build a C++ typeid expression with a type operand. ExprResult Sema::BuildCXXTypeId(QualType TypeInfoType, SourceLocation TypeidLoc, TypeSourceInfo *Operand, SourceLocation RParenLoc) { // C++ [expr.typeid]p4: // The top-level cv-qualifiers of the lvalue expression or the type-id // that is the operand of typeid are always ignored. // If the type of the type-id is a class type or a reference to a class // type, the class shall be completely-defined. Qualifiers Quals; QualType T = Context.getUnqualifiedArrayType(Operand->getType().getNonReferenceType(), Quals); if (T->getAs() && RequireCompleteType(TypeidLoc, T, diag::err_incomplete_typeid)) return ExprError(); if (T->isVariablyModifiedType()) return ExprError(Diag(TypeidLoc, diag::err_variably_modified_typeid) << T); if (CheckQualifiedFunctionForTypeId(T, TypeidLoc)) return ExprError(); return new (Context) CXXTypeidExpr(TypeInfoType.withConst(), Operand, SourceRange(TypeidLoc, RParenLoc)); } /// Build a C++ typeid expression with an expression operand. ExprResult Sema::BuildCXXTypeId(QualType TypeInfoType, SourceLocation TypeidLoc, Expr *E, SourceLocation RParenLoc) { bool WasEvaluated = false; if (E && !E->isTypeDependent()) { if (E->getType()->isPlaceholderType()) { ExprResult result = CheckPlaceholderExpr(E); if (result.isInvalid()) return ExprError(); E = result.get(); } QualType T = E->getType(); if (const RecordType *RecordT = T->getAs()) { CXXRecordDecl *RecordD = cast(RecordT->getDecl()); // C++ [expr.typeid]p3: // [...] If the type of the expression is a class type, the class // shall be completely-defined. if (RequireCompleteType(TypeidLoc, T, diag::err_incomplete_typeid)) return ExprError(); // C++ [expr.typeid]p3: // When typeid is applied to an expression other than an glvalue of a // polymorphic class type [...] [the] expression is an unevaluated // operand. [...] if (RecordD->isPolymorphic() && E->isGLValue()) { // The subexpression is potentially evaluated; switch the context // and recheck the subexpression. ExprResult Result = TransformToPotentiallyEvaluated(E); if (Result.isInvalid()) return ExprError(); E = Result.get(); // We require a vtable to query the type at run time. MarkVTableUsed(TypeidLoc, RecordD); WasEvaluated = true; } } ExprResult Result = CheckUnevaluatedOperand(E); if (Result.isInvalid()) return ExprError(); E = Result.get(); // C++ [expr.typeid]p4: // [...] If the type of the type-id is a reference to a possibly // cv-qualified type, the result of the typeid expression refers to a // std::type_info object representing the cv-unqualified referenced // type. Qualifiers Quals; QualType UnqualT = Context.getUnqualifiedArrayType(T, Quals); if (!Context.hasSameType(T, UnqualT)) { T = UnqualT; E = ImpCastExprToType(E, UnqualT, CK_NoOp, E->getValueKind()).get(); } } if (E->getType()->isVariablyModifiedType()) return ExprError(Diag(TypeidLoc, diag::err_variably_modified_typeid) << E->getType()); else if (!inTemplateInstantiation() && E->HasSideEffects(Context, WasEvaluated)) { // The expression operand for typeid is in an unevaluated expression // context, so side effects could result in unintended consequences. Diag(E->getExprLoc(), WasEvaluated ? diag::warn_side_effects_typeid : diag::warn_side_effects_unevaluated_context); } return new (Context) CXXTypeidExpr(TypeInfoType.withConst(), E, SourceRange(TypeidLoc, RParenLoc)); } /// ActOnCXXTypeidOfType - Parse typeid( type-id ) or typeid (expression); ExprResult Sema::ActOnCXXTypeid(SourceLocation OpLoc, SourceLocation LParenLoc, bool isType, void *TyOrExpr, SourceLocation RParenLoc) { // typeid is not supported in OpenCL. if (getLangOpts().OpenCLCPlusPlus) { return ExprError(Diag(OpLoc, diag::err_openclcxx_not_supported) << "typeid"); } // Find the std::type_info type. if (!getStdNamespace()) return ExprError(Diag(OpLoc, diag::err_need_header_before_typeid)); if (!CXXTypeInfoDecl) { IdentifierInfo *TypeInfoII = &PP.getIdentifierTable().get("type_info"); LookupResult R(*this, TypeInfoII, SourceLocation(), LookupTagName); LookupQualifiedName(R, getStdNamespace()); CXXTypeInfoDecl = R.getAsSingle(); // Microsoft's typeinfo doesn't have type_info in std but in the global // namespace if _HAS_EXCEPTIONS is defined to 0. See PR13153. if (!CXXTypeInfoDecl && LangOpts.MSVCCompat) { LookupQualifiedName(R, Context.getTranslationUnitDecl()); CXXTypeInfoDecl = R.getAsSingle(); } if (!CXXTypeInfoDecl) return ExprError(Diag(OpLoc, diag::err_need_header_before_typeid)); } if (!getLangOpts().RTTI) { return ExprError(Diag(OpLoc, diag::err_no_typeid_with_fno_rtti)); } QualType TypeInfoType = Context.getTypeDeclType(CXXTypeInfoDecl); if (isType) { // The operand is a type; handle it as such. TypeSourceInfo *TInfo = nullptr; QualType T = GetTypeFromParser(ParsedType::getFromOpaquePtr(TyOrExpr), &TInfo); if (T.isNull()) return ExprError(); if (!TInfo) TInfo = Context.getTrivialTypeSourceInfo(T, OpLoc); return BuildCXXTypeId(TypeInfoType, OpLoc, TInfo, RParenLoc); } // The operand is an expression. return BuildCXXTypeId(TypeInfoType, OpLoc, (Expr*)TyOrExpr, RParenLoc); } /// Grabs __declspec(uuid()) off a type, or returns 0 if we cannot resolve to /// a single GUID. static void getUuidAttrOfType(Sema &SemaRef, QualType QT, llvm::SmallSetVector &UuidAttrs) { // Optionally remove one level of pointer, reference or array indirection. const Type *Ty = QT.getTypePtr(); if (QT->isPointerType() || QT->isReferenceType()) Ty = QT->getPointeeType().getTypePtr(); else if (QT->isArrayType()) Ty = Ty->getBaseElementTypeUnsafe(); const auto *TD = Ty->getAsTagDecl(); if (!TD) return; if (const auto *Uuid = TD->getMostRecentDecl()->getAttr()) { UuidAttrs.insert(Uuid); return; } // __uuidof can grab UUIDs from template arguments. if (const auto *CTSD = dyn_cast(TD)) { const TemplateArgumentList &TAL = CTSD->getTemplateArgs(); for (const TemplateArgument &TA : TAL.asArray()) { const UuidAttr *UuidForTA = nullptr; if (TA.getKind() == TemplateArgument::Type) getUuidAttrOfType(SemaRef, TA.getAsType(), UuidAttrs); else if (TA.getKind() == TemplateArgument::Declaration) getUuidAttrOfType(SemaRef, TA.getAsDecl()->getType(), UuidAttrs); if (UuidForTA) UuidAttrs.insert(UuidForTA); } } } /// Build a Microsoft __uuidof expression with a type operand. ExprResult Sema::BuildCXXUuidof(QualType TypeInfoType, SourceLocation TypeidLoc, TypeSourceInfo *Operand, SourceLocation RParenLoc) { StringRef UuidStr; if (!Operand->getType()->isDependentType()) { llvm::SmallSetVector UuidAttrs; getUuidAttrOfType(*this, Operand->getType(), UuidAttrs); if (UuidAttrs.empty()) return ExprError(Diag(TypeidLoc, diag::err_uuidof_without_guid)); if (UuidAttrs.size() > 1) return ExprError(Diag(TypeidLoc, diag::err_uuidof_with_multiple_guids)); UuidStr = UuidAttrs.back()->getGuid(); } return new (Context) CXXUuidofExpr(TypeInfoType.withConst(), Operand, UuidStr, SourceRange(TypeidLoc, RParenLoc)); } /// Build a Microsoft __uuidof expression with an expression operand. ExprResult Sema::BuildCXXUuidof(QualType TypeInfoType, SourceLocation TypeidLoc, Expr *E, SourceLocation RParenLoc) { StringRef UuidStr; if (!E->getType()->isDependentType()) { if (E->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) { UuidStr = "00000000-0000-0000-0000-000000000000"; } else { llvm::SmallSetVector UuidAttrs; getUuidAttrOfType(*this, E->getType(), UuidAttrs); if (UuidAttrs.empty()) return ExprError(Diag(TypeidLoc, diag::err_uuidof_without_guid)); if (UuidAttrs.size() > 1) return ExprError(Diag(TypeidLoc, diag::err_uuidof_with_multiple_guids)); UuidStr = UuidAttrs.back()->getGuid(); } } return new (Context) CXXUuidofExpr(TypeInfoType.withConst(), E, UuidStr, SourceRange(TypeidLoc, RParenLoc)); } /// ActOnCXXUuidof - Parse __uuidof( type-id ) or __uuidof (expression); ExprResult Sema::ActOnCXXUuidof(SourceLocation OpLoc, SourceLocation LParenLoc, bool isType, void *TyOrExpr, SourceLocation RParenLoc) { // If MSVCGuidDecl has not been cached, do the lookup. if (!MSVCGuidDecl) { IdentifierInfo *GuidII = &PP.getIdentifierTable().get("_GUID"); LookupResult R(*this, GuidII, SourceLocation(), LookupTagName); LookupQualifiedName(R, Context.getTranslationUnitDecl()); MSVCGuidDecl = R.getAsSingle(); if (!MSVCGuidDecl) return ExprError(Diag(OpLoc, diag::err_need_header_before_ms_uuidof)); } QualType GuidType = Context.getTypeDeclType(MSVCGuidDecl); if (isType) { // The operand is a type; handle it as such. TypeSourceInfo *TInfo = nullptr; QualType T = GetTypeFromParser(ParsedType::getFromOpaquePtr(TyOrExpr), &TInfo); if (T.isNull()) return ExprError(); if (!TInfo) TInfo = Context.getTrivialTypeSourceInfo(T, OpLoc); return BuildCXXUuidof(GuidType, OpLoc, TInfo, RParenLoc); } // The operand is an expression. return BuildCXXUuidof(GuidType, OpLoc, (Expr*)TyOrExpr, RParenLoc); } /// ActOnCXXBoolLiteral - Parse {true,false} literals. ExprResult Sema::ActOnCXXBoolLiteral(SourceLocation OpLoc, tok::TokenKind Kind) { assert((Kind == tok::kw_true || Kind == tok::kw_false) && "Unknown C++ Boolean value!"); return new (Context) CXXBoolLiteralExpr(Kind == tok::kw_true, Context.BoolTy, OpLoc); } /// ActOnCXXNullPtrLiteral - Parse 'nullptr'. ExprResult Sema::ActOnCXXNullPtrLiteral(SourceLocation Loc) { return new (Context) CXXNullPtrLiteralExpr(Context.NullPtrTy, Loc); } /// ActOnCXXThrow - Parse throw expressions. ExprResult Sema::ActOnCXXThrow(Scope *S, SourceLocation OpLoc, Expr *Ex) { bool IsThrownVarInScope = false; if (Ex) { // C++0x [class.copymove]p31: // When certain criteria are met, an implementation is allowed to omit the // copy/move construction of a class object [...] // // - in a throw-expression, when the operand is the name of a // non-volatile automatic object (other than a function or catch- // clause parameter) whose scope does not extend beyond the end of the // innermost enclosing try-block (if there is one), the copy/move // operation from the operand to the exception object (15.1) can be // omitted by constructing the automatic object directly into the // exception object if (DeclRefExpr *DRE = dyn_cast(Ex->IgnoreParens())) if (VarDecl *Var = dyn_cast(DRE->getDecl())) { if (Var->hasLocalStorage() && !Var->getType().isVolatileQualified()) { for( ; S; S = S->getParent()) { if (S->isDeclScope(Var)) { IsThrownVarInScope = true; break; } if (S->getFlags() & (Scope::FnScope | Scope::ClassScope | Scope::BlockScope | Scope::FunctionPrototypeScope | Scope::ObjCMethodScope | Scope::TryScope)) break; } } } } return BuildCXXThrow(OpLoc, Ex, IsThrownVarInScope); } ExprResult Sema::BuildCXXThrow(SourceLocation OpLoc, Expr *Ex, bool IsThrownVarInScope) { // Don't report an error if 'throw' is used in system headers. if (!getLangOpts().CXXExceptions && !getSourceManager().isInSystemHeader(OpLoc) && !getLangOpts().CUDA) { // Delay error emission for the OpenMP device code. targetDiag(OpLoc, diag::err_exceptions_disabled) << "throw"; } // Exceptions aren't allowed in CUDA device code. if (getLangOpts().CUDA) CUDADiagIfDeviceCode(OpLoc, diag::err_cuda_device_exceptions) << "throw" << CurrentCUDATarget(); if (getCurScope() && getCurScope()->isOpenMPSimdDirectiveScope()) Diag(OpLoc, diag::err_omp_simd_region_cannot_use_stmt) << "throw"; if (Ex && !Ex->isTypeDependent()) { QualType ExceptionObjectTy = Context.getExceptionObjectType(Ex->getType()); if (CheckCXXThrowOperand(OpLoc, ExceptionObjectTy, Ex)) return ExprError(); // Initialize the exception result. This implicitly weeds out // abstract types or types with inaccessible copy constructors. // C++0x [class.copymove]p31: // When certain criteria are met, an implementation is allowed to omit the // copy/move construction of a class object [...] // // - in a throw-expression, when the operand is the name of a // non-volatile automatic object (other than a function or // catch-clause // parameter) whose scope does not extend beyond the end of the // innermost enclosing try-block (if there is one), the copy/move // operation from the operand to the exception object (15.1) can be // omitted by constructing the automatic object directly into the // exception object const VarDecl *NRVOVariable = nullptr; if (IsThrownVarInScope) NRVOVariable = getCopyElisionCandidate(QualType(), Ex, CES_Strict); InitializedEntity Entity = InitializedEntity::InitializeException( OpLoc, ExceptionObjectTy, /*NRVO=*/NRVOVariable != nullptr); ExprResult Res = PerformMoveOrCopyInitialization( Entity, NRVOVariable, QualType(), Ex, IsThrownVarInScope); if (Res.isInvalid()) return ExprError(); Ex = Res.get(); } return new (Context) CXXThrowExpr(Ex, Context.VoidTy, OpLoc, IsThrownVarInScope); } static void collectPublicBases(CXXRecordDecl *RD, llvm::DenseMap &SubobjectsSeen, llvm::SmallPtrSetImpl &VBases, llvm::SetVector &PublicSubobjectsSeen, bool ParentIsPublic) { for (const CXXBaseSpecifier &BS : RD->bases()) { CXXRecordDecl *BaseDecl = BS.getType()->getAsCXXRecordDecl(); bool NewSubobject; // Virtual bases constitute the same subobject. Non-virtual bases are // always distinct subobjects. if (BS.isVirtual()) NewSubobject = VBases.insert(BaseDecl).second; else NewSubobject = true; if (NewSubobject) ++SubobjectsSeen[BaseDecl]; // Only add subobjects which have public access throughout the entire chain. bool PublicPath = ParentIsPublic && BS.getAccessSpecifier() == AS_public; if (PublicPath) PublicSubobjectsSeen.insert(BaseDecl); // Recurse on to each base subobject. collectPublicBases(BaseDecl, SubobjectsSeen, VBases, PublicSubobjectsSeen, PublicPath); } } static void getUnambiguousPublicSubobjects( CXXRecordDecl *RD, llvm::SmallVectorImpl &Objects) { llvm::DenseMap SubobjectsSeen; llvm::SmallSet VBases; llvm::SetVector PublicSubobjectsSeen; SubobjectsSeen[RD] = 1; PublicSubobjectsSeen.insert(RD); collectPublicBases(RD, SubobjectsSeen, VBases, PublicSubobjectsSeen, /*ParentIsPublic=*/true); for (CXXRecordDecl *PublicSubobject : PublicSubobjectsSeen) { // Skip ambiguous objects. if (SubobjectsSeen[PublicSubobject] > 1) continue; Objects.push_back(PublicSubobject); } } /// CheckCXXThrowOperand - Validate the operand of a throw. bool Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, QualType ExceptionObjectTy, Expr *E) { // If the type of the exception would be an incomplete type or a pointer // to an incomplete type other than (cv) void the program is ill-formed. QualType Ty = ExceptionObjectTy; bool isPointer = false; if (const PointerType* Ptr = Ty->getAs()) { Ty = Ptr->getPointeeType(); isPointer = true; } if (!isPointer || !Ty->isVoidType()) { if (RequireCompleteType(ThrowLoc, Ty, isPointer ? diag::err_throw_incomplete_ptr : diag::err_throw_incomplete, E->getSourceRange())) return true; if (RequireNonAbstractType(ThrowLoc, ExceptionObjectTy, diag::err_throw_abstract_type, E)) return true; } // If the exception has class type, we need additional handling. CXXRecordDecl *RD = Ty->getAsCXXRecordDecl(); if (!RD) return false; // If we are throwing a polymorphic class type or pointer thereof, // exception handling will make use of the vtable. MarkVTableUsed(ThrowLoc, RD); // If a pointer is thrown, the referenced object will not be destroyed. if (isPointer) return false; // If the class has a destructor, we must be able to call it. if (!RD->hasIrrelevantDestructor()) { if (CXXDestructorDecl *Destructor = LookupDestructor(RD)) { MarkFunctionReferenced(E->getExprLoc(), Destructor); CheckDestructorAccess(E->getExprLoc(), Destructor, PDiag(diag::err_access_dtor_exception) << Ty); if (DiagnoseUseOfDecl(Destructor, E->getExprLoc())) return true; } } // The MSVC ABI creates a list of all types which can catch the exception // object. This list also references the appropriate copy constructor to call // if the object is caught by value and has a non-trivial copy constructor. if (Context.getTargetInfo().getCXXABI().isMicrosoft()) { // We are only interested in the public, unambiguous bases contained within // the exception object. Bases which are ambiguous or otherwise // inaccessible are not catchable types. llvm::SmallVector UnambiguousPublicSubobjects; getUnambiguousPublicSubobjects(RD, UnambiguousPublicSubobjects); for (CXXRecordDecl *Subobject : UnambiguousPublicSubobjects) { // Attempt to lookup the copy constructor. Various pieces of machinery // will spring into action, like template instantiation, which means this // cannot be a simple walk of the class's decls. Instead, we must perform // lookup and overload resolution. CXXConstructorDecl *CD = LookupCopyingConstructor(Subobject, 0); if (!CD || CD->isDeleted()) continue; // Mark the constructor referenced as it is used by this throw expression. MarkFunctionReferenced(E->getExprLoc(), CD); // Skip this copy constructor if it is trivial, we don't need to record it // in the catchable type data. if (CD->isTrivial()) continue; // The copy constructor is non-trivial, create a mapping from this class // type to this constructor. // N.B. The selection of copy constructor is not sensitive to this // particular throw-site. Lookup will be performed at the catch-site to // ensure that the copy constructor is, in fact, accessible (via // friendship or any other means). Context.addCopyConstructorForExceptionObject(Subobject, CD); // We don't keep the instantiated default argument expressions around so // we must rebuild them here. for (unsigned I = 1, E = CD->getNumParams(); I != E; ++I) { if (CheckCXXDefaultArgExpr(ThrowLoc, CD, CD->getParamDecl(I))) return true; } } } // Under the Itanium C++ ABI, memory for the exception object is allocated by // the runtime with no ability for the compiler to request additional // alignment. Warn if the exception type requires alignment beyond the minimum // guaranteed by the target C++ runtime. if (Context.getTargetInfo().getCXXABI().isItaniumFamily()) { CharUnits TypeAlign = Context.getTypeAlignInChars(Ty); CharUnits ExnObjAlign = Context.getExnObjectAlignment(); if (ExnObjAlign < TypeAlign) { Diag(ThrowLoc, diag::warn_throw_underaligned_obj); Diag(ThrowLoc, diag::note_throw_underaligned_obj) << Ty << (unsigned)TypeAlign.getQuantity() << (unsigned)ExnObjAlign.getQuantity(); } } return false; } static QualType adjustCVQualifiersForCXXThisWithinLambda( ArrayRef FunctionScopes, QualType ThisTy, DeclContext *CurSemaContext, ASTContext &ASTCtx) { QualType ClassType = ThisTy->getPointeeType(); LambdaScopeInfo *CurLSI = nullptr; DeclContext *CurDC = CurSemaContext; // Iterate through the stack of lambdas starting from the innermost lambda to // the outermost lambda, checking if '*this' is ever captured by copy - since // that could change the cv-qualifiers of the '*this' object. // The object referred to by '*this' starts out with the cv-qualifiers of its // member function. We then start with the innermost lambda and iterate // outward checking to see if any lambda performs a by-copy capture of '*this' // - and if so, any nested lambda must respect the 'constness' of that // capturing lamdbda's call operator. // // Since the FunctionScopeInfo stack is representative of the lexical // nesting of the lambda expressions during initial parsing (and is the best // place for querying information about captures about lambdas that are // partially processed) and perhaps during instantiation of function templates // that contain lambda expressions that need to be transformed BUT not // necessarily during instantiation of a nested generic lambda's function call // operator (which might even be instantiated at the end of the TU) - at which // time the DeclContext tree is mature enough to query capture information // reliably - we use a two pronged approach to walk through all the lexically // enclosing lambda expressions: // // 1) Climb down the FunctionScopeInfo stack as long as each item represents // a Lambda (i.e. LambdaScopeInfo) AND each LSI's 'closure-type' is lexically // enclosed by the call-operator of the LSI below it on the stack (while // tracking the enclosing DC for step 2 if needed). Note the topmost LSI on // the stack represents the innermost lambda. // // 2) If we run out of enclosing LSI's, check if the enclosing DeclContext // represents a lambda's call operator. If it does, we must be instantiating // a generic lambda's call operator (represented by the Current LSI, and // should be the only scenario where an inconsistency between the LSI and the // DeclContext should occur), so climb out the DeclContexts if they // represent lambdas, while querying the corresponding closure types // regarding capture information. // 1) Climb down the function scope info stack. for (int I = FunctionScopes.size(); I-- && isa(FunctionScopes[I]) && (!CurLSI || !CurLSI->Lambda || CurLSI->Lambda->getDeclContext() == cast(FunctionScopes[I])->CallOperator); CurDC = getLambdaAwareParentOfDeclContext(CurDC)) { CurLSI = cast(FunctionScopes[I]); if (!CurLSI->isCXXThisCaptured()) continue; auto C = CurLSI->getCXXThisCapture(); if (C.isCopyCapture()) { ClassType.removeLocalCVRQualifiers(Qualifiers::CVRMask); if (CurLSI->CallOperator->isConst()) ClassType.addConst(); return ASTCtx.getPointerType(ClassType); } } // 2) We've run out of ScopeInfos but check if CurDC is a lambda (which can // happen during instantiation of its nested generic lambda call operator) if (isLambdaCallOperator(CurDC)) { assert(CurLSI && "While computing 'this' capture-type for a generic " "lambda, we must have a corresponding LambdaScopeInfo"); assert(isGenericLambdaCallOperatorSpecialization(CurLSI->CallOperator) && "While computing 'this' capture-type for a generic lambda, when we " "run out of enclosing LSI's, yet the enclosing DC is a " "lambda-call-operator we must be (i.e. Current LSI) in a generic " "lambda call oeprator"); assert(CurDC == getLambdaAwareParentOfDeclContext(CurLSI->CallOperator)); auto IsThisCaptured = [](CXXRecordDecl *Closure, bool &IsByCopy, bool &IsConst) { IsConst = false; IsByCopy = false; for (auto &&C : Closure->captures()) { if (C.capturesThis()) { if (C.getCaptureKind() == LCK_StarThis) IsByCopy = true; if (Closure->getLambdaCallOperator()->isConst()) IsConst = true; return true; } } return false; }; bool IsByCopyCapture = false; bool IsConstCapture = false; CXXRecordDecl *Closure = cast(CurDC->getParent()); while (Closure && IsThisCaptured(Closure, IsByCopyCapture, IsConstCapture)) { if (IsByCopyCapture) { ClassType.removeLocalCVRQualifiers(Qualifiers::CVRMask); if (IsConstCapture) ClassType.addConst(); return ASTCtx.getPointerType(ClassType); } Closure = isLambdaCallOperator(Closure->getParent()) ? cast(Closure->getParent()->getParent()) : nullptr; } } return ASTCtx.getPointerType(ClassType); } QualType Sema::getCurrentThisType() { DeclContext *DC = getFunctionLevelDeclContext(); QualType ThisTy = CXXThisTypeOverride; if (CXXMethodDecl *method = dyn_cast(DC)) { if (method && method->isInstance()) ThisTy = method->getThisType(); } if (ThisTy.isNull() && isLambdaCallOperator(CurContext) && inTemplateInstantiation()) { assert(isa(DC) && "Trying to get 'this' type from static method?"); // This is a lambda call operator that is being instantiated as a default // initializer. DC must point to the enclosing class type, so we can recover // the 'this' type from it. QualType ClassTy = Context.getTypeDeclType(cast(DC)); // There are no cv-qualifiers for 'this' within default initializers, // per [expr.prim.general]p4. ThisTy = Context.getPointerType(ClassTy); } // If we are within a lambda's call operator, the cv-qualifiers of 'this' // might need to be adjusted if the lambda or any of its enclosing lambda's // captures '*this' by copy. if (!ThisTy.isNull() && isLambdaCallOperator(CurContext)) return adjustCVQualifiersForCXXThisWithinLambda(FunctionScopes, ThisTy, CurContext, Context); return ThisTy; } Sema::CXXThisScopeRAII::CXXThisScopeRAII(Sema &S, Decl *ContextDecl, Qualifiers CXXThisTypeQuals, bool Enabled) : S(S), OldCXXThisTypeOverride(S.CXXThisTypeOverride), Enabled(false) { if (!Enabled || !ContextDecl) return; CXXRecordDecl *Record = nullptr; if (ClassTemplateDecl *Template = dyn_cast(ContextDecl)) Record = Template->getTemplatedDecl(); else Record = cast(ContextDecl); QualType T = S.Context.getRecordType(Record); T = S.getASTContext().getQualifiedType(T, CXXThisTypeQuals); S.CXXThisTypeOverride = S.Context.getPointerType(T); this->Enabled = true; } Sema::CXXThisScopeRAII::~CXXThisScopeRAII() { if (Enabled) { S.CXXThisTypeOverride = OldCXXThisTypeOverride; } } bool Sema::CheckCXXThisCapture(SourceLocation Loc, const bool Explicit, bool BuildAndDiagnose, const unsigned *const FunctionScopeIndexToStopAt, const bool ByCopy) { // We don't need to capture this in an unevaluated context. if (isUnevaluatedContext() && !Explicit) return true; assert((!ByCopy || Explicit) && "cannot implicitly capture *this by value"); const int MaxFunctionScopesIndex = FunctionScopeIndexToStopAt ? *FunctionScopeIndexToStopAt : FunctionScopes.size() - 1; // Check that we can capture the *enclosing object* (referred to by '*this') // by the capturing-entity/closure (lambda/block/etc) at // MaxFunctionScopesIndex-deep on the FunctionScopes stack. // Note: The *enclosing object* can only be captured by-value by a // closure that is a lambda, using the explicit notation: // [*this] { ... }. // Every other capture of the *enclosing object* results in its by-reference // capture. // For a closure 'L' (at MaxFunctionScopesIndex in the FunctionScopes // stack), we can capture the *enclosing object* only if: // - 'L' has an explicit byref or byval capture of the *enclosing object* // - or, 'L' has an implicit capture. // AND // -- there is no enclosing closure // -- or, there is some enclosing closure 'E' that has already captured the // *enclosing object*, and every intervening closure (if any) between 'E' // and 'L' can implicitly capture the *enclosing object*. // -- or, every enclosing closure can implicitly capture the // *enclosing object* unsigned NumCapturingClosures = 0; for (int idx = MaxFunctionScopesIndex; idx >= 0; idx--) { if (CapturingScopeInfo *CSI = dyn_cast(FunctionScopes[idx])) { if (CSI->CXXThisCaptureIndex != 0) { // 'this' is already being captured; there isn't anything more to do. CSI->Captures[CSI->CXXThisCaptureIndex - 1].markUsed(BuildAndDiagnose); break; } LambdaScopeInfo *LSI = dyn_cast(CSI); if (LSI && isGenericLambdaCallOperatorSpecialization(LSI->CallOperator)) { // This context can't implicitly capture 'this'; fail out. if (BuildAndDiagnose) Diag(Loc, diag::err_this_capture) << (Explicit && idx == MaxFunctionScopesIndex); return true; } if (CSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_LambdaByref || CSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_LambdaByval || CSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_Block || CSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_CapturedRegion || (Explicit && idx == MaxFunctionScopesIndex)) { // Regarding (Explicit && idx == MaxFunctionScopesIndex): only the first // iteration through can be an explicit capture, all enclosing closures, // if any, must perform implicit captures. // This closure can capture 'this'; continue looking upwards. NumCapturingClosures++; continue; } // This context can't implicitly capture 'this'; fail out. if (BuildAndDiagnose) Diag(Loc, diag::err_this_capture) << (Explicit && idx == MaxFunctionScopesIndex); return true; } break; } if (!BuildAndDiagnose) return false; // If we got here, then the closure at MaxFunctionScopesIndex on the // FunctionScopes stack, can capture the *enclosing object*, so capture it // (including implicit by-reference captures in any enclosing closures). // In the loop below, respect the ByCopy flag only for the closure requesting // the capture (i.e. first iteration through the loop below). Ignore it for // all enclosing closure's up to NumCapturingClosures (since they must be // implicitly capturing the *enclosing object* by reference (see loop // above)). assert((!ByCopy || dyn_cast(FunctionScopes[MaxFunctionScopesIndex])) && "Only a lambda can capture the enclosing object (referred to by " "*this) by copy"); QualType ThisTy = getCurrentThisType(); for (int idx = MaxFunctionScopesIndex; NumCapturingClosures; --idx, --NumCapturingClosures) { CapturingScopeInfo *CSI = cast(FunctionScopes[idx]); // The type of the corresponding data member (not a 'this' pointer if 'by // copy'). QualType CaptureType = ThisTy; if (ByCopy) { // If we are capturing the object referred to by '*this' by copy, ignore // any cv qualifiers inherited from the type of the member function for // the type of the closure-type's corresponding data member and any use // of 'this'. CaptureType = ThisTy->getPointeeType(); CaptureType.removeLocalCVRQualifiers(Qualifiers::CVRMask); } bool isNested = NumCapturingClosures > 1; CSI->addThisCapture(isNested, Loc, CaptureType, ByCopy); } return false; } ExprResult Sema::ActOnCXXThis(SourceLocation Loc) { /// C++ 9.3.2: In the body of a non-static member function, the keyword this /// is a non-lvalue expression whose value is the address of the object for /// which the function is called. QualType ThisTy = getCurrentThisType(); if (ThisTy.isNull()) return Diag(Loc, diag::err_invalid_this_use); return BuildCXXThisExpr(Loc, ThisTy, /*IsImplicit=*/false); } Expr *Sema::BuildCXXThisExpr(SourceLocation Loc, QualType Type, bool IsImplicit) { auto *This = new (Context) CXXThisExpr(Loc, Type, IsImplicit); MarkThisReferenced(This); return This; } void Sema::MarkThisReferenced(CXXThisExpr *This) { CheckCXXThisCapture(This->getExprLoc()); } bool Sema::isThisOutsideMemberFunctionBody(QualType BaseType) { // If we're outside the body of a member function, then we'll have a specified // type for 'this'. if (CXXThisTypeOverride.isNull()) return false; // Determine whether we're looking into a class that's currently being // defined. CXXRecordDecl *Class = BaseType->getAsCXXRecordDecl(); return Class && Class->isBeingDefined(); } /// Parse construction of a specified type. /// Can be interpreted either as function-style casting ("int(x)") /// or class type construction ("ClassType(x,y,z)") /// or creation of a value-initialized type ("int()"). ExprResult Sema::ActOnCXXTypeConstructExpr(ParsedType TypeRep, SourceLocation LParenOrBraceLoc, MultiExprArg exprs, SourceLocation RParenOrBraceLoc, bool ListInitialization) { if (!TypeRep) return ExprError(); TypeSourceInfo *TInfo; QualType Ty = GetTypeFromParser(TypeRep, &TInfo); if (!TInfo) TInfo = Context.getTrivialTypeSourceInfo(Ty, SourceLocation()); auto Result = BuildCXXTypeConstructExpr(TInfo, LParenOrBraceLoc, exprs, RParenOrBraceLoc, ListInitialization); // Avoid creating a non-type-dependent expression that contains typos. // Non-type-dependent expressions are liable to be discarded without // checking for embedded typos. if (!Result.isInvalid() && Result.get()->isInstantiationDependent() && !Result.get()->isTypeDependent()) Result = CorrectDelayedTyposInExpr(Result.get()); return Result; } ExprResult Sema::BuildCXXTypeConstructExpr(TypeSourceInfo *TInfo, SourceLocation LParenOrBraceLoc, MultiExprArg Exprs, SourceLocation RParenOrBraceLoc, bool ListInitialization) { QualType Ty = TInfo->getType(); SourceLocation TyBeginLoc = TInfo->getTypeLoc().getBeginLoc(); if (Ty->isDependentType() || CallExpr::hasAnyTypeDependentArguments(Exprs)) { // FIXME: CXXUnresolvedConstructExpr does not model list-initialization // directly. We work around this by dropping the locations of the braces. SourceRange Locs = ListInitialization ? SourceRange() : SourceRange(LParenOrBraceLoc, RParenOrBraceLoc); return CXXUnresolvedConstructExpr::Create(Context, TInfo, Locs.getBegin(), Exprs, Locs.getEnd()); } assert((!ListInitialization || (Exprs.size() == 1 && isa(Exprs[0]))) && "List initialization must have initializer list as expression."); SourceRange FullRange = SourceRange(TyBeginLoc, RParenOrBraceLoc); InitializedEntity Entity = InitializedEntity::InitializeTemporary(TInfo); InitializationKind Kind = Exprs.size() ? ListInitialization ? InitializationKind::CreateDirectList( TyBeginLoc, LParenOrBraceLoc, RParenOrBraceLoc) : InitializationKind::CreateDirect(TyBeginLoc, LParenOrBraceLoc, RParenOrBraceLoc) : InitializationKind::CreateValue(TyBeginLoc, LParenOrBraceLoc, RParenOrBraceLoc); // C++1z [expr.type.conv]p1: // If the type is a placeholder for a deduced class type, [...perform class // template argument deduction...] DeducedType *Deduced = Ty->getContainedDeducedType(); if (Deduced && isa(Deduced)) { Ty = DeduceTemplateSpecializationFromInitializer(TInfo, Entity, Kind, Exprs); if (Ty.isNull()) return ExprError(); Entity = InitializedEntity::InitializeTemporary(TInfo, Ty); } // C++ [expr.type.conv]p1: // If the expression list is a parenthesized single expression, the type // conversion expression is equivalent (in definedness, and if defined in // meaning) to the corresponding cast expression. if (Exprs.size() == 1 && !ListInitialization && !isa(Exprs[0])) { Expr *Arg = Exprs[0]; return BuildCXXFunctionalCastExpr(TInfo, Ty, LParenOrBraceLoc, Arg, RParenOrBraceLoc); } // For an expression of the form T(), T shall not be an array type. QualType ElemTy = Ty; if (Ty->isArrayType()) { if (!ListInitialization) return ExprError(Diag(TyBeginLoc, diag::err_value_init_for_array_type) << FullRange); ElemTy = Context.getBaseElementType(Ty); } // There doesn't seem to be an explicit rule against this but sanity demands // we only construct objects with object types. if (Ty->isFunctionType()) return ExprError(Diag(TyBeginLoc, diag::err_init_for_function_type) << Ty << FullRange); // C++17 [expr.type.conv]p2: // If the type is cv void and the initializer is (), the expression is a // prvalue of the specified type that performs no initialization. if (!Ty->isVoidType() && RequireCompleteType(TyBeginLoc, ElemTy, diag::err_invalid_incomplete_type_use, FullRange)) return ExprError(); // Otherwise, the expression is a prvalue of the specified type whose // result object is direct-initialized (11.6) with the initializer. InitializationSequence InitSeq(*this, Entity, Kind, Exprs); ExprResult Result = InitSeq.Perform(*this, Entity, Kind, Exprs); if (Result.isInvalid()) return Result; Expr *Inner = Result.get(); if (CXXBindTemporaryExpr *BTE = dyn_cast_or_null(Inner)) Inner = BTE->getSubExpr(); if (!isa(Inner) && !isa(Inner)) { // If we created a CXXTemporaryObjectExpr, that node also represents the // functional cast. Otherwise, create an explicit cast to represent // the syntactic form of a functional-style cast that was used here. // // FIXME: Creating a CXXFunctionalCastExpr around a CXXConstructExpr // would give a more consistent AST representation than using a // CXXTemporaryObjectExpr. It's also weird that the functional cast // is sometimes handled by initialization and sometimes not. QualType ResultType = Result.get()->getType(); SourceRange Locs = ListInitialization ? SourceRange() : SourceRange(LParenOrBraceLoc, RParenOrBraceLoc); Result = CXXFunctionalCastExpr::Create( Context, ResultType, Expr::getValueKindForType(Ty), TInfo, CK_NoOp, Result.get(), /*Path=*/nullptr, Locs.getBegin(), Locs.getEnd()); } return Result; } bool Sema::isUsualDeallocationFunction(const CXXMethodDecl *Method) { // [CUDA] Ignore this function, if we can't call it. const FunctionDecl *Caller = dyn_cast(CurContext); if (getLangOpts().CUDA && IdentifyCUDAPreference(Caller, Method) <= CFP_WrongSide) return false; SmallVector PreventedBy; bool Result = Method->isUsualDeallocationFunction(PreventedBy); if (Result || !getLangOpts().CUDA || PreventedBy.empty()) return Result; // In case of CUDA, return true if none of the 1-argument deallocator // functions are actually callable. return llvm::none_of(PreventedBy, [&](const FunctionDecl *FD) { assert(FD->getNumParams() == 1 && "Only single-operand functions should be in PreventedBy"); return IdentifyCUDAPreference(Caller, FD) >= CFP_HostDevice; }); } /// Determine whether the given function is a non-placement /// deallocation function. static bool isNonPlacementDeallocationFunction(Sema &S, FunctionDecl *FD) { if (CXXMethodDecl *Method = dyn_cast(FD)) return S.isUsualDeallocationFunction(Method); if (FD->getOverloadedOperator() != OO_Delete && FD->getOverloadedOperator() != OO_Array_Delete) return false; unsigned UsualParams = 1; if (S.getLangOpts().SizedDeallocation && UsualParams < FD->getNumParams() && S.Context.hasSameUnqualifiedType( FD->getParamDecl(UsualParams)->getType(), S.Context.getSizeType())) ++UsualParams; if (S.getLangOpts().AlignedAllocation && UsualParams < FD->getNumParams() && S.Context.hasSameUnqualifiedType( FD->getParamDecl(UsualParams)->getType(), S.Context.getTypeDeclType(S.getStdAlignValT()))) ++UsualParams; return UsualParams == FD->getNumParams(); } namespace { struct UsualDeallocFnInfo { UsualDeallocFnInfo() : Found(), FD(nullptr) {} UsualDeallocFnInfo(Sema &S, DeclAccessPair Found) : Found(Found), FD(dyn_cast(Found->getUnderlyingDecl())), Destroying(false), HasSizeT(false), HasAlignValT(false), CUDAPref(Sema::CFP_Native) { // A function template declaration is never a usual deallocation function. if (!FD) return; unsigned NumBaseParams = 1; if (FD->isDestroyingOperatorDelete()) { Destroying = true; ++NumBaseParams; } if (NumBaseParams < FD->getNumParams() && S.Context.hasSameUnqualifiedType( FD->getParamDecl(NumBaseParams)->getType(), S.Context.getSizeType())) { ++NumBaseParams; HasSizeT = true; } if (NumBaseParams < FD->getNumParams() && FD->getParamDecl(NumBaseParams)->getType()->isAlignValT()) { ++NumBaseParams; HasAlignValT = true; } // In CUDA, determine how much we'd like / dislike to call this. if (S.getLangOpts().CUDA) if (auto *Caller = dyn_cast(S.CurContext)) CUDAPref = S.IdentifyCUDAPreference(Caller, FD); } explicit operator bool() const { return FD; } bool isBetterThan(const UsualDeallocFnInfo &Other, bool WantSize, bool WantAlign) const { // C++ P0722: // A destroying operator delete is preferred over a non-destroying // operator delete. if (Destroying != Other.Destroying) return Destroying; // C++17 [expr.delete]p10: // If the type has new-extended alignment, a function with a parameter // of type std::align_val_t is preferred; otherwise a function without // such a parameter is preferred if (HasAlignValT != Other.HasAlignValT) return HasAlignValT == WantAlign; if (HasSizeT != Other.HasSizeT) return HasSizeT == WantSize; // Use CUDA call preference as a tiebreaker. return CUDAPref > Other.CUDAPref; } DeclAccessPair Found; FunctionDecl *FD; bool Destroying, HasSizeT, HasAlignValT; Sema::CUDAFunctionPreference CUDAPref; }; } /// Determine whether a type has new-extended alignment. This may be called when /// the type is incomplete (for a delete-expression with an incomplete pointee /// type), in which case it will conservatively return false if the alignment is /// not known. static bool hasNewExtendedAlignment(Sema &S, QualType AllocType) { return S.getLangOpts().AlignedAllocation && S.getASTContext().getTypeAlignIfKnown(AllocType) > S.getASTContext().getTargetInfo().getNewAlign(); } /// Select the correct "usual" deallocation function to use from a selection of /// deallocation functions (either global or class-scope). static UsualDeallocFnInfo resolveDeallocationOverload( Sema &S, LookupResult &R, bool WantSize, bool WantAlign, llvm::SmallVectorImpl *BestFns = nullptr) { UsualDeallocFnInfo Best; for (auto I = R.begin(), E = R.end(); I != E; ++I) { UsualDeallocFnInfo Info(S, I.getPair()); if (!Info || !isNonPlacementDeallocationFunction(S, Info.FD) || Info.CUDAPref == Sema::CFP_Never) continue; if (!Best) { Best = Info; if (BestFns) BestFns->push_back(Info); continue; } if (Best.isBetterThan(Info, WantSize, WantAlign)) continue; // If more than one preferred function is found, all non-preferred // functions are eliminated from further consideration. if (BestFns && Info.isBetterThan(Best, WantSize, WantAlign)) BestFns->clear(); Best = Info; if (BestFns) BestFns->push_back(Info); } return Best; } /// Determine whether a given type is a class for which 'delete[]' would call /// a member 'operator delete[]' with a 'size_t' parameter. This implies that /// we need to store the array size (even if the type is /// trivially-destructible). static bool doesUsualArrayDeleteWantSize(Sema &S, SourceLocation loc, QualType allocType) { const RecordType *record = allocType->getBaseElementTypeUnsafe()->getAs(); if (!record) return false; // Try to find an operator delete[] in class scope. DeclarationName deleteName = S.Context.DeclarationNames.getCXXOperatorName(OO_Array_Delete); LookupResult ops(S, deleteName, loc, Sema::LookupOrdinaryName); S.LookupQualifiedName(ops, record->getDecl()); // We're just doing this for information. ops.suppressDiagnostics(); // Very likely: there's no operator delete[]. if (ops.empty()) return false; // If it's ambiguous, it should be illegal to call operator delete[] // on this thing, so it doesn't matter if we allocate extra space or not. if (ops.isAmbiguous()) return false; // C++17 [expr.delete]p10: // If the deallocation functions have class scope, the one without a // parameter of type std::size_t is selected. auto Best = resolveDeallocationOverload( S, ops, /*WantSize*/false, /*WantAlign*/hasNewExtendedAlignment(S, allocType)); return Best && Best.HasSizeT; } /// Parsed a C++ 'new' expression (C++ 5.3.4). /// /// E.g.: /// @code new (memory) int[size][4] @endcode /// or /// @code ::new Foo(23, "hello") @endcode /// /// \param StartLoc The first location of the expression. /// \param UseGlobal True if 'new' was prefixed with '::'. /// \param PlacementLParen Opening paren of the placement arguments. /// \param PlacementArgs Placement new arguments. /// \param PlacementRParen Closing paren of the placement arguments. /// \param TypeIdParens If the type is in parens, the source range. /// \param D The type to be allocated, as well as array dimensions. /// \param Initializer The initializing expression or initializer-list, or null /// if there is none. ExprResult Sema::ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal, SourceLocation PlacementLParen, MultiExprArg PlacementArgs, SourceLocation PlacementRParen, SourceRange TypeIdParens, Declarator &D, Expr *Initializer) { Optional ArraySize; // If the specified type is an array, unwrap it and save the expression. if (D.getNumTypeObjects() > 0 && D.getTypeObject(0).Kind == DeclaratorChunk::Array) { DeclaratorChunk &Chunk = D.getTypeObject(0); if (D.getDeclSpec().hasAutoTypeSpec()) return ExprError(Diag(Chunk.Loc, diag::err_new_array_of_auto) << D.getSourceRange()); if (Chunk.Arr.hasStatic) return ExprError(Diag(Chunk.Loc, diag::err_static_illegal_in_new) << D.getSourceRange()); if (!Chunk.Arr.NumElts && !Initializer) return ExprError(Diag(Chunk.Loc, diag::err_array_new_needs_size) << D.getSourceRange()); ArraySize = static_cast(Chunk.Arr.NumElts); D.DropFirstTypeObject(); } // Every dimension shall be of constant size. if (ArraySize) { for (unsigned I = 0, N = D.getNumTypeObjects(); I < N; ++I) { if (D.getTypeObject(I).Kind != DeclaratorChunk::Array) break; DeclaratorChunk::ArrayTypeInfo &Array = D.getTypeObject(I).Arr; if (Expr *NumElts = (Expr *)Array.NumElts) { if (!NumElts->isTypeDependent() && !NumElts->isValueDependent()) { if (getLangOpts().CPlusPlus14) { // C++1y [expr.new]p6: Every constant-expression in a noptr-new-declarator // shall be a converted constant expression (5.19) of type std::size_t // and shall evaluate to a strictly positive value. unsigned IntWidth = Context.getTargetInfo().getIntWidth(); assert(IntWidth && "Builtin type of size 0?"); llvm::APSInt Value(IntWidth); Array.NumElts = CheckConvertedConstantExpression(NumElts, Context.getSizeType(), Value, CCEK_NewExpr) .get(); } else { Array.NumElts = VerifyIntegerConstantExpression(NumElts, nullptr, diag::err_new_array_nonconst) .get(); } if (!Array.NumElts) return ExprError(); } } } } TypeSourceInfo *TInfo = GetTypeForDeclarator(D, /*Scope=*/nullptr); QualType AllocType = TInfo->getType(); if (D.isInvalidType()) return ExprError(); SourceRange DirectInitRange; if (ParenListExpr *List = dyn_cast_or_null(Initializer)) DirectInitRange = List->getSourceRange(); return BuildCXXNew(SourceRange(StartLoc, D.getEndLoc()), UseGlobal, PlacementLParen, PlacementArgs, PlacementRParen, TypeIdParens, AllocType, TInfo, ArraySize, DirectInitRange, Initializer); } static bool isLegalArrayNewInitializer(CXXNewExpr::InitializationStyle Style, Expr *Init) { if (!Init) return true; if (ParenListExpr *PLE = dyn_cast(Init)) return PLE->getNumExprs() == 0; if (isa(Init)) return true; else if (CXXConstructExpr *CCE = dyn_cast(Init)) return !CCE->isListInitialization() && CCE->getConstructor()->isDefaultConstructor(); else if (Style == CXXNewExpr::ListInit) { assert(isa(Init) && "Shouldn't create list CXXConstructExprs for arrays."); return true; } return false; } bool Sema::isUnavailableAlignedAllocationFunction(const FunctionDecl &FD) const { if (!getLangOpts().AlignedAllocationUnavailable) return false; if (FD.isDefined()) return false; bool IsAligned = false; if (FD.isReplaceableGlobalAllocationFunction(&IsAligned) && IsAligned) return true; return false; } // Emit a diagnostic if an aligned allocation/deallocation function that is not // implemented in the standard library is selected. void Sema::diagnoseUnavailableAlignedAllocation(const FunctionDecl &FD, SourceLocation Loc) { if (isUnavailableAlignedAllocationFunction(FD)) { const llvm::Triple &T = getASTContext().getTargetInfo().getTriple(); StringRef OSName = AvailabilityAttr::getPlatformNameSourceSpelling( getASTContext().getTargetInfo().getPlatformName()); OverloadedOperatorKind Kind = FD.getDeclName().getCXXOverloadedOperator(); bool IsDelete = Kind == OO_Delete || Kind == OO_Array_Delete; Diag(Loc, diag::err_aligned_allocation_unavailable) << IsDelete << FD.getType().getAsString() << OSName << alignedAllocMinVersion(T.getOS()).getAsString(); Diag(Loc, diag::note_silence_aligned_allocation_unavailable); } } ExprResult Sema::BuildCXXNew(SourceRange Range, bool UseGlobal, SourceLocation PlacementLParen, MultiExprArg PlacementArgs, SourceLocation PlacementRParen, SourceRange TypeIdParens, QualType AllocType, TypeSourceInfo *AllocTypeInfo, Optional ArraySize, SourceRange DirectInitRange, Expr *Initializer) { SourceRange TypeRange = AllocTypeInfo->getTypeLoc().getSourceRange(); SourceLocation StartLoc = Range.getBegin(); CXXNewExpr::InitializationStyle initStyle; if (DirectInitRange.isValid()) { assert(Initializer && "Have parens but no initializer."); initStyle = CXXNewExpr::CallInit; } else if (Initializer && isa(Initializer)) initStyle = CXXNewExpr::ListInit; else { assert((!Initializer || isa(Initializer) || isa(Initializer)) && "Initializer expression that cannot have been implicitly created."); initStyle = CXXNewExpr::NoInit; } Expr **Inits = &Initializer; unsigned NumInits = Initializer ? 1 : 0; if (ParenListExpr *List = dyn_cast_or_null(Initializer)) { assert(initStyle == CXXNewExpr::CallInit && "paren init for non-call init"); Inits = List->getExprs(); NumInits = List->getNumExprs(); } // C++11 [expr.new]p15: // A new-expression that creates an object of type T initializes that // object as follows: InitializationKind Kind // - If the new-initializer is omitted, the object is default- // initialized (8.5); if no initialization is performed, // the object has indeterminate value = initStyle == CXXNewExpr::NoInit ? InitializationKind::CreateDefault(TypeRange.getBegin()) // - Otherwise, the new-initializer is interpreted according to // the // initialization rules of 8.5 for direct-initialization. : initStyle == CXXNewExpr::ListInit ? InitializationKind::CreateDirectList( TypeRange.getBegin(), Initializer->getBeginLoc(), Initializer->getEndLoc()) : InitializationKind::CreateDirect(TypeRange.getBegin(), DirectInitRange.getBegin(), DirectInitRange.getEnd()); // C++11 [dcl.spec.auto]p6. Deduce the type which 'auto' stands in for. auto *Deduced = AllocType->getContainedDeducedType(); if (Deduced && isa(Deduced)) { if (ArraySize) return ExprError( Diag(ArraySize ? (*ArraySize)->getExprLoc() : TypeRange.getBegin(), diag::err_deduced_class_template_compound_type) << /*array*/ 2 << (ArraySize ? (*ArraySize)->getSourceRange() : TypeRange)); InitializedEntity Entity = InitializedEntity::InitializeNew(StartLoc, AllocType); AllocType = DeduceTemplateSpecializationFromInitializer( AllocTypeInfo, Entity, Kind, MultiExprArg(Inits, NumInits)); if (AllocType.isNull()) return ExprError(); } else if (Deduced) { bool Braced = (initStyle == CXXNewExpr::ListInit); if (NumInits == 1) { if (auto p = dyn_cast_or_null(Inits[0])) { Inits = p->getInits(); NumInits = p->getNumInits(); Braced = true; } } if (initStyle == CXXNewExpr::NoInit || NumInits == 0) return ExprError(Diag(StartLoc, diag::err_auto_new_requires_ctor_arg) << AllocType << TypeRange); if (NumInits > 1) { Expr *FirstBad = Inits[1]; return ExprError(Diag(FirstBad->getBeginLoc(), diag::err_auto_new_ctor_multiple_expressions) << AllocType << TypeRange); } if (Braced && !getLangOpts().CPlusPlus17) Diag(Initializer->getBeginLoc(), diag::ext_auto_new_list_init) << AllocType << TypeRange; Expr *Deduce = Inits[0]; QualType DeducedType; if (DeduceAutoType(AllocTypeInfo, Deduce, DeducedType) == DAR_Failed) return ExprError(Diag(StartLoc, diag::err_auto_new_deduction_failure) << AllocType << Deduce->getType() << TypeRange << Deduce->getSourceRange()); if (DeducedType.isNull()) return ExprError(); AllocType = DeducedType; } // Per C++0x [expr.new]p5, the type being constructed may be a // typedef of an array type. if (!ArraySize) { if (const ConstantArrayType *Array = Context.getAsConstantArrayType(AllocType)) { ArraySize = IntegerLiteral::Create(Context, Array->getSize(), Context.getSizeType(), TypeRange.getEnd()); AllocType = Array->getElementType(); } } if (CheckAllocatedType(AllocType, TypeRange.getBegin(), TypeRange)) return ExprError(); // In ARC, infer 'retaining' for the allocated if (getLangOpts().ObjCAutoRefCount && AllocType.getObjCLifetime() == Qualifiers::OCL_None && AllocType->isObjCLifetimeType()) { AllocType = Context.getLifetimeQualifiedType(AllocType, AllocType->getObjCARCImplicitLifetime()); } QualType ResultType = Context.getPointerType(AllocType); if (ArraySize && *ArraySize && (*ArraySize)->getType()->isNonOverloadPlaceholderType()) { ExprResult result = CheckPlaceholderExpr(*ArraySize); if (result.isInvalid()) return ExprError(); ArraySize = result.get(); } // C++98 5.3.4p6: "The expression in a direct-new-declarator shall have // integral or enumeration type with a non-negative value." // C++11 [expr.new]p6: The expression [...] shall be of integral or unscoped // enumeration type, or a class type for which a single non-explicit // conversion function to integral or unscoped enumeration type exists. // C++1y [expr.new]p6: The expression [...] is implicitly converted to // std::size_t. llvm::Optional KnownArraySize; if (ArraySize && *ArraySize && !(*ArraySize)->isTypeDependent()) { ExprResult ConvertedSize; if (getLangOpts().CPlusPlus14) { assert(Context.getTargetInfo().getIntWidth() && "Builtin type of size 0?"); ConvertedSize = PerformImplicitConversion(*ArraySize, Context.getSizeType(), AA_Converting); if (!ConvertedSize.isInvalid() && (*ArraySize)->getType()->getAs()) // Diagnose the compatibility of this conversion. Diag(StartLoc, diag::warn_cxx98_compat_array_size_conversion) << (*ArraySize)->getType() << 0 << "'size_t'"; } else { class SizeConvertDiagnoser : public ICEConvertDiagnoser { protected: Expr *ArraySize; public: SizeConvertDiagnoser(Expr *ArraySize) : ICEConvertDiagnoser(/*AllowScopedEnumerations*/false, false, false), ArraySize(ArraySize) {} SemaDiagnosticBuilder diagnoseNotInt(Sema &S, SourceLocation Loc, QualType T) override { return S.Diag(Loc, diag::err_array_size_not_integral) << S.getLangOpts().CPlusPlus11 << T; } SemaDiagnosticBuilder diagnoseIncomplete( Sema &S, SourceLocation Loc, QualType T) override { return S.Diag(Loc, diag::err_array_size_incomplete_type) << T << ArraySize->getSourceRange(); } SemaDiagnosticBuilder diagnoseExplicitConv( Sema &S, SourceLocation Loc, QualType T, QualType ConvTy) override { return S.Diag(Loc, diag::err_array_size_explicit_conversion) << T << ConvTy; } SemaDiagnosticBuilder noteExplicitConv( Sema &S, CXXConversionDecl *Conv, QualType ConvTy) override { return S.Diag(Conv->getLocation(), diag::note_array_size_conversion) << ConvTy->isEnumeralType() << ConvTy; } SemaDiagnosticBuilder diagnoseAmbiguous( Sema &S, SourceLocation Loc, QualType T) override { return S.Diag(Loc, diag::err_array_size_ambiguous_conversion) << T; } SemaDiagnosticBuilder noteAmbiguous( Sema &S, CXXConversionDecl *Conv, QualType ConvTy) override { return S.Diag(Conv->getLocation(), diag::note_array_size_conversion) << ConvTy->isEnumeralType() << ConvTy; } SemaDiagnosticBuilder diagnoseConversion(Sema &S, SourceLocation Loc, QualType T, QualType ConvTy) override { return S.Diag(Loc, S.getLangOpts().CPlusPlus11 ? diag::warn_cxx98_compat_array_size_conversion : diag::ext_array_size_conversion) << T << ConvTy->isEnumeralType() << ConvTy; } } SizeDiagnoser(*ArraySize); ConvertedSize = PerformContextualImplicitConversion(StartLoc, *ArraySize, SizeDiagnoser); } if (ConvertedSize.isInvalid()) return ExprError(); ArraySize = ConvertedSize.get(); QualType SizeType = (*ArraySize)->getType(); if (!SizeType->isIntegralOrUnscopedEnumerationType()) return ExprError(); // C++98 [expr.new]p7: // The expression in a direct-new-declarator shall have integral type // with a non-negative value. // // Let's see if this is a constant < 0. If so, we reject it out of hand, // per CWG1464. Otherwise, if it's not a constant, we must have an // unparenthesized array type. if (!(*ArraySize)->isValueDependent()) { llvm::APSInt Value; // We've already performed any required implicit conversion to integer or // unscoped enumeration type. // FIXME: Per CWG1464, we are required to check the value prior to // converting to size_t. This will never find a negative array size in // C++14 onwards, because Value is always unsigned here! if ((*ArraySize)->isIntegerConstantExpr(Value, Context)) { if (Value.isSigned() && Value.isNegative()) { return ExprError(Diag((*ArraySize)->getBeginLoc(), diag::err_typecheck_negative_array_size) << (*ArraySize)->getSourceRange()); } if (!AllocType->isDependentType()) { unsigned ActiveSizeBits = ConstantArrayType::getNumAddressingBits(Context, AllocType, Value); if (ActiveSizeBits > ConstantArrayType::getMaxSizeBits(Context)) return ExprError( Diag((*ArraySize)->getBeginLoc(), diag::err_array_too_large) << Value.toString(10) << (*ArraySize)->getSourceRange()); } KnownArraySize = Value.getZExtValue(); } else if (TypeIdParens.isValid()) { // Can't have dynamic array size when the type-id is in parentheses. Diag((*ArraySize)->getBeginLoc(), diag::ext_new_paren_array_nonconst) << (*ArraySize)->getSourceRange() << FixItHint::CreateRemoval(TypeIdParens.getBegin()) << FixItHint::CreateRemoval(TypeIdParens.getEnd()); TypeIdParens = SourceRange(); } } // Note that we do *not* convert the argument in any way. It can // be signed, larger than size_t, whatever. } FunctionDecl *OperatorNew = nullptr; FunctionDecl *OperatorDelete = nullptr; unsigned Alignment = AllocType->isDependentType() ? 0 : Context.getTypeAlign(AllocType); unsigned NewAlignment = Context.getTargetInfo().getNewAlign(); bool PassAlignment = getLangOpts().AlignedAllocation && Alignment > NewAlignment; AllocationFunctionScope Scope = UseGlobal ? AFS_Global : AFS_Both; if (!AllocType->isDependentType() && !Expr::hasAnyTypeDependentArguments(PlacementArgs) && FindAllocationFunctions( StartLoc, SourceRange(PlacementLParen, PlacementRParen), Scope, Scope, AllocType, ArraySize.hasValue(), PassAlignment, PlacementArgs, OperatorNew, OperatorDelete)) return ExprError(); // If this is an array allocation, compute whether the usual array // deallocation function for the type has a size_t parameter. bool UsualArrayDeleteWantsSize = false; if (ArraySize && !AllocType->isDependentType()) UsualArrayDeleteWantsSize = doesUsualArrayDeleteWantSize(*this, StartLoc, AllocType); SmallVector AllPlaceArgs; if (OperatorNew) { const FunctionProtoType *Proto = OperatorNew->getType()->getAs(); VariadicCallType CallType = Proto->isVariadic() ? VariadicFunction : VariadicDoesNotApply; // We've already converted the placement args, just fill in any default // arguments. Skip the first parameter because we don't have a corresponding // argument. Skip the second parameter too if we're passing in the // alignment; we've already filled it in. if (GatherArgumentsForCall(PlacementLParen, OperatorNew, Proto, PassAlignment ? 2 : 1, PlacementArgs, AllPlaceArgs, CallType)) return ExprError(); if (!AllPlaceArgs.empty()) PlacementArgs = AllPlaceArgs; // FIXME: This is wrong: PlacementArgs misses out the first (size) argument. DiagnoseSentinelCalls(OperatorNew, PlacementLParen, PlacementArgs); // FIXME: Missing call to CheckFunctionCall or equivalent // Warn if the type is over-aligned and is being allocated by (unaligned) // global operator new. if (PlacementArgs.empty() && !PassAlignment && (OperatorNew->isImplicit() || (OperatorNew->getBeginLoc().isValid() && getSourceManager().isInSystemHeader(OperatorNew->getBeginLoc())))) { if (Alignment > NewAlignment) Diag(StartLoc, diag::warn_overaligned_type) << AllocType << unsigned(Alignment / Context.getCharWidth()) << unsigned(NewAlignment / Context.getCharWidth()); } } // Array 'new' can't have any initializers except empty parentheses. // Initializer lists are also allowed, in C++11. Rely on the parser for the // dialect distinction. if (ArraySize && !isLegalArrayNewInitializer(initStyle, Initializer)) { SourceRange InitRange(Inits[0]->getBeginLoc(), Inits[NumInits - 1]->getEndLoc()); Diag(StartLoc, diag::err_new_array_init_args) << InitRange; return ExprError(); } // If we can perform the initialization, and we've not already done so, // do it now. if (!AllocType->isDependentType() && !Expr::hasAnyTypeDependentArguments( llvm::makeArrayRef(Inits, NumInits))) { // The type we initialize is the complete type, including the array bound. QualType InitType; if (KnownArraySize) InitType = Context.getConstantArrayType( AllocType, llvm::APInt(Context.getTypeSize(Context.getSizeType()), *KnownArraySize), *ArraySize, ArrayType::Normal, 0); else if (ArraySize) InitType = Context.getIncompleteArrayType(AllocType, ArrayType::Normal, 0); else InitType = AllocType; InitializedEntity Entity = InitializedEntity::InitializeNew(StartLoc, InitType); InitializationSequence InitSeq(*this, Entity, Kind, MultiExprArg(Inits, NumInits)); ExprResult FullInit = InitSeq.Perform(*this, Entity, Kind, MultiExprArg(Inits, NumInits)); if (FullInit.isInvalid()) return ExprError(); // FullInit is our initializer; strip off CXXBindTemporaryExprs, because // we don't want the initialized object to be destructed. // FIXME: We should not create these in the first place. if (CXXBindTemporaryExpr *Binder = dyn_cast_or_null(FullInit.get())) FullInit = Binder->getSubExpr(); Initializer = FullInit.get(); // FIXME: If we have a KnownArraySize, check that the array bound of the // initializer is no greater than that constant value. if (ArraySize && !*ArraySize) { auto *CAT = Context.getAsConstantArrayType(Initializer->getType()); if (CAT) { // FIXME: Track that the array size was inferred rather than explicitly // specified. ArraySize = IntegerLiteral::Create( Context, CAT->getSize(), Context.getSizeType(), TypeRange.getEnd()); } else { Diag(TypeRange.getEnd(), diag::err_new_array_size_unknown_from_init) << Initializer->getSourceRange(); } } } // Mark the new and delete operators as referenced. if (OperatorNew) { if (DiagnoseUseOfDecl(OperatorNew, StartLoc)) return ExprError(); MarkFunctionReferenced(StartLoc, OperatorNew); } if (OperatorDelete) { if (DiagnoseUseOfDecl(OperatorDelete, StartLoc)) return ExprError(); MarkFunctionReferenced(StartLoc, OperatorDelete); } return CXXNewExpr::Create(Context, UseGlobal, OperatorNew, OperatorDelete, PassAlignment, UsualArrayDeleteWantsSize, PlacementArgs, TypeIdParens, ArraySize, initStyle, Initializer, ResultType, AllocTypeInfo, Range, DirectInitRange); } /// Checks that a type is suitable as the allocated type /// in a new-expression. bool Sema::CheckAllocatedType(QualType AllocType, SourceLocation Loc, SourceRange R) { // C++ 5.3.4p1: "[The] type shall be a complete object type, but not an // abstract class type or array thereof. if (AllocType->isFunctionType()) return Diag(Loc, diag::err_bad_new_type) << AllocType << 0 << R; else if (AllocType->isReferenceType()) return Diag(Loc, diag::err_bad_new_type) << AllocType << 1 << R; else if (!AllocType->isDependentType() && RequireCompleteType(Loc, AllocType, diag::err_new_incomplete_type,R)) return true; else if (RequireNonAbstractType(Loc, AllocType, diag::err_allocation_of_abstract_type)) return true; else if (AllocType->isVariablyModifiedType()) return Diag(Loc, diag::err_variably_modified_new_type) << AllocType; else if (AllocType.getAddressSpace() != LangAS::Default && !getLangOpts().OpenCLCPlusPlus) return Diag(Loc, diag::err_address_space_qualified_new) << AllocType.getUnqualifiedType() << AllocType.getQualifiers().getAddressSpaceAttributePrintValue(); else if (getLangOpts().ObjCAutoRefCount) { if (const ArrayType *AT = Context.getAsArrayType(AllocType)) { QualType BaseAllocType = Context.getBaseElementType(AT); if (BaseAllocType.getObjCLifetime() == Qualifiers::OCL_None && BaseAllocType->isObjCLifetimeType()) return Diag(Loc, diag::err_arc_new_array_without_ownership) << BaseAllocType; } } return false; } static bool resolveAllocationOverload( Sema &S, LookupResult &R, SourceRange Range, SmallVectorImpl &Args, bool &PassAlignment, FunctionDecl *&Operator, OverloadCandidateSet *AlignedCandidates, Expr *AlignArg, bool Diagnose) { OverloadCandidateSet Candidates(R.getNameLoc(), OverloadCandidateSet::CSK_Normal); for (LookupResult::iterator Alloc = R.begin(), AllocEnd = R.end(); Alloc != AllocEnd; ++Alloc) { // Even member operator new/delete are implicitly treated as // static, so don't use AddMemberCandidate. NamedDecl *D = (*Alloc)->getUnderlyingDecl(); if (FunctionTemplateDecl *FnTemplate = dyn_cast(D)) { S.AddTemplateOverloadCandidate(FnTemplate, Alloc.getPair(), /*ExplicitTemplateArgs=*/nullptr, Args, Candidates, /*SuppressUserConversions=*/false); continue; } FunctionDecl *Fn = cast(D); S.AddOverloadCandidate(Fn, Alloc.getPair(), Args, Candidates, /*SuppressUserConversions=*/false); } // Do the resolution. OverloadCandidateSet::iterator Best; switch (Candidates.BestViableFunction(S, R.getNameLoc(), Best)) { case OR_Success: { // Got one! FunctionDecl *FnDecl = Best->Function; if (S.CheckAllocationAccess(R.getNameLoc(), Range, R.getNamingClass(), Best->FoundDecl) == Sema::AR_inaccessible) return true; Operator = FnDecl; return false; } case OR_No_Viable_Function: // C++17 [expr.new]p13: // If no matching function is found and the allocated object type has // new-extended alignment, the alignment argument is removed from the // argument list, and overload resolution is performed again. if (PassAlignment) { PassAlignment = false; AlignArg = Args[1]; Args.erase(Args.begin() + 1); return resolveAllocationOverload(S, R, Range, Args, PassAlignment, Operator, &Candidates, AlignArg, Diagnose); } // MSVC will fall back on trying to find a matching global operator new // if operator new[] cannot be found. Also, MSVC will leak by not // generating a call to operator delete or operator delete[], but we // will not replicate that bug. // FIXME: Find out how this interacts with the std::align_val_t fallback // once MSVC implements it. if (R.getLookupName().getCXXOverloadedOperator() == OO_Array_New && S.Context.getLangOpts().MSVCCompat) { R.clear(); R.setLookupName(S.Context.DeclarationNames.getCXXOperatorName(OO_New)); S.LookupQualifiedName(R, S.Context.getTranslationUnitDecl()); // FIXME: This will give bad diagnostics pointing at the wrong functions. return resolveAllocationOverload(S, R, Range, Args, PassAlignment, Operator, /*Candidates=*/nullptr, /*AlignArg=*/nullptr, Diagnose); } if (Diagnose) { PartialDiagnosticAt PD(R.getNameLoc(), S.PDiag(diag::err_ovl_no_viable_function_in_call) << R.getLookupName() << Range); // If we have aligned candidates, only note the align_val_t candidates // from AlignedCandidates and the non-align_val_t candidates from // Candidates. if (AlignedCandidates) { auto IsAligned = [](OverloadCandidate &C) { return C.Function->getNumParams() > 1 && C.Function->getParamDecl(1)->getType()->isAlignValT(); }; auto IsUnaligned = [&](OverloadCandidate &C) { return !IsAligned(C); }; // This was an overaligned allocation, so list the aligned candidates // first. Args.insert(Args.begin() + 1, AlignArg); AlignedCandidates->NoteCandidates(PD, S, OCD_AllCandidates, Args, "", R.getNameLoc(), IsAligned); Args.erase(Args.begin() + 1); Candidates.NoteCandidates(PD, S, OCD_AllCandidates, Args, "", R.getNameLoc(), IsUnaligned); } else { Candidates.NoteCandidates(PD, S, OCD_AllCandidates, Args); } } return true; case OR_Ambiguous: if (Diagnose) { Candidates.NoteCandidates( PartialDiagnosticAt(R.getNameLoc(), S.PDiag(diag::err_ovl_ambiguous_call) << R.getLookupName() << Range), S, OCD_AmbiguousCandidates, Args); } return true; case OR_Deleted: { if (Diagnose) { Candidates.NoteCandidates( PartialDiagnosticAt(R.getNameLoc(), S.PDiag(diag::err_ovl_deleted_call) << R.getLookupName() << Range), S, OCD_AllCandidates, Args); } return true; } } llvm_unreachable("Unreachable, bad result from BestViableFunction"); } bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range, AllocationFunctionScope NewScope, AllocationFunctionScope DeleteScope, QualType AllocType, bool IsArray, bool &PassAlignment, MultiExprArg PlaceArgs, FunctionDecl *&OperatorNew, FunctionDecl *&OperatorDelete, bool Diagnose) { // --- Choosing an allocation function --- // C++ 5.3.4p8 - 14 & 18 // 1) If looking in AFS_Global scope for allocation functions, only look in // the global scope. Else, if AFS_Class, only look in the scope of the // allocated class. If AFS_Both, look in both. // 2) If an array size is given, look for operator new[], else look for // operator new. // 3) The first argument is always size_t. Append the arguments from the // placement form. SmallVector AllocArgs; AllocArgs.reserve((PassAlignment ? 2 : 1) + PlaceArgs.size()); // We don't care about the actual value of these arguments. // FIXME: Should the Sema create the expression and embed it in the syntax // tree? Or should the consumer just recalculate the value? // FIXME: Using a dummy value will interact poorly with attribute enable_if. IntegerLiteral Size(Context, llvm::APInt::getNullValue( Context.getTargetInfo().getPointerWidth(0)), Context.getSizeType(), SourceLocation()); AllocArgs.push_back(&Size); QualType AlignValT = Context.VoidTy; if (PassAlignment) { DeclareGlobalNewDelete(); AlignValT = Context.getTypeDeclType(getStdAlignValT()); } CXXScalarValueInitExpr Align(AlignValT, nullptr, SourceLocation()); if (PassAlignment) AllocArgs.push_back(&Align); AllocArgs.insert(AllocArgs.end(), PlaceArgs.begin(), PlaceArgs.end()); // C++ [expr.new]p8: // If the allocated type is a non-array type, the allocation // function's name is operator new and the deallocation function's // name is operator delete. If the allocated type is an array // type, the allocation function's name is operator new[] and the // deallocation function's name is operator delete[]. DeclarationName NewName = Context.DeclarationNames.getCXXOperatorName( IsArray ? OO_Array_New : OO_New); QualType AllocElemType = Context.getBaseElementType(AllocType); // Find the allocation function. { LookupResult R(*this, NewName, StartLoc, LookupOrdinaryName); // C++1z [expr.new]p9: // If the new-expression begins with a unary :: operator, the allocation // function's name is looked up in the global scope. Otherwise, if the // allocated type is a class type T or array thereof, the allocation // function's name is looked up in the scope of T. if (AllocElemType->isRecordType() && NewScope != AFS_Global) LookupQualifiedName(R, AllocElemType->getAsCXXRecordDecl()); // We can see ambiguity here if the allocation function is found in // multiple base classes. if (R.isAmbiguous()) return true; // If this lookup fails to find the name, or if the allocated type is not // a class type, the allocation function's name is looked up in the // global scope. if (R.empty()) { if (NewScope == AFS_Class) return true; LookupQualifiedName(R, Context.getTranslationUnitDecl()); } if (getLangOpts().OpenCLCPlusPlus && R.empty()) { if (PlaceArgs.empty()) { Diag(StartLoc, diag::err_openclcxx_not_supported) << "default new"; } else { Diag(StartLoc, diag::err_openclcxx_placement_new); } return true; } assert(!R.empty() && "implicitly declared allocation functions not found"); assert(!R.isAmbiguous() && "global allocation functions are ambiguous"); // We do our own custom access checks below. R.suppressDiagnostics(); if (resolveAllocationOverload(*this, R, Range, AllocArgs, PassAlignment, OperatorNew, /*Candidates=*/nullptr, /*AlignArg=*/nullptr, Diagnose)) return true; } // We don't need an operator delete if we're running under -fno-exceptions. if (!getLangOpts().Exceptions) { OperatorDelete = nullptr; return false; } // Note, the name of OperatorNew might have been changed from array to // non-array by resolveAllocationOverload. DeclarationName DeleteName = Context.DeclarationNames.getCXXOperatorName( OperatorNew->getDeclName().getCXXOverloadedOperator() == OO_Array_New ? OO_Array_Delete : OO_Delete); // C++ [expr.new]p19: // // If the new-expression begins with a unary :: operator, the // deallocation function's name is looked up in the global // scope. Otherwise, if the allocated type is a class type T or an // array thereof, the deallocation function's name is looked up in // the scope of T. If this lookup fails to find the name, or if // the allocated type is not a class type or array thereof, the // deallocation function's name is looked up in the global scope. LookupResult FoundDelete(*this, DeleteName, StartLoc, LookupOrdinaryName); if (AllocElemType->isRecordType() && DeleteScope != AFS_Global) { auto *RD = cast(AllocElemType->castAs()->getDecl()); LookupQualifiedName(FoundDelete, RD); } if (FoundDelete.isAmbiguous()) return true; // FIXME: clean up expressions? bool FoundGlobalDelete = FoundDelete.empty(); if (FoundDelete.empty()) { if (DeleteScope == AFS_Class) return true; DeclareGlobalNewDelete(); LookupQualifiedName(FoundDelete, Context.getTranslationUnitDecl()); } FoundDelete.suppressDiagnostics(); SmallVector, 2> Matches; // Whether we're looking for a placement operator delete is dictated // by whether we selected a placement operator new, not by whether // we had explicit placement arguments. This matters for things like // struct A { void *operator new(size_t, int = 0); ... }; // A *a = new A() // // We don't have any definition for what a "placement allocation function" // is, but we assume it's any allocation function whose // parameter-declaration-clause is anything other than (size_t). // // FIXME: Should (size_t, std::align_val_t) also be considered non-placement? // This affects whether an exception from the constructor of an overaligned // type uses the sized or non-sized form of aligned operator delete. bool isPlacementNew = !PlaceArgs.empty() || OperatorNew->param_size() != 1 || OperatorNew->isVariadic(); if (isPlacementNew) { // C++ [expr.new]p20: // A declaration of a placement deallocation function matches the // declaration of a placement allocation function if it has the // same number of parameters and, after parameter transformations // (8.3.5), all parameter types except the first are // identical. [...] // // To perform this comparison, we compute the function type that // the deallocation function should have, and use that type both // for template argument deduction and for comparison purposes. QualType ExpectedFunctionType; { const FunctionProtoType *Proto = OperatorNew->getType()->getAs(); SmallVector ArgTypes; ArgTypes.push_back(Context.VoidPtrTy); for (unsigned I = 1, N = Proto->getNumParams(); I < N; ++I) ArgTypes.push_back(Proto->getParamType(I)); FunctionProtoType::ExtProtoInfo EPI; // FIXME: This is not part of the standard's rule. EPI.Variadic = Proto->isVariadic(); ExpectedFunctionType = Context.getFunctionType(Context.VoidTy, ArgTypes, EPI); } for (LookupResult::iterator D = FoundDelete.begin(), DEnd = FoundDelete.end(); D != DEnd; ++D) { FunctionDecl *Fn = nullptr; if (FunctionTemplateDecl *FnTmpl = dyn_cast((*D)->getUnderlyingDecl())) { // Perform template argument deduction to try to match the // expected function type. TemplateDeductionInfo Info(StartLoc); if (DeduceTemplateArguments(FnTmpl, nullptr, ExpectedFunctionType, Fn, Info)) continue; } else Fn = cast((*D)->getUnderlyingDecl()); if (Context.hasSameType(adjustCCAndNoReturn(Fn->getType(), ExpectedFunctionType, /*AdjustExcpetionSpec*/true), ExpectedFunctionType)) Matches.push_back(std::make_pair(D.getPair(), Fn)); } if (getLangOpts().CUDA) EraseUnwantedCUDAMatches(dyn_cast(CurContext), Matches); } else { // C++1y [expr.new]p22: // For a non-placement allocation function, the normal deallocation // function lookup is used // // Per [expr.delete]p10, this lookup prefers a member operator delete // without a size_t argument, but prefers a non-member operator delete // with a size_t where possible (which it always is in this case). llvm::SmallVector BestDeallocFns; UsualDeallocFnInfo Selected = resolveDeallocationOverload( *this, FoundDelete, /*WantSize*/ FoundGlobalDelete, /*WantAlign*/ hasNewExtendedAlignment(*this, AllocElemType), &BestDeallocFns); if (Selected) Matches.push_back(std::make_pair(Selected.Found, Selected.FD)); else { // If we failed to select an operator, all remaining functions are viable // but ambiguous. for (auto Fn : BestDeallocFns) Matches.push_back(std::make_pair(Fn.Found, Fn.FD)); } } // C++ [expr.new]p20: // [...] If the lookup finds a single matching deallocation // function, that function will be called; otherwise, no // deallocation function will be called. if (Matches.size() == 1) { OperatorDelete = Matches[0].second; // C++1z [expr.new]p23: // If the lookup finds a usual deallocation function (3.7.4.2) // with a parameter of type std::size_t and that function, considered // as a placement deallocation function, would have been // selected as a match for the allocation function, the program // is ill-formed. if (getLangOpts().CPlusPlus11 && isPlacementNew && isNonPlacementDeallocationFunction(*this, OperatorDelete)) { UsualDeallocFnInfo Info(*this, DeclAccessPair::make(OperatorDelete, AS_public)); // Core issue, per mail to core reflector, 2016-10-09: // If this is a member operator delete, and there is a corresponding // non-sized member operator delete, this isn't /really/ a sized // deallocation function, it just happens to have a size_t parameter. bool IsSizedDelete = Info.HasSizeT; if (IsSizedDelete && !FoundGlobalDelete) { auto NonSizedDelete = resolveDeallocationOverload(*this, FoundDelete, /*WantSize*/false, /*WantAlign*/Info.HasAlignValT); if (NonSizedDelete && !NonSizedDelete.HasSizeT && NonSizedDelete.HasAlignValT == Info.HasAlignValT) IsSizedDelete = false; } if (IsSizedDelete) { SourceRange R = PlaceArgs.empty() ? SourceRange() : SourceRange(PlaceArgs.front()->getBeginLoc(), PlaceArgs.back()->getEndLoc()); Diag(StartLoc, diag::err_placement_new_non_placement_delete) << R; if (!OperatorDelete->isImplicit()) Diag(OperatorDelete->getLocation(), diag::note_previous_decl) << DeleteName; } } CheckAllocationAccess(StartLoc, Range, FoundDelete.getNamingClass(), Matches[0].first); } else if (!Matches.empty()) { // We found multiple suitable operators. Per [expr.new]p20, that means we // call no 'operator delete' function, but we should at least warn the user. // FIXME: Suppress this warning if the construction cannot throw. Diag(StartLoc, diag::warn_ambiguous_suitable_delete_function_found) << DeleteName << AllocElemType; for (auto &Match : Matches) Diag(Match.second->getLocation(), diag::note_member_declared_here) << DeleteName; } return false; } /// DeclareGlobalNewDelete - Declare the global forms of operator new and /// delete. These are: /// @code /// // C++03: /// void* operator new(std::size_t) throw(std::bad_alloc); /// void* operator new[](std::size_t) throw(std::bad_alloc); /// void operator delete(void *) throw(); /// void operator delete[](void *) throw(); /// // C++11: /// void* operator new(std::size_t); /// void* operator new[](std::size_t); /// void operator delete(void *) noexcept; /// void operator delete[](void *) noexcept; /// // C++1y: /// void* operator new(std::size_t); /// void* operator new[](std::size_t); /// void operator delete(void *) noexcept; /// void operator delete[](void *) noexcept; /// void operator delete(void *, std::size_t) noexcept; /// void operator delete[](void *, std::size_t) noexcept; /// @endcode /// Note that the placement and nothrow forms of new are *not* implicitly /// declared. Their use requires including \. void Sema::DeclareGlobalNewDelete() { if (GlobalNewDeleteDeclared) return; // The implicitly declared new and delete operators // are not supported in OpenCL. if (getLangOpts().OpenCLCPlusPlus) return; // C++ [basic.std.dynamic]p2: // [...] The following allocation and deallocation functions (18.4) are // implicitly declared in global scope in each translation unit of a // program // // C++03: // void* operator new(std::size_t) throw(std::bad_alloc); // void* operator new[](std::size_t) throw(std::bad_alloc); // void operator delete(void*) throw(); // void operator delete[](void*) throw(); // C++11: // void* operator new(std::size_t); // void* operator new[](std::size_t); // void operator delete(void*) noexcept; // void operator delete[](void*) noexcept; // C++1y: // void* operator new(std::size_t); // void* operator new[](std::size_t); // void operator delete(void*) noexcept; // void operator delete[](void*) noexcept; // void operator delete(void*, std::size_t) noexcept; // void operator delete[](void*, std::size_t) noexcept; // // These implicit declarations introduce only the function names operator // new, operator new[], operator delete, operator delete[]. // // Here, we need to refer to std::bad_alloc, so we will implicitly declare // "std" or "bad_alloc" as necessary to form the exception specification. // However, we do not make these implicit declarations visible to name // lookup. if (!StdBadAlloc && !getLangOpts().CPlusPlus11) { // The "std::bad_alloc" class has not yet been declared, so build it // implicitly. StdBadAlloc = CXXRecordDecl::Create(Context, TTK_Class, getOrCreateStdNamespace(), SourceLocation(), SourceLocation(), &PP.getIdentifierTable().get("bad_alloc"), nullptr); getStdBadAlloc()->setImplicit(true); } if (!StdAlignValT && getLangOpts().AlignedAllocation) { // The "std::align_val_t" enum class has not yet been declared, so build it // implicitly. auto *AlignValT = EnumDecl::Create( Context, getOrCreateStdNamespace(), SourceLocation(), SourceLocation(), &PP.getIdentifierTable().get("align_val_t"), nullptr, true, true, true); AlignValT->setIntegerType(Context.getSizeType()); AlignValT->setPromotionType(Context.getSizeType()); AlignValT->setImplicit(true); StdAlignValT = AlignValT; } GlobalNewDeleteDeclared = true; QualType VoidPtr = Context.getPointerType(Context.VoidTy); QualType SizeT = Context.getSizeType(); auto DeclareGlobalAllocationFunctions = [&](OverloadedOperatorKind Kind, QualType Return, QualType Param) { llvm::SmallVector Params; Params.push_back(Param); // Create up to four variants of the function (sized/aligned). bool HasSizedVariant = getLangOpts().SizedDeallocation && (Kind == OO_Delete || Kind == OO_Array_Delete); bool HasAlignedVariant = getLangOpts().AlignedAllocation; int NumSizeVariants = (HasSizedVariant ? 2 : 1); int NumAlignVariants = (HasAlignedVariant ? 2 : 1); for (int Sized = 0; Sized < NumSizeVariants; ++Sized) { if (Sized) Params.push_back(SizeT); for (int Aligned = 0; Aligned < NumAlignVariants; ++Aligned) { if (Aligned) Params.push_back(Context.getTypeDeclType(getStdAlignValT())); DeclareGlobalAllocationFunction( Context.DeclarationNames.getCXXOperatorName(Kind), Return, Params); if (Aligned) Params.pop_back(); } } }; DeclareGlobalAllocationFunctions(OO_New, VoidPtr, SizeT); DeclareGlobalAllocationFunctions(OO_Array_New, VoidPtr, SizeT); DeclareGlobalAllocationFunctions(OO_Delete, Context.VoidTy, VoidPtr); DeclareGlobalAllocationFunctions(OO_Array_Delete, Context.VoidTy, VoidPtr); } /// DeclareGlobalAllocationFunction - Declares a single implicit global /// allocation function if it doesn't already exist. void Sema::DeclareGlobalAllocationFunction(DeclarationName Name, QualType Return, ArrayRef Params) { DeclContext *GlobalCtx = Context.getTranslationUnitDecl(); // Check if this function is already declared. DeclContext::lookup_result R = GlobalCtx->lookup(Name); for (DeclContext::lookup_iterator Alloc = R.begin(), AllocEnd = R.end(); Alloc != AllocEnd; ++Alloc) { // Only look at non-template functions, as it is the predefined, // non-templated allocation function we are trying to declare here. if (FunctionDecl *Func = dyn_cast(*Alloc)) { if (Func->getNumParams() == Params.size()) { llvm::SmallVector FuncParams; for (auto *P : Func->parameters()) FuncParams.push_back( Context.getCanonicalType(P->getType().getUnqualifiedType())); if (llvm::makeArrayRef(FuncParams) == Params) { // Make the function visible to name lookup, even if we found it in // an unimported module. It either is an implicitly-declared global // allocation function, or is suppressing that function. Func->setVisibleDespiteOwningModule(); return; } } } } FunctionProtoType::ExtProtoInfo EPI(Context.getDefaultCallingConvention( /*IsVariadic=*/false, /*IsCXXMethod=*/false, /*IsBuiltin=*/true)); QualType BadAllocType; bool HasBadAllocExceptionSpec = (Name.getCXXOverloadedOperator() == OO_New || Name.getCXXOverloadedOperator() == OO_Array_New); if (HasBadAllocExceptionSpec) { if (!getLangOpts().CPlusPlus11) { BadAllocType = Context.getTypeDeclType(getStdBadAlloc()); assert(StdBadAlloc && "Must have std::bad_alloc declared"); EPI.ExceptionSpec.Type = EST_Dynamic; EPI.ExceptionSpec.Exceptions = llvm::makeArrayRef(BadAllocType); } } else { EPI.ExceptionSpec = getLangOpts().CPlusPlus11 ? EST_BasicNoexcept : EST_DynamicNone; } auto CreateAllocationFunctionDecl = [&](Attr *ExtraAttr) { QualType FnType = Context.getFunctionType(Return, Params, EPI); FunctionDecl *Alloc = FunctionDecl::Create( Context, GlobalCtx, SourceLocation(), SourceLocation(), Name, FnType, /*TInfo=*/nullptr, SC_None, false, true); Alloc->setImplicit(); // Global allocation functions should always be visible. Alloc->setVisibleDespiteOwningModule(); Alloc->addAttr(VisibilityAttr::CreateImplicit( Context, LangOpts.GlobalAllocationFunctionVisibilityHidden ? VisibilityAttr::Hidden : VisibilityAttr::Default)); llvm::SmallVector ParamDecls; for (QualType T : Params) { ParamDecls.push_back(ParmVarDecl::Create( Context, Alloc, SourceLocation(), SourceLocation(), nullptr, T, /*TInfo=*/nullptr, SC_None, nullptr)); ParamDecls.back()->setImplicit(); } Alloc->setParams(ParamDecls); if (ExtraAttr) Alloc->addAttr(ExtraAttr); Context.getTranslationUnitDecl()->addDecl(Alloc); IdResolver.tryAddTopLevelDecl(Alloc, Name); }; if (!LangOpts.CUDA) CreateAllocationFunctionDecl(nullptr); else { // Host and device get their own declaration so each can be // defined or re-declared independently. CreateAllocationFunctionDecl(CUDAHostAttr::CreateImplicit(Context)); CreateAllocationFunctionDecl(CUDADeviceAttr::CreateImplicit(Context)); } } FunctionDecl *Sema::FindUsualDeallocationFunction(SourceLocation StartLoc, bool CanProvideSize, bool Overaligned, DeclarationName Name) { DeclareGlobalNewDelete(); LookupResult FoundDelete(*this, Name, StartLoc, LookupOrdinaryName); LookupQualifiedName(FoundDelete, Context.getTranslationUnitDecl()); // FIXME: It's possible for this to result in ambiguity, through a // user-declared variadic operator delete or the enable_if attribute. We // should probably not consider those cases to be usual deallocation // functions. But for now we just make an arbitrary choice in that case. auto Result = resolveDeallocationOverload(*this, FoundDelete, CanProvideSize, Overaligned); assert(Result.FD && "operator delete missing from global scope?"); return Result.FD; } FunctionDecl *Sema::FindDeallocationFunctionForDestructor(SourceLocation Loc, CXXRecordDecl *RD) { DeclarationName Name = Context.DeclarationNames.getCXXOperatorName(OO_Delete); FunctionDecl *OperatorDelete = nullptr; if (FindDeallocationFunction(Loc, RD, Name, OperatorDelete)) return nullptr; if (OperatorDelete) return OperatorDelete; // If there's no class-specific operator delete, look up the global // non-array delete. return FindUsualDeallocationFunction( Loc, true, hasNewExtendedAlignment(*this, Context.getRecordType(RD)), Name); } bool Sema::FindDeallocationFunction(SourceLocation StartLoc, CXXRecordDecl *RD, DeclarationName Name, FunctionDecl *&Operator, bool Diagnose) { LookupResult Found(*this, Name, StartLoc, LookupOrdinaryName); // Try to find operator delete/operator delete[] in class scope. LookupQualifiedName(Found, RD); if (Found.isAmbiguous()) return true; Found.suppressDiagnostics(); bool Overaligned = hasNewExtendedAlignment(*this, Context.getRecordType(RD)); // C++17 [expr.delete]p10: // If the deallocation functions have class scope, the one without a // parameter of type std::size_t is selected. llvm::SmallVector Matches; resolveDeallocationOverload(*this, Found, /*WantSize*/ false, /*WantAlign*/ Overaligned, &Matches); // If we could find an overload, use it. if (Matches.size() == 1) { Operator = cast(Matches[0].FD); // FIXME: DiagnoseUseOfDecl? if (Operator->isDeleted()) { if (Diagnose) { Diag(StartLoc, diag::err_deleted_function_use); NoteDeletedFunction(Operator); } return true; } if (CheckAllocationAccess(StartLoc, SourceRange(), Found.getNamingClass(), Matches[0].Found, Diagnose) == AR_inaccessible) return true; return false; } // We found multiple suitable operators; complain about the ambiguity. // FIXME: The standard doesn't say to do this; it appears that the intent // is that this should never happen. if (!Matches.empty()) { if (Diagnose) { Diag(StartLoc, diag::err_ambiguous_suitable_delete_member_function_found) << Name << RD; for (auto &Match : Matches) Diag(Match.FD->getLocation(), diag::note_member_declared_here) << Name; } return true; } // We did find operator delete/operator delete[] declarations, but // none of them were suitable. if (!Found.empty()) { if (Diagnose) { Diag(StartLoc, diag::err_no_suitable_delete_member_function_found) << Name << RD; for (NamedDecl *D : Found) Diag(D->getUnderlyingDecl()->getLocation(), diag::note_member_declared_here) << Name; } return true; } Operator = nullptr; return false; } namespace { /// Checks whether delete-expression, and new-expression used for /// initializing deletee have the same array form. class MismatchingNewDeleteDetector { public: enum MismatchResult { /// Indicates that there is no mismatch or a mismatch cannot be proven. NoMismatch, /// Indicates that variable is initialized with mismatching form of \a new. VarInitMismatches, /// Indicates that member is initialized with mismatching form of \a new. MemberInitMismatches, /// Indicates that 1 or more constructors' definitions could not been /// analyzed, and they will be checked again at the end of translation unit. AnalyzeLater }; /// \param EndOfTU True, if this is the final analysis at the end of /// translation unit. False, if this is the initial analysis at the point /// delete-expression was encountered. explicit MismatchingNewDeleteDetector(bool EndOfTU) : Field(nullptr), IsArrayForm(false), EndOfTU(EndOfTU), HasUndefinedConstructors(false) {} /// Checks whether pointee of a delete-expression is initialized with /// matching form of new-expression. /// /// If return value is \c VarInitMismatches or \c MemberInitMismatches at the /// point where delete-expression is encountered, then a warning will be /// issued immediately. If return value is \c AnalyzeLater at the point where /// delete-expression is seen, then member will be analyzed at the end of /// translation unit. \c AnalyzeLater is returned iff at least one constructor /// couldn't be analyzed. If at least one constructor initializes the member /// with matching type of new, the return value is \c NoMismatch. MismatchResult analyzeDeleteExpr(const CXXDeleteExpr *DE); /// Analyzes a class member. /// \param Field Class member to analyze. /// \param DeleteWasArrayForm Array form-ness of the delete-expression used /// for deleting the \p Field. MismatchResult analyzeField(FieldDecl *Field, bool DeleteWasArrayForm); FieldDecl *Field; /// List of mismatching new-expressions used for initialization of the pointee llvm::SmallVector NewExprs; /// Indicates whether delete-expression was in array form. bool IsArrayForm; private: const bool EndOfTU; /// Indicates that there is at least one constructor without body. bool HasUndefinedConstructors; /// Returns \c CXXNewExpr from given initialization expression. /// \param E Expression used for initializing pointee in delete-expression. /// E can be a single-element \c InitListExpr consisting of new-expression. const CXXNewExpr *getNewExprFromInitListOrExpr(const Expr *E); /// Returns whether member is initialized with mismatching form of /// \c new either by the member initializer or in-class initialization. /// /// If bodies of all constructors are not visible at the end of translation /// unit or at least one constructor initializes member with the matching /// form of \c new, mismatch cannot be proven, and this function will return /// \c NoMismatch. MismatchResult analyzeMemberExpr(const MemberExpr *ME); /// Returns whether variable is initialized with mismatching form of /// \c new. /// /// If variable is initialized with matching form of \c new or variable is not /// initialized with a \c new expression, this function will return true. /// If variable is initialized with mismatching form of \c new, returns false. /// \param D Variable to analyze. bool hasMatchingVarInit(const DeclRefExpr *D); /// Checks whether the constructor initializes pointee with mismatching /// form of \c new. /// /// Returns true, if member is initialized with matching form of \c new in /// member initializer list. Returns false, if member is initialized with the /// matching form of \c new in this constructor's initializer or given /// constructor isn't defined at the point where delete-expression is seen, or /// member isn't initialized by the constructor. bool hasMatchingNewInCtor(const CXXConstructorDecl *CD); /// Checks whether member is initialized with matching form of /// \c new in member initializer list. bool hasMatchingNewInCtorInit(const CXXCtorInitializer *CI); /// Checks whether member is initialized with mismatching form of \c new by /// in-class initializer. MismatchResult analyzeInClassInitializer(); }; } MismatchingNewDeleteDetector::MismatchResult MismatchingNewDeleteDetector::analyzeDeleteExpr(const CXXDeleteExpr *DE) { NewExprs.clear(); assert(DE && "Expected delete-expression"); IsArrayForm = DE->isArrayForm(); const Expr *E = DE->getArgument()->IgnoreParenImpCasts(); if (const MemberExpr *ME = dyn_cast(E)) { return analyzeMemberExpr(ME); } else if (const DeclRefExpr *D = dyn_cast(E)) { if (!hasMatchingVarInit(D)) return VarInitMismatches; } return NoMismatch; } const CXXNewExpr * MismatchingNewDeleteDetector::getNewExprFromInitListOrExpr(const Expr *E) { assert(E != nullptr && "Expected a valid initializer expression"); E = E->IgnoreParenImpCasts(); if (const InitListExpr *ILE = dyn_cast(E)) { if (ILE->getNumInits() == 1) E = dyn_cast(ILE->getInit(0)->IgnoreParenImpCasts()); } return dyn_cast_or_null(E); } bool MismatchingNewDeleteDetector::hasMatchingNewInCtorInit( const CXXCtorInitializer *CI) { const CXXNewExpr *NE = nullptr; if (Field == CI->getMember() && (NE = getNewExprFromInitListOrExpr(CI->getInit()))) { if (NE->isArray() == IsArrayForm) return true; else NewExprs.push_back(NE); } return false; } bool MismatchingNewDeleteDetector::hasMatchingNewInCtor( const CXXConstructorDecl *CD) { if (CD->isImplicit()) return false; const FunctionDecl *Definition = CD; if (!CD->isThisDeclarationADefinition() && !CD->isDefined(Definition)) { HasUndefinedConstructors = true; return EndOfTU; } for (const auto *CI : cast(Definition)->inits()) { if (hasMatchingNewInCtorInit(CI)) return true; } return false; } MismatchingNewDeleteDetector::MismatchResult MismatchingNewDeleteDetector::analyzeInClassInitializer() { assert(Field != nullptr && "This should be called only for members"); const Expr *InitExpr = Field->getInClassInitializer(); if (!InitExpr) return EndOfTU ? NoMismatch : AnalyzeLater; if (const CXXNewExpr *NE = getNewExprFromInitListOrExpr(InitExpr)) { if (NE->isArray() != IsArrayForm) { NewExprs.push_back(NE); return MemberInitMismatches; } } return NoMismatch; } MismatchingNewDeleteDetector::MismatchResult MismatchingNewDeleteDetector::analyzeField(FieldDecl *Field, bool DeleteWasArrayForm) { assert(Field != nullptr && "Analysis requires a valid class member."); this->Field = Field; IsArrayForm = DeleteWasArrayForm; const CXXRecordDecl *RD = cast(Field->getParent()); for (const auto *CD : RD->ctors()) { if (hasMatchingNewInCtor(CD)) return NoMismatch; } if (HasUndefinedConstructors) return EndOfTU ? NoMismatch : AnalyzeLater; if (!NewExprs.empty()) return MemberInitMismatches; return Field->hasInClassInitializer() ? analyzeInClassInitializer() : NoMismatch; } MismatchingNewDeleteDetector::MismatchResult MismatchingNewDeleteDetector::analyzeMemberExpr(const MemberExpr *ME) { assert(ME != nullptr && "Expected a member expression"); if (FieldDecl *F = dyn_cast(ME->getMemberDecl())) return analyzeField(F, IsArrayForm); return NoMismatch; } bool MismatchingNewDeleteDetector::hasMatchingVarInit(const DeclRefExpr *D) { const CXXNewExpr *NE = nullptr; if (const VarDecl *VD = dyn_cast(D->getDecl())) { if (VD->hasInit() && (NE = getNewExprFromInitListOrExpr(VD->getInit())) && NE->isArray() != IsArrayForm) { NewExprs.push_back(NE); } } return NewExprs.empty(); } static void DiagnoseMismatchedNewDelete(Sema &SemaRef, SourceLocation DeleteLoc, const MismatchingNewDeleteDetector &Detector) { SourceLocation EndOfDelete = SemaRef.getLocForEndOfToken(DeleteLoc); FixItHint H; if (!Detector.IsArrayForm) H = FixItHint::CreateInsertion(EndOfDelete, "[]"); else { SourceLocation RSquare = Lexer::findLocationAfterToken( DeleteLoc, tok::l_square, SemaRef.getSourceManager(), SemaRef.getLangOpts(), true); if (RSquare.isValid()) H = FixItHint::CreateRemoval(SourceRange(EndOfDelete, RSquare)); } SemaRef.Diag(DeleteLoc, diag::warn_mismatched_delete_new) << Detector.IsArrayForm << H; for (const auto *NE : Detector.NewExprs) SemaRef.Diag(NE->getExprLoc(), diag::note_allocated_here) << Detector.IsArrayForm; } void Sema::AnalyzeDeleteExprMismatch(const CXXDeleteExpr *DE) { if (Diags.isIgnored(diag::warn_mismatched_delete_new, SourceLocation())) return; MismatchingNewDeleteDetector Detector(/*EndOfTU=*/false); switch (Detector.analyzeDeleteExpr(DE)) { case MismatchingNewDeleteDetector::VarInitMismatches: case MismatchingNewDeleteDetector::MemberInitMismatches: { DiagnoseMismatchedNewDelete(*this, DE->getBeginLoc(), Detector); break; } case MismatchingNewDeleteDetector::AnalyzeLater: { DeleteExprs[Detector.Field].push_back( std::make_pair(DE->getBeginLoc(), DE->isArrayForm())); break; } case MismatchingNewDeleteDetector::NoMismatch: break; } } void Sema::AnalyzeDeleteExprMismatch(FieldDecl *Field, SourceLocation DeleteLoc, bool DeleteWasArrayForm) { MismatchingNewDeleteDetector Detector(/*EndOfTU=*/true); switch (Detector.analyzeField(Field, DeleteWasArrayForm)) { case MismatchingNewDeleteDetector::VarInitMismatches: llvm_unreachable("This analysis should have been done for class members."); case MismatchingNewDeleteDetector::AnalyzeLater: llvm_unreachable("Analysis cannot be postponed any point beyond end of " "translation unit."); case MismatchingNewDeleteDetector::MemberInitMismatches: DiagnoseMismatchedNewDelete(*this, DeleteLoc, Detector); break; case MismatchingNewDeleteDetector::NoMismatch: break; } } /// ActOnCXXDelete - Parsed a C++ 'delete' expression (C++ 5.3.5), as in: /// @code ::delete ptr; @endcode /// or /// @code delete [] ptr; @endcode ExprResult Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, bool ArrayForm, Expr *ExE) { // C++ [expr.delete]p1: // The operand shall have a pointer type, or a class type having a single // non-explicit conversion function to a pointer type. The result has type // void. // // DR599 amends "pointer type" to "pointer to object type" in both cases. ExprResult Ex = ExE; FunctionDecl *OperatorDelete = nullptr; bool ArrayFormAsWritten = ArrayForm; bool UsualArrayDeleteWantsSize = false; if (!Ex.get()->isTypeDependent()) { // Perform lvalue-to-rvalue cast, if needed. Ex = DefaultLvalueConversion(Ex.get()); if (Ex.isInvalid()) return ExprError(); QualType Type = Ex.get()->getType(); class DeleteConverter : public ContextualImplicitConverter { public: DeleteConverter() : ContextualImplicitConverter(false, true) {} bool match(QualType ConvType) override { // FIXME: If we have an operator T* and an operator void*, we must pick // the operator T*. if (const PointerType *ConvPtrType = ConvType->getAs()) if (ConvPtrType->getPointeeType()->isIncompleteOrObjectType()) return true; return false; } SemaDiagnosticBuilder diagnoseNoMatch(Sema &S, SourceLocation Loc, QualType T) override { return S.Diag(Loc, diag::err_delete_operand) << T; } SemaDiagnosticBuilder diagnoseIncomplete(Sema &S, SourceLocation Loc, QualType T) override { return S.Diag(Loc, diag::err_delete_incomplete_class_type) << T; } SemaDiagnosticBuilder diagnoseExplicitConv(Sema &S, SourceLocation Loc, QualType T, QualType ConvTy) override { return S.Diag(Loc, diag::err_delete_explicit_conversion) << T << ConvTy; } SemaDiagnosticBuilder noteExplicitConv(Sema &S, CXXConversionDecl *Conv, QualType ConvTy) override { return S.Diag(Conv->getLocation(), diag::note_delete_conversion) << ConvTy; } SemaDiagnosticBuilder diagnoseAmbiguous(Sema &S, SourceLocation Loc, QualType T) override { return S.Diag(Loc, diag::err_ambiguous_delete_operand) << T; } SemaDiagnosticBuilder noteAmbiguous(Sema &S, CXXConversionDecl *Conv, QualType ConvTy) override { return S.Diag(Conv->getLocation(), diag::note_delete_conversion) << ConvTy; } SemaDiagnosticBuilder diagnoseConversion(Sema &S, SourceLocation Loc, QualType T, QualType ConvTy) override { llvm_unreachable("conversion functions are permitted"); } } Converter; Ex = PerformContextualImplicitConversion(StartLoc, Ex.get(), Converter); if (Ex.isInvalid()) return ExprError(); Type = Ex.get()->getType(); if (!Converter.match(Type)) // FIXME: PerformContextualImplicitConversion should return ExprError // itself in this case. return ExprError(); QualType Pointee = Type->castAs()->getPointeeType(); QualType PointeeElem = Context.getBaseElementType(Pointee); if (Pointee.getAddressSpace() != LangAS::Default && !getLangOpts().OpenCLCPlusPlus) return Diag(Ex.get()->getBeginLoc(), diag::err_address_space_qualified_delete) << Pointee.getUnqualifiedType() << Pointee.getQualifiers().getAddressSpaceAttributePrintValue(); CXXRecordDecl *PointeeRD = nullptr; if (Pointee->isVoidType() && !isSFINAEContext()) { // The C++ standard bans deleting a pointer to a non-object type, which // effectively bans deletion of "void*". However, most compilers support // this, so we treat it as a warning unless we're in a SFINAE context. Diag(StartLoc, diag::ext_delete_void_ptr_operand) << Type << Ex.get()->getSourceRange(); } else if (Pointee->isFunctionType() || Pointee->isVoidType()) { return ExprError(Diag(StartLoc, diag::err_delete_operand) << Type << Ex.get()->getSourceRange()); } else if (!Pointee->isDependentType()) { // FIXME: This can result in errors if the definition was imported from a // module but is hidden. if (!RequireCompleteType(StartLoc, Pointee, diag::warn_delete_incomplete, Ex.get())) { if (const RecordType *RT = PointeeElem->getAs()) PointeeRD = cast(RT->getDecl()); } } if (Pointee->isArrayType() && !ArrayForm) { Diag(StartLoc, diag::warn_delete_array_type) << Type << Ex.get()->getSourceRange() << FixItHint::CreateInsertion(getLocForEndOfToken(StartLoc), "[]"); ArrayForm = true; } DeclarationName DeleteName = Context.DeclarationNames.getCXXOperatorName( ArrayForm ? OO_Array_Delete : OO_Delete); if (PointeeRD) { if (!UseGlobal && FindDeallocationFunction(StartLoc, PointeeRD, DeleteName, OperatorDelete)) return ExprError(); // If we're allocating an array of records, check whether the // usual operator delete[] has a size_t parameter. if (ArrayForm) { // If the user specifically asked to use the global allocator, // we'll need to do the lookup into the class. if (UseGlobal) UsualArrayDeleteWantsSize = doesUsualArrayDeleteWantSize(*this, StartLoc, PointeeElem); // Otherwise, the usual operator delete[] should be the // function we just found. else if (OperatorDelete && isa(OperatorDelete)) UsualArrayDeleteWantsSize = UsualDeallocFnInfo(*this, DeclAccessPair::make(OperatorDelete, AS_public)) .HasSizeT; } if (!PointeeRD->hasIrrelevantDestructor()) if (CXXDestructorDecl *Dtor = LookupDestructor(PointeeRD)) { MarkFunctionReferenced(StartLoc, const_cast(Dtor)); if (DiagnoseUseOfDecl(Dtor, StartLoc)) return ExprError(); } CheckVirtualDtorCall(PointeeRD->getDestructor(), StartLoc, /*IsDelete=*/true, /*CallCanBeVirtual=*/true, /*WarnOnNonAbstractTypes=*/!ArrayForm, SourceLocation()); } if (!OperatorDelete) { if (getLangOpts().OpenCLCPlusPlus) { Diag(StartLoc, diag::err_openclcxx_not_supported) << "default delete"; return ExprError(); } bool IsComplete = isCompleteType(StartLoc, Pointee); bool CanProvideSize = IsComplete && (!ArrayForm || UsualArrayDeleteWantsSize || Pointee.isDestructedType()); bool Overaligned = hasNewExtendedAlignment(*this, Pointee); // Look for a global declaration. OperatorDelete = FindUsualDeallocationFunction(StartLoc, CanProvideSize, Overaligned, DeleteName); } MarkFunctionReferenced(StartLoc, OperatorDelete); // Check access and ambiguity of destructor if we're going to call it. // Note that this is required even for a virtual delete. bool IsVirtualDelete = false; if (PointeeRD) { if (CXXDestructorDecl *Dtor = LookupDestructor(PointeeRD)) { CheckDestructorAccess(Ex.get()->getExprLoc(), Dtor, PDiag(diag::err_access_dtor) << PointeeElem); IsVirtualDelete = Dtor->isVirtual(); } } DiagnoseUseOfDecl(OperatorDelete, StartLoc); // Convert the operand to the type of the first parameter of operator // delete. This is only necessary if we selected a destroying operator // delete that we are going to call (non-virtually); converting to void* // is trivial and left to AST consumers to handle. QualType ParamType = OperatorDelete->getParamDecl(0)->getType(); if (!IsVirtualDelete && !ParamType->getPointeeType()->isVoidType()) { Qualifiers Qs = Pointee.getQualifiers(); if (Qs.hasCVRQualifiers()) { // Qualifiers are irrelevant to this conversion; we're only looking // for access and ambiguity. Qs.removeCVRQualifiers(); QualType Unqual = Context.getPointerType( Context.getQualifiedType(Pointee.getUnqualifiedType(), Qs)); Ex = ImpCastExprToType(Ex.get(), Unqual, CK_NoOp); } Ex = PerformImplicitConversion(Ex.get(), ParamType, AA_Passing); if (Ex.isInvalid()) return ExprError(); } } CXXDeleteExpr *Result = new (Context) CXXDeleteExpr( Context.VoidTy, UseGlobal, ArrayForm, ArrayFormAsWritten, UsualArrayDeleteWantsSize, OperatorDelete, Ex.get(), StartLoc); AnalyzeDeleteExprMismatch(Result); return Result; } static bool resolveBuiltinNewDeleteOverload(Sema &S, CallExpr *TheCall, bool IsDelete, FunctionDecl *&Operator) { DeclarationName NewName = S.Context.DeclarationNames.getCXXOperatorName( IsDelete ? OO_Delete : OO_New); LookupResult R(S, NewName, TheCall->getBeginLoc(), Sema::LookupOrdinaryName); S.LookupQualifiedName(R, S.Context.getTranslationUnitDecl()); assert(!R.empty() && "implicitly declared allocation functions not found"); assert(!R.isAmbiguous() && "global allocation functions are ambiguous"); // We do our own custom access checks below. R.suppressDiagnostics(); SmallVector Args(TheCall->arg_begin(), TheCall->arg_end()); OverloadCandidateSet Candidates(R.getNameLoc(), OverloadCandidateSet::CSK_Normal); for (LookupResult::iterator FnOvl = R.begin(), FnOvlEnd = R.end(); FnOvl != FnOvlEnd; ++FnOvl) { // Even member operator new/delete are implicitly treated as // static, so don't use AddMemberCandidate. NamedDecl *D = (*FnOvl)->getUnderlyingDecl(); if (FunctionTemplateDecl *FnTemplate = dyn_cast(D)) { S.AddTemplateOverloadCandidate(FnTemplate, FnOvl.getPair(), /*ExplicitTemplateArgs=*/nullptr, Args, Candidates, /*SuppressUserConversions=*/false); continue; } FunctionDecl *Fn = cast(D); S.AddOverloadCandidate(Fn, FnOvl.getPair(), Args, Candidates, /*SuppressUserConversions=*/false); } SourceRange Range = TheCall->getSourceRange(); // Do the resolution. OverloadCandidateSet::iterator Best; switch (Candidates.BestViableFunction(S, R.getNameLoc(), Best)) { case OR_Success: { // Got one! FunctionDecl *FnDecl = Best->Function; assert(R.getNamingClass() == nullptr && "class members should not be considered"); if (!FnDecl->isReplaceableGlobalAllocationFunction()) { S.Diag(R.getNameLoc(), diag::err_builtin_operator_new_delete_not_usual) << (IsDelete ? 1 : 0) << Range; S.Diag(FnDecl->getLocation(), diag::note_non_usual_function_declared_here) << R.getLookupName() << FnDecl->getSourceRange(); return true; } Operator = FnDecl; return false; } case OR_No_Viable_Function: Candidates.NoteCandidates( PartialDiagnosticAt(R.getNameLoc(), S.PDiag(diag::err_ovl_no_viable_function_in_call) << R.getLookupName() << Range), S, OCD_AllCandidates, Args); return true; case OR_Ambiguous: Candidates.NoteCandidates( PartialDiagnosticAt(R.getNameLoc(), S.PDiag(diag::err_ovl_ambiguous_call) << R.getLookupName() << Range), S, OCD_AmbiguousCandidates, Args); return true; case OR_Deleted: { Candidates.NoteCandidates( PartialDiagnosticAt(R.getNameLoc(), S.PDiag(diag::err_ovl_deleted_call) << R.getLookupName() << Range), S, OCD_AllCandidates, Args); return true; } } llvm_unreachable("Unreachable, bad result from BestViableFunction"); } ExprResult Sema::SemaBuiltinOperatorNewDeleteOverloaded(ExprResult TheCallResult, bool IsDelete) { CallExpr *TheCall = cast(TheCallResult.get()); if (!getLangOpts().CPlusPlus) { Diag(TheCall->getExprLoc(), diag::err_builtin_requires_language) << (IsDelete ? "__builtin_operator_delete" : "__builtin_operator_new") << "C++"; return ExprError(); } // CodeGen assumes it can find the global new and delete to call, // so ensure that they are declared. DeclareGlobalNewDelete(); FunctionDecl *OperatorNewOrDelete = nullptr; if (resolveBuiltinNewDeleteOverload(*this, TheCall, IsDelete, OperatorNewOrDelete)) return ExprError(); assert(OperatorNewOrDelete && "should be found"); DiagnoseUseOfDecl(OperatorNewOrDelete, TheCall->getExprLoc()); MarkFunctionReferenced(TheCall->getExprLoc(), OperatorNewOrDelete); TheCall->setType(OperatorNewOrDelete->getReturnType()); for (unsigned i = 0; i != TheCall->getNumArgs(); ++i) { QualType ParamTy = OperatorNewOrDelete->getParamDecl(i)->getType(); InitializedEntity Entity = InitializedEntity::InitializeParameter(Context, ParamTy, false); ExprResult Arg = PerformCopyInitialization( Entity, TheCall->getArg(i)->getBeginLoc(), TheCall->getArg(i)); if (Arg.isInvalid()) return ExprError(); TheCall->setArg(i, Arg.get()); } auto Callee = dyn_cast(TheCall->getCallee()); assert(Callee && Callee->getCastKind() == CK_BuiltinFnToFnPtr && "Callee expected to be implicit cast to a builtin function pointer"); Callee->setType(OperatorNewOrDelete->getType()); return TheCallResult; } void Sema::CheckVirtualDtorCall(CXXDestructorDecl *dtor, SourceLocation Loc, bool IsDelete, bool CallCanBeVirtual, bool WarnOnNonAbstractTypes, SourceLocation DtorLoc) { if (!dtor || dtor->isVirtual() || !CallCanBeVirtual || isUnevaluatedContext()) return; // C++ [expr.delete]p3: // In the first alternative (delete object), if the static type of the // object to be deleted is different from its dynamic type, the static // type shall be a base class of the dynamic type of the object to be // deleted and the static type shall have a virtual destructor or the // behavior is undefined. // const CXXRecordDecl *PointeeRD = dtor->getParent(); // Note: a final class cannot be derived from, no issue there if (!PointeeRD->isPolymorphic() || PointeeRD->hasAttr()) return; // If the superclass is in a system header, there's nothing that can be done. // The `delete` (where we emit the warning) can be in a system header, // what matters for this warning is where the deleted type is defined. if (getSourceManager().isInSystemHeader(PointeeRD->getLocation())) return; QualType ClassType = dtor->getThisType()->getPointeeType(); if (PointeeRD->isAbstract()) { // If the class is abstract, we warn by default, because we're // sure the code has undefined behavior. Diag(Loc, diag::warn_delete_abstract_non_virtual_dtor) << (IsDelete ? 0 : 1) << ClassType; } else if (WarnOnNonAbstractTypes) { // Otherwise, if this is not an array delete, it's a bit suspect, // but not necessarily wrong. Diag(Loc, diag::warn_delete_non_virtual_dtor) << (IsDelete ? 0 : 1) << ClassType; } if (!IsDelete) { std::string TypeStr; ClassType.getAsStringInternal(TypeStr, getPrintingPolicy()); Diag(DtorLoc, diag::note_delete_non_virtual) << FixItHint::CreateInsertion(DtorLoc, TypeStr + "::"); } } Sema::ConditionResult Sema::ActOnConditionVariable(Decl *ConditionVar, SourceLocation StmtLoc, ConditionKind CK) { ExprResult E = CheckConditionVariable(cast(ConditionVar), StmtLoc, CK); if (E.isInvalid()) return ConditionError(); return ConditionResult(*this, ConditionVar, MakeFullExpr(E.get(), StmtLoc), CK == ConditionKind::ConstexprIf); } /// Check the use of the given variable as a C++ condition in an if, /// while, do-while, or switch statement. ExprResult Sema::CheckConditionVariable(VarDecl *ConditionVar, SourceLocation StmtLoc, ConditionKind CK) { if (ConditionVar->isInvalidDecl()) return ExprError(); QualType T = ConditionVar->getType(); // C++ [stmt.select]p2: // The declarator shall not specify a function or an array. if (T->isFunctionType()) return ExprError(Diag(ConditionVar->getLocation(), diag::err_invalid_use_of_function_type) << ConditionVar->getSourceRange()); else if (T->isArrayType()) return ExprError(Diag(ConditionVar->getLocation(), diag::err_invalid_use_of_array_type) << ConditionVar->getSourceRange()); ExprResult Condition = BuildDeclRefExpr( ConditionVar, ConditionVar->getType().getNonReferenceType(), VK_LValue, ConditionVar->getLocation()); switch (CK) { case ConditionKind::Boolean: return CheckBooleanCondition(StmtLoc, Condition.get()); case ConditionKind::ConstexprIf: return CheckBooleanCondition(StmtLoc, Condition.get(), true); case ConditionKind::Switch: return CheckSwitchCondition(StmtLoc, Condition.get()); } llvm_unreachable("unexpected condition kind"); } /// CheckCXXBooleanCondition - Returns true if a conversion to bool is invalid. ExprResult Sema::CheckCXXBooleanCondition(Expr *CondExpr, bool IsConstexpr) { // C++ 6.4p4: // The value of a condition that is an initialized declaration in a statement // other than a switch statement is the value of the declared variable // implicitly converted to type bool. If that conversion is ill-formed, the // program is ill-formed. // The value of a condition that is an expression is the value of the // expression, implicitly converted to bool. // // FIXME: Return this value to the caller so they don't need to recompute it. llvm::APSInt Value(/*BitWidth*/1); return (IsConstexpr && !CondExpr->isValueDependent()) ? CheckConvertedConstantExpression(CondExpr, Context.BoolTy, Value, CCEK_ConstexprIf) : PerformContextuallyConvertToBool(CondExpr); } /// Helper function to determine whether this is the (deprecated) C++ /// conversion from a string literal to a pointer to non-const char or /// non-const wchar_t (for narrow and wide string literals, /// respectively). bool Sema::IsStringLiteralToNonConstPointerConversion(Expr *From, QualType ToType) { // Look inside the implicit cast, if it exists. if (ImplicitCastExpr *Cast = dyn_cast(From)) From = Cast->getSubExpr(); // A string literal (2.13.4) that is not a wide string literal can // be converted to an rvalue of type "pointer to char"; a wide // string literal can be converted to an rvalue of type "pointer // to wchar_t" (C++ 4.2p2). if (StringLiteral *StrLit = dyn_cast(From->IgnoreParens())) if (const PointerType *ToPtrType = ToType->getAs()) if (const BuiltinType *ToPointeeType = ToPtrType->getPointeeType()->getAs()) { // This conversion is considered only when there is an // explicit appropriate pointer target type (C++ 4.2p2). if (!ToPtrType->getPointeeType().hasQualifiers()) { switch (StrLit->getKind()) { case StringLiteral::UTF8: case StringLiteral::UTF16: case StringLiteral::UTF32: // We don't allow UTF literals to be implicitly converted break; case StringLiteral::Ascii: return (ToPointeeType->getKind() == BuiltinType::Char_U || ToPointeeType->getKind() == BuiltinType::Char_S); case StringLiteral::Wide: return Context.typesAreCompatible(Context.getWideCharType(), QualType(ToPointeeType, 0)); } } } return false; } static ExprResult BuildCXXCastArgument(Sema &S, SourceLocation CastLoc, QualType Ty, CastKind Kind, CXXMethodDecl *Method, DeclAccessPair FoundDecl, bool HadMultipleCandidates, Expr *From) { switch (Kind) { default: llvm_unreachable("Unhandled cast kind!"); case CK_ConstructorConversion: { CXXConstructorDecl *Constructor = cast(Method); SmallVector ConstructorArgs; if (S.RequireNonAbstractType(CastLoc, Ty, diag::err_allocation_of_abstract_type)) return ExprError(); if (S.CompleteConstructorCall(Constructor, From, CastLoc, ConstructorArgs)) return ExprError(); S.CheckConstructorAccess(CastLoc, Constructor, FoundDecl, InitializedEntity::InitializeTemporary(Ty)); if (S.DiagnoseUseOfDecl(Method, CastLoc)) return ExprError(); ExprResult Result = S.BuildCXXConstructExpr( CastLoc, Ty, FoundDecl, cast(Method), ConstructorArgs, HadMultipleCandidates, /*ListInit*/ false, /*StdInitListInit*/ false, /*ZeroInit*/ false, CXXConstructExpr::CK_Complete, SourceRange()); if (Result.isInvalid()) return ExprError(); return S.MaybeBindToTemporary(Result.getAs()); } case CK_UserDefinedConversion: { assert(!From->getType()->isPointerType() && "Arg can't have pointer type!"); S.CheckMemberOperatorAccess(CastLoc, From, /*arg*/ nullptr, FoundDecl); if (S.DiagnoseUseOfDecl(Method, CastLoc)) return ExprError(); // Create an implicit call expr that calls it. CXXConversionDecl *Conv = cast(Method); ExprResult Result = S.BuildCXXMemberCallExpr(From, FoundDecl, Conv, HadMultipleCandidates); if (Result.isInvalid()) return ExprError(); // Record usage of conversion in an implicit cast. Result = ImplicitCastExpr::Create(S.Context, Result.get()->getType(), CK_UserDefinedConversion, Result.get(), nullptr, Result.get()->getValueKind()); return S.MaybeBindToTemporary(Result.get()); } } } /// PerformImplicitConversion - Perform an implicit conversion of the /// expression From to the type ToType using the pre-computed implicit /// conversion sequence ICS. Returns the converted /// expression. Action is the kind of conversion we're performing, /// used in the error message. ExprResult Sema::PerformImplicitConversion(Expr *From, QualType ToType, const ImplicitConversionSequence &ICS, AssignmentAction Action, CheckedConversionKind CCK) { // C++ [over.match.oper]p7: [...] operands of class type are converted [...] if (CCK == CCK_ForBuiltinOverloadedOp && !From->getType()->isRecordType()) return From; switch (ICS.getKind()) { case ImplicitConversionSequence::StandardConversion: { ExprResult Res = PerformImplicitConversion(From, ToType, ICS.Standard, Action, CCK); if (Res.isInvalid()) return ExprError(); From = Res.get(); break; } case ImplicitConversionSequence::UserDefinedConversion: { FunctionDecl *FD = ICS.UserDefined.ConversionFunction; CastKind CastKind; QualType BeforeToType; assert(FD && "no conversion function for user-defined conversion seq"); if (const CXXConversionDecl *Conv = dyn_cast(FD)) { CastKind = CK_UserDefinedConversion; // If the user-defined conversion is specified by a conversion function, // the initial standard conversion sequence converts the source type to // the implicit object parameter of the conversion function. BeforeToType = Context.getTagDeclType(Conv->getParent()); } else { const CXXConstructorDecl *Ctor = cast(FD); CastKind = CK_ConstructorConversion; // Do no conversion if dealing with ... for the first conversion. if (!ICS.UserDefined.EllipsisConversion) { // If the user-defined conversion is specified by a constructor, the // initial standard conversion sequence converts the source type to // the type required by the argument of the constructor BeforeToType = Ctor->getParamDecl(0)->getType().getNonReferenceType(); } } // Watch out for ellipsis conversion. if (!ICS.UserDefined.EllipsisConversion) { ExprResult Res = PerformImplicitConversion(From, BeforeToType, ICS.UserDefined.Before, AA_Converting, CCK); if (Res.isInvalid()) return ExprError(); From = Res.get(); } ExprResult CastArg = BuildCXXCastArgument( *this, From->getBeginLoc(), ToType.getNonReferenceType(), CastKind, cast(FD), ICS.UserDefined.FoundConversionFunction, ICS.UserDefined.HadMultipleCandidates, From); if (CastArg.isInvalid()) return ExprError(); From = CastArg.get(); // C++ [over.match.oper]p7: // [...] the second standard conversion sequence of a user-defined // conversion sequence is not applied. if (CCK == CCK_ForBuiltinOverloadedOp) return From; return PerformImplicitConversion(From, ToType, ICS.UserDefined.After, AA_Converting, CCK); } case ImplicitConversionSequence::AmbiguousConversion: ICS.DiagnoseAmbiguousConversion(*this, From->getExprLoc(), PDiag(diag::err_typecheck_ambiguous_condition) << From->getSourceRange()); return ExprError(); case ImplicitConversionSequence::EllipsisConversion: llvm_unreachable("Cannot perform an ellipsis conversion"); case ImplicitConversionSequence::BadConversion: bool Diagnosed = DiagnoseAssignmentResult(Incompatible, From->getExprLoc(), ToType, From->getType(), From, Action); assert(Diagnosed && "failed to diagnose bad conversion"); (void)Diagnosed; return ExprError(); } // Everything went well. return From; } /// PerformImplicitConversion - Perform an implicit conversion of the /// expression From to the type ToType by following the standard /// conversion sequence SCS. Returns the converted /// expression. Flavor is the context in which we're performing this /// conversion, for use in error messages. ExprResult Sema::PerformImplicitConversion(Expr *From, QualType ToType, const StandardConversionSequence& SCS, AssignmentAction Action, CheckedConversionKind CCK) { bool CStyle = (CCK == CCK_CStyleCast || CCK == CCK_FunctionalCast); // Overall FIXME: we are recomputing too many types here and doing far too // much extra work. What this means is that we need to keep track of more // information that is computed when we try the implicit conversion initially, // so that we don't need to recompute anything here. QualType FromType = From->getType(); if (SCS.CopyConstructor) { // FIXME: When can ToType be a reference type? assert(!ToType->isReferenceType()); if (SCS.Second == ICK_Derived_To_Base) { SmallVector ConstructorArgs; if (CompleteConstructorCall(cast(SCS.CopyConstructor), From, /*FIXME:ConstructLoc*/SourceLocation(), ConstructorArgs)) return ExprError(); return BuildCXXConstructExpr( /*FIXME:ConstructLoc*/ SourceLocation(), ToType, SCS.FoundCopyConstructor, SCS.CopyConstructor, ConstructorArgs, /*HadMultipleCandidates*/ false, /*ListInit*/ false, /*StdInitListInit*/ false, /*ZeroInit*/ false, CXXConstructExpr::CK_Complete, SourceRange()); } return BuildCXXConstructExpr( /*FIXME:ConstructLoc*/ SourceLocation(), ToType, SCS.FoundCopyConstructor, SCS.CopyConstructor, From, /*HadMultipleCandidates*/ false, /*ListInit*/ false, /*StdInitListInit*/ false, /*ZeroInit*/ false, CXXConstructExpr::CK_Complete, SourceRange()); } // Resolve overloaded function references. if (Context.hasSameType(FromType, Context.OverloadTy)) { DeclAccessPair Found; FunctionDecl *Fn = ResolveAddressOfOverloadedFunction(From, ToType, true, Found); if (!Fn) return ExprError(); if (DiagnoseUseOfDecl(Fn, From->getBeginLoc())) return ExprError(); From = FixOverloadedFunctionReference(From, Found, Fn); FromType = From->getType(); } // If we're converting to an atomic type, first convert to the corresponding // non-atomic type. QualType ToAtomicType; if (const AtomicType *ToAtomic = ToType->getAs()) { ToAtomicType = ToType; ToType = ToAtomic->getValueType(); } QualType InitialFromType = FromType; // Perform the first implicit conversion. switch (SCS.First) { case ICK_Identity: if (const AtomicType *FromAtomic = FromType->getAs()) { FromType = FromAtomic->getValueType().getUnqualifiedType(); From = ImplicitCastExpr::Create(Context, FromType, CK_AtomicToNonAtomic, From, /*BasePath=*/nullptr, VK_RValue); } break; case ICK_Lvalue_To_Rvalue: { assert(From->getObjectKind() != OK_ObjCProperty); ExprResult FromRes = DefaultLvalueConversion(From); assert(!FromRes.isInvalid() && "Can't perform deduced conversion?!"); From = FromRes.get(); FromType = From->getType(); break; } case ICK_Array_To_Pointer: FromType = Context.getArrayDecayedType(FromType); From = ImpCastExprToType(From, FromType, CK_ArrayToPointerDecay, VK_RValue, /*BasePath=*/nullptr, CCK).get(); break; case ICK_Function_To_Pointer: FromType = Context.getPointerType(FromType); From = ImpCastExprToType(From, FromType, CK_FunctionToPointerDecay, VK_RValue, /*BasePath=*/nullptr, CCK).get(); break; default: llvm_unreachable("Improper first standard conversion"); } // Perform the second implicit conversion switch (SCS.Second) { case ICK_Identity: // C++ [except.spec]p5: // [For] assignment to and initialization of pointers to functions, // pointers to member functions, and references to functions: the // target entity shall allow at least the exceptions allowed by the // source value in the assignment or initialization. switch (Action) { case AA_Assigning: case AA_Initializing: // Note, function argument passing and returning are initialization. case AA_Passing: case AA_Returning: case AA_Sending: case AA_Passing_CFAudited: if (CheckExceptionSpecCompatibility(From, ToType)) return ExprError(); break; case AA_Casting: case AA_Converting: // Casts and implicit conversions are not initialization, so are not // checked for exception specification mismatches. break; } // Nothing else to do. break; case ICK_Integral_Promotion: case ICK_Integral_Conversion: if (ToType->isBooleanType()) { assert(FromType->castAs()->getDecl()->isFixed() && SCS.Second == ICK_Integral_Promotion && "only enums with fixed underlying type can promote to bool"); From = ImpCastExprToType(From, ToType, CK_IntegralToBoolean, VK_RValue, /*BasePath=*/nullptr, CCK).get(); } else { From = ImpCastExprToType(From, ToType, CK_IntegralCast, VK_RValue, /*BasePath=*/nullptr, CCK).get(); } break; case ICK_Floating_Promotion: case ICK_Floating_Conversion: From = ImpCastExprToType(From, ToType, CK_FloatingCast, VK_RValue, /*BasePath=*/nullptr, CCK).get(); break; case ICK_Complex_Promotion: case ICK_Complex_Conversion: { QualType FromEl = From->getType()->castAs()->getElementType(); QualType ToEl = ToType->castAs()->getElementType(); CastKind CK; if (FromEl->isRealFloatingType()) { if (ToEl->isRealFloatingType()) CK = CK_FloatingComplexCast; else CK = CK_FloatingComplexToIntegralComplex; } else if (ToEl->isRealFloatingType()) { CK = CK_IntegralComplexToFloatingComplex; } else { CK = CK_IntegralComplexCast; } From = ImpCastExprToType(From, ToType, CK, VK_RValue, /*BasePath=*/nullptr, CCK).get(); break; } case ICK_Floating_Integral: if (ToType->isRealFloatingType()) From = ImpCastExprToType(From, ToType, CK_IntegralToFloating, VK_RValue, /*BasePath=*/nullptr, CCK).get(); else From = ImpCastExprToType(From, ToType, CK_FloatingToIntegral, VK_RValue, /*BasePath=*/nullptr, CCK).get(); break; case ICK_Compatible_Conversion: From = ImpCastExprToType(From, ToType, CK_NoOp, VK_RValue, /*BasePath=*/nullptr, CCK).get(); break; case ICK_Writeback_Conversion: case ICK_Pointer_Conversion: { if (SCS.IncompatibleObjC && Action != AA_Casting) { // Diagnose incompatible Objective-C conversions if (Action == AA_Initializing || Action == AA_Assigning) Diag(From->getBeginLoc(), diag::ext_typecheck_convert_incompatible_pointer) << ToType << From->getType() << Action << From->getSourceRange() << 0; else Diag(From->getBeginLoc(), diag::ext_typecheck_convert_incompatible_pointer) << From->getType() << ToType << Action << From->getSourceRange() << 0; if (From->getType()->isObjCObjectPointerType() && ToType->isObjCObjectPointerType()) EmitRelatedResultTypeNote(From); } else if (getLangOpts().allowsNonTrivialObjCLifetimeQualifiers() && !CheckObjCARCUnavailableWeakConversion(ToType, From->getType())) { if (Action == AA_Initializing) Diag(From->getBeginLoc(), diag::err_arc_weak_unavailable_assign); else Diag(From->getBeginLoc(), diag::err_arc_convesion_of_weak_unavailable) << (Action == AA_Casting) << From->getType() << ToType << From->getSourceRange(); } // Defer address space conversion to the third conversion. QualType FromPteeType = From->getType()->getPointeeType(); QualType ToPteeType = ToType->getPointeeType(); QualType NewToType = ToType; if (!FromPteeType.isNull() && !ToPteeType.isNull() && FromPteeType.getAddressSpace() != ToPteeType.getAddressSpace()) { NewToType = Context.removeAddrSpaceQualType(ToPteeType); NewToType = Context.getAddrSpaceQualType(NewToType, FromPteeType.getAddressSpace()); if (ToType->isObjCObjectPointerType()) NewToType = Context.getObjCObjectPointerType(NewToType); else if (ToType->isBlockPointerType()) NewToType = Context.getBlockPointerType(NewToType); else NewToType = Context.getPointerType(NewToType); } CastKind Kind; CXXCastPath BasePath; if (CheckPointerConversion(From, NewToType, Kind, BasePath, CStyle)) return ExprError(); // Make sure we extend blocks if necessary. // FIXME: doing this here is really ugly. if (Kind == CK_BlockPointerToObjCPointerCast) { ExprResult E = From; (void) PrepareCastToObjCObjectPointer(E); From = E.get(); } if (getLangOpts().allowsNonTrivialObjCLifetimeQualifiers()) CheckObjCConversion(SourceRange(), NewToType, From, CCK); From = ImpCastExprToType(From, NewToType, Kind, VK_RValue, &BasePath, CCK) .get(); break; } case ICK_Pointer_Member: { CastKind Kind; CXXCastPath BasePath; if (CheckMemberPointerConversion(From, ToType, Kind, BasePath, CStyle)) return ExprError(); if (CheckExceptionSpecCompatibility(From, ToType)) return ExprError(); // We may not have been able to figure out what this member pointer resolved // to up until this exact point. Attempt to lock-in it's inheritance model. if (Context.getTargetInfo().getCXXABI().isMicrosoft()) { (void)isCompleteType(From->getExprLoc(), From->getType()); (void)isCompleteType(From->getExprLoc(), ToType); } From = ImpCastExprToType(From, ToType, Kind, VK_RValue, &BasePath, CCK) .get(); break; } case ICK_Boolean_Conversion: // Perform half-to-boolean conversion via float. if (From->getType()->isHalfType()) { From = ImpCastExprToType(From, Context.FloatTy, CK_FloatingCast).get(); FromType = Context.FloatTy; } From = ImpCastExprToType(From, Context.BoolTy, ScalarTypeToBooleanCastKind(FromType), VK_RValue, /*BasePath=*/nullptr, CCK).get(); break; case ICK_Derived_To_Base: { CXXCastPath BasePath; if (CheckDerivedToBaseConversion( From->getType(), ToType.getNonReferenceType(), From->getBeginLoc(), From->getSourceRange(), &BasePath, CStyle)) return ExprError(); From = ImpCastExprToType(From, ToType.getNonReferenceType(), CK_DerivedToBase, From->getValueKind(), &BasePath, CCK).get(); break; } case ICK_Vector_Conversion: From = ImpCastExprToType(From, ToType, CK_BitCast, VK_RValue, /*BasePath=*/nullptr, CCK).get(); break; case ICK_Vector_Splat: { // Vector splat from any arithmetic type to a vector. Expr *Elem = prepareVectorSplat(ToType, From).get(); From = ImpCastExprToType(Elem, ToType, CK_VectorSplat, VK_RValue, /*BasePath=*/nullptr, CCK).get(); break; } case ICK_Complex_Real: // Case 1. x -> _Complex y if (const ComplexType *ToComplex = ToType->getAs()) { QualType ElType = ToComplex->getElementType(); bool isFloatingComplex = ElType->isRealFloatingType(); // x -> y if (Context.hasSameUnqualifiedType(ElType, From->getType())) { // do nothing } else if (From->getType()->isRealFloatingType()) { From = ImpCastExprToType(From, ElType, isFloatingComplex ? CK_FloatingCast : CK_FloatingToIntegral).get(); } else { assert(From->getType()->isIntegerType()); From = ImpCastExprToType(From, ElType, isFloatingComplex ? CK_IntegralToFloating : CK_IntegralCast).get(); } // y -> _Complex y From = ImpCastExprToType(From, ToType, isFloatingComplex ? CK_FloatingRealToComplex : CK_IntegralRealToComplex).get(); // Case 2. _Complex x -> y } else { const ComplexType *FromComplex = From->getType()->getAs(); assert(FromComplex); QualType ElType = FromComplex->getElementType(); bool isFloatingComplex = ElType->isRealFloatingType(); // _Complex x -> x From = ImpCastExprToType(From, ElType, isFloatingComplex ? CK_FloatingComplexToReal : CK_IntegralComplexToReal, VK_RValue, /*BasePath=*/nullptr, CCK).get(); // x -> y if (Context.hasSameUnqualifiedType(ElType, ToType)) { // do nothing } else if (ToType->isRealFloatingType()) { From = ImpCastExprToType(From, ToType, isFloatingComplex ? CK_FloatingCast : CK_IntegralToFloating, VK_RValue, /*BasePath=*/nullptr, CCK).get(); } else { assert(ToType->isIntegerType()); From = ImpCastExprToType(From, ToType, isFloatingComplex ? CK_FloatingToIntegral : CK_IntegralCast, VK_RValue, /*BasePath=*/nullptr, CCK).get(); } } break; case ICK_Block_Pointer_Conversion: { LangAS AddrSpaceL = ToType->castAs()->getPointeeType().getAddressSpace(); LangAS AddrSpaceR = FromType->castAs()->getPointeeType().getAddressSpace(); assert(Qualifiers::isAddressSpaceSupersetOf(AddrSpaceL, AddrSpaceR) && "Invalid cast"); CastKind Kind = AddrSpaceL != AddrSpaceR ? CK_AddressSpaceConversion : CK_BitCast; From = ImpCastExprToType(From, ToType.getUnqualifiedType(), Kind, VK_RValue, /*BasePath=*/nullptr, CCK).get(); break; } case ICK_TransparentUnionConversion: { ExprResult FromRes = From; Sema::AssignConvertType ConvTy = CheckTransparentUnionArgumentConstraints(ToType, FromRes); if (FromRes.isInvalid()) return ExprError(); From = FromRes.get(); assert ((ConvTy == Sema::Compatible) && "Improper transparent union conversion"); (void)ConvTy; break; } case ICK_Zero_Event_Conversion: case ICK_Zero_Queue_Conversion: From = ImpCastExprToType(From, ToType, CK_ZeroToOCLOpaqueType, From->getValueKind()).get(); break; case ICK_Lvalue_To_Rvalue: case ICK_Array_To_Pointer: case ICK_Function_To_Pointer: case ICK_Function_Conversion: case ICK_Qualification: case ICK_Num_Conversion_Kinds: case ICK_C_Only_Conversion: case ICK_Incompatible_Pointer_Conversion: llvm_unreachable("Improper second standard conversion"); } switch (SCS.Third) { case ICK_Identity: // Nothing to do. break; case ICK_Function_Conversion: // If both sides are functions (or pointers/references to them), there could // be incompatible exception declarations. if (CheckExceptionSpecCompatibility(From, ToType)) return ExprError(); From = ImpCastExprToType(From, ToType, CK_NoOp, VK_RValue, /*BasePath=*/nullptr, CCK).get(); break; case ICK_Qualification: { // The qualification keeps the category of the inner expression, unless the // target type isn't a reference. ExprValueKind VK = ToType->isReferenceType() ? From->getValueKind() : VK_RValue; CastKind CK = CK_NoOp; if (ToType->isReferenceType() && ToType->getPointeeType().getAddressSpace() != From->getType().getAddressSpace()) CK = CK_AddressSpaceConversion; if (ToType->isPointerType() && ToType->getPointeeType().getAddressSpace() != From->getType()->getPointeeType().getAddressSpace()) CK = CK_AddressSpaceConversion; From = ImpCastExprToType(From, ToType.getNonLValueExprType(Context), CK, VK, /*BasePath=*/nullptr, CCK) .get(); if (SCS.DeprecatedStringLiteralToCharPtr && !getLangOpts().WritableStrings) { Diag(From->getBeginLoc(), getLangOpts().CPlusPlus11 ? diag::ext_deprecated_string_literal_conversion : diag::warn_deprecated_string_literal_conversion) << ToType.getNonReferenceType(); } break; } default: llvm_unreachable("Improper third standard conversion"); } // If this conversion sequence involved a scalar -> atomic conversion, perform // that conversion now. if (!ToAtomicType.isNull()) { assert(Context.hasSameType( ToAtomicType->castAs()->getValueType(), From->getType())); From = ImpCastExprToType(From, ToAtomicType, CK_NonAtomicToAtomic, VK_RValue, nullptr, CCK).get(); } // If this conversion sequence succeeded and involved implicitly converting a // _Nullable type to a _Nonnull one, complain. if (!isCast(CCK)) diagnoseNullableToNonnullConversion(ToType, InitialFromType, From->getBeginLoc()); return From; } /// Check the completeness of a type in a unary type trait. /// /// If the particular type trait requires a complete type, tries to complete /// it. If completing the type fails, a diagnostic is emitted and false /// returned. If completing the type succeeds or no completion was required, /// returns true. static bool CheckUnaryTypeTraitTypeCompleteness(Sema &S, TypeTrait UTT, SourceLocation Loc, QualType ArgTy) { // C++0x [meta.unary.prop]p3: // For all of the class templates X declared in this Clause, instantiating // that template with a template argument that is a class template // specialization may result in the implicit instantiation of the template // argument if and only if the semantics of X require that the argument // must be a complete type. // We apply this rule to all the type trait expressions used to implement // these class templates. We also try to follow any GCC documented behavior // in these expressions to ensure portability of standard libraries. switch (UTT) { default: llvm_unreachable("not a UTT"); // is_complete_type somewhat obviously cannot require a complete type. case UTT_IsCompleteType: // Fall-through // These traits are modeled on the type predicates in C++0x // [meta.unary.cat] and [meta.unary.comp]. They are not specified as // requiring a complete type, as whether or not they return true cannot be // impacted by the completeness of the type. case UTT_IsVoid: case UTT_IsIntegral: case UTT_IsFloatingPoint: case UTT_IsArray: case UTT_IsPointer: case UTT_IsLvalueReference: case UTT_IsRvalueReference: case UTT_IsMemberFunctionPointer: case UTT_IsMemberObjectPointer: case UTT_IsEnum: case UTT_IsUnion: case UTT_IsClass: case UTT_IsFunction: case UTT_IsReference: case UTT_IsArithmetic: case UTT_IsFundamental: case UTT_IsObject: case UTT_IsScalar: case UTT_IsCompound: case UTT_IsMemberPointer: // Fall-through // These traits are modeled on type predicates in C++0x [meta.unary.prop] // which requires some of its traits to have the complete type. However, // the completeness of the type cannot impact these traits' semantics, and // so they don't require it. This matches the comments on these traits in // Table 49. case UTT_IsConst: case UTT_IsVolatile: case UTT_IsSigned: case UTT_IsUnsigned: // This type trait always returns false, checking the type is moot. case UTT_IsInterfaceClass: return true; // C++14 [meta.unary.prop]: // If T is a non-union class type, T shall be a complete type. case UTT_IsEmpty: case UTT_IsPolymorphic: case UTT_IsAbstract: if (const auto *RD = ArgTy->getAsCXXRecordDecl()) if (!RD->isUnion()) return !S.RequireCompleteType( Loc, ArgTy, diag::err_incomplete_type_used_in_type_trait_expr); return true; // C++14 [meta.unary.prop]: // If T is a class type, T shall be a complete type. case UTT_IsFinal: case UTT_IsSealed: if (ArgTy->getAsCXXRecordDecl()) return !S.RequireCompleteType( Loc, ArgTy, diag::err_incomplete_type_used_in_type_trait_expr); return true; // C++1z [meta.unary.prop]: // remove_all_extents_t shall be a complete type or cv void. case UTT_IsAggregate: case UTT_IsTrivial: case UTT_IsTriviallyCopyable: case UTT_IsStandardLayout: case UTT_IsPOD: case UTT_IsLiteral: // Per the GCC type traits documentation, T shall be a complete type, cv void, // or an array of unknown bound. But GCC actually imposes the same constraints // as above. case UTT_HasNothrowAssign: case UTT_HasNothrowMoveAssign: case UTT_HasNothrowConstructor: case UTT_HasNothrowCopy: case UTT_HasTrivialAssign: case UTT_HasTrivialMoveAssign: case UTT_HasTrivialDefaultConstructor: case UTT_HasTrivialMoveConstructor: case UTT_HasTrivialCopy: case UTT_HasTrivialDestructor: case UTT_HasVirtualDestructor: ArgTy = QualType(ArgTy->getBaseElementTypeUnsafe(), 0); LLVM_FALLTHROUGH; // C++1z [meta.unary.prop]: // T shall be a complete type, cv void, or an array of unknown bound. case UTT_IsDestructible: case UTT_IsNothrowDestructible: case UTT_IsTriviallyDestructible: case UTT_HasUniqueObjectRepresentations: if (ArgTy->isIncompleteArrayType() || ArgTy->isVoidType()) return true; return !S.RequireCompleteType( Loc, ArgTy, diag::err_incomplete_type_used_in_type_trait_expr); } } static bool HasNoThrowOperator(const RecordType *RT, OverloadedOperatorKind Op, Sema &Self, SourceLocation KeyLoc, ASTContext &C, bool (CXXRecordDecl::*HasTrivial)() const, bool (CXXRecordDecl::*HasNonTrivial)() const, bool (CXXMethodDecl::*IsDesiredOp)() const) { CXXRecordDecl *RD = cast(RT->getDecl()); if ((RD->*HasTrivial)() && !(RD->*HasNonTrivial)()) return true; DeclarationName Name = C.DeclarationNames.getCXXOperatorName(Op); DeclarationNameInfo NameInfo(Name, KeyLoc); LookupResult Res(Self, NameInfo, Sema::LookupOrdinaryName); if (Self.LookupQualifiedName(Res, RD)) { bool FoundOperator = false; Res.suppressDiagnostics(); for (LookupResult::iterator Op = Res.begin(), OpEnd = Res.end(); Op != OpEnd; ++Op) { if (isa(*Op)) continue; CXXMethodDecl *Operator = cast(*Op); if((Operator->*IsDesiredOp)()) { FoundOperator = true; const FunctionProtoType *CPT = Operator->getType()->getAs(); CPT = Self.ResolveExceptionSpec(KeyLoc, CPT); if (!CPT || !CPT->isNothrow()) return false; } } return FoundOperator; } return false; } static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT, SourceLocation KeyLoc, QualType T) { assert(!T->isDependentType() && "Cannot evaluate traits of dependent type"); ASTContext &C = Self.Context; switch(UTT) { default: llvm_unreachable("not a UTT"); // Type trait expressions corresponding to the primary type category // predicates in C++0x [meta.unary.cat]. case UTT_IsVoid: return T->isVoidType(); case UTT_IsIntegral: return T->isIntegralType(C); case UTT_IsFloatingPoint: return T->isFloatingType(); case UTT_IsArray: return T->isArrayType(); case UTT_IsPointer: return T->isPointerType(); case UTT_IsLvalueReference: return T->isLValueReferenceType(); case UTT_IsRvalueReference: return T->isRValueReferenceType(); case UTT_IsMemberFunctionPointer: return T->isMemberFunctionPointerType(); case UTT_IsMemberObjectPointer: return T->isMemberDataPointerType(); case UTT_IsEnum: return T->isEnumeralType(); case UTT_IsUnion: return T->isUnionType(); case UTT_IsClass: return T->isClassType() || T->isStructureType() || T->isInterfaceType(); case UTT_IsFunction: return T->isFunctionType(); // Type trait expressions which correspond to the convenient composition // predicates in C++0x [meta.unary.comp]. case UTT_IsReference: return T->isReferenceType(); case UTT_IsArithmetic: return T->isArithmeticType() && !T->isEnumeralType(); case UTT_IsFundamental: return T->isFundamentalType(); case UTT_IsObject: return T->isObjectType(); case UTT_IsScalar: // Note: semantic analysis depends on Objective-C lifetime types to be // considered scalar types. However, such types do not actually behave // like scalar types at run time (since they may require retain/release // operations), so we report them as non-scalar. if (T->isObjCLifetimeType()) { switch (T.getObjCLifetime()) { case Qualifiers::OCL_None: case Qualifiers::OCL_ExplicitNone: return true; case Qualifiers::OCL_Strong: case Qualifiers::OCL_Weak: case Qualifiers::OCL_Autoreleasing: return false; } } return T->isScalarType(); case UTT_IsCompound: return T->isCompoundType(); case UTT_IsMemberPointer: return T->isMemberPointerType(); // Type trait expressions which correspond to the type property predicates // in C++0x [meta.unary.prop]. case UTT_IsConst: return T.isConstQualified(); case UTT_IsVolatile: return T.isVolatileQualified(); case UTT_IsTrivial: return T.isTrivialType(C); case UTT_IsTriviallyCopyable: return T.isTriviallyCopyableType(C); case UTT_IsStandardLayout: return T->isStandardLayoutType(); case UTT_IsPOD: return T.isPODType(C); case UTT_IsLiteral: return T->isLiteralType(C); case UTT_IsEmpty: if (const CXXRecordDecl *RD = T->getAsCXXRecordDecl()) return !RD->isUnion() && RD->isEmpty(); return false; case UTT_IsPolymorphic: if (const CXXRecordDecl *RD = T->getAsCXXRecordDecl()) return !RD->isUnion() && RD->isPolymorphic(); return false; case UTT_IsAbstract: if (const CXXRecordDecl *RD = T->getAsCXXRecordDecl()) return !RD->isUnion() && RD->isAbstract(); return false; case UTT_IsAggregate: // Report vector extensions and complex types as aggregates because they // support aggregate initialization. GCC mirrors this behavior for vectors // but not _Complex. return T->isAggregateType() || T->isVectorType() || T->isExtVectorType() || T->isAnyComplexType(); // __is_interface_class only returns true when CL is invoked in /CLR mode and // even then only when it is used with the 'interface struct ...' syntax // Clang doesn't support /CLR which makes this type trait moot. case UTT_IsInterfaceClass: return false; case UTT_IsFinal: case UTT_IsSealed: if (const CXXRecordDecl *RD = T->getAsCXXRecordDecl()) return RD->hasAttr(); return false; case UTT_IsSigned: // Enum types should always return false. // Floating points should always return true. return !T->isEnumeralType() && (T->isFloatingType() || T->isSignedIntegerType()); case UTT_IsUnsigned: return T->isUnsignedIntegerType(); // Type trait expressions which query classes regarding their construction, // destruction, and copying. Rather than being based directly on the // related type predicates in the standard, they are specified by both // GCC[1] and the Embarcadero C++ compiler[2], and Clang implements those // specifications. // // 1: http://gcc.gnu/.org/onlinedocs/gcc/Type-Traits.html // 2: http://docwiki.embarcadero.com/RADStudio/XE/en/Type_Trait_Functions_(C%2B%2B0x)_Index // // Note that these builtins do not behave as documented in g++: if a class // has both a trivial and a non-trivial special member of a particular kind, // they return false! For now, we emulate this behavior. // FIXME: This appears to be a g++ bug: more complex cases reveal that it // does not correctly compute triviality in the presence of multiple special // members of the same kind. Revisit this once the g++ bug is fixed. case UTT_HasTrivialDefaultConstructor: // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html: // If __is_pod (type) is true then the trait is true, else if type is // a cv class or union type (or array thereof) with a trivial default // constructor ([class.ctor]) then the trait is true, else it is false. if (T.isPODType(C)) return true; if (CXXRecordDecl *RD = C.getBaseElementType(T)->getAsCXXRecordDecl()) return RD->hasTrivialDefaultConstructor() && !RD->hasNonTrivialDefaultConstructor(); return false; case UTT_HasTrivialMoveConstructor: // This trait is implemented by MSVC 2012 and needed to parse the // standard library headers. Specifically this is used as the logic // behind std::is_trivially_move_constructible (20.9.4.3). if (T.isPODType(C)) return true; if (CXXRecordDecl *RD = C.getBaseElementType(T)->getAsCXXRecordDecl()) return RD->hasTrivialMoveConstructor() && !RD->hasNonTrivialMoveConstructor(); return false; case UTT_HasTrivialCopy: // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html: // If __is_pod (type) is true or type is a reference type then // the trait is true, else if type is a cv class or union type // with a trivial copy constructor ([class.copy]) then the trait // is true, else it is false. if (T.isPODType(C) || T->isReferenceType()) return true; if (CXXRecordDecl *RD = T->getAsCXXRecordDecl()) return RD->hasTrivialCopyConstructor() && !RD->hasNonTrivialCopyConstructor(); return false; case UTT_HasTrivialMoveAssign: // This trait is implemented by MSVC 2012 and needed to parse the // standard library headers. Specifically it is used as the logic // behind std::is_trivially_move_assignable (20.9.4.3) if (T.isPODType(C)) return true; if (CXXRecordDecl *RD = C.getBaseElementType(T)->getAsCXXRecordDecl()) return RD->hasTrivialMoveAssignment() && !RD->hasNonTrivialMoveAssignment(); return false; case UTT_HasTrivialAssign: // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html: // If type is const qualified or is a reference type then the // trait is false. Otherwise if __is_pod (type) is true then the // trait is true, else if type is a cv class or union type with // a trivial copy assignment ([class.copy]) then the trait is // true, else it is false. // Note: the const and reference restrictions are interesting, // given that const and reference members don't prevent a class // from having a trivial copy assignment operator (but do cause // errors if the copy assignment operator is actually used, q.v. // [class.copy]p12). if (T.isConstQualified()) return false; if (T.isPODType(C)) return true; if (CXXRecordDecl *RD = T->getAsCXXRecordDecl()) return RD->hasTrivialCopyAssignment() && !RD->hasNonTrivialCopyAssignment(); return false; case UTT_IsDestructible: case UTT_IsTriviallyDestructible: case UTT_IsNothrowDestructible: // C++14 [meta.unary.prop]: // For reference types, is_destructible::value is true. if (T->isReferenceType()) return true; // Objective-C++ ARC: autorelease types don't require destruction. if (T->isObjCLifetimeType() && T.getObjCLifetime() == Qualifiers::OCL_Autoreleasing) return true; // C++14 [meta.unary.prop]: // For incomplete types and function types, is_destructible::value is // false. if (T->isIncompleteType() || T->isFunctionType()) return false; // A type that requires destruction (via a non-trivial destructor or ARC // lifetime semantics) is not trivially-destructible. if (UTT == UTT_IsTriviallyDestructible && T.isDestructedType()) return false; // C++14 [meta.unary.prop]: // For object types and given U equal to remove_all_extents_t, if the // expression std::declval().~U() is well-formed when treated as an // unevaluated operand (Clause 5), then is_destructible::value is true if (auto *RD = C.getBaseElementType(T)->getAsCXXRecordDecl()) { CXXDestructorDecl *Destructor = Self.LookupDestructor(RD); if (!Destructor) return false; // C++14 [dcl.fct.def.delete]p2: // A program that refers to a deleted function implicitly or // explicitly, other than to declare it, is ill-formed. if (Destructor->isDeleted()) return false; if (C.getLangOpts().AccessControl && Destructor->getAccess() != AS_public) return false; if (UTT == UTT_IsNothrowDestructible) { const FunctionProtoType *CPT = Destructor->getType()->getAs(); CPT = Self.ResolveExceptionSpec(KeyLoc, CPT); if (!CPT || !CPT->isNothrow()) return false; } } return true; case UTT_HasTrivialDestructor: // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html // If __is_pod (type) is true or type is a reference type // then the trait is true, else if type is a cv class or union // type (or array thereof) with a trivial destructor // ([class.dtor]) then the trait is true, else it is // false. if (T.isPODType(C) || T->isReferenceType()) return true; // Objective-C++ ARC: autorelease types don't require destruction. if (T->isObjCLifetimeType() && T.getObjCLifetime() == Qualifiers::OCL_Autoreleasing) return true; if (CXXRecordDecl *RD = C.getBaseElementType(T)->getAsCXXRecordDecl()) return RD->hasTrivialDestructor(); return false; // TODO: Propagate nothrowness for implicitly declared special members. case UTT_HasNothrowAssign: // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html: // If type is const qualified or is a reference type then the // trait is false. Otherwise if __has_trivial_assign (type) // is true then the trait is true, else if type is a cv class // or union type with copy assignment operators that are known // not to throw an exception then the trait is true, else it is // false. if (C.getBaseElementType(T).isConstQualified()) return false; if (T->isReferenceType()) return false; if (T.isPODType(C) || T->isObjCLifetimeType()) return true; if (const RecordType *RT = T->getAs()) return HasNoThrowOperator(RT, OO_Equal, Self, KeyLoc, C, &CXXRecordDecl::hasTrivialCopyAssignment, &CXXRecordDecl::hasNonTrivialCopyAssignment, &CXXMethodDecl::isCopyAssignmentOperator); return false; case UTT_HasNothrowMoveAssign: // This trait is implemented by MSVC 2012 and needed to parse the // standard library headers. Specifically this is used as the logic // behind std::is_nothrow_move_assignable (20.9.4.3). if (T.isPODType(C)) return true; if (const RecordType *RT = C.getBaseElementType(T)->getAs()) return HasNoThrowOperator(RT, OO_Equal, Self, KeyLoc, C, &CXXRecordDecl::hasTrivialMoveAssignment, &CXXRecordDecl::hasNonTrivialMoveAssignment, &CXXMethodDecl::isMoveAssignmentOperator); return false; case UTT_HasNothrowCopy: // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html: // If __has_trivial_copy (type) is true then the trait is true, else // if type is a cv class or union type with copy constructors that are // known not to throw an exception then the trait is true, else it is // false. if (T.isPODType(C) || T->isReferenceType() || T->isObjCLifetimeType()) return true; if (CXXRecordDecl *RD = T->getAsCXXRecordDecl()) { if (RD->hasTrivialCopyConstructor() && !RD->hasNonTrivialCopyConstructor()) return true; bool FoundConstructor = false; unsigned FoundTQs; for (const auto *ND : Self.LookupConstructors(RD)) { // A template constructor is never a copy constructor. // FIXME: However, it may actually be selected at the actual overload // resolution point. if (isa(ND->getUnderlyingDecl())) continue; // UsingDecl itself is not a constructor if (isa(ND)) continue; auto *Constructor = cast(ND->getUnderlyingDecl()); if (Constructor->isCopyConstructor(FoundTQs)) { FoundConstructor = true; const FunctionProtoType *CPT = Constructor->getType()->getAs(); CPT = Self.ResolveExceptionSpec(KeyLoc, CPT); if (!CPT) return false; // TODO: check whether evaluating default arguments can throw. // For now, we'll be conservative and assume that they can throw. if (!CPT->isNothrow() || CPT->getNumParams() > 1) return false; } } return FoundConstructor; } return false; case UTT_HasNothrowConstructor: // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html // If __has_trivial_constructor (type) is true then the trait is // true, else if type is a cv class or union type (or array // thereof) with a default constructor that is known not to // throw an exception then the trait is true, else it is false. if (T.isPODType(C) || T->isObjCLifetimeType()) return true; if (CXXRecordDecl *RD = C.getBaseElementType(T)->getAsCXXRecordDecl()) { if (RD->hasTrivialDefaultConstructor() && !RD->hasNonTrivialDefaultConstructor()) return true; bool FoundConstructor = false; for (const auto *ND : Self.LookupConstructors(RD)) { // FIXME: In C++0x, a constructor template can be a default constructor. if (isa(ND->getUnderlyingDecl())) continue; // UsingDecl itself is not a constructor if (isa(ND)) continue; auto *Constructor = cast(ND->getUnderlyingDecl()); if (Constructor->isDefaultConstructor()) { FoundConstructor = true; const FunctionProtoType *CPT = Constructor->getType()->getAs(); CPT = Self.ResolveExceptionSpec(KeyLoc, CPT); if (!CPT) return false; // FIXME: check whether evaluating default arguments can throw. // For now, we'll be conservative and assume that they can throw. if (!CPT->isNothrow() || CPT->getNumParams() > 0) return false; } } return FoundConstructor; } return false; case UTT_HasVirtualDestructor: // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html: // If type is a class type with a virtual destructor ([class.dtor]) // then the trait is true, else it is false. if (CXXRecordDecl *RD = T->getAsCXXRecordDecl()) if (CXXDestructorDecl *Destructor = Self.LookupDestructor(RD)) return Destructor->isVirtual(); return false; // These type trait expressions are modeled on the specifications for the // Embarcadero C++0x type trait functions: // http://docwiki.embarcadero.com/RADStudio/XE/en/Type_Trait_Functions_(C%2B%2B0x)_Index case UTT_IsCompleteType: // http://docwiki.embarcadero.com/RADStudio/XE/en/Is_complete_type_(typename_T_): // Returns True if and only if T is a complete type at the point of the // function call. return !T->isIncompleteType(); case UTT_HasUniqueObjectRepresentations: return C.hasUniqueObjectRepresentations(T); } } static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, QualType LhsT, QualType RhsT, SourceLocation KeyLoc); static bool evaluateTypeTrait(Sema &S, TypeTrait Kind, SourceLocation KWLoc, ArrayRef Args, SourceLocation RParenLoc) { if (Kind <= UTT_Last) return EvaluateUnaryTypeTrait(S, Kind, KWLoc, Args[0]->getType()); // Evaluate BTT_ReferenceBindsToTemporary alongside the IsConstructible // traits to avoid duplication. if (Kind <= BTT_Last && Kind != BTT_ReferenceBindsToTemporary) return EvaluateBinaryTypeTrait(S, Kind, Args[0]->getType(), Args[1]->getType(), RParenLoc); switch (Kind) { case clang::BTT_ReferenceBindsToTemporary: case clang::TT_IsConstructible: case clang::TT_IsNothrowConstructible: case clang::TT_IsTriviallyConstructible: { // C++11 [meta.unary.prop]: // is_trivially_constructible is defined as: // // is_constructible::value is true and the variable // definition for is_constructible, as defined below, is known to call // no operation that is not trivial. // // The predicate condition for a template specialization // is_constructible shall be satisfied if and only if the // following variable definition would be well-formed for some invented // variable t: // // T t(create()...); assert(!Args.empty()); // Precondition: T and all types in the parameter pack Args shall be // complete types, (possibly cv-qualified) void, or arrays of // unknown bound. for (const auto *TSI : Args) { QualType ArgTy = TSI->getType(); if (ArgTy->isVoidType() || ArgTy->isIncompleteArrayType()) continue; if (S.RequireCompleteType(KWLoc, ArgTy, diag::err_incomplete_type_used_in_type_trait_expr)) return false; } // Make sure the first argument is not incomplete nor a function type. QualType T = Args[0]->getType(); if (T->isIncompleteType() || T->isFunctionType()) return false; // Make sure the first argument is not an abstract type. CXXRecordDecl *RD = T->getAsCXXRecordDecl(); if (RD && RD->isAbstract()) return false; SmallVector OpaqueArgExprs; SmallVector ArgExprs; ArgExprs.reserve(Args.size() - 1); for (unsigned I = 1, N = Args.size(); I != N; ++I) { QualType ArgTy = Args[I]->getType(); if (ArgTy->isObjectType() || ArgTy->isFunctionType()) ArgTy = S.Context.getRValueReferenceType(ArgTy); OpaqueArgExprs.push_back( OpaqueValueExpr(Args[I]->getTypeLoc().getBeginLoc(), ArgTy.getNonLValueExprType(S.Context), Expr::getValueKindForType(ArgTy))); } for (Expr &E : OpaqueArgExprs) ArgExprs.push_back(&E); // Perform the initialization in an unevaluated context within a SFINAE // trap at translation unit scope. EnterExpressionEvaluationContext Unevaluated( S, Sema::ExpressionEvaluationContext::Unevaluated); Sema::SFINAETrap SFINAE(S, /*AccessCheckingSFINAE=*/true); Sema::ContextRAII TUContext(S, S.Context.getTranslationUnitDecl()); InitializedEntity To(InitializedEntity::InitializeTemporary(Args[0])); InitializationKind InitKind(InitializationKind::CreateDirect(KWLoc, KWLoc, RParenLoc)); InitializationSequence Init(S, To, InitKind, ArgExprs); if (Init.Failed()) return false; ExprResult Result = Init.Perform(S, To, InitKind, ArgExprs); if (Result.isInvalid() || SFINAE.hasErrorOccurred()) return false; if (Kind == clang::TT_IsConstructible) return true; if (Kind == clang::BTT_ReferenceBindsToTemporary) { if (!T->isReferenceType()) return false; return !Init.isDirectReferenceBinding(); } if (Kind == clang::TT_IsNothrowConstructible) return S.canThrow(Result.get()) == CT_Cannot; if (Kind == clang::TT_IsTriviallyConstructible) { // Under Objective-C ARC and Weak, if the destination has non-trivial // Objective-C lifetime, this is a non-trivial construction. if (T.getNonReferenceType().hasNonTrivialObjCLifetime()) return false; // The initialization succeeded; now make sure there are no non-trivial // calls. return !Result.get()->hasNonTrivialCall(S.Context); } llvm_unreachable("unhandled type trait"); return false; } default: llvm_unreachable("not a TT"); } return false; } ExprResult Sema::BuildTypeTrait(TypeTrait Kind, SourceLocation KWLoc, ArrayRef Args, SourceLocation RParenLoc) { QualType ResultType = Context.getLogicalOperationType(); if (Kind <= UTT_Last && !CheckUnaryTypeTraitTypeCompleteness( *this, Kind, KWLoc, Args[0]->getType())) return ExprError(); bool Dependent = false; for (unsigned I = 0, N = Args.size(); I != N; ++I) { if (Args[I]->getType()->isDependentType()) { Dependent = true; break; } } bool Result = false; if (!Dependent) Result = evaluateTypeTrait(*this, Kind, KWLoc, Args, RParenLoc); return TypeTraitExpr::Create(Context, ResultType, KWLoc, Kind, Args, RParenLoc, Result); } ExprResult Sema::ActOnTypeTrait(TypeTrait Kind, SourceLocation KWLoc, ArrayRef Args, SourceLocation RParenLoc) { SmallVector ConvertedArgs; ConvertedArgs.reserve(Args.size()); for (unsigned I = 0, N = Args.size(); I != N; ++I) { TypeSourceInfo *TInfo; QualType T = GetTypeFromParser(Args[I], &TInfo); if (!TInfo) TInfo = Context.getTrivialTypeSourceInfo(T, KWLoc); ConvertedArgs.push_back(TInfo); } return BuildTypeTrait(Kind, KWLoc, ConvertedArgs, RParenLoc); } static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, QualType LhsT, QualType RhsT, SourceLocation KeyLoc) { assert(!LhsT->isDependentType() && !RhsT->isDependentType() && "Cannot evaluate traits of dependent types"); switch(BTT) { case BTT_IsBaseOf: { // C++0x [meta.rel]p2 // Base is a base class of Derived without regard to cv-qualifiers or // Base and Derived are not unions and name the same class type without // regard to cv-qualifiers. const RecordType *lhsRecord = LhsT->getAs(); const RecordType *rhsRecord = RhsT->getAs(); if (!rhsRecord || !lhsRecord) { const ObjCObjectType *LHSObjTy = LhsT->getAs(); const ObjCObjectType *RHSObjTy = RhsT->getAs(); if (!LHSObjTy || !RHSObjTy) return false; ObjCInterfaceDecl *BaseInterface = LHSObjTy->getInterface(); ObjCInterfaceDecl *DerivedInterface = RHSObjTy->getInterface(); if (!BaseInterface || !DerivedInterface) return false; if (Self.RequireCompleteType( KeyLoc, RhsT, diag::err_incomplete_type_used_in_type_trait_expr)) return false; return BaseInterface->isSuperClassOf(DerivedInterface); } assert(Self.Context.hasSameUnqualifiedType(LhsT, RhsT) == (lhsRecord == rhsRecord)); // Unions are never base classes, and never have base classes. // It doesn't matter if they are complete or not. See PR#41843 if (lhsRecord && lhsRecord->getDecl()->isUnion()) return false; if (rhsRecord && rhsRecord->getDecl()->isUnion()) return false; if (lhsRecord == rhsRecord) return true; // C++0x [meta.rel]p2: // If Base and Derived are class types and are different types // (ignoring possible cv-qualifiers) then Derived shall be a // complete type. if (Self.RequireCompleteType(KeyLoc, RhsT, diag::err_incomplete_type_used_in_type_trait_expr)) return false; return cast(rhsRecord->getDecl()) ->isDerivedFrom(cast(lhsRecord->getDecl())); } case BTT_IsSame: return Self.Context.hasSameType(LhsT, RhsT); case BTT_TypeCompatible: { // GCC ignores cv-qualifiers on arrays for this builtin. Qualifiers LhsQuals, RhsQuals; QualType Lhs = Self.getASTContext().getUnqualifiedArrayType(LhsT, LhsQuals); QualType Rhs = Self.getASTContext().getUnqualifiedArrayType(RhsT, RhsQuals); return Self.Context.typesAreCompatible(Lhs, Rhs); } case BTT_IsConvertible: case BTT_IsConvertibleTo: { // C++0x [meta.rel]p4: // Given the following function prototype: // // template // typename add_rvalue_reference::type create(); // // the predicate condition for a template specialization // is_convertible shall be satisfied if and only if // the return expression in the following code would be // well-formed, including any implicit conversions to the return // type of the function: // // To test() { // return create(); // } // // Access checking is performed as if in a context unrelated to To and // From. Only the validity of the immediate context of the expression // of the return-statement (including conversions to the return type) // is considered. // // We model the initialization as a copy-initialization of a temporary // of the appropriate type, which for this expression is identical to the // return statement (since NRVO doesn't apply). // Functions aren't allowed to return function or array types. if (RhsT->isFunctionType() || RhsT->isArrayType()) return false; // A return statement in a void function must have void type. if (RhsT->isVoidType()) return LhsT->isVoidType(); // A function definition requires a complete, non-abstract return type. if (!Self.isCompleteType(KeyLoc, RhsT) || Self.isAbstractType(KeyLoc, RhsT)) return false; // Compute the result of add_rvalue_reference. if (LhsT->isObjectType() || LhsT->isFunctionType()) LhsT = Self.Context.getRValueReferenceType(LhsT); // Build a fake source and destination for initialization. InitializedEntity To(InitializedEntity::InitializeTemporary(RhsT)); OpaqueValueExpr From(KeyLoc, LhsT.getNonLValueExprType(Self.Context), Expr::getValueKindForType(LhsT)); Expr *FromPtr = &From; InitializationKind Kind(InitializationKind::CreateCopy(KeyLoc, SourceLocation())); // Perform the initialization in an unevaluated context within a SFINAE // trap at translation unit scope. EnterExpressionEvaluationContext Unevaluated( Self, Sema::ExpressionEvaluationContext::Unevaluated); Sema::SFINAETrap SFINAE(Self, /*AccessCheckingSFINAE=*/true); Sema::ContextRAII TUContext(Self, Self.Context.getTranslationUnitDecl()); InitializationSequence Init(Self, To, Kind, FromPtr); if (Init.Failed()) return false; ExprResult Result = Init.Perform(Self, To, Kind, FromPtr); return !Result.isInvalid() && !SFINAE.hasErrorOccurred(); } case BTT_IsAssignable: case BTT_IsNothrowAssignable: case BTT_IsTriviallyAssignable: { // C++11 [meta.unary.prop]p3: // is_trivially_assignable is defined as: // is_assignable::value is true and the assignment, as defined by // is_assignable, is known to call no operation that is not trivial // // is_assignable is defined as: // The expression declval() = declval() is well-formed when // treated as an unevaluated operand (Clause 5). // // For both, T and U shall be complete types, (possibly cv-qualified) // void, or arrays of unknown bound. if (!LhsT->isVoidType() && !LhsT->isIncompleteArrayType() && Self.RequireCompleteType(KeyLoc, LhsT, diag::err_incomplete_type_used_in_type_trait_expr)) return false; if (!RhsT->isVoidType() && !RhsT->isIncompleteArrayType() && Self.RequireCompleteType(KeyLoc, RhsT, diag::err_incomplete_type_used_in_type_trait_expr)) return false; // cv void is never assignable. if (LhsT->isVoidType() || RhsT->isVoidType()) return false; // Build expressions that emulate the effect of declval() and // declval(). if (LhsT->isObjectType() || LhsT->isFunctionType()) LhsT = Self.Context.getRValueReferenceType(LhsT); if (RhsT->isObjectType() || RhsT->isFunctionType()) RhsT = Self.Context.getRValueReferenceType(RhsT); OpaqueValueExpr Lhs(KeyLoc, LhsT.getNonLValueExprType(Self.Context), Expr::getValueKindForType(LhsT)); OpaqueValueExpr Rhs(KeyLoc, RhsT.getNonLValueExprType(Self.Context), Expr::getValueKindForType(RhsT)); // Attempt the assignment in an unevaluated context within a SFINAE // trap at translation unit scope. EnterExpressionEvaluationContext Unevaluated( Self, Sema::ExpressionEvaluationContext::Unevaluated); Sema::SFINAETrap SFINAE(Self, /*AccessCheckingSFINAE=*/true); Sema::ContextRAII TUContext(Self, Self.Context.getTranslationUnitDecl()); ExprResult Result = Self.BuildBinOp(/*S=*/nullptr, KeyLoc, BO_Assign, &Lhs, &Rhs); if (Result.isInvalid()) return false; // Treat the assignment as unused for the purpose of -Wdeprecated-volatile. Self.CheckUnusedVolatileAssignment(Result.get()); if (SFINAE.hasErrorOccurred()) return false; if (BTT == BTT_IsAssignable) return true; if (BTT == BTT_IsNothrowAssignable) return Self.canThrow(Result.get()) == CT_Cannot; if (BTT == BTT_IsTriviallyAssignable) { // Under Objective-C ARC and Weak, if the destination has non-trivial // Objective-C lifetime, this is a non-trivial assignment. if (LhsT.getNonReferenceType().hasNonTrivialObjCLifetime()) return false; return !Result.get()->hasNonTrivialCall(Self.Context); } llvm_unreachable("unhandled type trait"); return false; } default: llvm_unreachable("not a BTT"); } llvm_unreachable("Unknown type trait or not implemented"); } ExprResult Sema::ActOnArrayTypeTrait(ArrayTypeTrait ATT, SourceLocation KWLoc, ParsedType Ty, Expr* DimExpr, SourceLocation RParen) { TypeSourceInfo *TSInfo; QualType T = GetTypeFromParser(Ty, &TSInfo); if (!TSInfo) TSInfo = Context.getTrivialTypeSourceInfo(T); return BuildArrayTypeTrait(ATT, KWLoc, TSInfo, DimExpr, RParen); } static uint64_t EvaluateArrayTypeTrait(Sema &Self, ArrayTypeTrait ATT, QualType T, Expr *DimExpr, SourceLocation KeyLoc) { assert(!T->isDependentType() && "Cannot evaluate traits of dependent type"); switch(ATT) { case ATT_ArrayRank: if (T->isArrayType()) { unsigned Dim = 0; while (const ArrayType *AT = Self.Context.getAsArrayType(T)) { ++Dim; T = AT->getElementType(); } return Dim; } return 0; case ATT_ArrayExtent: { llvm::APSInt Value; uint64_t Dim; if (Self.VerifyIntegerConstantExpression(DimExpr, &Value, diag::err_dimension_expr_not_constant_integer, false).isInvalid()) return 0; if (Value.isSigned() && Value.isNegative()) { Self.Diag(KeyLoc, diag::err_dimension_expr_not_constant_integer) << DimExpr->getSourceRange(); return 0; } Dim = Value.getLimitedValue(); if (T->isArrayType()) { unsigned D = 0; bool Matched = false; while (const ArrayType *AT = Self.Context.getAsArrayType(T)) { if (Dim == D) { Matched = true; break; } ++D; T = AT->getElementType(); } if (Matched && T->isArrayType()) { if (const ConstantArrayType *CAT = Self.Context.getAsConstantArrayType(T)) return CAT->getSize().getLimitedValue(); } } return 0; } } llvm_unreachable("Unknown type trait or not implemented"); } ExprResult Sema::BuildArrayTypeTrait(ArrayTypeTrait ATT, SourceLocation KWLoc, TypeSourceInfo *TSInfo, Expr* DimExpr, SourceLocation RParen) { QualType T = TSInfo->getType(); // FIXME: This should likely be tracked as an APInt to remove any host // assumptions about the width of size_t on the target. uint64_t Value = 0; if (!T->isDependentType()) Value = EvaluateArrayTypeTrait(*this, ATT, T, DimExpr, KWLoc); // While the specification for these traits from the Embarcadero C++ // compiler's documentation says the return type is 'unsigned int', Clang // returns 'size_t'. On Windows, the primary platform for the Embarcadero // compiler, there is no difference. On several other platforms this is an // important distinction. return new (Context) ArrayTypeTraitExpr(KWLoc, ATT, TSInfo, Value, DimExpr, RParen, Context.getSizeType()); } ExprResult Sema::ActOnExpressionTrait(ExpressionTrait ET, SourceLocation KWLoc, Expr *Queried, SourceLocation RParen) { // If error parsing the expression, ignore. if (!Queried) return ExprError(); ExprResult Result = BuildExpressionTrait(ET, KWLoc, Queried, RParen); return Result; } static bool EvaluateExpressionTrait(ExpressionTrait ET, Expr *E) { switch (ET) { case ET_IsLValueExpr: return E->isLValue(); case ET_IsRValueExpr: return E->isRValue(); } llvm_unreachable("Expression trait not covered by switch"); } ExprResult Sema::BuildExpressionTrait(ExpressionTrait ET, SourceLocation KWLoc, Expr *Queried, SourceLocation RParen) { if (Queried->isTypeDependent()) { // Delay type-checking for type-dependent expressions. } else if (Queried->getType()->isPlaceholderType()) { ExprResult PE = CheckPlaceholderExpr(Queried); if (PE.isInvalid()) return ExprError(); return BuildExpressionTrait(ET, KWLoc, PE.get(), RParen); } bool Value = EvaluateExpressionTrait(ET, Queried); return new (Context) ExpressionTraitExpr(KWLoc, ET, Queried, Value, RParen, Context.BoolTy); } QualType Sema::CheckPointerToMemberOperands(ExprResult &LHS, ExprResult &RHS, ExprValueKind &VK, SourceLocation Loc, bool isIndirect) { assert(!LHS.get()->getType()->isPlaceholderType() && !RHS.get()->getType()->isPlaceholderType() && "placeholders should have been weeded out by now"); // The LHS undergoes lvalue conversions if this is ->*, and undergoes the // temporary materialization conversion otherwise. if (isIndirect) LHS = DefaultLvalueConversion(LHS.get()); else if (LHS.get()->isRValue()) LHS = TemporaryMaterializationConversion(LHS.get()); if (LHS.isInvalid()) return QualType(); // The RHS always undergoes lvalue conversions. RHS = DefaultLvalueConversion(RHS.get()); if (RHS.isInvalid()) return QualType(); const char *OpSpelling = isIndirect ? "->*" : ".*"; // C++ 5.5p2 // The binary operator .* [p3: ->*] binds its second operand, which shall // be of type "pointer to member of T" (where T is a completely-defined // class type) [...] QualType RHSType = RHS.get()->getType(); const MemberPointerType *MemPtr = RHSType->getAs(); if (!MemPtr) { Diag(Loc, diag::err_bad_memptr_rhs) << OpSpelling << RHSType << RHS.get()->getSourceRange(); return QualType(); } QualType Class(MemPtr->getClass(), 0); // Note: C++ [expr.mptr.oper]p2-3 says that the class type into which the // member pointer points must be completely-defined. However, there is no // reason for this semantic distinction, and the rule is not enforced by // other compilers. Therefore, we do not check this property, as it is // likely to be considered a defect. // C++ 5.5p2 // [...] to its first operand, which shall be of class T or of a class of // which T is an unambiguous and accessible base class. [p3: a pointer to // such a class] QualType LHSType = LHS.get()->getType(); if (isIndirect) { if (const PointerType *Ptr = LHSType->getAs()) LHSType = Ptr->getPointeeType(); else { Diag(Loc, diag::err_bad_memptr_lhs) << OpSpelling << 1 << LHSType << FixItHint::CreateReplacement(SourceRange(Loc), ".*"); return QualType(); } } if (!Context.hasSameUnqualifiedType(Class, LHSType)) { // If we want to check the hierarchy, we need a complete type. if (RequireCompleteType(Loc, LHSType, diag::err_bad_memptr_lhs, OpSpelling, (int)isIndirect)) { return QualType(); } if (!IsDerivedFrom(Loc, LHSType, Class)) { Diag(Loc, diag::err_bad_memptr_lhs) << OpSpelling << (int)isIndirect << LHS.get()->getType(); return QualType(); } CXXCastPath BasePath; if (CheckDerivedToBaseConversion( LHSType, Class, Loc, SourceRange(LHS.get()->getBeginLoc(), RHS.get()->getEndLoc()), &BasePath)) return QualType(); // Cast LHS to type of use. QualType UseType = Context.getQualifiedType(Class, LHSType.getQualifiers()); if (isIndirect) UseType = Context.getPointerType(UseType); ExprValueKind VK = isIndirect ? VK_RValue : LHS.get()->getValueKind(); LHS = ImpCastExprToType(LHS.get(), UseType, CK_DerivedToBase, VK, &BasePath); } if (isa(RHS.get()->IgnoreParens())) { // Diagnose use of pointer-to-member type which when used as // the functional cast in a pointer-to-member expression. Diag(Loc, diag::err_pointer_to_member_type) << isIndirect; return QualType(); } // C++ 5.5p2 // The result is an object or a function of the type specified by the // second operand. // The cv qualifiers are the union of those in the pointer and the left side, // in accordance with 5.5p5 and 5.2.5. QualType Result = MemPtr->getPointeeType(); Result = Context.getCVRQualifiedType(Result, LHSType.getCVRQualifiers()); // C++0x [expr.mptr.oper]p6: // In a .* expression whose object expression is an rvalue, the program is // ill-formed if the second operand is a pointer to member function with // ref-qualifier &. In a ->* expression or in a .* expression whose object // expression is an lvalue, the program is ill-formed if the second operand // is a pointer to member function with ref-qualifier &&. if (const FunctionProtoType *Proto = Result->getAs()) { switch (Proto->getRefQualifier()) { case RQ_None: // Do nothing break; case RQ_LValue: if (!isIndirect && !LHS.get()->Classify(Context).isLValue()) { // C++2a allows functions with ref-qualifier & if their cv-qualifier-seq // is (exactly) 'const'. if (Proto->isConst() && !Proto->isVolatile()) Diag(Loc, getLangOpts().CPlusPlus2a ? diag::warn_cxx17_compat_pointer_to_const_ref_member_on_rvalue : diag::ext_pointer_to_const_ref_member_on_rvalue); else Diag(Loc, diag::err_pointer_to_member_oper_value_classify) << RHSType << 1 << LHS.get()->getSourceRange(); } break; case RQ_RValue: if (isIndirect || !LHS.get()->Classify(Context).isRValue()) Diag(Loc, diag::err_pointer_to_member_oper_value_classify) << RHSType << 0 << LHS.get()->getSourceRange(); break; } } // C++ [expr.mptr.oper]p6: // The result of a .* expression whose second operand is a pointer // to a data member is of the same value category as its // first operand. The result of a .* expression whose second // operand is a pointer to a member function is a prvalue. The // result of an ->* expression is an lvalue if its second operand // is a pointer to data member and a prvalue otherwise. if (Result->isFunctionType()) { VK = VK_RValue; return Context.BoundMemberTy; } else if (isIndirect) { VK = VK_LValue; } else { VK = LHS.get()->getValueKind(); } return Result; } /// Try to convert a type to another according to C++11 5.16p3. /// /// This is part of the parameter validation for the ? operator. If either /// value operand is a class type, the two operands are attempted to be /// converted to each other. This function does the conversion in one direction. /// It returns true if the program is ill-formed and has already been diagnosed /// as such. static bool TryClassUnification(Sema &Self, Expr *From, Expr *To, SourceLocation QuestionLoc, bool &HaveConversion, QualType &ToType) { HaveConversion = false; ToType = To->getType(); InitializationKind Kind = InitializationKind::CreateCopy(To->getBeginLoc(), SourceLocation()); // C++11 5.16p3 // The process for determining whether an operand expression E1 of type T1 // can be converted to match an operand expression E2 of type T2 is defined // as follows: // -- If E2 is an lvalue: E1 can be converted to match E2 if E1 can be // implicitly converted to type "lvalue reference to T2", subject to the // constraint that in the conversion the reference must bind directly to // an lvalue. // -- If E2 is an xvalue: E1 can be converted to match E2 if E1 can be // implicitly converted to the type "rvalue reference to R2", subject to // the constraint that the reference must bind directly. if (To->isLValue() || To->isXValue()) { QualType T = To->isLValue() ? Self.Context.getLValueReferenceType(ToType) : Self.Context.getRValueReferenceType(ToType); InitializedEntity Entity = InitializedEntity::InitializeTemporary(T); InitializationSequence InitSeq(Self, Entity, Kind, From); if (InitSeq.isDirectReferenceBinding()) { ToType = T; HaveConversion = true; return false; } if (InitSeq.isAmbiguous()) return InitSeq.Diagnose(Self, Entity, Kind, From); } // -- If E2 is an rvalue, or if the conversion above cannot be done: // -- if E1 and E2 have class type, and the underlying class types are // the same or one is a base class of the other: QualType FTy = From->getType(); QualType TTy = To->getType(); const RecordType *FRec = FTy->getAs(); const RecordType *TRec = TTy->getAs(); bool FDerivedFromT = FRec && TRec && FRec != TRec && Self.IsDerivedFrom(QuestionLoc, FTy, TTy); if (FRec && TRec && (FRec == TRec || FDerivedFromT || Self.IsDerivedFrom(QuestionLoc, TTy, FTy))) { // E1 can be converted to match E2 if the class of T2 is the // same type as, or a base class of, the class of T1, and // [cv2 > cv1]. if (FRec == TRec || FDerivedFromT) { if (TTy.isAtLeastAsQualifiedAs(FTy)) { InitializedEntity Entity = InitializedEntity::InitializeTemporary(TTy); InitializationSequence InitSeq(Self, Entity, Kind, From); if (InitSeq) { HaveConversion = true; return false; } if (InitSeq.isAmbiguous()) return InitSeq.Diagnose(Self, Entity, Kind, From); } } return false; } // -- Otherwise: E1 can be converted to match E2 if E1 can be // implicitly converted to the type that expression E2 would have // if E2 were converted to an rvalue (or the type it has, if E2 is // an rvalue). // // This actually refers very narrowly to the lvalue-to-rvalue conversion, not // to the array-to-pointer or function-to-pointer conversions. TTy = TTy.getNonLValueExprType(Self.Context); InitializedEntity Entity = InitializedEntity::InitializeTemporary(TTy); InitializationSequence InitSeq(Self, Entity, Kind, From); HaveConversion = !InitSeq.Failed(); ToType = TTy; if (InitSeq.isAmbiguous()) return InitSeq.Diagnose(Self, Entity, Kind, From); return false; } /// Try to find a common type for two according to C++0x 5.16p5. /// /// This is part of the parameter validation for the ? operator. If either /// value operand is a class type, overload resolution is used to find a /// conversion to a common type. static bool FindConditionalOverload(Sema &Self, ExprResult &LHS, ExprResult &RHS, SourceLocation QuestionLoc) { Expr *Args[2] = { LHS.get(), RHS.get() }; OverloadCandidateSet CandidateSet(QuestionLoc, OverloadCandidateSet::CSK_Operator); Self.AddBuiltinOperatorCandidates(OO_Conditional, QuestionLoc, Args, CandidateSet); OverloadCandidateSet::iterator Best; switch (CandidateSet.BestViableFunction(Self, QuestionLoc, Best)) { case OR_Success: { // We found a match. Perform the conversions on the arguments and move on. ExprResult LHSRes = Self.PerformImplicitConversion( LHS.get(), Best->BuiltinParamTypes[0], Best->Conversions[0], Sema::AA_Converting); if (LHSRes.isInvalid()) break; LHS = LHSRes; ExprResult RHSRes = Self.PerformImplicitConversion( RHS.get(), Best->BuiltinParamTypes[1], Best->Conversions[1], Sema::AA_Converting); if (RHSRes.isInvalid()) break; RHS = RHSRes; if (Best->Function) Self.MarkFunctionReferenced(QuestionLoc, Best->Function); return false; } case OR_No_Viable_Function: // Emit a better diagnostic if one of the expressions is a null pointer // constant and the other is a pointer type. In this case, the user most // likely forgot to take the address of the other expression. if (Self.DiagnoseConditionalForNull(LHS.get(), RHS.get(), QuestionLoc)) return true; Self.Diag(QuestionLoc, diag::err_typecheck_cond_incompatible_operands) << LHS.get()->getType() << RHS.get()->getType() << LHS.get()->getSourceRange() << RHS.get()->getSourceRange(); return true; case OR_Ambiguous: Self.Diag(QuestionLoc, diag::err_conditional_ambiguous_ovl) << LHS.get()->getType() << RHS.get()->getType() << LHS.get()->getSourceRange() << RHS.get()->getSourceRange(); // FIXME: Print the possible common types by printing the return types of // the viable candidates. break; case OR_Deleted: llvm_unreachable("Conditional operator has only built-in overloads"); } return true; } /// Perform an "extended" implicit conversion as returned by /// TryClassUnification. static bool ConvertForConditional(Sema &Self, ExprResult &E, QualType T) { InitializedEntity Entity = InitializedEntity::InitializeTemporary(T); InitializationKind Kind = InitializationKind::CreateCopy(E.get()->getBeginLoc(), SourceLocation()); Expr *Arg = E.get(); InitializationSequence InitSeq(Self, Entity, Kind, Arg); ExprResult Result = InitSeq.Perform(Self, Entity, Kind, Arg); if (Result.isInvalid()) return true; E = Result; return false; } // Check the condition operand of ?: to see if it is valid for the GCC // extension. static bool isValidVectorForConditionalCondition(ASTContext &Ctx, QualType CondTy) { if (!CondTy->isVectorType() || CondTy->isExtVectorType()) return false; const QualType EltTy = cast(CondTy.getCanonicalType())->getElementType(); assert(!EltTy->isBooleanType() && !EltTy->isEnumeralType() && "Vectors cant be boolean or enum types"); return EltTy->isIntegralType(Ctx); } QualType Sema::CheckGNUVectorConditionalTypes(ExprResult &Cond, ExprResult &LHS, ExprResult &RHS, SourceLocation QuestionLoc) { LHS = DefaultFunctionArrayLvalueConversion(LHS.get()); RHS = DefaultFunctionArrayLvalueConversion(RHS.get()); QualType CondType = Cond.get()->getType(); const auto *CondVT = CondType->getAs(); QualType CondElementTy = CondVT->getElementType(); unsigned CondElementCount = CondVT->getNumElements(); QualType LHSType = LHS.get()->getType(); const auto *LHSVT = LHSType->getAs(); QualType RHSType = RHS.get()->getType(); const auto *RHSVT = RHSType->getAs(); QualType ResultType; // FIXME: In the future we should define what the Extvector conditional // operator looks like. if (LHSVT && isa(LHSVT)) { Diag(QuestionLoc, diag::err_conditional_vector_operand_type) << /*isExtVector*/ true << LHSType; return {}; } if (RHSVT && isa(RHSVT)) { Diag(QuestionLoc, diag::err_conditional_vector_operand_type) << /*isExtVector*/ true << RHSType; return {}; } if (LHSVT && RHSVT) { // If both are vector types, they must be the same type. if (!Context.hasSameType(LHSType, RHSType)) { Diag(QuestionLoc, diag::err_conditional_vector_mismatched_vectors) << LHSType << RHSType; return {}; } ResultType = LHSType; } else if (LHSVT || RHSVT) { ResultType = CheckVectorOperands( LHS, RHS, QuestionLoc, /*isCompAssign*/ false, /*AllowBothBool*/ true, /*AllowBoolConversions*/ false); if (ResultType.isNull()) return {}; } else { // Both are scalar. QualType ResultElementTy; LHSType = LHSType.getCanonicalType().getUnqualifiedType(); RHSType = RHSType.getCanonicalType().getUnqualifiedType(); if (Context.hasSameType(LHSType, RHSType)) ResultElementTy = LHSType; else ResultElementTy = UsualArithmeticConversions(LHS, RHS, QuestionLoc, ACK_Conditional); if (ResultElementTy->isEnumeralType()) { Diag(QuestionLoc, diag::err_conditional_vector_operand_type) << /*isExtVector*/ false << ResultElementTy; return {}; } ResultType = Context.getVectorType( ResultElementTy, CondType->getAs()->getNumElements(), VectorType::GenericVector); LHS = ImpCastExprToType(LHS.get(), ResultType, CK_VectorSplat); RHS = ImpCastExprToType(RHS.get(), ResultType, CK_VectorSplat); } assert(!ResultType.isNull() && ResultType->isVectorType() && "Result should have been a vector type"); QualType ResultElementTy = ResultType->getAs()->getElementType(); unsigned ResultElementCount = ResultType->getAs()->getNumElements(); if (ResultElementCount != CondElementCount) { Diag(QuestionLoc, diag::err_conditional_vector_size) << CondType << ResultType; return {}; } if (Context.getTypeSize(ResultElementTy) != Context.getTypeSize(CondElementTy)) { Diag(QuestionLoc, diag::err_conditional_vector_element_size) << CondType << ResultType; return {}; } return ResultType; } /// Check the operands of ?: under C++ semantics. /// /// See C++ [expr.cond]. Note that LHS is never null, even for the GNU x ?: y /// extension. In this case, LHS == Cond. (But they're not aliases.) /// /// This function also implements GCC's vector extension for conditionals. /// GCC's vector extension permits the use of a?b:c where the type of /// a is that of a integer vector with the same number of elements and /// size as the vectors of b and c. If one of either b or c is a scalar /// it is implicitly converted to match the type of the vector. /// Otherwise the expression is ill-formed. If both b and c are scalars, /// then b and c are checked and converted to the type of a if possible. /// Unlike the OpenCL ?: operator, the expression is evaluated as /// (a[0] != 0 ? b[0] : c[0], .. , a[n] != 0 ? b[n] : c[n]). QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, ExprResult &RHS, ExprValueKind &VK, ExprObjectKind &OK, SourceLocation QuestionLoc) { // FIXME: Handle C99's complex types, block pointers and Obj-C++ interface // pointers. // Assume r-value. VK = VK_RValue; OK = OK_Ordinary; bool IsVectorConditional = isValidVectorForConditionalCondition(Context, Cond.get()->getType()); // C++11 [expr.cond]p1 // The first expression is contextually converted to bool. if (!Cond.get()->isTypeDependent()) { ExprResult CondRes = IsVectorConditional ? DefaultFunctionArrayLvalueConversion(Cond.get()) : CheckCXXBooleanCondition(Cond.get()); if (CondRes.isInvalid()) return QualType(); Cond = CondRes; } else { // To implement C++, the first expression typically doesn't alter the result // type of the conditional, however the GCC compatible vector extension // changes the result type to be that of the conditional. Since we cannot // know if this is a vector extension here, delay the conversion of the // LHS/RHS below until later. return Context.DependentTy; } // Either of the arguments dependent? if (LHS.get()->isTypeDependent() || RHS.get()->isTypeDependent()) return Context.DependentTy; // C++11 [expr.cond]p2 // If either the second or the third operand has type (cv) void, ... QualType LTy = LHS.get()->getType(); QualType RTy = RHS.get()->getType(); bool LVoid = LTy->isVoidType(); bool RVoid = RTy->isVoidType(); if (LVoid || RVoid) { // ... one of the following shall hold: // -- The second or the third operand (but not both) is a (possibly // parenthesized) throw-expression; the result is of the type // and value category of the other. bool LThrow = isa(LHS.get()->IgnoreParenImpCasts()); bool RThrow = isa(RHS.get()->IgnoreParenImpCasts()); // Void expressions aren't legal in the vector-conditional expressions. if (IsVectorConditional) { SourceRange DiagLoc = LVoid ? LHS.get()->getSourceRange() : RHS.get()->getSourceRange(); bool IsThrow = LVoid ? LThrow : RThrow; Diag(DiagLoc.getBegin(), diag::err_conditional_vector_has_void) << DiagLoc << IsThrow; return QualType(); } if (LThrow != RThrow) { Expr *NonThrow = LThrow ? RHS.get() : LHS.get(); VK = NonThrow->getValueKind(); // DR (no number yet): the result is a bit-field if the // non-throw-expression operand is a bit-field. OK = NonThrow->getObjectKind(); return NonThrow->getType(); } // -- Both the second and third operands have type void; the result is of // type void and is a prvalue. if (LVoid && RVoid) return Context.VoidTy; // Neither holds, error. Diag(QuestionLoc, diag::err_conditional_void_nonvoid) << (LVoid ? RTy : LTy) << (LVoid ? 0 : 1) << LHS.get()->getSourceRange() << RHS.get()->getSourceRange(); return QualType(); } // Neither is void. if (IsVectorConditional) return CheckGNUVectorConditionalTypes(Cond, LHS, RHS, QuestionLoc); // C++11 [expr.cond]p3 // Otherwise, if the second and third operand have different types, and // either has (cv) class type [...] an attempt is made to convert each of // those operands to the type of the other. if (!Context.hasSameType(LTy, RTy) && (LTy->isRecordType() || RTy->isRecordType())) { // These return true if a single direction is already ambiguous. QualType L2RType, R2LType; bool HaveL2R, HaveR2L; if (TryClassUnification(*this, LHS.get(), RHS.get(), QuestionLoc, HaveL2R, L2RType)) return QualType(); if (TryClassUnification(*this, RHS.get(), LHS.get(), QuestionLoc, HaveR2L, R2LType)) return QualType(); // If both can be converted, [...] the program is ill-formed. if (HaveL2R && HaveR2L) { Diag(QuestionLoc, diag::err_conditional_ambiguous) << LTy << RTy << LHS.get()->getSourceRange() << RHS.get()->getSourceRange(); return QualType(); } // If exactly one conversion is possible, that conversion is applied to // the chosen operand and the converted operands are used in place of the // original operands for the remainder of this section. if (HaveL2R) { if (ConvertForConditional(*this, LHS, L2RType) || LHS.isInvalid()) return QualType(); LTy = LHS.get()->getType(); } else if (HaveR2L) { if (ConvertForConditional(*this, RHS, R2LType) || RHS.isInvalid()) return QualType(); RTy = RHS.get()->getType(); } } // C++11 [expr.cond]p3 // if both are glvalues of the same value category and the same type except // for cv-qualification, an attempt is made to convert each of those // operands to the type of the other. // FIXME: // Resolving a defect in P0012R1: we extend this to cover all cases where // one of the operands is reference-compatible with the other, in order // to support conditionals between functions differing in noexcept. This // will similarly cover difference in array bounds after P0388R4. // FIXME: If LTy and RTy have a composite pointer type, should we convert to // that instead? ExprValueKind LVK = LHS.get()->getValueKind(); ExprValueKind RVK = RHS.get()->getValueKind(); if (!Context.hasSameType(LTy, RTy) && LVK == RVK && LVK != VK_RValue) { // DerivedToBase was already handled by the class-specific case above. // FIXME: Should we allow ObjC conversions here? const ReferenceConversions AllowedConversions = ReferenceConversions::Qualification | ReferenceConversions::NestedQualification | ReferenceConversions::Function; ReferenceConversions RefConv; if (CompareReferenceRelationship(QuestionLoc, LTy, RTy, &RefConv) == Ref_Compatible && !(RefConv & ~AllowedConversions) && // [...] subject to the constraint that the reference must bind // directly [...] !RHS.get()->refersToBitField() && !RHS.get()->refersToVectorElement()) { RHS = ImpCastExprToType(RHS.get(), LTy, CK_NoOp, RVK); RTy = RHS.get()->getType(); } else if (CompareReferenceRelationship(QuestionLoc, RTy, LTy, &RefConv) == Ref_Compatible && !(RefConv & ~AllowedConversions) && !LHS.get()->refersToBitField() && !LHS.get()->refersToVectorElement()) { LHS = ImpCastExprToType(LHS.get(), RTy, CK_NoOp, LVK); LTy = LHS.get()->getType(); } } // C++11 [expr.cond]p4 // If the second and third operands are glvalues of the same value // category and have the same type, the result is of that type and // value category and it is a bit-field if the second or the third // operand is a bit-field, or if both are bit-fields. // We only extend this to bitfields, not to the crazy other kinds of // l-values. bool Same = Context.hasSameType(LTy, RTy); if (Same && LVK == RVK && LVK != VK_RValue && LHS.get()->isOrdinaryOrBitFieldObject() && RHS.get()->isOrdinaryOrBitFieldObject()) { VK = LHS.get()->getValueKind(); if (LHS.get()->getObjectKind() == OK_BitField || RHS.get()->getObjectKind() == OK_BitField) OK = OK_BitField; // If we have function pointer types, unify them anyway to unify their // exception specifications, if any. if (LTy->isFunctionPointerType() || LTy->isMemberFunctionPointerType()) { Qualifiers Qs = LTy.getQualifiers(); LTy = FindCompositePointerType(QuestionLoc, LHS, RHS, /*ConvertArgs*/false); LTy = Context.getQualifiedType(LTy, Qs); assert(!LTy.isNull() && "failed to find composite pointer type for " "canonically equivalent function ptr types"); assert(Context.hasSameType(LTy, RTy) && "bad composite pointer type"); } return LTy; } // C++11 [expr.cond]p5 // Otherwise, the result is a prvalue. If the second and third operands // do not have the same type, and either has (cv) class type, ... if (!Same && (LTy->isRecordType() || RTy->isRecordType())) { // ... overload resolution is used to determine the conversions (if any) // to be applied to the operands. If the overload resolution fails, the // program is ill-formed. if (FindConditionalOverload(*this, LHS, RHS, QuestionLoc)) return QualType(); } // C++11 [expr.cond]p6 // Lvalue-to-rvalue, array-to-pointer, and function-to-pointer standard // conversions are performed on the second and third operands. LHS = DefaultFunctionArrayLvalueConversion(LHS.get()); RHS = DefaultFunctionArrayLvalueConversion(RHS.get()); if (LHS.isInvalid() || RHS.isInvalid()) return QualType(); LTy = LHS.get()->getType(); RTy = RHS.get()->getType(); // After those conversions, one of the following shall hold: // -- The second and third operands have the same type; the result // is of that type. If the operands have class type, the result // is a prvalue temporary of the result type, which is // copy-initialized from either the second operand or the third // operand depending on the value of the first operand. if (Context.getCanonicalType(LTy) == Context.getCanonicalType(RTy)) { if (LTy->isRecordType()) { // The operands have class type. Make a temporary copy. InitializedEntity Entity = InitializedEntity::InitializeTemporary(LTy); ExprResult LHSCopy = PerformCopyInitialization(Entity, SourceLocation(), LHS); if (LHSCopy.isInvalid()) return QualType(); ExprResult RHSCopy = PerformCopyInitialization(Entity, SourceLocation(), RHS); if (RHSCopy.isInvalid()) return QualType(); LHS = LHSCopy; RHS = RHSCopy; } // If we have function pointer types, unify them anyway to unify their // exception specifications, if any. if (LTy->isFunctionPointerType() || LTy->isMemberFunctionPointerType()) { LTy = FindCompositePointerType(QuestionLoc, LHS, RHS); assert(!LTy.isNull() && "failed to find composite pointer type for " "canonically equivalent function ptr types"); } return LTy; } // Extension: conditional operator involving vector types. if (LTy->isVectorType() || RTy->isVectorType()) return CheckVectorOperands(LHS, RHS, QuestionLoc, /*isCompAssign*/false, /*AllowBothBool*/true, /*AllowBoolConversions*/false); // -- The second and third operands have arithmetic or enumeration type; // the usual arithmetic conversions are performed to bring them to a // common type, and the result is of that type. if (LTy->isArithmeticType() && RTy->isArithmeticType()) { QualType ResTy = UsualArithmeticConversions(LHS, RHS, QuestionLoc, ACK_Conditional); if (LHS.isInvalid() || RHS.isInvalid()) return QualType(); if (ResTy.isNull()) { Diag(QuestionLoc, diag::err_typecheck_cond_incompatible_operands) << LTy << RTy << LHS.get()->getSourceRange() << RHS.get()->getSourceRange(); return QualType(); } LHS = ImpCastExprToType(LHS.get(), ResTy, PrepareScalarCast(LHS, ResTy)); RHS = ImpCastExprToType(RHS.get(), ResTy, PrepareScalarCast(RHS, ResTy)); return ResTy; } // -- The second and third operands have pointer type, or one has pointer // type and the other is a null pointer constant, or both are null // pointer constants, at least one of which is non-integral; pointer // conversions and qualification conversions are performed to bring them // to their composite pointer type. The result is of the composite // pointer type. // -- The second and third operands have pointer to member type, or one has // pointer to member type and the other is a null pointer constant; // pointer to member conversions and qualification conversions are // performed to bring them to a common type, whose cv-qualification // shall match the cv-qualification of either the second or the third // operand. The result is of the common type. QualType Composite = FindCompositePointerType(QuestionLoc, LHS, RHS); if (!Composite.isNull()) return Composite; // Similarly, attempt to find composite type of two objective-c pointers. Composite = FindCompositeObjCPointerType(LHS, RHS, QuestionLoc); if (!Composite.isNull()) return Composite; // Check if we are using a null with a non-pointer type. if (DiagnoseConditionalForNull(LHS.get(), RHS.get(), QuestionLoc)) return QualType(); Diag(QuestionLoc, diag::err_typecheck_cond_incompatible_operands) << LHS.get()->getType() << RHS.get()->getType() << LHS.get()->getSourceRange() << RHS.get()->getSourceRange(); return QualType(); } static FunctionProtoType::ExceptionSpecInfo mergeExceptionSpecs(Sema &S, FunctionProtoType::ExceptionSpecInfo ESI1, FunctionProtoType::ExceptionSpecInfo ESI2, SmallVectorImpl &ExceptionTypeStorage) { ExceptionSpecificationType EST1 = ESI1.Type; ExceptionSpecificationType EST2 = ESI2.Type; // If either of them can throw anything, that is the result. if (EST1 == EST_None) return ESI1; if (EST2 == EST_None) return ESI2; if (EST1 == EST_MSAny) return ESI1; if (EST2 == EST_MSAny) return ESI2; if (EST1 == EST_NoexceptFalse) return ESI1; if (EST2 == EST_NoexceptFalse) return ESI2; // If either of them is non-throwing, the result is the other. if (EST1 == EST_NoThrow) return ESI2; if (EST2 == EST_NoThrow) return ESI1; if (EST1 == EST_DynamicNone) return ESI2; if (EST2 == EST_DynamicNone) return ESI1; if (EST1 == EST_BasicNoexcept) return ESI2; if (EST2 == EST_BasicNoexcept) return ESI1; if (EST1 == EST_NoexceptTrue) return ESI2; if (EST2 == EST_NoexceptTrue) return ESI1; // If we're left with value-dependent computed noexcept expressions, we're // stuck. Before C++17, we can just drop the exception specification entirely, // since it's not actually part of the canonical type. And this should never // happen in C++17, because it would mean we were computing the composite // pointer type of dependent types, which should never happen. if (EST1 == EST_DependentNoexcept || EST2 == EST_DependentNoexcept) { assert(!S.getLangOpts().CPlusPlus17 && "computing composite pointer type of dependent types"); return FunctionProtoType::ExceptionSpecInfo(); } // Switch over the possibilities so that people adding new values know to // update this function. switch (EST1) { case EST_None: case EST_DynamicNone: case EST_MSAny: case EST_BasicNoexcept: case EST_DependentNoexcept: case EST_NoexceptFalse: case EST_NoexceptTrue: case EST_NoThrow: llvm_unreachable("handled above"); case EST_Dynamic: { // This is the fun case: both exception specifications are dynamic. Form // the union of the two lists. assert(EST2 == EST_Dynamic && "other cases should already be handled"); llvm::SmallPtrSet Found; for (auto &Exceptions : {ESI1.Exceptions, ESI2.Exceptions}) for (QualType E : Exceptions) if (Found.insert(S.Context.getCanonicalType(E)).second) ExceptionTypeStorage.push_back(E); FunctionProtoType::ExceptionSpecInfo Result(EST_Dynamic); Result.Exceptions = ExceptionTypeStorage; return Result; } case EST_Unevaluated: case EST_Uninstantiated: case EST_Unparsed: llvm_unreachable("shouldn't see unresolved exception specifications here"); } llvm_unreachable("invalid ExceptionSpecificationType"); } /// Find a merged pointer type and convert the two expressions to it. /// /// This finds the composite pointer type for \p E1 and \p E2 according to /// C++2a [expr.type]p3. It converts both expressions to this type and returns /// it. It does not emit diagnostics (FIXME: that's not true if \p ConvertArgs /// is \c true). /// /// \param Loc The location of the operator requiring these two expressions to /// be converted to the composite pointer type. /// /// \param ConvertArgs If \c false, do not convert E1 and E2 to the target type. QualType Sema::FindCompositePointerType(SourceLocation Loc, Expr *&E1, Expr *&E2, bool ConvertArgs) { assert(getLangOpts().CPlusPlus && "This function assumes C++"); // C++1z [expr]p14: // The composite pointer type of two operands p1 and p2 having types T1 // and T2 QualType T1 = E1->getType(), T2 = E2->getType(); // where at least one is a pointer or pointer to member type or // std::nullptr_t is: bool T1IsPointerLike = T1->isAnyPointerType() || T1->isMemberPointerType() || T1->isNullPtrType(); bool T2IsPointerLike = T2->isAnyPointerType() || T2->isMemberPointerType() || T2->isNullPtrType(); if (!T1IsPointerLike && !T2IsPointerLike) return QualType(); // - if both p1 and p2 are null pointer constants, std::nullptr_t; // This can't actually happen, following the standard, but we also use this // to implement the end of [expr.conv], which hits this case. // // - if either p1 or p2 is a null pointer constant, T2 or T1, respectively; if (T1IsPointerLike && E2->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) { if (ConvertArgs) E2 = ImpCastExprToType(E2, T1, T1->isMemberPointerType() ? CK_NullToMemberPointer : CK_NullToPointer).get(); return T1; } if (T2IsPointerLike && E1->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) { if (ConvertArgs) E1 = ImpCastExprToType(E1, T2, T2->isMemberPointerType() ? CK_NullToMemberPointer : CK_NullToPointer).get(); return T2; } // Now both have to be pointers or member pointers. if (!T1IsPointerLike || !T2IsPointerLike) return QualType(); assert(!T1->isNullPtrType() && !T2->isNullPtrType() && "nullptr_t should be a null pointer constant"); struct Step { enum Kind { Pointer, ObjCPointer, MemberPointer, Array } K; // Qualifiers to apply under the step kind. Qualifiers Quals; /// The class for a pointer-to-member; a constant array type with a bound /// (if any) for an array. const Type *ClassOrBound; Step(Kind K, const Type *ClassOrBound = nullptr) : K(K), Quals(), ClassOrBound(ClassOrBound) {} QualType rebuild(ASTContext &Ctx, QualType T) const { T = Ctx.getQualifiedType(T, Quals); switch (K) { case Pointer: return Ctx.getPointerType(T); case MemberPointer: return Ctx.getMemberPointerType(T, ClassOrBound); case ObjCPointer: return Ctx.getObjCObjectPointerType(T); case Array: if (auto *CAT = cast_or_null(ClassOrBound)) return Ctx.getConstantArrayType(T, CAT->getSize(), nullptr, ArrayType::Normal, 0); else return Ctx.getIncompleteArrayType(T, ArrayType::Normal, 0); } llvm_unreachable("unknown step kind"); } }; SmallVector Steps; // - if T1 is "pointer to cv1 C1" and T2 is "pointer to cv2 C2", where C1 // is reference-related to C2 or C2 is reference-related to C1 (8.6.3), // the cv-combined type of T1 and T2 or the cv-combined type of T2 and T1, // respectively; // - if T1 is "pointer to member of C1 of type cv1 U1" and T2 is "pointer // to member of C2 of type cv2 U2" for some non-function type U, where // C1 is reference-related to C2 or C2 is reference-related to C1, the // cv-combined type of T2 and T1 or the cv-combined type of T1 and T2, // respectively; // - if T1 and T2 are similar types (4.5), the cv-combined type of T1 and // T2; // // Dismantle T1 and T2 to simultaneously determine whether they are similar // and to prepare to form the cv-combined type if so. QualType Composite1 = T1; QualType Composite2 = T2; unsigned NeedConstBefore = 0; while (true) { assert(!Composite1.isNull() && !Composite2.isNull()); Qualifiers Q1, Q2; Composite1 = Context.getUnqualifiedArrayType(Composite1, Q1); Composite2 = Context.getUnqualifiedArrayType(Composite2, Q2); // Top-level qualifiers are ignored. Merge at all lower levels. if (!Steps.empty()) { // Find the qualifier union: (approximately) the unique minimal set of // qualifiers that is compatible with both types. Qualifiers Quals = Qualifiers::fromCVRUMask(Q1.getCVRUQualifiers() | Q2.getCVRUQualifiers()); // Under one level of pointer or pointer-to-member, we can change to an // unambiguous compatible address space. if (Q1.getAddressSpace() == Q2.getAddressSpace()) { Quals.setAddressSpace(Q1.getAddressSpace()); } else if (Steps.size() == 1) { bool MaybeQ1 = Q1.isAddressSpaceSupersetOf(Q2); bool MaybeQ2 = Q2.isAddressSpaceSupersetOf(Q1); if (MaybeQ1 == MaybeQ2) return QualType(); // No unique best address space. Quals.setAddressSpace(MaybeQ1 ? Q1.getAddressSpace() : Q2.getAddressSpace()); } else { return QualType(); } // FIXME: In C, we merge __strong and none to __strong at the top level. if (Q1.getObjCGCAttr() == Q2.getObjCGCAttr()) Quals.setObjCGCAttr(Q1.getObjCGCAttr()); else return QualType(); // Mismatched lifetime qualifiers never compatibly include each other. if (Q1.getObjCLifetime() == Q2.getObjCLifetime()) Quals.setObjCLifetime(Q1.getObjCLifetime()); else return QualType(); Steps.back().Quals = Quals; if (Q1 != Quals || Q2 != Quals) NeedConstBefore = Steps.size() - 1; } // FIXME: Can we unify the following with UnwrapSimilarTypes? const PointerType *Ptr1, *Ptr2; if ((Ptr1 = Composite1->getAs()) && (Ptr2 = Composite2->getAs())) { Composite1 = Ptr1->getPointeeType(); Composite2 = Ptr2->getPointeeType(); Steps.emplace_back(Step::Pointer); continue; } const ObjCObjectPointerType *ObjPtr1, *ObjPtr2; if ((ObjPtr1 = Composite1->getAs()) && (ObjPtr2 = Composite2->getAs())) { Composite1 = ObjPtr1->getPointeeType(); Composite2 = ObjPtr2->getPointeeType(); Steps.emplace_back(Step::ObjCPointer); continue; } const MemberPointerType *MemPtr1, *MemPtr2; if ((MemPtr1 = Composite1->getAs()) && (MemPtr2 = Composite2->getAs())) { Composite1 = MemPtr1->getPointeeType(); Composite2 = MemPtr2->getPointeeType(); // At the top level, we can perform a base-to-derived pointer-to-member // conversion: // // - [...] where C1 is reference-related to C2 or C2 is // reference-related to C1 // // (Note that the only kinds of reference-relatedness in scope here are // "same type or derived from".) At any other level, the class must // exactly match. const Type *Class = nullptr; QualType Cls1(MemPtr1->getClass(), 0); QualType Cls2(MemPtr2->getClass(), 0); if (Context.hasSameType(Cls1, Cls2)) Class = MemPtr1->getClass(); else if (Steps.empty()) Class = IsDerivedFrom(Loc, Cls1, Cls2) ? MemPtr1->getClass() : IsDerivedFrom(Loc, Cls2, Cls1) ? MemPtr2->getClass() : nullptr; if (!Class) return QualType(); Steps.emplace_back(Step::MemberPointer, Class); continue; } // Special case: at the top level, we can decompose an Objective-C pointer // and a 'cv void *'. Unify the qualifiers. if (Steps.empty() && ((Composite1->isVoidPointerType() && Composite2->isObjCObjectPointerType()) || (Composite1->isObjCObjectPointerType() && Composite2->isVoidPointerType()))) { Composite1 = Composite1->getPointeeType(); Composite2 = Composite2->getPointeeType(); Steps.emplace_back(Step::Pointer); continue; } // FIXME: arrays // FIXME: block pointer types? // Cannot unwrap any more types. break; } // - if T1 or T2 is "pointer to noexcept function" and the other type is // "pointer to function", where the function types are otherwise the same, // "pointer to function"; // - if T1 or T2 is "pointer to member of C1 of type function", the other // type is "pointer to member of C2 of type noexcept function", and C1 // is reference-related to C2 or C2 is reference-related to C1, where // the function types are otherwise the same, "pointer to member of C2 of // type function" or "pointer to member of C1 of type function", // respectively; // // We also support 'noreturn' here, so as a Clang extension we generalize the // above to: // // - [Clang] If T1 and T2 are both of type "pointer to function" or // "pointer to member function" and the pointee types can be unified // by a function pointer conversion, that conversion is applied // before checking the following rules. // // We've already unwrapped down to the function types, and we want to merge // rather than just convert, so do this ourselves rather than calling // IsFunctionConversion. // // FIXME: In order to match the standard wording as closely as possible, we // currently only do this under a single level of pointers. Ideally, we would // allow this in general, and set NeedConstBefore to the relevant depth on // the side(s) where we changed anything. If we permit that, we should also // consider this conversion when determining type similarity and model it as // a qualification conversion. if (Steps.size() == 1) { if (auto *FPT1 = Composite1->getAs()) { if (auto *FPT2 = Composite2->getAs()) { FunctionProtoType::ExtProtoInfo EPI1 = FPT1->getExtProtoInfo(); FunctionProtoType::ExtProtoInfo EPI2 = FPT2->getExtProtoInfo(); // The result is noreturn if both operands are. bool Noreturn = EPI1.ExtInfo.getNoReturn() && EPI2.ExtInfo.getNoReturn(); EPI1.ExtInfo = EPI1.ExtInfo.withNoReturn(Noreturn); EPI2.ExtInfo = EPI2.ExtInfo.withNoReturn(Noreturn); // The result is nothrow if both operands are. SmallVector ExceptionTypeStorage; EPI1.ExceptionSpec = EPI2.ExceptionSpec = mergeExceptionSpecs(*this, EPI1.ExceptionSpec, EPI2.ExceptionSpec, ExceptionTypeStorage); Composite1 = Context.getFunctionType(FPT1->getReturnType(), FPT1->getParamTypes(), EPI1); Composite2 = Context.getFunctionType(FPT2->getReturnType(), FPT2->getParamTypes(), EPI2); } } } // There are some more conversions we can perform under exactly one pointer. if (Steps.size() == 1 && Steps.front().K == Step::Pointer && !Context.hasSameType(Composite1, Composite2)) { // - if T1 or T2 is "pointer to cv1 void" and the other type is // "pointer to cv2 T", where T is an object type or void, // "pointer to cv12 void", where cv12 is the union of cv1 and cv2; if (Composite1->isVoidType() && Composite2->isObjectType()) Composite2 = Composite1; else if (Composite2->isVoidType() && Composite1->isObjectType()) Composite1 = Composite2; // - if T1 is "pointer to cv1 C1" and T2 is "pointer to cv2 C2", where C1 // is reference-related to C2 or C2 is reference-related to C1 (8.6.3), // the cv-combined type of T1 and T2 or the cv-combined type of T2 and // T1, respectively; // // The "similar type" handling covers all of this except for the "T1 is a // base class of T2" case in the definition of reference-related. else if (IsDerivedFrom(Loc, Composite1, Composite2)) Composite1 = Composite2; else if (IsDerivedFrom(Loc, Composite2, Composite1)) Composite2 = Composite1; } // At this point, either the inner types are the same or we have failed to // find a composite pointer type. if (!Context.hasSameType(Composite1, Composite2)) return QualType(); // Per C++ [conv.qual]p3, add 'const' to every level before the last // differing qualifier. for (unsigned I = 0; I != NeedConstBefore; ++I) Steps[I].Quals.addConst(); // Rebuild the composite type. QualType Composite = Composite1; for (auto &S : llvm::reverse(Steps)) Composite = S.rebuild(Context, Composite); if (ConvertArgs) { // Convert the expressions to the composite pointer type. InitializedEntity Entity = InitializedEntity::InitializeTemporary(Composite); InitializationKind Kind = InitializationKind::CreateCopy(Loc, SourceLocation()); InitializationSequence E1ToC(*this, Entity, Kind, E1); if (!E1ToC) return QualType(); InitializationSequence E2ToC(*this, Entity, Kind, E2); if (!E2ToC) return QualType(); // FIXME: Let the caller know if these fail to avoid duplicate diagnostics. ExprResult E1Result = E1ToC.Perform(*this, Entity, Kind, E1); if (E1Result.isInvalid()) return QualType(); E1 = E1Result.get(); ExprResult E2Result = E2ToC.Perform(*this, Entity, Kind, E2); if (E2Result.isInvalid()) return QualType(); E2 = E2Result.get(); } return Composite; } ExprResult Sema::MaybeBindToTemporary(Expr *E) { if (!E) return ExprError(); assert(!isa(E) && "Double-bound temporary?"); // If the result is a glvalue, we shouldn't bind it. if (!E->isRValue()) return E; // In ARC, calls that return a retainable type can return retained, // in which case we have to insert a consuming cast. if (getLangOpts().ObjCAutoRefCount && E->getType()->isObjCRetainableType()) { bool ReturnsRetained; // For actual calls, we compute this by examining the type of the // called value. if (CallExpr *Call = dyn_cast(E)) { Expr *Callee = Call->getCallee()->IgnoreParens(); QualType T = Callee->getType(); if (T == Context.BoundMemberTy) { // Handle pointer-to-members. if (BinaryOperator *BinOp = dyn_cast(Callee)) T = BinOp->getRHS()->getType(); else if (MemberExpr *Mem = dyn_cast(Callee)) T = Mem->getMemberDecl()->getType(); } if (const PointerType *Ptr = T->getAs()) T = Ptr->getPointeeType(); else if (const BlockPointerType *Ptr = T->getAs()) T = Ptr->getPointeeType(); else if (const MemberPointerType *MemPtr = T->getAs()) T = MemPtr->getPointeeType(); const FunctionType *FTy = T->getAs(); assert(FTy && "call to value not of function type?"); ReturnsRetained = FTy->getExtInfo().getProducesResult(); // ActOnStmtExpr arranges things so that StmtExprs of retainable // type always produce a +1 object. } else if (isa(E)) { ReturnsRetained = true; // We hit this case with the lambda conversion-to-block optimization; // we don't want any extra casts here. } else if (isa(E) && isa(cast(E)->getSubExpr())) { return E; // For message sends and property references, we try to find an // actual method. FIXME: we should infer retention by selector in // cases where we don't have an actual method. } else { ObjCMethodDecl *D = nullptr; if (ObjCMessageExpr *Send = dyn_cast(E)) { D = Send->getMethodDecl(); } else if (ObjCBoxedExpr *BoxedExpr = dyn_cast(E)) { D = BoxedExpr->getBoxingMethod(); } else if (ObjCArrayLiteral *ArrayLit = dyn_cast(E)) { // Don't do reclaims if we're using the zero-element array // constant. if (ArrayLit->getNumElements() == 0 && Context.getLangOpts().ObjCRuntime.hasEmptyCollections()) return E; D = ArrayLit->getArrayWithObjectsMethod(); } else if (ObjCDictionaryLiteral *DictLit = dyn_cast(E)) { // Don't do reclaims if we're using the zero-element dictionary // constant. if (DictLit->getNumElements() == 0 && Context.getLangOpts().ObjCRuntime.hasEmptyCollections()) return E; D = DictLit->getDictWithObjectsMethod(); } ReturnsRetained = (D && D->hasAttr()); // Don't do reclaims on performSelector calls; despite their // return type, the invoked method doesn't necessarily actually // return an object. if (!ReturnsRetained && D && D->getMethodFamily() == OMF_performSelector) return E; } // Don't reclaim an object of Class type. if (!ReturnsRetained && E->getType()->isObjCARCImplicitlyUnretainedType()) return E; Cleanup.setExprNeedsCleanups(true); CastKind ck = (ReturnsRetained ? CK_ARCConsumeObject : CK_ARCReclaimReturnedObject); return ImplicitCastExpr::Create(Context, E->getType(), ck, E, nullptr, VK_RValue); } if (!getLangOpts().CPlusPlus) return E; // Search for the base element type (cf. ASTContext::getBaseElementType) with // a fast path for the common case that the type is directly a RecordType. const Type *T = Context.getCanonicalType(E->getType().getTypePtr()); const RecordType *RT = nullptr; while (!RT) { switch (T->getTypeClass()) { case Type::Record: RT = cast(T); break; case Type::ConstantArray: case Type::IncompleteArray: case Type::VariableArray: case Type::DependentSizedArray: T = cast(T)->getElementType().getTypePtr(); break; default: return E; } } // That should be enough to guarantee that this type is complete, if we're // not processing a decltype expression. CXXRecordDecl *RD = cast(RT->getDecl()); if (RD->isInvalidDecl() || RD->isDependentContext()) return E; bool IsDecltype = ExprEvalContexts.back().ExprContext == ExpressionEvaluationContextRecord::EK_Decltype; CXXDestructorDecl *Destructor = IsDecltype ? nullptr : LookupDestructor(RD); if (Destructor) { MarkFunctionReferenced(E->getExprLoc(), Destructor); CheckDestructorAccess(E->getExprLoc(), Destructor, PDiag(diag::err_access_dtor_temp) << E->getType()); if (DiagnoseUseOfDecl(Destructor, E->getExprLoc())) return ExprError(); // If destructor is trivial, we can avoid the extra copy. if (Destructor->isTrivial()) return E; // We need a cleanup, but we don't need to remember the temporary. Cleanup.setExprNeedsCleanups(true); } CXXTemporary *Temp = CXXTemporary::Create(Context, Destructor); CXXBindTemporaryExpr *Bind = CXXBindTemporaryExpr::Create(Context, Temp, E); if (IsDecltype) ExprEvalContexts.back().DelayedDecltypeBinds.push_back(Bind); return Bind; } ExprResult Sema::MaybeCreateExprWithCleanups(ExprResult SubExpr) { if (SubExpr.isInvalid()) return ExprError(); return MaybeCreateExprWithCleanups(SubExpr.get()); } Expr *Sema::MaybeCreateExprWithCleanups(Expr *SubExpr) { assert(SubExpr && "subexpression can't be null!"); CleanupVarDeclMarking(); unsigned FirstCleanup = ExprEvalContexts.back().NumCleanupObjects; assert(ExprCleanupObjects.size() >= FirstCleanup); assert(Cleanup.exprNeedsCleanups() || ExprCleanupObjects.size() == FirstCleanup); if (!Cleanup.exprNeedsCleanups()) return SubExpr; auto Cleanups = llvm::makeArrayRef(ExprCleanupObjects.begin() + FirstCleanup, ExprCleanupObjects.size() - FirstCleanup); auto *E = ExprWithCleanups::Create( Context, SubExpr, Cleanup.cleanupsHaveSideEffects(), Cleanups); DiscardCleanupsInEvaluationContext(); return E; } Stmt *Sema::MaybeCreateStmtWithCleanups(Stmt *SubStmt) { assert(SubStmt && "sub-statement can't be null!"); CleanupVarDeclMarking(); if (!Cleanup.exprNeedsCleanups()) return SubStmt; // FIXME: In order to attach the temporaries, wrap the statement into // a StmtExpr; currently this is only used for asm statements. // This is hacky, either create a new CXXStmtWithTemporaries statement or // a new AsmStmtWithTemporaries. CompoundStmt *CompStmt = CompoundStmt::Create( Context, SubStmt, SourceLocation(), SourceLocation()); Expr *E = new (Context) StmtExpr(CompStmt, Context.VoidTy, SourceLocation(), SourceLocation(), - CurContext->isDependentContext()); + /*FIXME TemplateDepth=*/0); return MaybeCreateExprWithCleanups(E); } /// Process the expression contained within a decltype. For such expressions, /// certain semantic checks on temporaries are delayed until this point, and /// are omitted for the 'topmost' call in the decltype expression. If the /// topmost call bound a temporary, strip that temporary off the expression. ExprResult Sema::ActOnDecltypeExpression(Expr *E) { assert(ExprEvalContexts.back().ExprContext == ExpressionEvaluationContextRecord::EK_Decltype && "not in a decltype expression"); ExprResult Result = CheckPlaceholderExpr(E); if (Result.isInvalid()) return ExprError(); E = Result.get(); // C++11 [expr.call]p11: // If a function call is a prvalue of object type, // -- if the function call is either // -- the operand of a decltype-specifier, or // -- the right operand of a comma operator that is the operand of a // decltype-specifier, // a temporary object is not introduced for the prvalue. // Recursively rebuild ParenExprs and comma expressions to strip out the // outermost CXXBindTemporaryExpr, if any. if (ParenExpr *PE = dyn_cast(E)) { ExprResult SubExpr = ActOnDecltypeExpression(PE->getSubExpr()); if (SubExpr.isInvalid()) return ExprError(); if (SubExpr.get() == PE->getSubExpr()) return E; return ActOnParenExpr(PE->getLParen(), PE->getRParen(), SubExpr.get()); } if (BinaryOperator *BO = dyn_cast(E)) { if (BO->getOpcode() == BO_Comma) { ExprResult RHS = ActOnDecltypeExpression(BO->getRHS()); if (RHS.isInvalid()) return ExprError(); if (RHS.get() == BO->getRHS()) return E; return new (Context) BinaryOperator( BO->getLHS(), RHS.get(), BO_Comma, BO->getType(), BO->getValueKind(), BO->getObjectKind(), BO->getOperatorLoc(), BO->getFPFeatures()); } } CXXBindTemporaryExpr *TopBind = dyn_cast(E); CallExpr *TopCall = TopBind ? dyn_cast(TopBind->getSubExpr()) : nullptr; if (TopCall) E = TopCall; else TopBind = nullptr; // Disable the special decltype handling now. ExprEvalContexts.back().ExprContext = ExpressionEvaluationContextRecord::EK_Other; Result = CheckUnevaluatedOperand(E); if (Result.isInvalid()) return ExprError(); E = Result.get(); // In MS mode, don't perform any extra checking of call return types within a // decltype expression. if (getLangOpts().MSVCCompat) return E; // Perform the semantic checks we delayed until this point. for (unsigned I = 0, N = ExprEvalContexts.back().DelayedDecltypeCalls.size(); I != N; ++I) { CallExpr *Call = ExprEvalContexts.back().DelayedDecltypeCalls[I]; if (Call == TopCall) continue; if (CheckCallReturnType(Call->getCallReturnType(Context), Call->getBeginLoc(), Call, Call->getDirectCallee())) return ExprError(); } // Now all relevant types are complete, check the destructors are accessible // and non-deleted, and annotate them on the temporaries. for (unsigned I = 0, N = ExprEvalContexts.back().DelayedDecltypeBinds.size(); I != N; ++I) { CXXBindTemporaryExpr *Bind = ExprEvalContexts.back().DelayedDecltypeBinds[I]; if (Bind == TopBind) continue; CXXTemporary *Temp = Bind->getTemporary(); CXXRecordDecl *RD = Bind->getType()->getBaseElementTypeUnsafe()->getAsCXXRecordDecl(); CXXDestructorDecl *Destructor = LookupDestructor(RD); Temp->setDestructor(Destructor); MarkFunctionReferenced(Bind->getExprLoc(), Destructor); CheckDestructorAccess(Bind->getExprLoc(), Destructor, PDiag(diag::err_access_dtor_temp) << Bind->getType()); if (DiagnoseUseOfDecl(Destructor, Bind->getExprLoc())) return ExprError(); // We need a cleanup, but we don't need to remember the temporary. Cleanup.setExprNeedsCleanups(true); } // Possibly strip off the top CXXBindTemporaryExpr. return E; } /// Note a set of 'operator->' functions that were used for a member access. static void noteOperatorArrows(Sema &S, ArrayRef OperatorArrows) { unsigned SkipStart = OperatorArrows.size(), SkipCount = 0; // FIXME: Make this configurable? unsigned Limit = 9; if (OperatorArrows.size() > Limit) { // Produce Limit-1 normal notes and one 'skipping' note. SkipStart = (Limit - 1) / 2 + (Limit - 1) % 2; SkipCount = OperatorArrows.size() - (Limit - 1); } for (unsigned I = 0; I < OperatorArrows.size(); /**/) { if (I == SkipStart) { S.Diag(OperatorArrows[I]->getLocation(), diag::note_operator_arrows_suppressed) << SkipCount; I += SkipCount; } else { S.Diag(OperatorArrows[I]->getLocation(), diag::note_operator_arrow_here) << OperatorArrows[I]->getCallResultType(); ++I; } } } ExprResult Sema::ActOnStartCXXMemberReference(Scope *S, Expr *Base, SourceLocation OpLoc, tok::TokenKind OpKind, ParsedType &ObjectType, bool &MayBePseudoDestructor) { // Since this might be a postfix expression, get rid of ParenListExprs. ExprResult Result = MaybeConvertParenListExprToParenExpr(S, Base); if (Result.isInvalid()) return ExprError(); Base = Result.get(); Result = CheckPlaceholderExpr(Base); if (Result.isInvalid()) return ExprError(); Base = Result.get(); QualType BaseType = Base->getType(); MayBePseudoDestructor = false; if (BaseType->isDependentType()) { // If we have a pointer to a dependent type and are using the -> operator, // the object type is the type that the pointer points to. We might still // have enough information about that type to do something useful. if (OpKind == tok::arrow) if (const PointerType *Ptr = BaseType->getAs()) BaseType = Ptr->getPointeeType(); ObjectType = ParsedType::make(BaseType); MayBePseudoDestructor = true; return Base; } // C++ [over.match.oper]p8: // [...] When operator->returns, the operator-> is applied to the value // returned, with the original second operand. if (OpKind == tok::arrow) { QualType StartingType = BaseType; bool NoArrowOperatorFound = false; bool FirstIteration = true; FunctionDecl *CurFD = dyn_cast(CurContext); // The set of types we've considered so far. llvm::SmallPtrSet CTypes; SmallVector OperatorArrows; CTypes.insert(Context.getCanonicalType(BaseType)); while (BaseType->isRecordType()) { if (OperatorArrows.size() >= getLangOpts().ArrowDepth) { Diag(OpLoc, diag::err_operator_arrow_depth_exceeded) << StartingType << getLangOpts().ArrowDepth << Base->getSourceRange(); noteOperatorArrows(*this, OperatorArrows); Diag(OpLoc, diag::note_operator_arrow_depth) << getLangOpts().ArrowDepth; return ExprError(); } Result = BuildOverloadedArrowExpr( S, Base, OpLoc, // When in a template specialization and on the first loop iteration, // potentially give the default diagnostic (with the fixit in a // separate note) instead of having the error reported back to here // and giving a diagnostic with a fixit attached to the error itself. (FirstIteration && CurFD && CurFD->isFunctionTemplateSpecialization()) ? nullptr : &NoArrowOperatorFound); if (Result.isInvalid()) { if (NoArrowOperatorFound) { if (FirstIteration) { Diag(OpLoc, diag::err_typecheck_member_reference_suggestion) << BaseType << 1 << Base->getSourceRange() << FixItHint::CreateReplacement(OpLoc, "."); OpKind = tok::period; break; } Diag(OpLoc, diag::err_typecheck_member_reference_arrow) << BaseType << Base->getSourceRange(); CallExpr *CE = dyn_cast(Base); if (Decl *CD = (CE ? CE->getCalleeDecl() : nullptr)) { Diag(CD->getBeginLoc(), diag::note_member_reference_arrow_from_operator_arrow); } } return ExprError(); } Base = Result.get(); if (CXXOperatorCallExpr *OpCall = dyn_cast(Base)) OperatorArrows.push_back(OpCall->getDirectCallee()); BaseType = Base->getType(); CanQualType CBaseType = Context.getCanonicalType(BaseType); if (!CTypes.insert(CBaseType).second) { Diag(OpLoc, diag::err_operator_arrow_circular) << StartingType; noteOperatorArrows(*this, OperatorArrows); return ExprError(); } FirstIteration = false; } if (OpKind == tok::arrow) { if (BaseType->isPointerType()) BaseType = BaseType->getPointeeType(); else if (auto *AT = Context.getAsArrayType(BaseType)) BaseType = AT->getElementType(); } } // Objective-C properties allow "." access on Objective-C pointer types, // so adjust the base type to the object type itself. if (BaseType->isObjCObjectPointerType()) BaseType = BaseType->getPointeeType(); // C++ [basic.lookup.classref]p2: // [...] If the type of the object expression is of pointer to scalar // type, the unqualified-id is looked up in the context of the complete // postfix-expression. // // This also indicates that we could be parsing a pseudo-destructor-name. // Note that Objective-C class and object types can be pseudo-destructor // expressions or normal member (ivar or property) access expressions, and // it's legal for the type to be incomplete if this is a pseudo-destructor // call. We'll do more incomplete-type checks later in the lookup process, // so just skip this check for ObjC types. if (!BaseType->isRecordType()) { ObjectType = ParsedType::make(BaseType); MayBePseudoDestructor = true; return Base; } // The object type must be complete (or dependent), or // C++11 [expr.prim.general]p3: // Unlike the object expression in other contexts, *this is not required to // be of complete type for purposes of class member access (5.2.5) outside // the member function body. if (!BaseType->isDependentType() && !isThisOutsideMemberFunctionBody(BaseType) && RequireCompleteType(OpLoc, BaseType, diag::err_incomplete_member_access)) return ExprError(); // C++ [basic.lookup.classref]p2: // If the id-expression in a class member access (5.2.5) is an // unqualified-id, and the type of the object expression is of a class // type C (or of pointer to a class type C), the unqualified-id is looked // up in the scope of class C. [...] ObjectType = ParsedType::make(BaseType); return Base; } static bool CheckArrow(Sema& S, QualType& ObjectType, Expr *&Base, tok::TokenKind& OpKind, SourceLocation OpLoc) { if (Base->hasPlaceholderType()) { ExprResult result = S.CheckPlaceholderExpr(Base); if (result.isInvalid()) return true; Base = result.get(); } ObjectType = Base->getType(); // C++ [expr.pseudo]p2: // The left-hand side of the dot operator shall be of scalar type. The // left-hand side of the arrow operator shall be of pointer to scalar type. // This scalar type is the object type. // Note that this is rather different from the normal handling for the // arrow operator. if (OpKind == tok::arrow) { if (const PointerType *Ptr = ObjectType->getAs()) { ObjectType = Ptr->getPointeeType(); } else if (!Base->isTypeDependent()) { // The user wrote "p->" when they probably meant "p."; fix it. S.Diag(OpLoc, diag::err_typecheck_member_reference_suggestion) << ObjectType << true << FixItHint::CreateReplacement(OpLoc, "."); if (S.isSFINAEContext()) return true; OpKind = tok::period; } } return false; } /// Check if it's ok to try and recover dot pseudo destructor calls on /// pointer objects. static bool canRecoverDotPseudoDestructorCallsOnPointerObjects(Sema &SemaRef, QualType DestructedType) { // If this is a record type, check if its destructor is callable. if (auto *RD = DestructedType->getAsCXXRecordDecl()) { if (RD->hasDefinition()) if (CXXDestructorDecl *D = SemaRef.LookupDestructor(RD)) return SemaRef.CanUseDecl(D, /*TreatUnavailableAsInvalid=*/false); return false; } // Otherwise, check if it's a type for which it's valid to use a pseudo-dtor. return DestructedType->isDependentType() || DestructedType->isScalarType() || DestructedType->isVectorType(); } ExprResult Sema::BuildPseudoDestructorExpr(Expr *Base, SourceLocation OpLoc, tok::TokenKind OpKind, const CXXScopeSpec &SS, TypeSourceInfo *ScopeTypeInfo, SourceLocation CCLoc, SourceLocation TildeLoc, PseudoDestructorTypeStorage Destructed) { TypeSourceInfo *DestructedTypeInfo = Destructed.getTypeSourceInfo(); QualType ObjectType; if (CheckArrow(*this, ObjectType, Base, OpKind, OpLoc)) return ExprError(); if (!ObjectType->isDependentType() && !ObjectType->isScalarType() && !ObjectType->isVectorType()) { if (getLangOpts().MSVCCompat && ObjectType->isVoidType()) Diag(OpLoc, diag::ext_pseudo_dtor_on_void) << Base->getSourceRange(); else { Diag(OpLoc, diag::err_pseudo_dtor_base_not_scalar) << ObjectType << Base->getSourceRange(); return ExprError(); } } // C++ [expr.pseudo]p2: // [...] The cv-unqualified versions of the object type and of the type // designated by the pseudo-destructor-name shall be the same type. if (DestructedTypeInfo) { QualType DestructedType = DestructedTypeInfo->getType(); SourceLocation DestructedTypeStart = DestructedTypeInfo->getTypeLoc().getLocalSourceRange().getBegin(); if (!DestructedType->isDependentType() && !ObjectType->isDependentType()) { if (!Context.hasSameUnqualifiedType(DestructedType, ObjectType)) { // Detect dot pseudo destructor calls on pointer objects, e.g.: // Foo *foo; // foo.~Foo(); if (OpKind == tok::period && ObjectType->isPointerType() && Context.hasSameUnqualifiedType(DestructedType, ObjectType->getPointeeType())) { auto Diagnostic = Diag(OpLoc, diag::err_typecheck_member_reference_suggestion) << ObjectType << /*IsArrow=*/0 << Base->getSourceRange(); // Issue a fixit only when the destructor is valid. if (canRecoverDotPseudoDestructorCallsOnPointerObjects( *this, DestructedType)) Diagnostic << FixItHint::CreateReplacement(OpLoc, "->"); // Recover by setting the object type to the destructed type and the // operator to '->'. ObjectType = DestructedType; OpKind = tok::arrow; } else { Diag(DestructedTypeStart, diag::err_pseudo_dtor_type_mismatch) << ObjectType << DestructedType << Base->getSourceRange() << DestructedTypeInfo->getTypeLoc().getLocalSourceRange(); // Recover by setting the destructed type to the object type. DestructedType = ObjectType; DestructedTypeInfo = Context.getTrivialTypeSourceInfo(ObjectType, DestructedTypeStart); Destructed = PseudoDestructorTypeStorage(DestructedTypeInfo); } } else if (DestructedType.getObjCLifetime() != ObjectType.getObjCLifetime()) { if (DestructedType.getObjCLifetime() == Qualifiers::OCL_None) { // Okay: just pretend that the user provided the correctly-qualified // type. } else { Diag(DestructedTypeStart, diag::err_arc_pseudo_dtor_inconstant_quals) << ObjectType << DestructedType << Base->getSourceRange() << DestructedTypeInfo->getTypeLoc().getLocalSourceRange(); } // Recover by setting the destructed type to the object type. DestructedType = ObjectType; DestructedTypeInfo = Context.getTrivialTypeSourceInfo(ObjectType, DestructedTypeStart); Destructed = PseudoDestructorTypeStorage(DestructedTypeInfo); } } } // C++ [expr.pseudo]p2: // [...] Furthermore, the two type-names in a pseudo-destructor-name of the // form // // ::[opt] nested-name-specifier[opt] type-name :: ~ type-name // // shall designate the same scalar type. if (ScopeTypeInfo) { QualType ScopeType = ScopeTypeInfo->getType(); if (!ScopeType->isDependentType() && !ObjectType->isDependentType() && !Context.hasSameUnqualifiedType(ScopeType, ObjectType)) { Diag(ScopeTypeInfo->getTypeLoc().getLocalSourceRange().getBegin(), diag::err_pseudo_dtor_type_mismatch) << ObjectType << ScopeType << Base->getSourceRange() << ScopeTypeInfo->getTypeLoc().getLocalSourceRange(); ScopeType = QualType(); ScopeTypeInfo = nullptr; } } Expr *Result = new (Context) CXXPseudoDestructorExpr(Context, Base, OpKind == tok::arrow, OpLoc, SS.getWithLocInContext(Context), ScopeTypeInfo, CCLoc, TildeLoc, Destructed); return Result; } ExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, Expr *Base, SourceLocation OpLoc, tok::TokenKind OpKind, CXXScopeSpec &SS, UnqualifiedId &FirstTypeName, SourceLocation CCLoc, SourceLocation TildeLoc, UnqualifiedId &SecondTypeName) { assert((FirstTypeName.getKind() == UnqualifiedIdKind::IK_TemplateId || FirstTypeName.getKind() == UnqualifiedIdKind::IK_Identifier) && "Invalid first type name in pseudo-destructor"); assert((SecondTypeName.getKind() == UnqualifiedIdKind::IK_TemplateId || SecondTypeName.getKind() == UnqualifiedIdKind::IK_Identifier) && "Invalid second type name in pseudo-destructor"); QualType ObjectType; if (CheckArrow(*this, ObjectType, Base, OpKind, OpLoc)) return ExprError(); // Compute the object type that we should use for name lookup purposes. Only // record types and dependent types matter. ParsedType ObjectTypePtrForLookup; if (!SS.isSet()) { if (ObjectType->isRecordType()) ObjectTypePtrForLookup = ParsedType::make(ObjectType); else if (ObjectType->isDependentType()) ObjectTypePtrForLookup = ParsedType::make(Context.DependentTy); } // Convert the name of the type being destructed (following the ~) into a // type (with source-location information). QualType DestructedType; TypeSourceInfo *DestructedTypeInfo = nullptr; PseudoDestructorTypeStorage Destructed; if (SecondTypeName.getKind() == UnqualifiedIdKind::IK_Identifier) { ParsedType T = getTypeName(*SecondTypeName.Identifier, SecondTypeName.StartLocation, S, &SS, true, false, ObjectTypePtrForLookup, /*IsCtorOrDtorName*/true); if (!T && ((SS.isSet() && !computeDeclContext(SS, false)) || (!SS.isSet() && ObjectType->isDependentType()))) { // The name of the type being destroyed is a dependent name, and we // couldn't find anything useful in scope. Just store the identifier and // it's location, and we'll perform (qualified) name lookup again at // template instantiation time. Destructed = PseudoDestructorTypeStorage(SecondTypeName.Identifier, SecondTypeName.StartLocation); } else if (!T) { Diag(SecondTypeName.StartLocation, diag::err_pseudo_dtor_destructor_non_type) << SecondTypeName.Identifier << ObjectType; if (isSFINAEContext()) return ExprError(); // Recover by assuming we had the right type all along. DestructedType = ObjectType; } else DestructedType = GetTypeFromParser(T, &DestructedTypeInfo); } else { // Resolve the template-id to a type. TemplateIdAnnotation *TemplateId = SecondTypeName.TemplateId; ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(), TemplateId->NumArgs); TypeResult T = ActOnTemplateIdType(S, SS, TemplateId->TemplateKWLoc, TemplateId->Template, TemplateId->Name, TemplateId->TemplateNameLoc, TemplateId->LAngleLoc, TemplateArgsPtr, TemplateId->RAngleLoc, /*IsCtorOrDtorName*/true); if (T.isInvalid() || !T.get()) { // Recover by assuming we had the right type all along. DestructedType = ObjectType; } else DestructedType = GetTypeFromParser(T.get(), &DestructedTypeInfo); } // If we've performed some kind of recovery, (re-)build the type source // information. if (!DestructedType.isNull()) { if (!DestructedTypeInfo) DestructedTypeInfo = Context.getTrivialTypeSourceInfo(DestructedType, SecondTypeName.StartLocation); Destructed = PseudoDestructorTypeStorage(DestructedTypeInfo); } // Convert the name of the scope type (the type prior to '::') into a type. TypeSourceInfo *ScopeTypeInfo = nullptr; QualType ScopeType; if (FirstTypeName.getKind() == UnqualifiedIdKind::IK_TemplateId || FirstTypeName.Identifier) { if (FirstTypeName.getKind() == UnqualifiedIdKind::IK_Identifier) { ParsedType T = getTypeName(*FirstTypeName.Identifier, FirstTypeName.StartLocation, S, &SS, true, false, ObjectTypePtrForLookup, /*IsCtorOrDtorName*/true); if (!T) { Diag(FirstTypeName.StartLocation, diag::err_pseudo_dtor_destructor_non_type) << FirstTypeName.Identifier << ObjectType; if (isSFINAEContext()) return ExprError(); // Just drop this type. It's unnecessary anyway. ScopeType = QualType(); } else ScopeType = GetTypeFromParser(T, &ScopeTypeInfo); } else { // Resolve the template-id to a type. TemplateIdAnnotation *TemplateId = FirstTypeName.TemplateId; ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(), TemplateId->NumArgs); TypeResult T = ActOnTemplateIdType(S, SS, TemplateId->TemplateKWLoc, TemplateId->Template, TemplateId->Name, TemplateId->TemplateNameLoc, TemplateId->LAngleLoc, TemplateArgsPtr, TemplateId->RAngleLoc, /*IsCtorOrDtorName*/true); if (T.isInvalid() || !T.get()) { // Recover by dropping this type. ScopeType = QualType(); } else ScopeType = GetTypeFromParser(T.get(), &ScopeTypeInfo); } } if (!ScopeType.isNull() && !ScopeTypeInfo) ScopeTypeInfo = Context.getTrivialTypeSourceInfo(ScopeType, FirstTypeName.StartLocation); return BuildPseudoDestructorExpr(Base, OpLoc, OpKind, SS, ScopeTypeInfo, CCLoc, TildeLoc, Destructed); } ExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, Expr *Base, SourceLocation OpLoc, tok::TokenKind OpKind, SourceLocation TildeLoc, const DeclSpec& DS) { QualType ObjectType; if (CheckArrow(*this, ObjectType, Base, OpKind, OpLoc)) return ExprError(); QualType T = BuildDecltypeType(DS.getRepAsExpr(), DS.getTypeSpecTypeLoc(), false); TypeLocBuilder TLB; DecltypeTypeLoc DecltypeTL = TLB.push(T); DecltypeTL.setNameLoc(DS.getTypeSpecTypeLoc()); TypeSourceInfo *DestructedTypeInfo = TLB.getTypeSourceInfo(Context, T); PseudoDestructorTypeStorage Destructed(DestructedTypeInfo); return BuildPseudoDestructorExpr(Base, OpLoc, OpKind, CXXScopeSpec(), nullptr, SourceLocation(), TildeLoc, Destructed); } ExprResult Sema::BuildCXXMemberCallExpr(Expr *E, NamedDecl *FoundDecl, CXXConversionDecl *Method, bool HadMultipleCandidates) { // Convert the expression to match the conversion function's implicit object // parameter. ExprResult Exp = PerformObjectArgumentInitialization(E, /*Qualifier=*/nullptr, FoundDecl, Method); if (Exp.isInvalid()) return true; if (Method->getParent()->isLambda() && Method->getConversionType()->isBlockPointerType()) { // This is a lambda conversion to block pointer; check if the argument // was a LambdaExpr. Expr *SubE = E; CastExpr *CE = dyn_cast(SubE); if (CE && CE->getCastKind() == CK_NoOp) SubE = CE->getSubExpr(); SubE = SubE->IgnoreParens(); if (CXXBindTemporaryExpr *BE = dyn_cast(SubE)) SubE = BE->getSubExpr(); if (isa(SubE)) { // For the conversion to block pointer on a lambda expression, we // construct a special BlockLiteral instead; this doesn't really make // a difference in ARC, but outside of ARC the resulting block literal // follows the normal lifetime rules for block literals instead of being // autoreleased. DiagnosticErrorTrap Trap(Diags); PushExpressionEvaluationContext( ExpressionEvaluationContext::PotentiallyEvaluated); ExprResult BlockExp = BuildBlockForLambdaConversion( Exp.get()->getExprLoc(), Exp.get()->getExprLoc(), Method, Exp.get()); PopExpressionEvaluationContext(); if (BlockExp.isInvalid()) Diag(Exp.get()->getExprLoc(), diag::note_lambda_to_block_conv); return BlockExp; } } MemberExpr *ME = BuildMemberExpr(Exp.get(), /*IsArrow=*/false, SourceLocation(), NestedNameSpecifierLoc(), SourceLocation(), Method, DeclAccessPair::make(FoundDecl, FoundDecl->getAccess()), HadMultipleCandidates, DeclarationNameInfo(), Context.BoundMemberTy, VK_RValue, OK_Ordinary); QualType ResultType = Method->getReturnType(); ExprValueKind VK = Expr::getValueKindForType(ResultType); ResultType = ResultType.getNonLValueExprType(Context); CXXMemberCallExpr *CE = CXXMemberCallExpr::Create( Context, ME, /*Args=*/{}, ResultType, VK, Exp.get()->getEndLoc()); if (CheckFunctionCall(Method, CE, Method->getType()->castAs())) return ExprError(); return CE; } ExprResult Sema::BuildCXXNoexceptExpr(SourceLocation KeyLoc, Expr *Operand, SourceLocation RParen) { // If the operand is an unresolved lookup expression, the expression is ill- // formed per [over.over]p1, because overloaded function names cannot be used // without arguments except in explicit contexts. ExprResult R = CheckPlaceholderExpr(Operand); if (R.isInvalid()) return R; R = CheckUnevaluatedOperand(R.get()); if (R.isInvalid()) return ExprError(); Operand = R.get(); if (!inTemplateInstantiation() && Operand->HasSideEffects(Context, false)) { // The expression operand for noexcept is in an unevaluated expression // context, so side effects could result in unintended consequences. Diag(Operand->getExprLoc(), diag::warn_side_effects_unevaluated_context); } CanThrowResult CanThrow = canThrow(Operand); return new (Context) CXXNoexceptExpr(Context.BoolTy, Operand, CanThrow, KeyLoc, RParen); } ExprResult Sema::ActOnNoexceptExpr(SourceLocation KeyLoc, SourceLocation, Expr *Operand, SourceLocation RParen) { return BuildCXXNoexceptExpr(KeyLoc, Operand, RParen); } static bool IsSpecialDiscardedValue(Expr *E) { // In C++11, discarded-value expressions of a certain form are special, // according to [expr]p10: // The lvalue-to-rvalue conversion (4.1) is applied only if the // expression is an lvalue of volatile-qualified type and it has // one of the following forms: E = E->IgnoreParens(); // - id-expression (5.1.1), if (isa(E)) return true; // - subscripting (5.2.1), if (isa(E)) return true; // - class member access (5.2.5), if (isa(E)) return true; // - indirection (5.3.1), if (UnaryOperator *UO = dyn_cast(E)) if (UO->getOpcode() == UO_Deref) return true; if (BinaryOperator *BO = dyn_cast(E)) { // - pointer-to-member operation (5.5), if (BO->isPtrMemOp()) return true; // - comma expression (5.18) where the right operand is one of the above. if (BO->getOpcode() == BO_Comma) return IsSpecialDiscardedValue(BO->getRHS()); } // - conditional expression (5.16) where both the second and the third // operands are one of the above, or if (ConditionalOperator *CO = dyn_cast(E)) return IsSpecialDiscardedValue(CO->getTrueExpr()) && IsSpecialDiscardedValue(CO->getFalseExpr()); // The related edge case of "*x ?: *x". if (BinaryConditionalOperator *BCO = dyn_cast(E)) { if (OpaqueValueExpr *OVE = dyn_cast(BCO->getTrueExpr())) return IsSpecialDiscardedValue(OVE->getSourceExpr()) && IsSpecialDiscardedValue(BCO->getFalseExpr()); } // Objective-C++ extensions to the rule. if (isa(E) || isa(E)) return true; return false; } /// Perform the conversions required for an expression used in a /// context that ignores the result. ExprResult Sema::IgnoredValueConversions(Expr *E) { if (E->hasPlaceholderType()) { ExprResult result = CheckPlaceholderExpr(E); if (result.isInvalid()) return E; E = result.get(); } // C99 6.3.2.1: // [Except in specific positions,] an lvalue that does not have // array type is converted to the value stored in the // designated object (and is no longer an lvalue). if (E->isRValue()) { // In C, function designators (i.e. expressions of function type) // are r-values, but we still want to do function-to-pointer decay // on them. This is both technically correct and convenient for // some clients. if (!getLangOpts().CPlusPlus && E->getType()->isFunctionType()) return DefaultFunctionArrayConversion(E); return E; } if (getLangOpts().CPlusPlus) { // The C++11 standard defines the notion of a discarded-value expression; // normally, we don't need to do anything to handle it, but if it is a // volatile lvalue with a special form, we perform an lvalue-to-rvalue // conversion. if (getLangOpts().CPlusPlus11 && E->isGLValue() && E->getType().isVolatileQualified()) { if (IsSpecialDiscardedValue(E)) { ExprResult Res = DefaultLvalueConversion(E); if (Res.isInvalid()) return E; E = Res.get(); } else { // Per C++2a [expr.ass]p5, a volatile assignment is not deprecated if // it occurs as a discarded-value expression. CheckUnusedVolatileAssignment(E); } } // C++1z: // If the expression is a prvalue after this optional conversion, the // temporary materialization conversion is applied. // // We skip this step: IR generation is able to synthesize the storage for // itself in the aggregate case, and adding the extra node to the AST is // just clutter. // FIXME: We don't emit lifetime markers for the temporaries due to this. // FIXME: Do any other AST consumers care about this? return E; } // GCC seems to also exclude expressions of incomplete enum type. if (const EnumType *T = E->getType()->getAs()) { if (!T->getDecl()->isComplete()) { // FIXME: stupid workaround for a codegen bug! E = ImpCastExprToType(E, Context.VoidTy, CK_ToVoid).get(); return E; } } ExprResult Res = DefaultFunctionArrayLvalueConversion(E); if (Res.isInvalid()) return E; E = Res.get(); if (!E->getType()->isVoidType()) RequireCompleteType(E->getExprLoc(), E->getType(), diag::err_incomplete_type); return E; } ExprResult Sema::CheckUnevaluatedOperand(Expr *E) { // Per C++2a [expr.ass]p5, a volatile assignment is not deprecated if // it occurs as an unevaluated operand. CheckUnusedVolatileAssignment(E); return E; } // If we can unambiguously determine whether Var can never be used // in a constant expression, return true. // - if the variable and its initializer are non-dependent, then // we can unambiguously check if the variable is a constant expression. // - if the initializer is not value dependent - we can determine whether // it can be used to initialize a constant expression. If Init can not // be used to initialize a constant expression we conclude that Var can // never be a constant expression. // - FXIME: if the initializer is dependent, we can still do some analysis and // identify certain cases unambiguously as non-const by using a Visitor: // - such as those that involve odr-use of a ParmVarDecl, involve a new // delete, lambda-expr, dynamic-cast, reinterpret-cast etc... static inline bool VariableCanNeverBeAConstantExpression(VarDecl *Var, ASTContext &Context) { if (isa(Var)) return true; const VarDecl *DefVD = nullptr; // If there is no initializer - this can not be a constant expression. if (!Var->getAnyInitializer(DefVD)) return true; assert(DefVD); if (DefVD->isWeak()) return false; EvaluatedStmt *Eval = DefVD->ensureEvaluatedStmt(); Expr *Init = cast(Eval->Value); if (Var->getType()->isDependentType() || Init->isValueDependent()) { // FIXME: Teach the constant evaluator to deal with the non-dependent parts // of value-dependent expressions, and use it here to determine whether the // initializer is a potential constant expression. return false; } return !Var->isUsableInConstantExpressions(Context); } /// Check if the current lambda has any potential captures /// that must be captured by any of its enclosing lambdas that are ready to /// capture. If there is a lambda that can capture a nested /// potential-capture, go ahead and do so. Also, check to see if any /// variables are uncaptureable or do not involve an odr-use so do not /// need to be captured. static void CheckIfAnyEnclosingLambdasMustCaptureAnyPotentialCaptures( Expr *const FE, LambdaScopeInfo *const CurrentLSI, Sema &S) { assert(!S.isUnevaluatedContext()); assert(S.CurContext->isDependentContext()); #ifndef NDEBUG DeclContext *DC = S.CurContext; while (DC && isa(DC)) DC = DC->getParent(); assert( CurrentLSI->CallOperator == DC && "The current call operator must be synchronized with Sema's CurContext"); #endif // NDEBUG const bool IsFullExprInstantiationDependent = FE->isInstantiationDependent(); // All the potentially captureable variables in the current nested // lambda (within a generic outer lambda), must be captured by an // outer lambda that is enclosed within a non-dependent context. CurrentLSI->visitPotentialCaptures([&] (VarDecl *Var, Expr *VarExpr) { // If the variable is clearly identified as non-odr-used and the full // expression is not instantiation dependent, only then do we not // need to check enclosing lambda's for speculative captures. // For e.g.: // Even though 'x' is not odr-used, it should be captured. // int test() { // const int x = 10; // auto L = [=](auto a) { // (void) +x + a; // }; // } if (CurrentLSI->isVariableExprMarkedAsNonODRUsed(VarExpr) && !IsFullExprInstantiationDependent) return; // If we have a capture-capable lambda for the variable, go ahead and // capture the variable in that lambda (and all its enclosing lambdas). if (const Optional Index = getStackIndexOfNearestEnclosingCaptureCapableLambda( S.FunctionScopes, Var, S)) S.MarkCaptureUsedInEnclosingContext(Var, VarExpr->getExprLoc(), Index.getValue()); const bool IsVarNeverAConstantExpression = VariableCanNeverBeAConstantExpression(Var, S.Context); if (!IsFullExprInstantiationDependent || IsVarNeverAConstantExpression) { // This full expression is not instantiation dependent or the variable // can not be used in a constant expression - which means // this variable must be odr-used here, so diagnose a // capture violation early, if the variable is un-captureable. // This is purely for diagnosing errors early. Otherwise, this // error would get diagnosed when the lambda becomes capture ready. QualType CaptureType, DeclRefType; SourceLocation ExprLoc = VarExpr->getExprLoc(); if (S.tryCaptureVariable(Var, ExprLoc, S.TryCapture_Implicit, /*EllipsisLoc*/ SourceLocation(), /*BuildAndDiagnose*/false, CaptureType, DeclRefType, nullptr)) { // We will never be able to capture this variable, and we need // to be able to in any and all instantiations, so diagnose it. S.tryCaptureVariable(Var, ExprLoc, S.TryCapture_Implicit, /*EllipsisLoc*/ SourceLocation(), /*BuildAndDiagnose*/true, CaptureType, DeclRefType, nullptr); } } }); // Check if 'this' needs to be captured. if (CurrentLSI->hasPotentialThisCapture()) { // If we have a capture-capable lambda for 'this', go ahead and capture // 'this' in that lambda (and all its enclosing lambdas). if (const Optional Index = getStackIndexOfNearestEnclosingCaptureCapableLambda( S.FunctionScopes, /*0 is 'this'*/ nullptr, S)) { const unsigned FunctionScopeIndexOfCapturableLambda = Index.getValue(); S.CheckCXXThisCapture(CurrentLSI->PotentialThisCaptureLocation, /*Explicit*/ false, /*BuildAndDiagnose*/ true, &FunctionScopeIndexOfCapturableLambda); } } // Reset all the potential captures at the end of each full-expression. CurrentLSI->clearPotentialCaptures(); } static ExprResult attemptRecovery(Sema &SemaRef, const TypoCorrectionConsumer &Consumer, const TypoCorrection &TC) { LookupResult R(SemaRef, Consumer.getLookupResult().getLookupNameInfo(), Consumer.getLookupResult().getLookupKind()); const CXXScopeSpec *SS = Consumer.getSS(); CXXScopeSpec NewSS; // Use an approprate CXXScopeSpec for building the expr. if (auto *NNS = TC.getCorrectionSpecifier()) NewSS.MakeTrivial(SemaRef.Context, NNS, TC.getCorrectionRange()); else if (SS && !TC.WillReplaceSpecifier()) NewSS = *SS; if (auto *ND = TC.getFoundDecl()) { R.setLookupName(ND->getDeclName()); R.addDecl(ND); if (ND->isCXXClassMember()) { // Figure out the correct naming class to add to the LookupResult. CXXRecordDecl *Record = nullptr; if (auto *NNS = TC.getCorrectionSpecifier()) Record = NNS->getAsType()->getAsCXXRecordDecl(); if (!Record) Record = dyn_cast(ND->getDeclContext()->getRedeclContext()); if (Record) R.setNamingClass(Record); // Detect and handle the case where the decl might be an implicit // member. bool MightBeImplicitMember; if (!Consumer.isAddressOfOperand()) MightBeImplicitMember = true; else if (!NewSS.isEmpty()) MightBeImplicitMember = false; else if (R.isOverloadedResult()) MightBeImplicitMember = false; else if (R.isUnresolvableResult()) MightBeImplicitMember = true; else MightBeImplicitMember = isa(ND) || isa(ND) || isa(ND); if (MightBeImplicitMember) return SemaRef.BuildPossibleImplicitMemberExpr( NewSS, /*TemplateKWLoc*/ SourceLocation(), R, /*TemplateArgs*/ nullptr, /*S*/ nullptr); } else if (auto *Ivar = dyn_cast(ND)) { return SemaRef.LookupInObjCMethod(R, Consumer.getScope(), Ivar->getIdentifier()); } } return SemaRef.BuildDeclarationNameExpr(NewSS, R, /*NeedsADL*/ false, /*AcceptInvalidDecl*/ true); } namespace { class FindTypoExprs : public RecursiveASTVisitor { llvm::SmallSetVector &TypoExprs; public: explicit FindTypoExprs(llvm::SmallSetVector &TypoExprs) : TypoExprs(TypoExprs) {} bool VisitTypoExpr(TypoExpr *TE) { TypoExprs.insert(TE); return true; } }; class TransformTypos : public TreeTransform { typedef TreeTransform BaseTransform; VarDecl *InitDecl; // A decl to avoid as a correction because it is in the // process of being initialized. llvm::function_ref ExprFilter; llvm::SmallSetVector TypoExprs, AmbiguousTypoExprs; llvm::SmallDenseMap TransformCache; llvm::SmallDenseMap OverloadResolution; /// Emit diagnostics for all of the TypoExprs encountered. /// /// If the TypoExprs were successfully corrected, then the diagnostics should /// suggest the corrections. Otherwise the diagnostics will not suggest /// anything (having been passed an empty TypoCorrection). /// /// If we've failed to correct due to ambiguous corrections, we need to /// be sure to pass empty corrections and replacements. Otherwise it's /// possible that the Consumer has a TypoCorrection that failed to ambiguity /// and we don't want to report those diagnostics. void EmitAllDiagnostics(bool IsAmbiguous) { for (TypoExpr *TE : TypoExprs) { auto &State = SemaRef.getTypoExprState(TE); if (State.DiagHandler) { TypoCorrection TC = IsAmbiguous ? TypoCorrection() : State.Consumer->getCurrentCorrection(); ExprResult Replacement = IsAmbiguous ? ExprError() : TransformCache[TE]; // Extract the NamedDecl from the transformed TypoExpr and add it to the // TypoCorrection, replacing the existing decls. This ensures the right // NamedDecl is used in diagnostics e.g. in the case where overload // resolution was used to select one from several possible decls that // had been stored in the TypoCorrection. if (auto *ND = getDeclFromExpr( Replacement.isInvalid() ? nullptr : Replacement.get())) TC.setCorrectionDecl(ND); State.DiagHandler(TC); } SemaRef.clearDelayedTypo(TE); } } /// If corrections for the first TypoExpr have been exhausted for a /// given combination of the other TypoExprs, retry those corrections against /// the next combination of substitutions for the other TypoExprs by advancing /// to the next potential correction of the second TypoExpr. For the second /// and subsequent TypoExprs, if its stream of corrections has been exhausted, /// the stream is reset and the next TypoExpr's stream is advanced by one (a /// TypoExpr's correction stream is advanced by removing the TypoExpr from the /// TransformCache). Returns true if there is still any untried combinations /// of corrections. bool CheckAndAdvanceTypoExprCorrectionStreams() { for (auto TE : TypoExprs) { auto &State = SemaRef.getTypoExprState(TE); TransformCache.erase(TE); if (!State.Consumer->finished()) return true; State.Consumer->resetCorrectionStream(); } return false; } NamedDecl *getDeclFromExpr(Expr *E) { if (auto *OE = dyn_cast_or_null(E)) E = OverloadResolution[OE]; if (!E) return nullptr; if (auto *DRE = dyn_cast(E)) return DRE->getFoundDecl(); if (auto *ME = dyn_cast(E)) return ME->getFoundDecl(); // FIXME: Add any other expr types that could be be seen by the delayed typo // correction TreeTransform for which the corresponding TypoCorrection could // contain multiple decls. return nullptr; } ExprResult TryTransform(Expr *E) { Sema::SFINAETrap Trap(SemaRef); ExprResult Res = TransformExpr(E); if (Trap.hasErrorOccurred() || Res.isInvalid()) return ExprError(); return ExprFilter(Res.get()); } // Since correcting typos may intoduce new TypoExprs, this function // checks for new TypoExprs and recurses if it finds any. Note that it will // only succeed if it is able to correct all typos in the given expression. ExprResult CheckForRecursiveTypos(ExprResult Res, bool &IsAmbiguous) { if (Res.isInvalid()) { return Res; } // Check to see if any new TypoExprs were created. If so, we need to recurse // to check their validity. Expr *FixedExpr = Res.get(); auto SavedTypoExprs = std::move(TypoExprs); auto SavedAmbiguousTypoExprs = std::move(AmbiguousTypoExprs); TypoExprs.clear(); AmbiguousTypoExprs.clear(); FindTypoExprs(TypoExprs).TraverseStmt(FixedExpr); if (!TypoExprs.empty()) { // Recurse to handle newly created TypoExprs. If we're not able to // handle them, discard these TypoExprs. ExprResult RecurResult = RecursiveTransformLoop(FixedExpr, IsAmbiguous); if (RecurResult.isInvalid()) { Res = ExprError(); // Recursive corrections didn't work, wipe them away and don't add // them to the TypoExprs set. Remove them from Sema's TypoExpr list // since we don't want to clear them twice. Note: it's possible the // TypoExprs were created recursively and thus won't be in our // Sema's TypoExprs - they were created in our `RecursiveTransformLoop`. auto &SemaTypoExprs = SemaRef.TypoExprs; for (auto TE : TypoExprs) { TransformCache.erase(TE); SemaRef.clearDelayedTypo(TE); auto SI = find(SemaTypoExprs, TE); if (SI != SemaTypoExprs.end()) { SemaTypoExprs.erase(SI); } } } else { // TypoExpr is valid: add newly created TypoExprs since we were // able to correct them. Res = RecurResult; SavedTypoExprs.set_union(TypoExprs); } } TypoExprs = std::move(SavedTypoExprs); AmbiguousTypoExprs = std::move(SavedAmbiguousTypoExprs); return Res; } // Try to transform the given expression, looping through the correction // candidates with `CheckAndAdvanceTypoExprCorrectionStreams`. // // If valid ambiguous typo corrections are seen, `IsAmbiguous` is set to // true and this method immediately will return an `ExprError`. ExprResult RecursiveTransformLoop(Expr *E, bool &IsAmbiguous) { ExprResult Res; auto SavedTypoExprs = std::move(SemaRef.TypoExprs); SemaRef.TypoExprs.clear(); while (true) { Res = CheckForRecursiveTypos(TryTransform(E), IsAmbiguous); // Recursion encountered an ambiguous correction. This means that our // correction itself is ambiguous, so stop now. if (IsAmbiguous) break; // If the transform is still valid after checking for any new typos, // it's good to go. if (!Res.isInvalid()) break; // The transform was invalid, see if we have any TypoExprs with untried // correction candidates. if (!CheckAndAdvanceTypoExprCorrectionStreams()) break; } // If we found a valid result, double check to make sure it's not ambiguous. if (!IsAmbiguous && !Res.isInvalid() && !AmbiguousTypoExprs.empty()) { auto SavedTransformCache = llvm::SmallDenseMap(TransformCache); // Ensure none of the TypoExprs have multiple typo correction candidates // with the same edit length that pass all the checks and filters. while (!AmbiguousTypoExprs.empty()) { auto TE = AmbiguousTypoExprs.back(); // TryTransform itself can create new Typos, adding them to the TypoExpr map // and invalidating our TypoExprState, so always fetch it instead of storing. SemaRef.getTypoExprState(TE).Consumer->saveCurrentPosition(); TypoCorrection TC = SemaRef.getTypoExprState(TE).Consumer->peekNextCorrection(); TypoCorrection Next; do { // Fetch the next correction by erasing the typo from the cache and calling // `TryTransform` which will iterate through corrections in // `TransformTypoExpr`. TransformCache.erase(TE); ExprResult AmbigRes = CheckForRecursiveTypos(TryTransform(E), IsAmbiguous); if (!AmbigRes.isInvalid() || IsAmbiguous) { SemaRef.getTypoExprState(TE).Consumer->resetCorrectionStream(); SavedTransformCache.erase(TE); Res = ExprError(); IsAmbiguous = true; break; } } while ((Next = SemaRef.getTypoExprState(TE).Consumer->peekNextCorrection()) && Next.getEditDistance(false) == TC.getEditDistance(false)); if (IsAmbiguous) break; AmbiguousTypoExprs.remove(TE); SemaRef.getTypoExprState(TE).Consumer->restoreSavedPosition(); } TransformCache = std::move(SavedTransformCache); } // Wipe away any newly created TypoExprs that we don't know about. Since we // clear any invalid TypoExprs in `CheckForRecursiveTypos`, this is only // possible if a `TypoExpr` is created during a transformation but then // fails before we can discover it. auto &SemaTypoExprs = SemaRef.TypoExprs; for (auto Iterator = SemaTypoExprs.begin(); Iterator != SemaTypoExprs.end();) { auto TE = *Iterator; auto FI = find(TypoExprs, TE); if (FI != TypoExprs.end()) { Iterator++; continue; } SemaRef.clearDelayedTypo(TE); Iterator = SemaTypoExprs.erase(Iterator); } SemaRef.TypoExprs = std::move(SavedTypoExprs); return Res; } public: TransformTypos(Sema &SemaRef, VarDecl *InitDecl, llvm::function_ref Filter) : BaseTransform(SemaRef), InitDecl(InitDecl), ExprFilter(Filter) {} ExprResult RebuildCallExpr(Expr *Callee, SourceLocation LParenLoc, MultiExprArg Args, SourceLocation RParenLoc, Expr *ExecConfig = nullptr) { auto Result = BaseTransform::RebuildCallExpr(Callee, LParenLoc, Args, RParenLoc, ExecConfig); if (auto *OE = dyn_cast(Callee)) { if (Result.isUsable()) { Expr *ResultCall = Result.get(); if (auto *BE = dyn_cast(ResultCall)) ResultCall = BE->getSubExpr(); if (auto *CE = dyn_cast(ResultCall)) OverloadResolution[OE] = CE->getCallee(); } } return Result; } ExprResult TransformLambdaExpr(LambdaExpr *E) { return Owned(E); } ExprResult TransformBlockExpr(BlockExpr *E) { return Owned(E); } ExprResult Transform(Expr *E) { bool IsAmbiguous = false; ExprResult Res = RecursiveTransformLoop(E, IsAmbiguous); if (!Res.isUsable()) FindTypoExprs(TypoExprs).TraverseStmt(E); EmitAllDiagnostics(IsAmbiguous); return Res; } ExprResult TransformTypoExpr(TypoExpr *E) { // If the TypoExpr hasn't been seen before, record it. Otherwise, return the // cached transformation result if there is one and the TypoExpr isn't the // first one that was encountered. auto &CacheEntry = TransformCache[E]; if (!TypoExprs.insert(E) && !CacheEntry.isUnset()) { return CacheEntry; } auto &State = SemaRef.getTypoExprState(E); assert(State.Consumer && "Cannot transform a cleared TypoExpr"); // For the first TypoExpr and an uncached TypoExpr, find the next likely // typo correction and return it. while (TypoCorrection TC = State.Consumer->getNextCorrection()) { if (InitDecl && TC.getFoundDecl() == InitDecl) continue; // FIXME: If we would typo-correct to an invalid declaration, it's // probably best to just suppress all errors from this typo correction. ExprResult NE = State.RecoveryHandler ? State.RecoveryHandler(SemaRef, E, TC) : attemptRecovery(SemaRef, *State.Consumer, TC); if (!NE.isInvalid()) { // Check whether there may be a second viable correction with the same // edit distance; if so, remember this TypoExpr may have an ambiguous // correction so it can be more thoroughly vetted later. TypoCorrection Next; if ((Next = State.Consumer->peekNextCorrection()) && Next.getEditDistance(false) == TC.getEditDistance(false)) { AmbiguousTypoExprs.insert(E); } else { AmbiguousTypoExprs.remove(E); } assert(!NE.isUnset() && "Typo was transformed into a valid-but-null ExprResult"); return CacheEntry = NE; } } return CacheEntry = ExprError(); } }; } ExprResult Sema::CorrectDelayedTyposInExpr(Expr *E, VarDecl *InitDecl, llvm::function_ref Filter) { // If the current evaluation context indicates there are uncorrected typos // and the current expression isn't guaranteed to not have typos, try to // resolve any TypoExpr nodes that might be in the expression. if (E && !ExprEvalContexts.empty() && ExprEvalContexts.back().NumTypos && (E->isTypeDependent() || E->isValueDependent() || E->isInstantiationDependent())) { auto TyposResolved = DelayedTypos.size(); auto Result = TransformTypos(*this, InitDecl, Filter).Transform(E); TyposResolved -= DelayedTypos.size(); if (Result.isInvalid() || Result.get() != E) { ExprEvalContexts.back().NumTypos -= TyposResolved; return Result; } assert(TyposResolved == 0 && "Corrected typo but got same Expr back?"); } return E; } ExprResult Sema::ActOnFinishFullExpr(Expr *FE, SourceLocation CC, bool DiscardedValue, bool IsConstexpr) { ExprResult FullExpr = FE; if (!FullExpr.get()) return ExprError(); if (DiagnoseUnexpandedParameterPack(FullExpr.get())) return ExprError(); if (DiscardedValue) { // Top-level expressions default to 'id' when we're in a debugger. if (getLangOpts().DebuggerCastResultToId && FullExpr.get()->getType() == Context.UnknownAnyTy) { FullExpr = forceUnknownAnyToType(FullExpr.get(), Context.getObjCIdType()); if (FullExpr.isInvalid()) return ExprError(); } FullExpr = CheckPlaceholderExpr(FullExpr.get()); if (FullExpr.isInvalid()) return ExprError(); FullExpr = IgnoredValueConversions(FullExpr.get()); if (FullExpr.isInvalid()) return ExprError(); DiagnoseUnusedExprResult(FullExpr.get()); } FullExpr = CorrectDelayedTyposInExpr(FullExpr.get()); if (FullExpr.isInvalid()) return ExprError(); CheckCompletedExpr(FullExpr.get(), CC, IsConstexpr); // At the end of this full expression (which could be a deeply nested // lambda), if there is a potential capture within the nested lambda, // have the outer capture-able lambda try and capture it. // Consider the following code: // void f(int, int); // void f(const int&, double); // void foo() { // const int x = 10, y = 20; // auto L = [=](auto a) { // auto M = [=](auto b) { // f(x, b); <-- requires x to be captured by L and M // f(y, a); <-- requires y to be captured by L, but not all Ms // }; // }; // } // FIXME: Also consider what happens for something like this that involves // the gnu-extension statement-expressions or even lambda-init-captures: // void f() { // const int n = 0; // auto L = [&](auto a) { // +n + ({ 0; a; }); // }; // } // // Here, we see +n, and then the full-expression 0; ends, so we don't // capture n (and instead remove it from our list of potential captures), // and then the full-expression +n + ({ 0; }); ends, but it's too late // for us to see that we need to capture n after all. LambdaScopeInfo *const CurrentLSI = getCurLambda(/*IgnoreCapturedRegions=*/true); // FIXME: PR 17877 showed that getCurLambda() can return a valid pointer // even if CurContext is not a lambda call operator. Refer to that Bug Report // for an example of the code that might cause this asynchrony. // By ensuring we are in the context of a lambda's call operator // we can fix the bug (we only need to check whether we need to capture // if we are within a lambda's body); but per the comments in that // PR, a proper fix would entail : // "Alternative suggestion: // - Add to Sema an integer holding the smallest (outermost) scope // index that we are *lexically* within, and save/restore/set to // FunctionScopes.size() in InstantiatingTemplate's // constructor/destructor. // - Teach the handful of places that iterate over FunctionScopes to // stop at the outermost enclosing lexical scope." DeclContext *DC = CurContext; while (DC && isa(DC)) DC = DC->getParent(); const bool IsInLambdaDeclContext = isLambdaCallOperator(DC); if (IsInLambdaDeclContext && CurrentLSI && CurrentLSI->hasPotentialCaptures() && !FullExpr.isInvalid()) CheckIfAnyEnclosingLambdasMustCaptureAnyPotentialCaptures(FE, CurrentLSI, *this); return MaybeCreateExprWithCleanups(FullExpr); } StmtResult Sema::ActOnFinishFullStmt(Stmt *FullStmt) { if (!FullStmt) return StmtError(); return MaybeCreateStmtWithCleanups(FullStmt); } Sema::IfExistsResult Sema::CheckMicrosoftIfExistsSymbol(Scope *S, CXXScopeSpec &SS, const DeclarationNameInfo &TargetNameInfo) { DeclarationName TargetName = TargetNameInfo.getName(); if (!TargetName) return IER_DoesNotExist; // If the name itself is dependent, then the result is dependent. if (TargetName.isDependentName()) return IER_Dependent; // Do the redeclaration lookup in the current scope. LookupResult R(*this, TargetNameInfo, Sema::LookupAnyName, Sema::NotForRedeclaration); LookupParsedName(R, S, &SS); R.suppressDiagnostics(); switch (R.getResultKind()) { case LookupResult::Found: case LookupResult::FoundOverloaded: case LookupResult::FoundUnresolvedValue: case LookupResult::Ambiguous: return IER_Exists; case LookupResult::NotFound: return IER_DoesNotExist; case LookupResult::NotFoundInCurrentInstantiation: return IER_Dependent; } llvm_unreachable("Invalid LookupResult Kind!"); } Sema::IfExistsResult Sema::CheckMicrosoftIfExistsSymbol(Scope *S, SourceLocation KeywordLoc, bool IsIfExists, CXXScopeSpec &SS, UnqualifiedId &Name) { DeclarationNameInfo TargetNameInfo = GetNameFromUnqualifiedId(Name); // Check for an unexpanded parameter pack. auto UPPC = IsIfExists ? UPPC_IfExists : UPPC_IfNotExists; if (DiagnoseUnexpandedParameterPack(SS, UPPC) || DiagnoseUnexpandedParameterPack(TargetNameInfo, UPPC)) return IER_Error; return CheckMicrosoftIfExistsSymbol(S, SS, TargetNameInfo); } concepts::Requirement *Sema::ActOnSimpleRequirement(Expr *E) { return BuildExprRequirement(E, /*IsSimple=*/true, /*NoexceptLoc=*/SourceLocation(), /*ReturnTypeRequirement=*/{}); } concepts::Requirement * Sema::ActOnTypeRequirement(SourceLocation TypenameKWLoc, CXXScopeSpec &SS, SourceLocation NameLoc, IdentifierInfo *TypeName, TemplateIdAnnotation *TemplateId) { assert(((!TypeName && TemplateId) || (TypeName && !TemplateId)) && "Exactly one of TypeName and TemplateId must be specified."); TypeSourceInfo *TSI = nullptr; if (TypeName) { QualType T = CheckTypenameType(ETK_Typename, TypenameKWLoc, SS.getWithLocInContext(Context), *TypeName, NameLoc, &TSI, /*DeducedTypeContext=*/false); if (T.isNull()) return nullptr; } else { ASTTemplateArgsPtr ArgsPtr(TemplateId->getTemplateArgs(), TemplateId->NumArgs); TypeResult T = ActOnTypenameType(CurScope, TypenameKWLoc, SS, TemplateId->TemplateKWLoc, TemplateId->Template, TemplateId->Name, TemplateId->TemplateNameLoc, TemplateId->LAngleLoc, ArgsPtr, TemplateId->RAngleLoc); if (T.isInvalid()) return nullptr; if (GetTypeFromParser(T.get(), &TSI).isNull()) return nullptr; } return BuildTypeRequirement(TSI); } concepts::Requirement * Sema::ActOnCompoundRequirement(Expr *E, SourceLocation NoexceptLoc) { return BuildExprRequirement(E, /*IsSimple=*/false, NoexceptLoc, /*ReturnTypeRequirement=*/{}); } concepts::Requirement * Sema::ActOnCompoundRequirement( Expr *E, SourceLocation NoexceptLoc, CXXScopeSpec &SS, TemplateIdAnnotation *TypeConstraint, unsigned Depth) { // C++2a [expr.prim.req.compound] p1.3.3 // [..] the expression is deduced against an invented function template // F [...] F is a void function template with a single type template // parameter T declared with the constrained-parameter. Form a new // cv-qualifier-seq cv by taking the union of const and volatile specifiers // around the constrained-parameter. F has a single parameter whose // type-specifier is cv T followed by the abstract-declarator. [...] // // The cv part is done in the calling function - we get the concept with // arguments and the abstract declarator with the correct CV qualification and // have to synthesize T and the single parameter of F. auto &II = Context.Idents.get("expr-type"); auto *TParam = TemplateTypeParmDecl::Create(Context, CurContext, SourceLocation(), SourceLocation(), Depth, /*Index=*/0, &II, /*Typename=*/true, /*ParameterPack=*/false, /*HasTypeConstraint=*/true); if (ActOnTypeConstraint(SS, TypeConstraint, TParam, /*EllpsisLoc=*/SourceLocation())) // Just produce a requirement with no type requirements. return BuildExprRequirement(E, /*IsSimple=*/false, NoexceptLoc, {}); auto *TPL = TemplateParameterList::Create(Context, SourceLocation(), SourceLocation(), ArrayRef(TParam), SourceLocation(), /*RequiresClause=*/nullptr); return BuildExprRequirement( E, /*IsSimple=*/false, NoexceptLoc, concepts::ExprRequirement::ReturnTypeRequirement(TPL)); } concepts::ExprRequirement * Sema::BuildExprRequirement( Expr *E, bool IsSimple, SourceLocation NoexceptLoc, concepts::ExprRequirement::ReturnTypeRequirement ReturnTypeRequirement) { auto Status = concepts::ExprRequirement::SS_Satisfied; ConceptSpecializationExpr *SubstitutedConstraintExpr = nullptr; if (E->isInstantiationDependent() || ReturnTypeRequirement.isDependent()) Status = concepts::ExprRequirement::SS_Dependent; else if (NoexceptLoc.isValid() && canThrow(E) == CanThrowResult::CT_Can) Status = concepts::ExprRequirement::SS_NoexceptNotMet; else if (ReturnTypeRequirement.isSubstitutionFailure()) Status = concepts::ExprRequirement::SS_TypeRequirementSubstitutionFailure; else if (ReturnTypeRequirement.isTypeConstraint()) { // C++2a [expr.prim.req]p1.3.3 // The immediately-declared constraint ([temp]) of decltype((E)) shall // be satisfied. TemplateParameterList *TPL = ReturnTypeRequirement.getTypeConstraintTemplateParameterList(); QualType MatchedType = BuildDecltypeType(E, E->getBeginLoc()).getCanonicalType(); llvm::SmallVector Args; Args.push_back(TemplateArgument(MatchedType)); TemplateArgumentList TAL(TemplateArgumentList::OnStack, Args); MultiLevelTemplateArgumentList MLTAL(TAL); for (unsigned I = 0; I < TPL->getDepth(); ++I) MLTAL.addOuterRetainedLevel(); Expr *IDC = cast(TPL->getParam(0))->getTypeConstraint() ->getImmediatelyDeclaredConstraint(); ExprResult Constraint = SubstExpr(IDC, MLTAL); assert(!Constraint.isInvalid() && "Substitution cannot fail as it is simply putting a type template " "argument into a concept specialization expression's parameter."); SubstitutedConstraintExpr = cast(Constraint.get()); if (!SubstitutedConstraintExpr->isSatisfied()) Status = concepts::ExprRequirement::SS_ConstraintsNotSatisfied; } return new (Context) concepts::ExprRequirement(E, IsSimple, NoexceptLoc, ReturnTypeRequirement, Status, SubstitutedConstraintExpr); } concepts::ExprRequirement * Sema::BuildExprRequirement( concepts::Requirement::SubstitutionDiagnostic *ExprSubstitutionDiagnostic, bool IsSimple, SourceLocation NoexceptLoc, concepts::ExprRequirement::ReturnTypeRequirement ReturnTypeRequirement) { return new (Context) concepts::ExprRequirement(ExprSubstitutionDiagnostic, IsSimple, NoexceptLoc, ReturnTypeRequirement); } concepts::TypeRequirement * Sema::BuildTypeRequirement(TypeSourceInfo *Type) { return new (Context) concepts::TypeRequirement(Type); } concepts::TypeRequirement * Sema::BuildTypeRequirement( concepts::Requirement::SubstitutionDiagnostic *SubstDiag) { return new (Context) concepts::TypeRequirement(SubstDiag); } concepts::Requirement *Sema::ActOnNestedRequirement(Expr *Constraint) { return BuildNestedRequirement(Constraint); } concepts::NestedRequirement * Sema::BuildNestedRequirement(Expr *Constraint) { ConstraintSatisfaction Satisfaction; if (!Constraint->isInstantiationDependent() && CheckConstraintSatisfaction(nullptr, {Constraint}, /*TemplateArgs=*/{}, Constraint->getSourceRange(), Satisfaction)) return nullptr; return new (Context) concepts::NestedRequirement(Context, Constraint, Satisfaction); } concepts::NestedRequirement * Sema::BuildNestedRequirement( concepts::Requirement::SubstitutionDiagnostic *SubstDiag) { return new (Context) concepts::NestedRequirement(SubstDiag); } RequiresExprBodyDecl * Sema::ActOnStartRequiresExpr(SourceLocation RequiresKWLoc, ArrayRef LocalParameters, Scope *BodyScope) { assert(BodyScope); RequiresExprBodyDecl *Body = RequiresExprBodyDecl::Create(Context, CurContext, RequiresKWLoc); PushDeclContext(BodyScope, Body); for (ParmVarDecl *Param : LocalParameters) { if (Param->hasDefaultArg()) // C++2a [expr.prim.req] p4 // [...] A local parameter of a requires-expression shall not have a // default argument. [...] Diag(Param->getDefaultArgRange().getBegin(), diag::err_requires_expr_local_parameter_default_argument); // Ignore default argument and move on Param->setDeclContext(Body); // If this has an identifier, add it to the scope stack. if (Param->getIdentifier()) { CheckShadow(BodyScope, Param); PushOnScopeChains(Param, BodyScope); } } return Body; } void Sema::ActOnFinishRequiresExpr() { assert(CurContext && "DeclContext imbalance!"); CurContext = CurContext->getLexicalParent(); assert(CurContext && "Popped translation unit!"); } ExprResult Sema::ActOnRequiresExpr(SourceLocation RequiresKWLoc, RequiresExprBodyDecl *Body, ArrayRef LocalParameters, ArrayRef Requirements, SourceLocation ClosingBraceLoc) { return RequiresExpr::Create(Context, RequiresKWLoc, Body, LocalParameters, Requirements, ClosingBraceLoc); } Index: vendor/llvm-project/release-10.x/clang/lib/Sema/SemaTemplate.cpp =================================================================== --- vendor/llvm-project/release-10.x/clang/lib/Sema/SemaTemplate.cpp (revision 359078) +++ vendor/llvm-project/release-10.x/clang/lib/Sema/SemaTemplate.cpp (revision 359079) @@ -1,10815 +1,10863 @@ //===------- SemaTemplate.cpp - Semantic Analysis for C++ Templates -------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception //===----------------------------------------------------------------------===// // // This file implements semantic analysis for C++ templates. //===----------------------------------------------------------------------===// #include "TreeTransform.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclFriend.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/TypeVisitor.h" #include "clang/Basic/Builtins.h" #include "clang/Basic/LangOptions.h" #include "clang/Basic/PartialDiagnostic.h" #include "clang/Basic/Stack.h" #include "clang/Basic/TargetInfo.h" #include "clang/Sema/DeclSpec.h" #include "clang/Sema/Lookup.h" #include "clang/Sema/Overload.h" #include "clang/Sema/ParsedTemplate.h" #include "clang/Sema/Scope.h" #include "clang/Sema/SemaInternal.h" #include "clang/Sema/Template.h" #include "clang/Sema/TemplateDeduction.h" #include "llvm/ADT/SmallBitVector.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringExtras.h" #include using namespace clang; using namespace sema; // Exported for use by Parser. SourceRange clang::getTemplateParamsRange(TemplateParameterList const * const *Ps, unsigned N) { if (!N) return SourceRange(); return SourceRange(Ps[0]->getTemplateLoc(), Ps[N-1]->getRAngleLoc()); } +unsigned Sema::getTemplateDepth(Scope *S) const { + unsigned Depth = 0; + + // Each template parameter scope represents one level of template parameter + // depth. + for (Scope *TempParamScope = S->getTemplateParamParent(); + TempParamScope && !Depth; + TempParamScope = TempParamScope->getParent()->getTemplateParamParent()) { + ++Depth; + } + + // Note that there are template parameters with the given depth. + auto ParamsAtDepth = [&](unsigned D) { Depth = std::max(Depth, D + 1); }; + + // Look for parameters of an enclosing generic lambda. We don't create a + // template parameter scope for these. + for (FunctionScopeInfo *FSI : getFunctionScopes()) { + if (auto *LSI = dyn_cast(FSI)) { + if (!LSI->TemplateParams.empty()) { + ParamsAtDepth(LSI->AutoTemplateParameterDepth); + break; + } + if (LSI->GLTemplateParameterList) { + ParamsAtDepth(LSI->GLTemplateParameterList->getDepth()); + break; + } + } + } + + // Look for parameters of an enclosing terse function template. We don't + // create a template parameter scope for these either. + for (const InventedTemplateParameterInfo &Info : + getInventedParameterInfos()) { + if (!Info.TemplateParams.empty()) { + ParamsAtDepth(Info.AutoTemplateParameterDepth); + break; + } + } + + return Depth; +} + /// \brief Determine whether the declaration found is acceptable as the name /// of a template and, if so, return that template declaration. Otherwise, /// returns null. /// /// Note that this may return an UnresolvedUsingValueDecl if AllowDependent /// is true. In all other cases it will return a TemplateDecl (or null). NamedDecl *Sema::getAsTemplateNameDecl(NamedDecl *D, bool AllowFunctionTemplates, bool AllowDependent) { D = D->getUnderlyingDecl(); if (isa(D)) { if (!AllowFunctionTemplates && isa(D)) return nullptr; return D; } if (CXXRecordDecl *Record = dyn_cast(D)) { // C++ [temp.local]p1: // Like normal (non-template) classes, class templates have an // injected-class-name (Clause 9). The injected-class-name // can be used with or without a template-argument-list. When // it is used without a template-argument-list, it is // equivalent to the injected-class-name followed by the // template-parameters of the class template enclosed in // <>. When it is used with a template-argument-list, it // refers to the specified class template specialization, // which could be the current specialization or another // specialization. if (Record->isInjectedClassName()) { Record = cast(Record->getDeclContext()); if (Record->getDescribedClassTemplate()) return Record->getDescribedClassTemplate(); if (ClassTemplateSpecializationDecl *Spec = dyn_cast(Record)) return Spec->getSpecializedTemplate(); } return nullptr; } // 'using Dependent::foo;' can resolve to a template name. // 'using typename Dependent::foo;' cannot (not even if 'foo' is an // injected-class-name). if (AllowDependent && isa(D)) return D; return nullptr; } void Sema::FilterAcceptableTemplateNames(LookupResult &R, bool AllowFunctionTemplates, bool AllowDependent) { LookupResult::Filter filter = R.makeFilter(); while (filter.hasNext()) { NamedDecl *Orig = filter.next(); if (!getAsTemplateNameDecl(Orig, AllowFunctionTemplates, AllowDependent)) filter.erase(); } filter.done(); } bool Sema::hasAnyAcceptableTemplateNames(LookupResult &R, bool AllowFunctionTemplates, bool AllowDependent, bool AllowNonTemplateFunctions) { for (LookupResult::iterator I = R.begin(), IEnd = R.end(); I != IEnd; ++I) { if (getAsTemplateNameDecl(*I, AllowFunctionTemplates, AllowDependent)) return true; if (AllowNonTemplateFunctions && isa((*I)->getUnderlyingDecl())) return true; } return false; } TemplateNameKind Sema::isTemplateName(Scope *S, CXXScopeSpec &SS, bool hasTemplateKeyword, const UnqualifiedId &Name, ParsedType ObjectTypePtr, bool EnteringContext, TemplateTy &TemplateResult, bool &MemberOfUnknownSpecialization) { assert(getLangOpts().CPlusPlus && "No template names in C!"); DeclarationName TName; MemberOfUnknownSpecialization = false; switch (Name.getKind()) { case UnqualifiedIdKind::IK_Identifier: TName = DeclarationName(Name.Identifier); break; case UnqualifiedIdKind::IK_OperatorFunctionId: TName = Context.DeclarationNames.getCXXOperatorName( Name.OperatorFunctionId.Operator); break; case UnqualifiedIdKind::IK_LiteralOperatorId: TName = Context.DeclarationNames.getCXXLiteralOperatorName(Name.Identifier); break; default: return TNK_Non_template; } QualType ObjectType = ObjectTypePtr.get(); AssumedTemplateKind AssumedTemplate; LookupResult R(*this, TName, Name.getBeginLoc(), LookupOrdinaryName); if (LookupTemplateName(R, S, SS, ObjectType, EnteringContext, MemberOfUnknownSpecialization, SourceLocation(), &AssumedTemplate)) return TNK_Non_template; if (AssumedTemplate != AssumedTemplateKind::None) { TemplateResult = TemplateTy::make(Context.getAssumedTemplateName(TName)); // Let the parser know whether we found nothing or found functions; if we // found nothing, we want to more carefully check whether this is actually // a function template name versus some other kind of undeclared identifier. return AssumedTemplate == AssumedTemplateKind::FoundNothing ? TNK_Undeclared_template : TNK_Function_template; } if (R.empty()) return TNK_Non_template; NamedDecl *D = nullptr; if (R.isAmbiguous()) { // If we got an ambiguity involving a non-function template, treat this // as a template name, and pick an arbitrary template for error recovery. bool AnyFunctionTemplates = false; for (NamedDecl *FoundD : R) { if (NamedDecl *FoundTemplate = getAsTemplateNameDecl(FoundD)) { if (isa(FoundTemplate)) AnyFunctionTemplates = true; else { D = FoundTemplate; break; } } } // If we didn't find any templates at all, this isn't a template name. // Leave the ambiguity for a later lookup to diagnose. if (!D && !AnyFunctionTemplates) { R.suppressDiagnostics(); return TNK_Non_template; } // If the only templates were function templates, filter out the rest. // We'll diagnose the ambiguity later. if (!D) FilterAcceptableTemplateNames(R); } // At this point, we have either picked a single template name declaration D // or we have a non-empty set of results R containing either one template name // declaration or a set of function templates. TemplateName Template; TemplateNameKind TemplateKind; unsigned ResultCount = R.end() - R.begin(); if (!D && ResultCount > 1) { // We assume that we'll preserve the qualifier from a function // template name in other ways. Template = Context.getOverloadedTemplateName(R.begin(), R.end()); TemplateKind = TNK_Function_template; // We'll do this lookup again later. R.suppressDiagnostics(); } else { if (!D) { D = getAsTemplateNameDecl(*R.begin()); assert(D && "unambiguous result is not a template name"); } if (isa(D)) { // We don't yet know whether this is a template-name or not. MemberOfUnknownSpecialization = true; return TNK_Non_template; } TemplateDecl *TD = cast(D); if (SS.isSet() && !SS.isInvalid()) { NestedNameSpecifier *Qualifier = SS.getScopeRep(); Template = Context.getQualifiedTemplateName(Qualifier, hasTemplateKeyword, TD); } else { Template = TemplateName(TD); } if (isa(TD)) { TemplateKind = TNK_Function_template; // We'll do this lookup again later. R.suppressDiagnostics(); } else { assert(isa(TD) || isa(TD) || isa(TD) || isa(TD) || isa(TD) || isa(TD)); TemplateKind = isa(TD) ? TNK_Var_template : isa(TD) ? TNK_Concept_template : TNK_Type_template; } } TemplateResult = TemplateTy::make(Template); return TemplateKind; } bool Sema::isDeductionGuideName(Scope *S, const IdentifierInfo &Name, SourceLocation NameLoc, ParsedTemplateTy *Template) { CXXScopeSpec SS; bool MemberOfUnknownSpecialization = false; // We could use redeclaration lookup here, but we don't need to: the // syntactic form of a deduction guide is enough to identify it even // if we can't look up the template name at all. LookupResult R(*this, DeclarationName(&Name), NameLoc, LookupOrdinaryName); if (LookupTemplateName(R, S, SS, /*ObjectType*/ QualType(), /*EnteringContext*/ false, MemberOfUnknownSpecialization)) return false; if (R.empty()) return false; if (R.isAmbiguous()) { // FIXME: Diagnose an ambiguity if we find at least one template. R.suppressDiagnostics(); return false; } // We only treat template-names that name type templates as valid deduction // guide names. TemplateDecl *TD = R.getAsSingle(); if (!TD || !getAsTypeTemplateDecl(TD)) return false; if (Template) *Template = TemplateTy::make(TemplateName(TD)); return true; } bool Sema::DiagnoseUnknownTemplateName(const IdentifierInfo &II, SourceLocation IILoc, Scope *S, const CXXScopeSpec *SS, TemplateTy &SuggestedTemplate, TemplateNameKind &SuggestedKind) { // We can't recover unless there's a dependent scope specifier preceding the // template name. // FIXME: Typo correction? if (!SS || !SS->isSet() || !isDependentScopeSpecifier(*SS) || computeDeclContext(*SS)) return false; // The code is missing a 'template' keyword prior to the dependent template // name. NestedNameSpecifier *Qualifier = (NestedNameSpecifier*)SS->getScopeRep(); Diag(IILoc, diag::err_template_kw_missing) << Qualifier << II.getName() << FixItHint::CreateInsertion(IILoc, "template "); SuggestedTemplate = TemplateTy::make(Context.getDependentTemplateName(Qualifier, &II)); SuggestedKind = TNK_Dependent_template_name; return true; } bool Sema::LookupTemplateName(LookupResult &Found, Scope *S, CXXScopeSpec &SS, QualType ObjectType, bool EnteringContext, bool &MemberOfUnknownSpecialization, SourceLocation TemplateKWLoc, AssumedTemplateKind *ATK) { if (ATK) *ATK = AssumedTemplateKind::None; Found.setTemplateNameLookup(true); // Determine where to perform name lookup MemberOfUnknownSpecialization = false; DeclContext *LookupCtx = nullptr; bool IsDependent = false; if (!ObjectType.isNull()) { // This nested-name-specifier occurs in a member access expression, e.g., // x->B::f, and we are looking into the type of the object. assert(!SS.isSet() && "ObjectType and scope specifier cannot coexist"); LookupCtx = computeDeclContext(ObjectType); IsDependent = !LookupCtx && ObjectType->isDependentType(); assert((IsDependent || !ObjectType->isIncompleteType() || ObjectType->castAs()->isBeingDefined()) && "Caller should have completed object type"); // Template names cannot appear inside an Objective-C class or object type // or a vector type. // // FIXME: This is wrong. For example: // // template using Vec = T __attribute__((ext_vector_type(4))); // Vec vi; // vi.Vec::~Vec(); // // ... should be accepted but we will not treat 'Vec' as a template name // here. The right thing to do would be to check if the name is a valid // vector component name, and look up a template name if not. And similarly // for lookups into Objective-C class and object types, where the same // problem can arise. if (ObjectType->isObjCObjectOrInterfaceType() || ObjectType->isVectorType()) { Found.clear(); return false; } } else if (SS.isSet()) { // This nested-name-specifier occurs after another nested-name-specifier, // so long into the context associated with the prior nested-name-specifier. LookupCtx = computeDeclContext(SS, EnteringContext); IsDependent = !LookupCtx; // The declaration context must be complete. if (LookupCtx && RequireCompleteDeclContext(SS, LookupCtx)) return true; } bool ObjectTypeSearchedInScope = false; bool AllowFunctionTemplatesInLookup = true; if (LookupCtx) { // Perform "qualified" name lookup into the declaration context we // computed, which is either the type of the base of a member access // expression or the declaration context associated with a prior // nested-name-specifier. LookupQualifiedName(Found, LookupCtx); // FIXME: The C++ standard does not clearly specify what happens in the // case where the object type is dependent, and implementations vary. In // Clang, we treat a name after a . or -> as a template-name if lookup // finds a non-dependent member or member of the current instantiation that // is a type template, or finds no such members and lookup in the context // of the postfix-expression finds a type template. In the latter case, the // name is nonetheless dependent, and we may resolve it to a member of an // unknown specialization when we come to instantiate the template. IsDependent |= Found.wasNotFoundInCurrentInstantiation(); } if (!SS.isSet() && (ObjectType.isNull() || Found.empty())) { // C++ [basic.lookup.classref]p1: // In a class member access expression (5.2.5), if the . or -> token is // immediately followed by an identifier followed by a <, the // identifier must be looked up to determine whether the < is the // beginning of a template argument list (14.2) or a less-than operator. // The identifier is first looked up in the class of the object // expression. If the identifier is not found, it is then looked up in // the context of the entire postfix-expression and shall name a class // template. if (S) LookupName(Found, S); if (!ObjectType.isNull()) { // FIXME: We should filter out all non-type templates here, particularly // variable templates and concepts. But the exclusion of alias templates // and template template parameters is a wording defect. AllowFunctionTemplatesInLookup = false; ObjectTypeSearchedInScope = true; } IsDependent |= Found.wasNotFoundInCurrentInstantiation(); } if (Found.isAmbiguous()) return false; if (ATK && !SS.isSet() && ObjectType.isNull() && TemplateKWLoc.isInvalid()) { // C++2a [temp.names]p2: // A name is also considered to refer to a template if it is an // unqualified-id followed by a < and name lookup finds either one or more // functions or finds nothing. // // To keep our behavior consistent, we apply the "finds nothing" part in // all language modes, and diagnose the empty lookup in ActOnCallExpr if we // successfully form a call to an undeclared template-id. bool AllFunctions = getLangOpts().CPlusPlus2a && std::all_of(Found.begin(), Found.end(), [](NamedDecl *ND) { return isa(ND->getUnderlyingDecl()); }); if (AllFunctions || (Found.empty() && !IsDependent)) { // If lookup found any functions, or if this is a name that can only be // used for a function, then strongly assume this is a function // template-id. *ATK = (Found.empty() && Found.getLookupName().isIdentifier()) ? AssumedTemplateKind::FoundNothing : AssumedTemplateKind::FoundFunctions; Found.clear(); return false; } } if (Found.empty() && !IsDependent) { // If we did not find any names, attempt to correct any typos. DeclarationName Name = Found.getLookupName(); Found.clear(); // Simple filter callback that, for keywords, only accepts the C++ *_cast DefaultFilterCCC FilterCCC{}; FilterCCC.WantTypeSpecifiers = false; FilterCCC.WantExpressionKeywords = false; FilterCCC.WantRemainingKeywords = false; FilterCCC.WantCXXNamedCasts = true; if (TypoCorrection Corrected = CorrectTypo(Found.getLookupNameInfo(), Found.getLookupKind(), S, &SS, FilterCCC, CTK_ErrorRecovery, LookupCtx)) { if (auto *ND = Corrected.getFoundDecl()) Found.addDecl(ND); FilterAcceptableTemplateNames(Found); if (Found.isAmbiguous()) { Found.clear(); } else if (!Found.empty()) { Found.setLookupName(Corrected.getCorrection()); if (LookupCtx) { std::string CorrectedStr(Corrected.getAsString(getLangOpts())); bool DroppedSpecifier = Corrected.WillReplaceSpecifier() && Name.getAsString() == CorrectedStr; diagnoseTypo(Corrected, PDiag(diag::err_no_member_template_suggest) << Name << LookupCtx << DroppedSpecifier << SS.getRange()); } else { diagnoseTypo(Corrected, PDiag(diag::err_no_template_suggest) << Name); } } } } NamedDecl *ExampleLookupResult = Found.empty() ? nullptr : Found.getRepresentativeDecl(); FilterAcceptableTemplateNames(Found, AllowFunctionTemplatesInLookup); if (Found.empty()) { if (IsDependent) { MemberOfUnknownSpecialization = true; return false; } // If a 'template' keyword was used, a lookup that finds only non-template // names is an error. if (ExampleLookupResult && TemplateKWLoc.isValid()) { Diag(Found.getNameLoc(), diag::err_template_kw_refers_to_non_template) << Found.getLookupName() << SS.getRange(); Diag(ExampleLookupResult->getUnderlyingDecl()->getLocation(), diag::note_template_kw_refers_to_non_template) << Found.getLookupName(); return true; } return false; } if (S && !ObjectType.isNull() && !ObjectTypeSearchedInScope && !getLangOpts().CPlusPlus11) { // C++03 [basic.lookup.classref]p1: // [...] If the lookup in the class of the object expression finds a // template, the name is also looked up in the context of the entire // postfix-expression and [...] // // Note: C++11 does not perform this second lookup. LookupResult FoundOuter(*this, Found.getLookupName(), Found.getNameLoc(), LookupOrdinaryName); FoundOuter.setTemplateNameLookup(true); LookupName(FoundOuter, S); // FIXME: We silently accept an ambiguous lookup here, in violation of // [basic.lookup]/1. FilterAcceptableTemplateNames(FoundOuter, /*AllowFunctionTemplates=*/false); NamedDecl *OuterTemplate; if (FoundOuter.empty()) { // - if the name is not found, the name found in the class of the // object expression is used, otherwise } else if (FoundOuter.isAmbiguous() || !FoundOuter.isSingleResult() || !(OuterTemplate = getAsTemplateNameDecl(FoundOuter.getFoundDecl()))) { // - if the name is found in the context of the entire // postfix-expression and does not name a class template, the name // found in the class of the object expression is used, otherwise FoundOuter.clear(); } else if (!Found.isSuppressingDiagnostics()) { // - if the name found is a class template, it must refer to the same // entity as the one found in the class of the object expression, // otherwise the program is ill-formed. if (!Found.isSingleResult() || getAsTemplateNameDecl(Found.getFoundDecl())->getCanonicalDecl() != OuterTemplate->getCanonicalDecl()) { Diag(Found.getNameLoc(), diag::ext_nested_name_member_ref_lookup_ambiguous) << Found.getLookupName() << ObjectType; Diag(Found.getRepresentativeDecl()->getLocation(), diag::note_ambig_member_ref_object_type) << ObjectType; Diag(FoundOuter.getFoundDecl()->getLocation(), diag::note_ambig_member_ref_scope); // Recover by taking the template that we found in the object // expression's type. } } } return false; } void Sema::diagnoseExprIntendedAsTemplateName(Scope *S, ExprResult TemplateName, SourceLocation Less, SourceLocation Greater) { if (TemplateName.isInvalid()) return; DeclarationNameInfo NameInfo; CXXScopeSpec SS; LookupNameKind LookupKind; DeclContext *LookupCtx = nullptr; NamedDecl *Found = nullptr; bool MissingTemplateKeyword = false; // Figure out what name we looked up. if (auto *DRE = dyn_cast(TemplateName.get())) { NameInfo = DRE->getNameInfo(); SS.Adopt(DRE->getQualifierLoc()); LookupKind = LookupOrdinaryName; Found = DRE->getFoundDecl(); } else if (auto *ME = dyn_cast(TemplateName.get())) { NameInfo = ME->getMemberNameInfo(); SS.Adopt(ME->getQualifierLoc()); LookupKind = LookupMemberName; LookupCtx = ME->getBase()->getType()->getAsCXXRecordDecl(); Found = ME->getMemberDecl(); } else if (auto *DSDRE = dyn_cast(TemplateName.get())) { NameInfo = DSDRE->getNameInfo(); SS.Adopt(DSDRE->getQualifierLoc()); MissingTemplateKeyword = true; } else if (auto *DSME = dyn_cast(TemplateName.get())) { NameInfo = DSME->getMemberNameInfo(); SS.Adopt(DSME->getQualifierLoc()); MissingTemplateKeyword = true; } else { llvm_unreachable("unexpected kind of potential template name"); } // If this is a dependent-scope lookup, diagnose that the 'template' keyword // was missing. if (MissingTemplateKeyword) { Diag(NameInfo.getBeginLoc(), diag::err_template_kw_missing) << "" << NameInfo.getName().getAsString() << SourceRange(Less, Greater); return; } // Try to correct the name by looking for templates and C++ named casts. struct TemplateCandidateFilter : CorrectionCandidateCallback { Sema &S; TemplateCandidateFilter(Sema &S) : S(S) { WantTypeSpecifiers = false; WantExpressionKeywords = false; WantRemainingKeywords = false; WantCXXNamedCasts = true; }; bool ValidateCandidate(const TypoCorrection &Candidate) override { if (auto *ND = Candidate.getCorrectionDecl()) return S.getAsTemplateNameDecl(ND); return Candidate.isKeyword(); } std::unique_ptr clone() override { return std::make_unique(*this); } }; DeclarationName Name = NameInfo.getName(); TemplateCandidateFilter CCC(*this); if (TypoCorrection Corrected = CorrectTypo(NameInfo, LookupKind, S, &SS, CCC, CTK_ErrorRecovery, LookupCtx)) { auto *ND = Corrected.getFoundDecl(); if (ND) ND = getAsTemplateNameDecl(ND); if (ND || Corrected.isKeyword()) { if (LookupCtx) { std::string CorrectedStr(Corrected.getAsString(getLangOpts())); bool DroppedSpecifier = Corrected.WillReplaceSpecifier() && Name.getAsString() == CorrectedStr; diagnoseTypo(Corrected, PDiag(diag::err_non_template_in_member_template_id_suggest) << Name << LookupCtx << DroppedSpecifier << SS.getRange(), false); } else { diagnoseTypo(Corrected, PDiag(diag::err_non_template_in_template_id_suggest) << Name, false); } if (Found) Diag(Found->getLocation(), diag::note_non_template_in_template_id_found); return; } } Diag(NameInfo.getLoc(), diag::err_non_template_in_template_id) << Name << SourceRange(Less, Greater); if (Found) Diag(Found->getLocation(), diag::note_non_template_in_template_id_found); } /// ActOnDependentIdExpression - Handle a dependent id-expression that /// was just parsed. This is only possible with an explicit scope /// specifier naming a dependent type. ExprResult Sema::ActOnDependentIdExpression(const CXXScopeSpec &SS, SourceLocation TemplateKWLoc, const DeclarationNameInfo &NameInfo, bool isAddressOfOperand, const TemplateArgumentListInfo *TemplateArgs) { DeclContext *DC = getFunctionLevelDeclContext(); // C++11 [expr.prim.general]p12: // An id-expression that denotes a non-static data member or non-static // member function of a class can only be used: // (...) // - if that id-expression denotes a non-static data member and it // appears in an unevaluated operand. // // If this might be the case, form a DependentScopeDeclRefExpr instead of a // CXXDependentScopeMemberExpr. The former can instantiate to either // DeclRefExpr or MemberExpr depending on lookup results, while the latter is // always a MemberExpr. bool MightBeCxx11UnevalField = getLangOpts().CPlusPlus11 && isUnevaluatedContext(); // Check if the nested name specifier is an enum type. bool IsEnum = false; if (NestedNameSpecifier *NNS = SS.getScopeRep()) IsEnum = dyn_cast_or_null(NNS->getAsType()); if (!MightBeCxx11UnevalField && !isAddressOfOperand && !IsEnum && isa(DC) && cast(DC)->isInstance()) { QualType ThisType = cast(DC)->getThisType(); // Since the 'this' expression is synthesized, we don't need to // perform the double-lookup check. NamedDecl *FirstQualifierInScope = nullptr; return CXXDependentScopeMemberExpr::Create( Context, /*This*/ nullptr, ThisType, /*IsArrow*/ true, /*Op*/ SourceLocation(), SS.getWithLocInContext(Context), TemplateKWLoc, FirstQualifierInScope, NameInfo, TemplateArgs); } return BuildDependentDeclRefExpr(SS, TemplateKWLoc, NameInfo, TemplateArgs); } ExprResult Sema::BuildDependentDeclRefExpr(const CXXScopeSpec &SS, SourceLocation TemplateKWLoc, const DeclarationNameInfo &NameInfo, const TemplateArgumentListInfo *TemplateArgs) { // DependentScopeDeclRefExpr::Create requires a valid QualifierLoc NestedNameSpecifierLoc QualifierLoc = SS.getWithLocInContext(Context); if (!QualifierLoc) return ExprError(); return DependentScopeDeclRefExpr::Create( Context, QualifierLoc, TemplateKWLoc, NameInfo, TemplateArgs); } /// Determine whether we would be unable to instantiate this template (because /// it either has no definition, or is in the process of being instantiated). bool Sema::DiagnoseUninstantiableTemplate(SourceLocation PointOfInstantiation, NamedDecl *Instantiation, bool InstantiatedFromMember, const NamedDecl *Pattern, const NamedDecl *PatternDef, TemplateSpecializationKind TSK, bool Complain /*= true*/) { assert(isa(Instantiation) || isa(Instantiation) || isa(Instantiation)); bool IsEntityBeingDefined = false; if (const TagDecl *TD = dyn_cast_or_null(PatternDef)) IsEntityBeingDefined = TD->isBeingDefined(); if (PatternDef && !IsEntityBeingDefined) { NamedDecl *SuggestedDef = nullptr; if (!hasVisibleDefinition(const_cast(PatternDef), &SuggestedDef, /*OnlyNeedComplete*/false)) { // If we're allowed to diagnose this and recover, do so. bool Recover = Complain && !isSFINAEContext(); if (Complain) diagnoseMissingImport(PointOfInstantiation, SuggestedDef, Sema::MissingImportKind::Definition, Recover); return !Recover; } return false; } if (!Complain || (PatternDef && PatternDef->isInvalidDecl())) return true; llvm::Optional Note; QualType InstantiationTy; if (TagDecl *TD = dyn_cast(Instantiation)) InstantiationTy = Context.getTypeDeclType(TD); if (PatternDef) { Diag(PointOfInstantiation, diag::err_template_instantiate_within_definition) << /*implicit|explicit*/(TSK != TSK_ImplicitInstantiation) << InstantiationTy; // Not much point in noting the template declaration here, since // we're lexically inside it. Instantiation->setInvalidDecl(); } else if (InstantiatedFromMember) { if (isa(Instantiation)) { Diag(PointOfInstantiation, diag::err_explicit_instantiation_undefined_member) << /*member function*/ 1 << Instantiation->getDeclName() << Instantiation->getDeclContext(); Note = diag::note_explicit_instantiation_here; } else { assert(isa(Instantiation) && "Must be a TagDecl!"); Diag(PointOfInstantiation, diag::err_implicit_instantiate_member_undefined) << InstantiationTy; Note = diag::note_member_declared_at; } } else { if (isa(Instantiation)) { Diag(PointOfInstantiation, diag::err_explicit_instantiation_undefined_func_template) << Pattern; Note = diag::note_explicit_instantiation_here; } else if (isa(Instantiation)) { Diag(PointOfInstantiation, diag::err_template_instantiate_undefined) << (TSK != TSK_ImplicitInstantiation) << InstantiationTy; Note = diag::note_template_decl_here; } else { assert(isa(Instantiation) && "Must be a VarDecl!"); if (isa(Instantiation)) { Diag(PointOfInstantiation, diag::err_explicit_instantiation_undefined_var_template) << Instantiation; Instantiation->setInvalidDecl(); } else Diag(PointOfInstantiation, diag::err_explicit_instantiation_undefined_member) << /*static data member*/ 2 << Instantiation->getDeclName() << Instantiation->getDeclContext(); Note = diag::note_explicit_instantiation_here; } } if (Note) // Diagnostics were emitted. Diag(Pattern->getLocation(), Note.getValue()); // In general, Instantiation isn't marked invalid to get more than one // error for multiple undefined instantiations. But the code that does // explicit declaration -> explicit definition conversion can't handle // invalid declarations, so mark as invalid in that case. if (TSK == TSK_ExplicitInstantiationDeclaration) Instantiation->setInvalidDecl(); return true; } /// DiagnoseTemplateParameterShadow - Produce a diagnostic complaining /// that the template parameter 'PrevDecl' is being shadowed by a new /// declaration at location Loc. Returns true to indicate that this is /// an error, and false otherwise. void Sema::DiagnoseTemplateParameterShadow(SourceLocation Loc, Decl *PrevDecl) { assert(PrevDecl->isTemplateParameter() && "Not a template parameter"); // C++ [temp.local]p4: // A template-parameter shall not be redeclared within its // scope (including nested scopes). // // Make this a warning when MSVC compatibility is requested. unsigned DiagId = getLangOpts().MSVCCompat ? diag::ext_template_param_shadow : diag::err_template_param_shadow; Diag(Loc, DiagId) << cast(PrevDecl)->getDeclName(); Diag(PrevDecl->getLocation(), diag::note_template_param_here); } /// AdjustDeclIfTemplate - If the given decl happens to be a template, reset /// the parameter D to reference the templated declaration and return a pointer /// to the template declaration. Otherwise, do nothing to D and return null. TemplateDecl *Sema::AdjustDeclIfTemplate(Decl *&D) { if (TemplateDecl *Temp = dyn_cast_or_null(D)) { D = Temp->getTemplatedDecl(); return Temp; } return nullptr; } ParsedTemplateArgument ParsedTemplateArgument::getTemplatePackExpansion( SourceLocation EllipsisLoc) const { assert(Kind == Template && "Only template template arguments can be pack expansions here"); assert(getAsTemplate().get().containsUnexpandedParameterPack() && "Template template argument pack expansion without packs"); ParsedTemplateArgument Result(*this); Result.EllipsisLoc = EllipsisLoc; return Result; } static TemplateArgumentLoc translateTemplateArgument(Sema &SemaRef, const ParsedTemplateArgument &Arg) { switch (Arg.getKind()) { case ParsedTemplateArgument::Type: { TypeSourceInfo *DI; QualType T = SemaRef.GetTypeFromParser(Arg.getAsType(), &DI); if (!DI) DI = SemaRef.Context.getTrivialTypeSourceInfo(T, Arg.getLocation()); return TemplateArgumentLoc(TemplateArgument(T), DI); } case ParsedTemplateArgument::NonType: { Expr *E = static_cast(Arg.getAsExpr()); return TemplateArgumentLoc(TemplateArgument(E), E); } case ParsedTemplateArgument::Template: { TemplateName Template = Arg.getAsTemplate().get(); TemplateArgument TArg; if (Arg.getEllipsisLoc().isValid()) TArg = TemplateArgument(Template, Optional()); else TArg = Template; return TemplateArgumentLoc(TArg, Arg.getScopeSpec().getWithLocInContext( SemaRef.Context), Arg.getLocation(), Arg.getEllipsisLoc()); } } llvm_unreachable("Unhandled parsed template argument"); } /// Translates template arguments as provided by the parser /// into template arguments used by semantic analysis. void Sema::translateTemplateArguments(const ASTTemplateArgsPtr &TemplateArgsIn, TemplateArgumentListInfo &TemplateArgs) { for (unsigned I = 0, Last = TemplateArgsIn.size(); I != Last; ++I) TemplateArgs.addArgument(translateTemplateArgument(*this, TemplateArgsIn[I])); } static void maybeDiagnoseTemplateParameterShadow(Sema &SemaRef, Scope *S, SourceLocation Loc, IdentifierInfo *Name) { NamedDecl *PrevDecl = SemaRef.LookupSingleName( S, Name, Loc, Sema::LookupOrdinaryName, Sema::ForVisibleRedeclaration); if (PrevDecl && PrevDecl->isTemplateParameter()) SemaRef.DiagnoseTemplateParameterShadow(Loc, PrevDecl); } /// Convert a parsed type into a parsed template argument. This is mostly /// trivial, except that we may have parsed a C++17 deduced class template /// specialization type, in which case we should form a template template /// argument instead of a type template argument. ParsedTemplateArgument Sema::ActOnTemplateTypeArgument(TypeResult ParsedType) { TypeSourceInfo *TInfo; QualType T = GetTypeFromParser(ParsedType.get(), &TInfo); if (T.isNull()) return ParsedTemplateArgument(); assert(TInfo && "template argument with no location"); // If we might have formed a deduced template specialization type, convert // it to a template template argument. if (getLangOpts().CPlusPlus17) { TypeLoc TL = TInfo->getTypeLoc(); SourceLocation EllipsisLoc; if (auto PET = TL.getAs()) { EllipsisLoc = PET.getEllipsisLoc(); TL = PET.getPatternLoc(); } CXXScopeSpec SS; if (auto ET = TL.getAs()) { SS.Adopt(ET.getQualifierLoc()); TL = ET.getNamedTypeLoc(); } if (auto DTST = TL.getAs()) { TemplateName Name = DTST.getTypePtr()->getTemplateName(); if (SS.isSet()) Name = Context.getQualifiedTemplateName(SS.getScopeRep(), /*HasTemplateKeyword*/ false, Name.getAsTemplateDecl()); ParsedTemplateArgument Result(SS, TemplateTy::make(Name), DTST.getTemplateNameLoc()); if (EllipsisLoc.isValid()) Result = Result.getTemplatePackExpansion(EllipsisLoc); return Result; } } // This is a normal type template argument. Note, if the type template // argument is an injected-class-name for a template, it has a dual nature // and can be used as either a type or a template. We handle that in // convertTypeTemplateArgumentToTemplate. return ParsedTemplateArgument(ParsedTemplateArgument::Type, ParsedType.get().getAsOpaquePtr(), TInfo->getTypeLoc().getBeginLoc()); } /// ActOnTypeParameter - Called when a C++ template type parameter /// (e.g., "typename T") has been parsed. Typename specifies whether /// the keyword "typename" was used to declare the type parameter /// (otherwise, "class" was used), and KeyLoc is the location of the /// "class" or "typename" keyword. ParamName is the name of the /// parameter (NULL indicates an unnamed template parameter) and /// ParamNameLoc is the location of the parameter name (if any). /// If the type parameter has a default argument, it will be added /// later via ActOnTypeParameterDefault. NamedDecl *Sema::ActOnTypeParameter(Scope *S, bool Typename, SourceLocation EllipsisLoc, SourceLocation KeyLoc, IdentifierInfo *ParamName, SourceLocation ParamNameLoc, unsigned Depth, unsigned Position, SourceLocation EqualLoc, ParsedType DefaultArg, bool HasTypeConstraint) { assert(S->isTemplateParamScope() && "Template type parameter not in template parameter scope!"); bool IsParameterPack = EllipsisLoc.isValid(); TemplateTypeParmDecl *Param = TemplateTypeParmDecl::Create(Context, Context.getTranslationUnitDecl(), KeyLoc, ParamNameLoc, Depth, Position, ParamName, Typename, IsParameterPack, HasTypeConstraint); Param->setAccess(AS_public); if (Param->isParameterPack()) if (auto *LSI = getEnclosingLambda()) LSI->LocalPacks.push_back(Param); if (ParamName) { maybeDiagnoseTemplateParameterShadow(*this, S, ParamNameLoc, ParamName); // Add the template parameter into the current scope. S->AddDecl(Param); IdResolver.AddDecl(Param); } // C++0x [temp.param]p9: // A default template-argument may be specified for any kind of // template-parameter that is not a template parameter pack. if (DefaultArg && IsParameterPack) { Diag(EqualLoc, diag::err_template_param_pack_default_arg); DefaultArg = nullptr; } // Handle the default argument, if provided. if (DefaultArg) { TypeSourceInfo *DefaultTInfo; GetTypeFromParser(DefaultArg, &DefaultTInfo); assert(DefaultTInfo && "expected source information for type"); // Check for unexpanded parameter packs. if (DiagnoseUnexpandedParameterPack(ParamNameLoc, DefaultTInfo, UPPC_DefaultArgument)) return Param; // Check the template argument itself. if (CheckTemplateArgument(Param, DefaultTInfo)) { Param->setInvalidDecl(); return Param; } Param->setDefaultArgument(DefaultTInfo); } return Param; } /// Convert the parser's template argument list representation into our form. static TemplateArgumentListInfo makeTemplateArgumentListInfo(Sema &S, TemplateIdAnnotation &TemplateId) { TemplateArgumentListInfo TemplateArgs(TemplateId.LAngleLoc, TemplateId.RAngleLoc); ASTTemplateArgsPtr TemplateArgsPtr(TemplateId.getTemplateArgs(), TemplateId.NumArgs); S.translateTemplateArguments(TemplateArgsPtr, TemplateArgs); return TemplateArgs; } bool Sema::ActOnTypeConstraint(const CXXScopeSpec &SS, TemplateIdAnnotation *TypeConstr, TemplateTypeParmDecl *ConstrainedParameter, SourceLocation EllipsisLoc) { ConceptDecl *CD = cast(TypeConstr->Template.get().getAsTemplateDecl()); // C++2a [temp.param]p4: // [...] The concept designated by a type-constraint shall be a type // concept ([temp.concept]). if (!CD->isTypeConcept()) { Diag(TypeConstr->TemplateNameLoc, diag::err_type_constraint_non_type_concept); return true; } bool WereArgsSpecified = TypeConstr->LAngleLoc.isValid(); if (!WereArgsSpecified && CD->getTemplateParameters()->getMinRequiredArguments() > 1) { Diag(TypeConstr->TemplateNameLoc, diag::err_type_constraint_missing_arguments) << CD; return true; } TemplateArgumentListInfo TemplateArgs; if (TypeConstr->LAngleLoc.isValid()) { TemplateArgs = makeTemplateArgumentListInfo(*this, *TypeConstr); } return AttachTypeConstraint( SS.isSet() ? SS.getWithLocInContext(Context) : NestedNameSpecifierLoc(), DeclarationNameInfo(DeclarationName(TypeConstr->Name), TypeConstr->TemplateNameLoc), CD, TypeConstr->LAngleLoc.isValid() ? &TemplateArgs : nullptr, ConstrainedParameter, EllipsisLoc); } template static ExprResult formImmediatelyDeclaredConstraint( Sema &S, NestedNameSpecifierLoc NS, DeclarationNameInfo NameInfo, ConceptDecl *NamedConcept, SourceLocation LAngleLoc, SourceLocation RAngleLoc, QualType ConstrainedType, SourceLocation ParamNameLoc, ArgumentLocAppender Appender, SourceLocation EllipsisLoc) { TemplateArgumentListInfo ConstraintArgs; ConstraintArgs.addArgument( S.getTrivialTemplateArgumentLoc(TemplateArgument(ConstrainedType), /*NTTPType=*/QualType(), ParamNameLoc)); ConstraintArgs.setRAngleLoc(RAngleLoc); ConstraintArgs.setLAngleLoc(LAngleLoc); Appender(ConstraintArgs); // C++2a [temp.param]p4: // [...] This constraint-expression E is called the immediately-declared // constraint of T. [...] CXXScopeSpec SS; SS.Adopt(NS); ExprResult ImmediatelyDeclaredConstraint = S.CheckConceptTemplateId( SS, /*TemplateKWLoc=*/SourceLocation(), NameInfo, /*FoundDecl=*/NamedConcept, NamedConcept, &ConstraintArgs); if (ImmediatelyDeclaredConstraint.isInvalid() || !EllipsisLoc.isValid()) return ImmediatelyDeclaredConstraint; // C++2a [temp.param]p4: // [...] If T is not a pack, then E is E', otherwise E is (E' && ...). // // We have the following case: // // template concept C1 = true; // template struct s1; // // The constraint: (C1 && ...) return S.BuildCXXFoldExpr(/*LParenLoc=*/SourceLocation(), ImmediatelyDeclaredConstraint.get(), BO_LAnd, EllipsisLoc, /*RHS=*/nullptr, /*RParenLoc=*/SourceLocation(), /*NumExpansions=*/None); } /// Attach a type-constraint to a template parameter. /// \returns true if an error occured. This can happen if the /// immediately-declared constraint could not be formed (e.g. incorrect number /// of arguments for the named concept). bool Sema::AttachTypeConstraint(NestedNameSpecifierLoc NS, DeclarationNameInfo NameInfo, ConceptDecl *NamedConcept, const TemplateArgumentListInfo *TemplateArgs, TemplateTypeParmDecl *ConstrainedParameter, SourceLocation EllipsisLoc) { // C++2a [temp.param]p4: // [...] If Q is of the form C, then let E' be // C. Otherwise, let E' be C. [...] const ASTTemplateArgumentListInfo *ArgsAsWritten = TemplateArgs ? ASTTemplateArgumentListInfo::Create(Context, *TemplateArgs) : nullptr; QualType ParamAsArgument(ConstrainedParameter->getTypeForDecl(), 0); ExprResult ImmediatelyDeclaredConstraint = formImmediatelyDeclaredConstraint( *this, NS, NameInfo, NamedConcept, TemplateArgs ? TemplateArgs->getLAngleLoc() : SourceLocation(), TemplateArgs ? TemplateArgs->getRAngleLoc() : SourceLocation(), ParamAsArgument, ConstrainedParameter->getLocation(), [&] (TemplateArgumentListInfo &ConstraintArgs) { if (TemplateArgs) for (const auto &ArgLoc : TemplateArgs->arguments()) ConstraintArgs.addArgument(ArgLoc); }, EllipsisLoc); if (ImmediatelyDeclaredConstraint.isInvalid()) return true; ConstrainedParameter->setTypeConstraint(NS, NameInfo, /*FoundDecl=*/NamedConcept, NamedConcept, ArgsAsWritten, ImmediatelyDeclaredConstraint.get()); return false; } bool Sema::AttachTypeConstraint(AutoTypeLoc TL, NonTypeTemplateParmDecl *NTTP, SourceLocation EllipsisLoc) { if (NTTP->getType() != TL.getType() || TL.getAutoKeyword() != AutoTypeKeyword::Auto) { Diag(NTTP->getTypeSourceInfo()->getTypeLoc().getBeginLoc(), diag::err_unsupported_placeholder_constraint) << NTTP->getTypeSourceInfo()->getTypeLoc().getSourceRange(); return true; } // FIXME: Concepts: This should be the type of the placeholder, but this is // unclear in the wording right now. DeclRefExpr *Ref = BuildDeclRefExpr(NTTP, NTTP->getType(), VK_RValue, NTTP->getLocation()); if (!Ref) return true; ExprResult ImmediatelyDeclaredConstraint = formImmediatelyDeclaredConstraint( *this, TL.getNestedNameSpecifierLoc(), TL.getConceptNameInfo(), TL.getNamedConcept(), TL.getLAngleLoc(), TL.getRAngleLoc(), BuildDecltypeType(Ref, NTTP->getLocation()), NTTP->getLocation(), [&] (TemplateArgumentListInfo &ConstraintArgs) { for (unsigned I = 0, C = TL.getNumArgs(); I != C; ++I) ConstraintArgs.addArgument(TL.getArgLoc(I)); }, EllipsisLoc); if (ImmediatelyDeclaredConstraint.isInvalid() || !ImmediatelyDeclaredConstraint.isUsable()) return true; NTTP->setPlaceholderTypeConstraint(ImmediatelyDeclaredConstraint.get()); return false; } /// Check that the type of a non-type template parameter is /// well-formed. /// /// \returns the (possibly-promoted) parameter type if valid; /// otherwise, produces a diagnostic and returns a NULL type. QualType Sema::CheckNonTypeTemplateParameterType(TypeSourceInfo *&TSI, SourceLocation Loc) { if (TSI->getType()->isUndeducedType()) { // C++17 [temp.dep.expr]p3: // An id-expression is type-dependent if it contains // - an identifier associated by name lookup with a non-type // template-parameter declared with a type that contains a // placeholder type (7.1.7.4), TSI = SubstAutoTypeSourceInfo(TSI, Context.DependentTy); } return CheckNonTypeTemplateParameterType(TSI->getType(), Loc); } QualType Sema::CheckNonTypeTemplateParameterType(QualType T, SourceLocation Loc) { // We don't allow variably-modified types as the type of non-type template // parameters. if (T->isVariablyModifiedType()) { Diag(Loc, diag::err_variably_modified_nontype_template_param) << T; return QualType(); } // C++ [temp.param]p4: // // A non-type template-parameter shall have one of the following // (optionally cv-qualified) types: // // -- integral or enumeration type, if (T->isIntegralOrEnumerationType() || // -- pointer to object or pointer to function, T->isPointerType() || // -- reference to object or reference to function, T->isReferenceType() || // -- pointer to member, T->isMemberPointerType() || // -- std::nullptr_t. T->isNullPtrType() || // Allow use of auto in template parameter declarations. T->isUndeducedType()) { // C++ [temp.param]p5: The top-level cv-qualifiers on the template-parameter // are ignored when determining its type. return T.getUnqualifiedType(); } // C++ [temp.param]p8: // // A non-type template-parameter of type "array of T" or // "function returning T" is adjusted to be of type "pointer to // T" or "pointer to function returning T", respectively. if (T->isArrayType() || T->isFunctionType()) return Context.getDecayedType(T); // If T is a dependent type, we can't do the check now, so we // assume that it is well-formed. Note that stripping off the // qualifiers here is not really correct if T turns out to be // an array type, but we'll recompute the type everywhere it's // used during instantiation, so that should be OK. (Using the // qualified type is equally wrong.) if (T->isDependentType()) return T.getUnqualifiedType(); Diag(Loc, diag::err_template_nontype_parm_bad_type) << T; return QualType(); } NamedDecl *Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D, unsigned Depth, unsigned Position, SourceLocation EqualLoc, Expr *Default) { TypeSourceInfo *TInfo = GetTypeForDeclarator(D, S); // Check that we have valid decl-specifiers specified. auto CheckValidDeclSpecifiers = [this, &D] { // C++ [temp.param] // p1 // template-parameter: // ... // parameter-declaration // p2 // ... A storage class shall not be specified in a template-parameter // declaration. // [dcl.typedef]p1: // The typedef specifier [...] shall not be used in the decl-specifier-seq // of a parameter-declaration const DeclSpec &DS = D.getDeclSpec(); auto EmitDiag = [this](SourceLocation Loc) { Diag(Loc, diag::err_invalid_decl_specifier_in_nontype_parm) << FixItHint::CreateRemoval(Loc); }; if (DS.getStorageClassSpec() != DeclSpec::SCS_unspecified) EmitDiag(DS.getStorageClassSpecLoc()); if (DS.getThreadStorageClassSpec() != TSCS_unspecified) EmitDiag(DS.getThreadStorageClassSpecLoc()); // [dcl.inline]p1: // The inline specifier can be applied only to the declaration or // definition of a variable or function. if (DS.isInlineSpecified()) EmitDiag(DS.getInlineSpecLoc()); // [dcl.constexpr]p1: // The constexpr specifier shall be applied only to the definition of a // variable or variable template or the declaration of a function or // function template. if (DS.hasConstexprSpecifier()) EmitDiag(DS.getConstexprSpecLoc()); // [dcl.fct.spec]p1: // Function-specifiers can be used only in function declarations. if (DS.isVirtualSpecified()) EmitDiag(DS.getVirtualSpecLoc()); if (DS.hasExplicitSpecifier()) EmitDiag(DS.getExplicitSpecLoc()); if (DS.isNoreturnSpecified()) EmitDiag(DS.getNoreturnSpecLoc()); }; CheckValidDeclSpecifiers(); if (TInfo->getType()->isUndeducedType()) { Diag(D.getIdentifierLoc(), diag::warn_cxx14_compat_template_nontype_parm_auto_type) << QualType(TInfo->getType()->getContainedAutoType(), 0); } assert(S->isTemplateParamScope() && "Non-type template parameter not in template parameter scope!"); bool Invalid = false; QualType T = CheckNonTypeTemplateParameterType(TInfo, D.getIdentifierLoc()); if (T.isNull()) { T = Context.IntTy; // Recover with an 'int' type. Invalid = true; } CheckFunctionOrTemplateParamDeclarator(S, D); IdentifierInfo *ParamName = D.getIdentifier(); bool IsParameterPack = D.hasEllipsis(); NonTypeTemplateParmDecl *Param = NonTypeTemplateParmDecl::Create( Context, Context.getTranslationUnitDecl(), D.getBeginLoc(), D.getIdentifierLoc(), Depth, Position, ParamName, T, IsParameterPack, TInfo); Param->setAccess(AS_public); if (AutoTypeLoc TL = TInfo->getTypeLoc().getContainedAutoTypeLoc()) if (TL.isConstrained()) if (AttachTypeConstraint(TL, Param, D.getEllipsisLoc())) Invalid = true; if (Invalid) Param->setInvalidDecl(); if (Param->isParameterPack()) if (auto *LSI = getEnclosingLambda()) LSI->LocalPacks.push_back(Param); if (ParamName) { maybeDiagnoseTemplateParameterShadow(*this, S, D.getIdentifierLoc(), ParamName); // Add the template parameter into the current scope. S->AddDecl(Param); IdResolver.AddDecl(Param); } // C++0x [temp.param]p9: // A default template-argument may be specified for any kind of // template-parameter that is not a template parameter pack. if (Default && IsParameterPack) { Diag(EqualLoc, diag::err_template_param_pack_default_arg); Default = nullptr; } // Check the well-formedness of the default template argument, if provided. if (Default) { // Check for unexpanded parameter packs. if (DiagnoseUnexpandedParameterPack(Default, UPPC_DefaultArgument)) return Param; TemplateArgument Converted; ExprResult DefaultRes = CheckTemplateArgument(Param, Param->getType(), Default, Converted); if (DefaultRes.isInvalid()) { Param->setInvalidDecl(); return Param; } Default = DefaultRes.get(); Param->setDefaultArgument(Default); } return Param; } /// ActOnTemplateTemplateParameter - Called when a C++ template template /// parameter (e.g. T in template