diff --git a/contrib/llvm-project/clang/include/clang/AST/Expr.h b/contrib/llvm-project/clang/include/clang/AST/Expr.h index 16956c27a114..bcb960540001 100644 --- a/contrib/llvm-project/clang/include/clang/AST/Expr.h +++ b/contrib/llvm-project/clang/include/clang/AST/Expr.h @@ -1,6006 +1,6006 @@ //===--- 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: - // FIXME: Does type-dependence need to be computed differently? - // FIXME: Do we need to compute instantiation instantiation-dependence for - // statements? (ugh!) StmtExpr(CompoundStmt *substmt, QualType T, - SourceLocation lp, SourceLocation rp) : + 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(), false, false, false), - SubStmt(substmt), LParenLoc(lp), RParenLoc(rp) { } + T->isDependentType(), InDependentContext, InDependentContext, false), + SubStmt(substmt), LParenLoc(lp), RParenLoc(rp) {} /// 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; } 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 diff --git a/contrib/llvm-project/clang/include/clang/Sema/Sema.h b/contrib/llvm-project/clang/include/clang/Sema/Sema.h index 697d1911be8f..2b5f7c1a7203 100644 --- a/contrib/llvm-project/clang/include/clang/Sema/Sema.h +++ b/contrib/llvm-project/clang/include/clang/Sema/Sema.h @@ -1,12117 +1,12117 @@ //===--- 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; /// 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; 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; public: ContextRAII(Sema &S, DeclContext *ContextToPush, bool NewThisContext = true) : S(S), SavedContext(S.CurContext), SavedContextState(S.DelayedDiagnostics.pushUndelayed()), SavedCXXThisTypeOverride(S.CXXThisTypeOverride) { assert(ContextToPush && "pushing null context"); S.CurContext = ContextToPush; if (NewThisContext) S.CXXThisTypeOverride = QualType(); } void pop() { if (!SavedContext) return; S.CurContext = SavedContext; S.DelayedDiagnostics.popUndelayed(SavedContextState); S.CXXThisTypeOverride = SavedCXXThisTypeOverride; 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(SourceLocation LPLoc, Stmt *SubStmt, + ExprResult ActOnStmtExpr(Scope *S, SourceLocation LPLoc, Stmt *SubStmt, SourceLocation RPLoc); // "({..})" // 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; } /// 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 diff --git a/contrib/llvm-project/clang/lib/AST/ASTImporter.cpp b/contrib/llvm-project/clang/lib/AST/ASTImporter.cpp index 1f2ce30398c9..f42361500a91 100644 --- a/contrib/llvm-project/clang/lib/AST/ASTImporter.cpp +++ b/contrib/llvm-project/clang/lib/AST/ASTImporter.cpp @@ -1,9050 +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); + return new (Importer.getToContext()) + StmtExpr(ToSubStmt, ToType, ToLParenLoc, ToRParenLoc, + E->isInstantiationDependent()); } 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); } diff --git a/contrib/llvm-project/clang/lib/Format/TokenAnnotator.cpp b/contrib/llvm-project/clang/lib/Format/TokenAnnotator.cpp index 88564e02f23e..70bcd7048c55 100644 --- a/contrib/llvm-project/clang/lib/Format/TokenAnnotator.cpp +++ b/contrib/llvm-project/clang/lib/Format/TokenAnnotator.cpp @@ -1,3676 +1,3683 @@ //===--- TokenAnnotator.cpp - Format C++ code -----------------------------===// // // 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 /// This file implements a token annotator, i.e. creates /// \c AnnotatedTokens out of \c FormatTokens with required extra information. /// //===----------------------------------------------------------------------===// #include "TokenAnnotator.h" #include "FormatToken.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/TokenKinds.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/Support/Debug.h" #define DEBUG_TYPE "format-token-annotator" namespace clang { namespace format { namespace { /// Returns \c true if the token can be used as an identifier in /// an Objective-C \c @selector, \c false otherwise. /// /// Because getFormattingLangOpts() always lexes source code as /// Objective-C++, C++ keywords like \c new and \c delete are /// lexed as tok::kw_*, not tok::identifier, even for Objective-C. /// /// For Objective-C and Objective-C++, both identifiers and keywords /// are valid inside @selector(...) (or a macro which /// invokes @selector(...)). So, we allow treat any identifier or /// keyword as a potential Objective-C selector component. static bool canBeObjCSelectorComponent(const FormatToken &Tok) { return Tok.Tok.getIdentifierInfo() != nullptr; } /// With `Left` being '(', check if we're at either `[...](` or /// `[...]<...>(`, where the [ opens a lambda capture list. static bool isLambdaParameterList(const FormatToken *Left) { // Skip <...> if present. if (Left->Previous && Left->Previous->is(tok::greater) && Left->Previous->MatchingParen && Left->Previous->MatchingParen->is(TT_TemplateOpener)) Left = Left->Previous->MatchingParen; // Check for `[...]`. return Left->Previous && Left->Previous->is(tok::r_square) && Left->Previous->MatchingParen && Left->Previous->MatchingParen->is(TT_LambdaLSquare); } /// A parser that gathers additional information about tokens. /// /// The \c TokenAnnotator tries to match parenthesis and square brakets and /// store a parenthesis levels. It also tries to resolve matching "<" and ">" /// into template parameter lists. class AnnotatingParser { public: AnnotatingParser(const FormatStyle &Style, AnnotatedLine &Line, const AdditionalKeywords &Keywords) : Style(Style), Line(Line), CurrentToken(Line.First), AutoFound(false), Keywords(Keywords) { Contexts.push_back(Context(tok::unknown, 1, /*IsExpression=*/false)); resetTokenMetadata(CurrentToken); } private: bool parseAngle() { if (!CurrentToken || !CurrentToken->Previous) return false; if (NonTemplateLess.count(CurrentToken->Previous)) return false; const FormatToken &Previous = *CurrentToken->Previous; // The '<'. if (Previous.Previous) { if (Previous.Previous->Tok.isLiteral()) return false; if (Previous.Previous->is(tok::r_paren) && Contexts.size() > 1 && (!Previous.Previous->MatchingParen || !Previous.Previous->MatchingParen->is(TT_OverloadedOperatorLParen))) return false; } FormatToken *Left = CurrentToken->Previous; Left->ParentBracket = Contexts.back().ContextKind; ScopedContextCreator ContextCreator(*this, tok::less, 12); // If this angle is in the context of an expression, we need to be more // hesitant to detect it as opening template parameters. bool InExprContext = Contexts.back().IsExpression; Contexts.back().IsExpression = false; // If there's a template keyword before the opening angle bracket, this is a // template parameter, not an argument. Contexts.back().InTemplateArgument = Left->Previous && Left->Previous->Tok.isNot(tok::kw_template); if (Style.Language == FormatStyle::LK_Java && CurrentToken->is(tok::question)) next(); while (CurrentToken) { if (CurrentToken->is(tok::greater)) { Left->MatchingParen = CurrentToken; CurrentToken->MatchingParen = Left; // In TT_Proto, we must distignuish between: // map // msg < item: data > // msg: < item: data > // In TT_TextProto, map does not occur. if (Style.Language == FormatStyle::LK_TextProto || (Style.Language == FormatStyle::LK_Proto && Left->Previous && Left->Previous->isOneOf(TT_SelectorName, TT_DictLiteral))) CurrentToken->Type = TT_DictLiteral; else CurrentToken->Type = TT_TemplateCloser; next(); return true; } if (CurrentToken->is(tok::question) && Style.Language == FormatStyle::LK_Java) { next(); continue; } if (CurrentToken->isOneOf(tok::r_paren, tok::r_square, tok::r_brace) || (CurrentToken->isOneOf(tok::colon, tok::question) && InExprContext && Style.Language != FormatStyle::LK_Proto && Style.Language != FormatStyle::LK_TextProto)) return false; // If a && or || is found and interpreted as a binary operator, this set // of angles is likely part of something like "a < b && c > d". If the // angles are inside an expression, the ||/&& might also be a binary // operator that was misinterpreted because we are parsing template // parameters. // FIXME: This is getting out of hand, write a decent parser. if (CurrentToken->Previous->isOneOf(tok::pipepipe, tok::ampamp) && CurrentToken->Previous->is(TT_BinaryOperator) && Contexts[Contexts.size() - 2].IsExpression && !Line.startsWith(tok::kw_template)) return false; updateParameterCount(Left, CurrentToken); if (Style.Language == FormatStyle::LK_Proto) { if (FormatToken *Previous = CurrentToken->getPreviousNonComment()) { if (CurrentToken->is(tok::colon) || (CurrentToken->isOneOf(tok::l_brace, tok::less) && Previous->isNot(tok::colon))) Previous->Type = TT_SelectorName; } } if (!consumeToken()) return false; } return false; } bool parseParens(bool LookForDecls = false) { if (!CurrentToken) return false; FormatToken *Left = CurrentToken->Previous; Left->ParentBracket = Contexts.back().ContextKind; ScopedContextCreator ContextCreator(*this, tok::l_paren, 1); // FIXME: This is a bit of a hack. Do better. Contexts.back().ColonIsForRangeExpr = Contexts.size() == 2 && Contexts[0].ColonIsForRangeExpr; bool StartsObjCMethodExpr = false; if (FormatToken *MaybeSel = Left->Previous) { // @selector( starts a selector. if (MaybeSel->isObjCAtKeyword(tok::objc_selector) && MaybeSel->Previous && MaybeSel->Previous->is(tok::at)) { StartsObjCMethodExpr = true; } } if (Left->is(TT_OverloadedOperatorLParen)) { Contexts.back().IsExpression = false; } else if (Style.Language == FormatStyle::LK_JavaScript && (Line.startsWith(Keywords.kw_type, tok::identifier) || Line.startsWith(tok::kw_export, Keywords.kw_type, tok::identifier))) { // type X = (...); // export type X = (...); Contexts.back().IsExpression = false; } else if (Left->Previous && (Left->Previous->isOneOf(tok::kw_static_assert, tok::kw_decltype, tok::kw_while, tok::l_paren, tok::comma) || Left->Previous->isIf() || Left->Previous->is(TT_BinaryOperator))) { // static_assert, if and while usually contain expressions. Contexts.back().IsExpression = true; } else if (Style.Language == FormatStyle::LK_JavaScript && Left->Previous && (Left->Previous->is(Keywords.kw_function) || (Left->Previous->endsSequence(tok::identifier, Keywords.kw_function)))) { // function(...) or function f(...) Contexts.back().IsExpression = false; } else if (Style.Language == FormatStyle::LK_JavaScript && Left->Previous && Left->Previous->is(TT_JsTypeColon)) { // let x: (SomeType); Contexts.back().IsExpression = false; } else if (isLambdaParameterList(Left)) { // This is a parameter list of a lambda expression. Contexts.back().IsExpression = false; } else if (Line.InPPDirective && (!Left->Previous || !Left->Previous->is(tok::identifier))) { Contexts.back().IsExpression = true; } else if (Contexts[Contexts.size() - 2].CaretFound) { // This is the parameter list of an ObjC block. Contexts.back().IsExpression = false; } else if (Left->Previous && Left->Previous->is(tok::kw___attribute)) { Left->Type = TT_AttributeParen; } else if (Left->Previous && Left->Previous->is(TT_ForEachMacro)) { // The first argument to a foreach macro is a declaration. Contexts.back().IsForEachMacro = true; Contexts.back().IsExpression = false; } else if (Left->Previous && Left->Previous->MatchingParen && Left->Previous->MatchingParen->is(TT_ObjCBlockLParen)) { Contexts.back().IsExpression = false; } else if (!Line.MustBeDeclaration && !Line.InPPDirective) { bool IsForOrCatch = Left->Previous && Left->Previous->isOneOf(tok::kw_for, tok::kw_catch); Contexts.back().IsExpression = !IsForOrCatch; } if (StartsObjCMethodExpr) { Contexts.back().ColonIsObjCMethodExpr = true; Left->Type = TT_ObjCMethodExpr; } // MightBeFunctionType and ProbablyFunctionType are used for // function pointer and reference types as well as Objective-C // block types: // // void (*FunctionPointer)(void); // void (&FunctionReference)(void); // void (^ObjCBlock)(void); bool MightBeFunctionType = !Contexts[Contexts.size() - 2].IsExpression; bool ProbablyFunctionType = CurrentToken->isOneOf(tok::star, tok::amp, tok::caret); bool HasMultipleLines = false; bool HasMultipleParametersOnALine = false; bool MightBeObjCForRangeLoop = Left->Previous && Left->Previous->is(tok::kw_for); FormatToken *PossibleObjCForInToken = nullptr; while (CurrentToken) { // LookForDecls is set when "if (" has been seen. Check for // 'identifier' '*' 'identifier' followed by not '=' -- this // '*' has to be a binary operator but determineStarAmpUsage() will // categorize it as an unary operator, so set the right type here. if (LookForDecls && CurrentToken->Next) { FormatToken *Prev = CurrentToken->getPreviousNonComment(); if (Prev) { FormatToken *PrevPrev = Prev->getPreviousNonComment(); FormatToken *Next = CurrentToken->Next; if (PrevPrev && PrevPrev->is(tok::identifier) && Prev->isOneOf(tok::star, tok::amp, tok::ampamp) && CurrentToken->is(tok::identifier) && Next->isNot(tok::equal)) { Prev->Type = TT_BinaryOperator; LookForDecls = false; } } } if (CurrentToken->Previous->is(TT_PointerOrReference) && CurrentToken->Previous->Previous->isOneOf(tok::l_paren, tok::coloncolon)) ProbablyFunctionType = true; if (CurrentToken->is(tok::comma)) MightBeFunctionType = false; if (CurrentToken->Previous->is(TT_BinaryOperator)) Contexts.back().IsExpression = true; if (CurrentToken->is(tok::r_paren)) { if (MightBeFunctionType && ProbablyFunctionType && CurrentToken->Next && (CurrentToken->Next->is(tok::l_paren) || (CurrentToken->Next->is(tok::l_square) && Line.MustBeDeclaration))) Left->Type = Left->Next->is(tok::caret) ? TT_ObjCBlockLParen : TT_FunctionTypeLParen; Left->MatchingParen = CurrentToken; CurrentToken->MatchingParen = Left; if (CurrentToken->Next && CurrentToken->Next->is(tok::l_brace) && Left->Previous && Left->Previous->is(tok::l_paren)) { // Detect the case where macros are used to generate lambdas or // function bodies, e.g.: // auto my_lambda = MARCO((Type *type, int i) { .. body .. }); for (FormatToken *Tok = Left; Tok != CurrentToken; Tok = Tok->Next) { if (Tok->is(TT_BinaryOperator) && Tok->isOneOf(tok::star, tok::amp, tok::ampamp)) Tok->Type = TT_PointerOrReference; } } if (StartsObjCMethodExpr) { CurrentToken->Type = TT_ObjCMethodExpr; if (Contexts.back().FirstObjCSelectorName) { Contexts.back().FirstObjCSelectorName->LongestObjCSelectorName = Contexts.back().LongestObjCSelectorName; } } if (Left->is(TT_AttributeParen)) CurrentToken->Type = TT_AttributeParen; if (Left->Previous && Left->Previous->is(TT_JavaAnnotation)) CurrentToken->Type = TT_JavaAnnotation; if (Left->Previous && Left->Previous->is(TT_LeadingJavaAnnotation)) CurrentToken->Type = TT_LeadingJavaAnnotation; if (Left->Previous && Left->Previous->is(TT_AttributeSquare)) CurrentToken->Type = TT_AttributeSquare; if (!HasMultipleLines) Left->PackingKind = PPK_Inconclusive; else if (HasMultipleParametersOnALine) Left->PackingKind = PPK_BinPacked; else Left->PackingKind = PPK_OnePerLine; next(); return true; } if (CurrentToken->isOneOf(tok::r_square, tok::r_brace)) return false; if (CurrentToken->is(tok::l_brace)) Left->Type = TT_Unknown; // Not TT_ObjCBlockLParen if (CurrentToken->is(tok::comma) && CurrentToken->Next && !CurrentToken->Next->HasUnescapedNewline && !CurrentToken->Next->isTrailingComment()) HasMultipleParametersOnALine = true; if ((CurrentToken->Previous->isOneOf(tok::kw_const, tok::kw_auto) || CurrentToken->Previous->isSimpleTypeSpecifier()) && !CurrentToken->is(tok::l_brace)) Contexts.back().IsExpression = false; if (CurrentToken->isOneOf(tok::semi, tok::colon)) { MightBeObjCForRangeLoop = false; if (PossibleObjCForInToken) { PossibleObjCForInToken->Type = TT_Unknown; PossibleObjCForInToken = nullptr; } } if (MightBeObjCForRangeLoop && CurrentToken->is(Keywords.kw_in)) { PossibleObjCForInToken = CurrentToken; PossibleObjCForInToken->Type = TT_ObjCForIn; } // When we discover a 'new', we set CanBeExpression to 'false' in order to // parse the type correctly. Reset that after a comma. if (CurrentToken->is(tok::comma)) Contexts.back().CanBeExpression = true; FormatToken *Tok = CurrentToken; if (!consumeToken()) return false; updateParameterCount(Left, Tok); if (CurrentToken && CurrentToken->HasUnescapedNewline) HasMultipleLines = true; } return false; } bool isCSharpAttributeSpecifier(const FormatToken &Tok) { if (!Style.isCSharp()) return false; const FormatToken *AttrTok = Tok.Next; if (!AttrTok) return false; // Just an empty declaration e.g. string []. if (AttrTok->is(tok::r_square)) return false; // Move along the tokens inbetween the '[' and ']' e.g. [STAThread]. while (AttrTok && AttrTok->isNot(tok::r_square)) { AttrTok = AttrTok->Next; } if (!AttrTok) return false; // Move past the end of ']'. AttrTok = AttrTok->Next; if (!AttrTok) return false; // Limit this to being an access modifier that follows. if (AttrTok->isOneOf(tok::kw_public, tok::kw_private, tok::kw_protected, tok::kw_class, tok::kw_static, tok::l_square, Keywords.kw_internal)) { return true; } // incase its a [XXX] retval func(.... if (AttrTok->Next && AttrTok->Next->startsSequence(tok::identifier, tok::l_paren)) return true; return false; } bool isCpp11AttributeSpecifier(const FormatToken &Tok) { if (!Style.isCpp() || !Tok.startsSequence(tok::l_square, tok::l_square)) return false; // The first square bracket is part of an ObjC array literal if (Tok.Previous && Tok.Previous->is(tok::at)) { return false; } const FormatToken *AttrTok = Tok.Next->Next; if (!AttrTok) return false; // C++17 '[[using ns: foo, bar(baz, blech)]]' // We assume nobody will name an ObjC variable 'using'. if (AttrTok->startsSequence(tok::kw_using, tok::identifier, tok::colon)) return true; if (AttrTok->isNot(tok::identifier)) return false; while (AttrTok && !AttrTok->startsSequence(tok::r_square, tok::r_square)) { // ObjC message send. We assume nobody will use : in a C++11 attribute // specifier parameter, although this is technically valid: // [[foo(:)]]. if (AttrTok->is(tok::colon) || AttrTok->startsSequence(tok::identifier, tok::identifier) || AttrTok->startsSequence(tok::r_paren, tok::identifier)) return false; if (AttrTok->is(tok::ellipsis)) return true; AttrTok = AttrTok->Next; } return AttrTok && AttrTok->startsSequence(tok::r_square, tok::r_square); } bool parseSquare() { if (!CurrentToken) return false; // A '[' could be an index subscript (after an identifier or after // ')' or ']'), it could be the start of an Objective-C method // expression, it could the start of an Objective-C array literal, // or it could be a C++ attribute specifier [[foo::bar]]. FormatToken *Left = CurrentToken->Previous; Left->ParentBracket = Contexts.back().ContextKind; FormatToken *Parent = Left->getPreviousNonComment(); // Cases where '>' is followed by '['. // In C++, this can happen either in array of templates (foo[10]) // or when array is a nested template type (unique_ptr[]>). bool CppArrayTemplates = Style.isCpp() && Parent && Parent->is(TT_TemplateCloser) && (Contexts.back().CanBeExpression || Contexts.back().IsExpression || Contexts.back().InTemplateArgument); bool IsCpp11AttributeSpecifier = isCpp11AttributeSpecifier(*Left) || Contexts.back().InCpp11AttributeSpecifier; // Treat C# Attributes [STAThread] much like C++ attributes [[...]]. bool IsCSharp11AttributeSpecifier = isCSharpAttributeSpecifier(*Left) || Contexts.back().InCSharpAttributeSpecifier; bool InsideInlineASM = Line.startsWith(tok::kw_asm); bool IsCppStructuredBinding = Left->isCppStructuredBinding(Style); bool StartsObjCMethodExpr = !IsCppStructuredBinding && !InsideInlineASM && !CppArrayTemplates && Style.isCpp() && !IsCpp11AttributeSpecifier && Contexts.back().CanBeExpression && Left->isNot(TT_LambdaLSquare) && !CurrentToken->isOneOf(tok::l_brace, tok::r_square) && (!Parent || Parent->isOneOf(tok::colon, tok::l_square, tok::l_paren, tok::kw_return, tok::kw_throw) || Parent->isUnaryOperator() || // FIXME(bug 36976): ObjC return types shouldn't use TT_CastRParen. Parent->isOneOf(TT_ObjCForIn, TT_CastRParen) || (getBinOpPrecedence(Parent->Tok.getKind(), true, true) > prec::Unknown)); bool ColonFound = false; unsigned BindingIncrease = 1; if (IsCppStructuredBinding) { Left->Type = TT_StructuredBindingLSquare; } else if (Left->is(TT_Unknown)) { if (StartsObjCMethodExpr) { Left->Type = TT_ObjCMethodExpr; } else if (IsCpp11AttributeSpecifier) { Left->Type = TT_AttributeSquare; } else if (Style.Language == FormatStyle::LK_JavaScript && Parent && Contexts.back().ContextKind == tok::l_brace && Parent->isOneOf(tok::l_brace, tok::comma)) { Left->Type = TT_JsComputedPropertyName; } else if (Style.isCpp() && Contexts.back().ContextKind == tok::l_brace && Parent && Parent->isOneOf(tok::l_brace, tok::comma)) { Left->Type = TT_DesignatedInitializerLSquare; } else if (IsCSharp11AttributeSpecifier) { Left->Type = TT_AttributeSquare; } else if (CurrentToken->is(tok::r_square) && Parent && Parent->is(TT_TemplateCloser)) { Left->Type = TT_ArraySubscriptLSquare; } else if (Style.Language == FormatStyle::LK_Proto || Style.Language == FormatStyle::LK_TextProto) { // Square braces in LK_Proto can either be message field attributes: // // optional Aaa aaa = 1 [ // (aaa) = aaa // ]; // // extensions 123 [ // (aaa) = aaa // ]; // // or text proto extensions (in options): // // option (Aaa.options) = { // [type.type/type] { // key: value // } // } // // or repeated fields (in options): // // option (Aaa.options) = { // keys: [ 1, 2, 3 ] // } // // In the first and the third case we want to spread the contents inside // the square braces; in the second we want to keep them inline. Left->Type = TT_ArrayInitializerLSquare; if (!Left->endsSequence(tok::l_square, tok::numeric_constant, tok::equal) && !Left->endsSequence(tok::l_square, tok::numeric_constant, tok::identifier) && !Left->endsSequence(tok::l_square, tok::colon, TT_SelectorName)) { Left->Type = TT_ProtoExtensionLSquare; BindingIncrease = 10; } } else if (!CppArrayTemplates && Parent && Parent->isOneOf(TT_BinaryOperator, TT_TemplateCloser, tok::at, tok::comma, tok::l_paren, tok::l_square, tok::question, tok::colon, tok::kw_return, // Should only be relevant to JavaScript: tok::kw_default)) { Left->Type = TT_ArrayInitializerLSquare; } else { BindingIncrease = 10; Left->Type = TT_ArraySubscriptLSquare; } } ScopedContextCreator ContextCreator(*this, tok::l_square, BindingIncrease); Contexts.back().IsExpression = true; if (Style.Language == FormatStyle::LK_JavaScript && Parent && Parent->is(TT_JsTypeColon)) Contexts.back().IsExpression = false; Contexts.back().ColonIsObjCMethodExpr = StartsObjCMethodExpr; Contexts.back().InCpp11AttributeSpecifier = IsCpp11AttributeSpecifier; Contexts.back().InCSharpAttributeSpecifier = IsCSharp11AttributeSpecifier; while (CurrentToken) { if (CurrentToken->is(tok::r_square)) { if (IsCpp11AttributeSpecifier) CurrentToken->Type = TT_AttributeSquare; if (IsCSharp11AttributeSpecifier) CurrentToken->Type = TT_AttributeSquare; else if (((CurrentToken->Next && CurrentToken->Next->is(tok::l_paren)) || (CurrentToken->Previous && CurrentToken->Previous->Previous == Left)) && Left->is(TT_ObjCMethodExpr)) { // An ObjC method call is rarely followed by an open parenthesis. It // also can't be composed of just one token, unless it's a macro that // will be expanded to more tokens. // FIXME: Do we incorrectly label ":" with this? StartsObjCMethodExpr = false; Left->Type = TT_Unknown; } if (StartsObjCMethodExpr && CurrentToken->Previous != Left) { CurrentToken->Type = TT_ObjCMethodExpr; // If we haven't seen a colon yet, make sure the last identifier // before the r_square is tagged as a selector name component. if (!ColonFound && CurrentToken->Previous && CurrentToken->Previous->is(TT_Unknown) && canBeObjCSelectorComponent(*CurrentToken->Previous)) CurrentToken->Previous->Type = TT_SelectorName; // determineStarAmpUsage() thinks that '*' '[' is allocating an // array of pointers, but if '[' starts a selector then '*' is a // binary operator. if (Parent && Parent->is(TT_PointerOrReference)) Parent->Type = TT_BinaryOperator; } // An arrow after an ObjC method expression is not a lambda arrow. if (CurrentToken->Type == TT_ObjCMethodExpr && CurrentToken->Next && CurrentToken->Next->is(TT_LambdaArrow)) CurrentToken->Next->Type = TT_Unknown; Left->MatchingParen = CurrentToken; CurrentToken->MatchingParen = Left; // FirstObjCSelectorName is set when a colon is found. This does // not work, however, when the method has no parameters. // Here, we set FirstObjCSelectorName when the end of the method call is // reached, in case it was not set already. if (!Contexts.back().FirstObjCSelectorName) { FormatToken *Previous = CurrentToken->getPreviousNonComment(); if (Previous && Previous->is(TT_SelectorName)) { Previous->ObjCSelectorNameParts = 1; Contexts.back().FirstObjCSelectorName = Previous; } } else { Left->ParameterCount = Contexts.back().FirstObjCSelectorName->ObjCSelectorNameParts; } if (Contexts.back().FirstObjCSelectorName) { Contexts.back().FirstObjCSelectorName->LongestObjCSelectorName = Contexts.back().LongestObjCSelectorName; if (Left->BlockParameterCount > 1) Contexts.back().FirstObjCSelectorName->LongestObjCSelectorName = 0; } next(); return true; } if (CurrentToken->isOneOf(tok::r_paren, tok::r_brace)) return false; if (CurrentToken->is(tok::colon)) { if (IsCpp11AttributeSpecifier && CurrentToken->endsSequence(tok::colon, tok::identifier, tok::kw_using)) { // Remember that this is a [[using ns: foo]] C++ attribute, so we // don't add a space before the colon (unlike other colons). CurrentToken->Type = TT_AttributeColon; } else if (Left->isOneOf(TT_ArraySubscriptLSquare, TT_DesignatedInitializerLSquare)) { Left->Type = TT_ObjCMethodExpr; StartsObjCMethodExpr = true; Contexts.back().ColonIsObjCMethodExpr = true; if (Parent && Parent->is(tok::r_paren)) // FIXME(bug 36976): ObjC return types shouldn't use TT_CastRParen. Parent->Type = TT_CastRParen; } ColonFound = true; } if (CurrentToken->is(tok::comma) && Left->is(TT_ObjCMethodExpr) && !ColonFound) Left->Type = TT_ArrayInitializerLSquare; FormatToken *Tok = CurrentToken; if (!consumeToken()) return false; updateParameterCount(Left, Tok); } return false; } bool parseBrace() { if (CurrentToken) { FormatToken *Left = CurrentToken->Previous; Left->ParentBracket = Contexts.back().ContextKind; if (Contexts.back().CaretFound) Left->Type = TT_ObjCBlockLBrace; Contexts.back().CaretFound = false; ScopedContextCreator ContextCreator(*this, tok::l_brace, 1); Contexts.back().ColonIsDictLiteral = true; if (Left->BlockKind == BK_BracedInit) Contexts.back().IsExpression = true; if (Style.Language == FormatStyle::LK_JavaScript && Left->Previous && Left->Previous->is(TT_JsTypeColon)) Contexts.back().IsExpression = false; while (CurrentToken) { if (CurrentToken->is(tok::r_brace)) { Left->MatchingParen = CurrentToken; CurrentToken->MatchingParen = Left; next(); return true; } if (CurrentToken->isOneOf(tok::r_paren, tok::r_square)) return false; updateParameterCount(Left, CurrentToken); if (CurrentToken->isOneOf(tok::colon, tok::l_brace, tok::less)) { FormatToken *Previous = CurrentToken->getPreviousNonComment(); if (Previous->is(TT_JsTypeOptionalQuestion)) Previous = Previous->getPreviousNonComment(); if ((CurrentToken->is(tok::colon) && (!Contexts.back().ColonIsDictLiteral || !Style.isCpp())) || Style.Language == FormatStyle::LK_Proto || Style.Language == FormatStyle::LK_TextProto) { Left->Type = TT_DictLiteral; if (Previous->Tok.getIdentifierInfo() || Previous->is(tok::string_literal)) Previous->Type = TT_SelectorName; } if (CurrentToken->is(tok::colon) || Style.Language == FormatStyle::LK_JavaScript) Left->Type = TT_DictLiteral; } if (CurrentToken->is(tok::comma) && Style.Language == FormatStyle::LK_JavaScript) Left->Type = TT_DictLiteral; if (!consumeToken()) return false; } } return true; } void updateParameterCount(FormatToken *Left, FormatToken *Current) { // For ObjC methods, the number of parameters is calculated differently as // method declarations have a different structure (the parameters are not // inside a bracket scope). if (Current->is(tok::l_brace) && Current->BlockKind == BK_Block) ++Left->BlockParameterCount; if (Current->is(tok::comma)) { ++Left->ParameterCount; if (!Left->Role) Left->Role.reset(new CommaSeparatedList(Style)); Left->Role->CommaFound(Current); } else if (Left->ParameterCount == 0 && Current->isNot(tok::comment)) { Left->ParameterCount = 1; } } bool parseConditional() { while (CurrentToken) { if (CurrentToken->is(tok::colon)) { CurrentToken->Type = TT_ConditionalExpr; next(); return true; } if (!consumeToken()) return false; } return false; } bool parseTemplateDeclaration() { if (CurrentToken && CurrentToken->is(tok::less)) { CurrentToken->Type = TT_TemplateOpener; next(); if (!parseAngle()) return false; if (CurrentToken) CurrentToken->Previous->ClosesTemplateDeclaration = true; return true; } return false; } bool consumeToken() { FormatToken *Tok = CurrentToken; next(); switch (Tok->Tok.getKind()) { case tok::plus: case tok::minus: if (!Tok->Previous && Line.MustBeDeclaration) Tok->Type = TT_ObjCMethodSpecifier; break; case tok::colon: if (!Tok->Previous) return false; // Colons from ?: are handled in parseConditional(). if (Style.Language == FormatStyle::LK_JavaScript) { if (Contexts.back().ColonIsForRangeExpr || // colon in for loop (Contexts.size() == 1 && // switch/case labels !Line.First->isOneOf(tok::kw_enum, tok::kw_case)) || Contexts.back().ContextKind == tok::l_paren || // function params Contexts.back().ContextKind == tok::l_square || // array type (!Contexts.back().IsExpression && Contexts.back().ContextKind == tok::l_brace) || // object type (Contexts.size() == 1 && Line.MustBeDeclaration)) { // method/property declaration Contexts.back().IsExpression = false; Tok->Type = TT_JsTypeColon; break; } } if (Contexts.back().ColonIsDictLiteral || Style.Language == FormatStyle::LK_Proto || Style.Language == FormatStyle::LK_TextProto) { Tok->Type = TT_DictLiteral; if (Style.Language == FormatStyle::LK_TextProto) { if (FormatToken *Previous = Tok->getPreviousNonComment()) Previous->Type = TT_SelectorName; } } else if (Contexts.back().ColonIsObjCMethodExpr || Line.startsWith(TT_ObjCMethodSpecifier)) { Tok->Type = TT_ObjCMethodExpr; const FormatToken *BeforePrevious = Tok->Previous->Previous; // Ensure we tag all identifiers in method declarations as // TT_SelectorName. bool UnknownIdentifierInMethodDeclaration = Line.startsWith(TT_ObjCMethodSpecifier) && Tok->Previous->is(tok::identifier) && Tok->Previous->is(TT_Unknown); if (!BeforePrevious || // FIXME(bug 36976): ObjC return types shouldn't use TT_CastRParen. !(BeforePrevious->is(TT_CastRParen) || (BeforePrevious->is(TT_ObjCMethodExpr) && BeforePrevious->is(tok::colon))) || BeforePrevious->is(tok::r_square) || Contexts.back().LongestObjCSelectorName == 0 || UnknownIdentifierInMethodDeclaration) { Tok->Previous->Type = TT_SelectorName; if (!Contexts.back().FirstObjCSelectorName) Contexts.back().FirstObjCSelectorName = Tok->Previous; else if (Tok->Previous->ColumnWidth > Contexts.back().LongestObjCSelectorName) Contexts.back().LongestObjCSelectorName = Tok->Previous->ColumnWidth; Tok->Previous->ParameterIndex = Contexts.back().FirstObjCSelectorName->ObjCSelectorNameParts; ++Contexts.back().FirstObjCSelectorName->ObjCSelectorNameParts; } } else if (Contexts.back().ColonIsForRangeExpr) { Tok->Type = TT_RangeBasedForLoopColon; } else if (CurrentToken && CurrentToken->is(tok::numeric_constant)) { Tok->Type = TT_BitFieldColon; } else if (Contexts.size() == 1 && !Line.First->isOneOf(tok::kw_enum, tok::kw_case)) { if (Tok->getPreviousNonComment()->isOneOf(tok::r_paren, tok::kw_noexcept)) Tok->Type = TT_CtorInitializerColon; else Tok->Type = TT_InheritanceColon; } else if (canBeObjCSelectorComponent(*Tok->Previous) && Tok->Next && (Tok->Next->isOneOf(tok::r_paren, tok::comma) || (canBeObjCSelectorComponent(*Tok->Next) && Tok->Next->Next && Tok->Next->Next->is(tok::colon)))) { // This handles a special macro in ObjC code where selectors including // the colon are passed as macro arguments. Tok->Type = TT_ObjCMethodExpr; } else if (Contexts.back().ContextKind == tok::l_paren) { Tok->Type = TT_InlineASMColon; } break; case tok::pipe: case tok::amp: // | and & in declarations/type expressions represent union and // intersection types, respectively. if (Style.Language == FormatStyle::LK_JavaScript && !Contexts.back().IsExpression) Tok->Type = TT_JsTypeOperator; break; case tok::kw_if: case tok::kw_while: if (Tok->is(tok::kw_if) && CurrentToken && CurrentToken->isOneOf(tok::kw_constexpr, tok::identifier)) next(); if (CurrentToken && CurrentToken->is(tok::l_paren)) { next(); if (!parseParens(/*LookForDecls=*/true)) return false; } break; case tok::kw_for: if (Style.Language == FormatStyle::LK_JavaScript) { // x.for and {for: ...} if ((Tok->Previous && Tok->Previous->is(tok::period)) || (Tok->Next && Tok->Next->is(tok::colon))) break; // JS' for await ( ... if (CurrentToken && CurrentToken->is(Keywords.kw_await)) next(); } Contexts.back().ColonIsForRangeExpr = true; next(); if (!parseParens()) return false; break; case tok::l_paren: // When faced with 'operator()()', the kw_operator handler incorrectly // marks the first l_paren as a OverloadedOperatorLParen. Here, we make // the first two parens OverloadedOperators and the second l_paren an // OverloadedOperatorLParen. if (Tok->Previous && Tok->Previous->is(tok::r_paren) && Tok->Previous->MatchingParen && Tok->Previous->MatchingParen->is(TT_OverloadedOperatorLParen)) { Tok->Previous->Type = TT_OverloadedOperator; Tok->Previous->MatchingParen->Type = TT_OverloadedOperator; Tok->Type = TT_OverloadedOperatorLParen; } if (!parseParens()) return false; if (Line.MustBeDeclaration && Contexts.size() == 1 && !Contexts.back().IsExpression && !Line.startsWith(TT_ObjCProperty) && (!Tok->Previous || !Tok->Previous->isOneOf(tok::kw_decltype, tok::kw___attribute, TT_LeadingJavaAnnotation))) Line.MightBeFunctionDecl = true; break; case tok::l_square: if (!parseSquare()) return false; break; case tok::l_brace: if (Style.Language == FormatStyle::LK_TextProto) { FormatToken *Previous = Tok->getPreviousNonComment(); if (Previous && Previous->Type != TT_DictLiteral) Previous->Type = TT_SelectorName; } if (!parseBrace()) return false; break; case tok::less: if (parseAngle()) { Tok->Type = TT_TemplateOpener; // In TT_Proto, we must distignuish between: // map // msg < item: data > // msg: < item: data > // In TT_TextProto, map does not occur. if (Style.Language == FormatStyle::LK_TextProto || (Style.Language == FormatStyle::LK_Proto && Tok->Previous && Tok->Previous->isOneOf(TT_SelectorName, TT_DictLiteral))) { Tok->Type = TT_DictLiteral; FormatToken *Previous = Tok->getPreviousNonComment(); if (Previous && Previous->Type != TT_DictLiteral) Previous->Type = TT_SelectorName; } } else { Tok->Type = TT_BinaryOperator; NonTemplateLess.insert(Tok); CurrentToken = Tok; next(); } break; case tok::r_paren: case tok::r_square: return false; case tok::r_brace: // Lines can start with '}'. if (Tok->Previous) return false; break; case tok::greater: if (Style.Language != FormatStyle::LK_TextProto) Tok->Type = TT_BinaryOperator; if (Tok->Previous && Tok->Previous->is(TT_TemplateCloser)) Tok->SpacesRequiredBefore = 1; break; case tok::kw_operator: if (Style.Language == FormatStyle::LK_TextProto || Style.Language == FormatStyle::LK_Proto) break; while (CurrentToken && !CurrentToken->isOneOf(tok::l_paren, tok::semi, tok::r_paren)) { if (CurrentToken->isOneOf(tok::star, tok::amp)) CurrentToken->Type = TT_PointerOrReference; consumeToken(); if (CurrentToken && CurrentToken->Previous->isOneOf( TT_BinaryOperator, TT_UnaryOperator, tok::comma, tok::star, tok::arrow, tok::amp, tok::ampamp)) CurrentToken->Previous->Type = TT_OverloadedOperator; } if (CurrentToken) { CurrentToken->Type = TT_OverloadedOperatorLParen; if (CurrentToken->Previous->is(TT_BinaryOperator)) CurrentToken->Previous->Type = TT_OverloadedOperator; } break; case tok::question: if (Style.Language == FormatStyle::LK_JavaScript && Tok->Next && Tok->Next->isOneOf(tok::semi, tok::comma, tok::colon, tok::r_paren, tok::r_brace)) { // Question marks before semicolons, colons, etc. indicate optional // types (fields, parameters), e.g. // function(x?: string, y?) {...} // class X { y?; } Tok->Type = TT_JsTypeOptionalQuestion; break; } // Declarations cannot be conditional expressions, this can only be part // of a type declaration. if (Line.MustBeDeclaration && !Contexts.back().IsExpression && Style.Language == FormatStyle::LK_JavaScript) break; parseConditional(); break; case tok::kw_template: parseTemplateDeclaration(); break; case tok::comma: if (Contexts.back().InCtorInitializer) Tok->Type = TT_CtorInitializerComma; else if (Contexts.back().InInheritanceList) Tok->Type = TT_InheritanceComma; else if (Contexts.back().FirstStartOfName && (Contexts.size() == 1 || Line.startsWith(tok::kw_for))) { Contexts.back().FirstStartOfName->PartOfMultiVariableDeclStmt = true; Line.IsMultiVariableDeclStmt = true; } if (Contexts.back().IsForEachMacro) Contexts.back().IsExpression = true; break; case tok::identifier: if (Tok->isOneOf(Keywords.kw___has_include, Keywords.kw___has_include_next)) { parseHasInclude(); } break; default: break; } return true; } void parseIncludeDirective() { if (CurrentToken && CurrentToken->is(tok::less)) { next(); while (CurrentToken) { // Mark tokens up to the trailing line comments as implicit string // literals. if (CurrentToken->isNot(tok::comment) && !CurrentToken->TokenText.startswith("//")) CurrentToken->Type = TT_ImplicitStringLiteral; next(); } } } void parseWarningOrError() { next(); // We still want to format the whitespace left of the first token of the // warning or error. next(); while (CurrentToken) { CurrentToken->Type = TT_ImplicitStringLiteral; next(); } } void parsePragma() { next(); // Consume "pragma". if (CurrentToken && CurrentToken->isOneOf(Keywords.kw_mark, Keywords.kw_option)) { bool IsMark = CurrentToken->is(Keywords.kw_mark); next(); // Consume "mark". next(); // Consume first token (so we fix leading whitespace). while (CurrentToken) { if (IsMark || CurrentToken->Previous->is(TT_BinaryOperator)) CurrentToken->Type = TT_ImplicitStringLiteral; next(); } } } void parseHasInclude() { if (!CurrentToken || !CurrentToken->is(tok::l_paren)) return; next(); // '(' parseIncludeDirective(); next(); // ')' } LineType parsePreprocessorDirective() { bool IsFirstToken = CurrentToken->IsFirst; LineType Type = LT_PreprocessorDirective; next(); if (!CurrentToken) return Type; if (Style.Language == FormatStyle::LK_JavaScript && IsFirstToken) { // JavaScript files can contain shebang lines of the form: // #!/usr/bin/env node // Treat these like C++ #include directives. while (CurrentToken) { // Tokens cannot be comments here. CurrentToken->Type = TT_ImplicitStringLiteral; next(); } return LT_ImportStatement; } if (CurrentToken->Tok.is(tok::numeric_constant)) { CurrentToken->SpacesRequiredBefore = 1; return Type; } // Hashes in the middle of a line can lead to any strange token // sequence. if (!CurrentToken->Tok.getIdentifierInfo()) return Type; switch (CurrentToken->Tok.getIdentifierInfo()->getPPKeywordID()) { case tok::pp_include: case tok::pp_include_next: case tok::pp_import: next(); parseIncludeDirective(); Type = LT_ImportStatement; break; case tok::pp_error: case tok::pp_warning: parseWarningOrError(); break; case tok::pp_pragma: parsePragma(); break; case tok::pp_if: case tok::pp_elif: Contexts.back().IsExpression = true; next(); parseLine(); break; default: break; } while (CurrentToken) { FormatToken *Tok = CurrentToken; next(); if (Tok->is(tok::l_paren)) parseParens(); else if (Tok->isOneOf(Keywords.kw___has_include, Keywords.kw___has_include_next)) parseHasInclude(); } return Type; } public: LineType parseLine() { if (!CurrentToken) return LT_Invalid; NonTemplateLess.clear(); if (CurrentToken->is(tok::hash)) return parsePreprocessorDirective(); // Directly allow to 'import ' to support protocol buffer // definitions (github.com/google/protobuf) or missing "#" (either way we // should not break the line). IdentifierInfo *Info = CurrentToken->Tok.getIdentifierInfo(); if ((Style.Language == FormatStyle::LK_Java && CurrentToken->is(Keywords.kw_package)) || (Info && Info->getPPKeywordID() == tok::pp_import && CurrentToken->Next && CurrentToken->Next->isOneOf(tok::string_literal, tok::identifier, tok::kw_static))) { next(); parseIncludeDirective(); return LT_ImportStatement; } // If this line starts and ends in '<' and '>', respectively, it is likely // part of "#define ". if (CurrentToken->is(tok::less) && Line.Last->is(tok::greater)) { parseIncludeDirective(); return LT_ImportStatement; } // In .proto files, top-level options and package statements are very // similar to import statements and should not be line-wrapped. if (Style.Language == FormatStyle::LK_Proto && Line.Level == 0 && CurrentToken->isOneOf(Keywords.kw_option, Keywords.kw_package)) { next(); if (CurrentToken && CurrentToken->is(tok::identifier)) { while (CurrentToken) next(); return LT_ImportStatement; } } bool KeywordVirtualFound = false; bool ImportStatement = false; // import {...} from '...'; if (Style.Language == FormatStyle::LK_JavaScript && CurrentToken->is(Keywords.kw_import)) ImportStatement = true; while (CurrentToken) { if (CurrentToken->is(tok::kw_virtual)) KeywordVirtualFound = true; if (Style.Language == FormatStyle::LK_JavaScript) { // export {...} from '...'; // An export followed by "from 'some string';" is a re-export from // another module identified by a URI and is treated as a // LT_ImportStatement (i.e. prevent wraps on it for long URIs). // Just "export {...};" or "export class ..." should not be treated as // an import in this sense. if (Line.First->is(tok::kw_export) && CurrentToken->is(Keywords.kw_from) && CurrentToken->Next && CurrentToken->Next->isStringLiteral()) ImportStatement = true; if (isClosureImportStatement(*CurrentToken)) ImportStatement = true; } if (!consumeToken()) return LT_Invalid; } if (KeywordVirtualFound) return LT_VirtualFunctionDecl; if (ImportStatement) return LT_ImportStatement; if (Line.startsWith(TT_ObjCMethodSpecifier)) { if (Contexts.back().FirstObjCSelectorName) Contexts.back().FirstObjCSelectorName->LongestObjCSelectorName = Contexts.back().LongestObjCSelectorName; return LT_ObjCMethodDecl; } return LT_Other; } private: bool isClosureImportStatement(const FormatToken &Tok) { // FIXME: Closure-library specific stuff should not be hard-coded but be // configurable. return Tok.TokenText == "goog" && Tok.Next && Tok.Next->is(tok::period) && Tok.Next->Next && (Tok.Next->Next->TokenText == "module" || Tok.Next->Next->TokenText == "provide" || Tok.Next->Next->TokenText == "require" || Tok.Next->Next->TokenText == "requireType" || Tok.Next->Next->TokenText == "forwardDeclare") && Tok.Next->Next->Next && Tok.Next->Next->Next->is(tok::l_paren); } void resetTokenMetadata(FormatToken *Token) { if (!Token) return; // Reset token type in case we have already looked at it and then // recovered from an error (e.g. failure to find the matching >). if (!CurrentToken->isOneOf( TT_LambdaLSquare, TT_LambdaLBrace, TT_ForEachMacro, TT_TypenameMacro, TT_FunctionLBrace, TT_ImplicitStringLiteral, TT_InlineASMBrace, TT_JsFatArrow, TT_LambdaArrow, TT_NamespaceMacro, TT_OverloadedOperator, TT_RegexLiteral, TT_TemplateString, TT_ObjCStringLiteral)) CurrentToken->Type = TT_Unknown; CurrentToken->Role.reset(); CurrentToken->MatchingParen = nullptr; CurrentToken->FakeLParens.clear(); CurrentToken->FakeRParens = 0; } void next() { if (CurrentToken) { CurrentToken->NestingLevel = Contexts.size() - 1; CurrentToken->BindingStrength = Contexts.back().BindingStrength; modifyContext(*CurrentToken); determineTokenType(*CurrentToken); CurrentToken = CurrentToken->Next; } resetTokenMetadata(CurrentToken); } /// A struct to hold information valid in a specific context, e.g. /// a pair of parenthesis. struct Context { Context(tok::TokenKind ContextKind, unsigned BindingStrength, bool IsExpression) : ContextKind(ContextKind), BindingStrength(BindingStrength), IsExpression(IsExpression) {} tok::TokenKind ContextKind; unsigned BindingStrength; bool IsExpression; unsigned LongestObjCSelectorName = 0; bool ColonIsForRangeExpr = false; bool ColonIsDictLiteral = false; bool ColonIsObjCMethodExpr = false; FormatToken *FirstObjCSelectorName = nullptr; FormatToken *FirstStartOfName = nullptr; bool CanBeExpression = true; bool InTemplateArgument = false; bool InCtorInitializer = false; bool InInheritanceList = false; bool CaretFound = false; bool IsForEachMacro = false; bool InCpp11AttributeSpecifier = false; bool InCSharpAttributeSpecifier = false; }; /// Puts a new \c Context onto the stack \c Contexts for the lifetime /// of each instance. struct ScopedContextCreator { AnnotatingParser &P; ScopedContextCreator(AnnotatingParser &P, tok::TokenKind ContextKind, unsigned Increase) : P(P) { P.Contexts.push_back(Context(ContextKind, P.Contexts.back().BindingStrength + Increase, P.Contexts.back().IsExpression)); } ~ScopedContextCreator() { P.Contexts.pop_back(); } }; void modifyContext(const FormatToken &Current) { if (Current.getPrecedence() == prec::Assignment && !Line.First->isOneOf(tok::kw_template, tok::kw_using, tok::kw_return) && // Type aliases use `type X = ...;` in TypeScript and can be exported // using `export type ...`. !(Style.Language == FormatStyle::LK_JavaScript && (Line.startsWith(Keywords.kw_type, tok::identifier) || Line.startsWith(tok::kw_export, Keywords.kw_type, tok::identifier))) && (!Current.Previous || Current.Previous->isNot(tok::kw_operator))) { Contexts.back().IsExpression = true; if (!Line.startsWith(TT_UnaryOperator)) { for (FormatToken *Previous = Current.Previous; Previous && Previous->Previous && !Previous->Previous->isOneOf(tok::comma, tok::semi); Previous = Previous->Previous) { if (Previous->isOneOf(tok::r_square, tok::r_paren)) { Previous = Previous->MatchingParen; if (!Previous) break; } if (Previous->opensScope()) break; if (Previous->isOneOf(TT_BinaryOperator, TT_UnaryOperator) && Previous->isOneOf(tok::star, tok::amp, tok::ampamp) && Previous->Previous && Previous->Previous->isNot(tok::equal)) Previous->Type = TT_PointerOrReference; } } } else if (Current.is(tok::lessless) && (!Current.Previous || !Current.Previous->is(tok::kw_operator))) { Contexts.back().IsExpression = true; } else if (Current.isOneOf(tok::kw_return, tok::kw_throw)) { Contexts.back().IsExpression = true; } else if (Current.is(TT_TrailingReturnArrow)) { Contexts.back().IsExpression = false; } else if (Current.is(TT_LambdaArrow) || Current.is(Keywords.kw_assert)) { Contexts.back().IsExpression = Style.Language == FormatStyle::LK_Java; } else if (Current.Previous && Current.Previous->is(TT_CtorInitializerColon)) { Contexts.back().IsExpression = true; Contexts.back().InCtorInitializer = true; } else if (Current.Previous && Current.Previous->is(TT_InheritanceColon)) { Contexts.back().InInheritanceList = true; } else if (Current.isOneOf(tok::r_paren, tok::greater, tok::comma)) { for (FormatToken *Previous = Current.Previous; Previous && Previous->isOneOf(tok::star, tok::amp); Previous = Previous->Previous) Previous->Type = TT_PointerOrReference; if (Line.MustBeDeclaration && !Contexts.front().InCtorInitializer) Contexts.back().IsExpression = false; } else if (Current.is(tok::kw_new)) { Contexts.back().CanBeExpression = false; } else if (Current.is(tok::semi) || (Current.is(tok::exclaim) && Current.Previous && !Current.Previous->is(tok::kw_operator))) { // This should be the condition or increment in a for-loop. // But not operator !() (can't use TT_OverloadedOperator here as its not // been annotated yet). Contexts.back().IsExpression = true; } } static FormatToken *untilMatchingParen(FormatToken *Current) { // Used when `MatchingParen` is not yet established. int ParenLevel = 0; while (Current) { if (Current->is(tok::l_paren)) ParenLevel++; if (Current->is(tok::r_paren)) ParenLevel--; if (ParenLevel < 1) break; Current = Current->Next; } return Current; } static bool isDeductionGuide(FormatToken &Current) { // Look for a deduction guide template A(...) -> A<...>; if (Current.Previous && Current.Previous->is(tok::r_paren) && Current.startsSequence(tok::arrow, tok::identifier, tok::less)) { // Find the TemplateCloser. FormatToken *TemplateCloser = Current.Next->Next; int NestingLevel = 0; while (TemplateCloser) { // Skip over an expressions in parens A<(3 < 2)>; if (TemplateCloser->is(tok::l_paren)) { // No Matching Paren yet so skip to matching paren TemplateCloser = untilMatchingParen(TemplateCloser); } if (TemplateCloser->is(tok::less)) NestingLevel++; if (TemplateCloser->is(tok::greater)) NestingLevel--; if (NestingLevel < 1) break; TemplateCloser = TemplateCloser->Next; } // Assuming we have found the end of the template ensure its followed // with a semi-colon. if (TemplateCloser && TemplateCloser->Next && TemplateCloser->Next->is(tok::semi) && Current.Previous->MatchingParen) { // Determine if the identifier `A` prior to the A<..>; is the same as // prior to the A(..) FormatToken *LeadingIdentifier = Current.Previous->MatchingParen->Previous; // Differentiate a deduction guide by seeing the // > of the template prior to the leading identifier. if (LeadingIdentifier) { FormatToken *PriorLeadingIdentifier = LeadingIdentifier->Previous; // Skip back past explicit decoration if (PriorLeadingIdentifier && PriorLeadingIdentifier->is(tok::kw_explicit)) PriorLeadingIdentifier = PriorLeadingIdentifier->Previous; return (PriorLeadingIdentifier && PriorLeadingIdentifier->is(TT_TemplateCloser) && LeadingIdentifier->TokenText == Current.Next->TokenText); } } } return false; } void determineTokenType(FormatToken &Current) { if (!Current.is(TT_Unknown)) // The token type is already known. return; if (Style.Language == FormatStyle::LK_JavaScript) { if (Current.is(tok::exclaim)) { if (Current.Previous && (Current.Previous->isOneOf(tok::identifier, tok::kw_namespace, tok::r_paren, tok::r_square, tok::r_brace) || Current.Previous->Tok.isLiteral())) { Current.Type = TT_JsNonNullAssertion; return; } if (Current.Next && Current.Next->isOneOf(TT_BinaryOperator, Keywords.kw_as)) { Current.Type = TT_JsNonNullAssertion; return; } } } // Line.MightBeFunctionDecl can only be true after the parentheses of a // function declaration have been found. In this case, 'Current' is a // trailing token of this declaration and thus cannot be a name. if (Current.is(Keywords.kw_instanceof)) { Current.Type = TT_BinaryOperator; } else if (isStartOfName(Current) && (!Line.MightBeFunctionDecl || Current.NestingLevel != 0)) { Contexts.back().FirstStartOfName = &Current; Current.Type = TT_StartOfName; } else if (Current.is(tok::semi)) { // Reset FirstStartOfName after finding a semicolon so that a for loop // with multiple increment statements is not confused with a for loop // having multiple variable declarations. Contexts.back().FirstStartOfName = nullptr; } else if (Current.isOneOf(tok::kw_auto, tok::kw___auto_type)) { AutoFound = true; } else if (Current.is(tok::arrow) && Style.Language == FormatStyle::LK_Java) { Current.Type = TT_LambdaArrow; } else if (Current.is(tok::arrow) && AutoFound && Line.MustBeDeclaration && Current.NestingLevel == 0 && !Current.Previous->is(tok::kw_operator)) { // not auto operator->() -> xxx; Current.Type = TT_TrailingReturnArrow; } else if (isDeductionGuide(Current)) { // Deduction guides trailing arrow " A(...) -> A;". Current.Type = TT_TrailingReturnArrow; } else if (Current.isOneOf(tok::star, tok::amp, tok::ampamp)) { Current.Type = determineStarAmpUsage(Current, Contexts.back().CanBeExpression && Contexts.back().IsExpression, Contexts.back().InTemplateArgument); } else if (Current.isOneOf(tok::minus, tok::plus, tok::caret)) { Current.Type = determinePlusMinusCaretUsage(Current); if (Current.is(TT_UnaryOperator) && Current.is(tok::caret)) Contexts.back().CaretFound = true; } else if (Current.isOneOf(tok::minusminus, tok::plusplus)) { Current.Type = determineIncrementUsage(Current); } else if (Current.isOneOf(tok::exclaim, tok::tilde)) { Current.Type = TT_UnaryOperator; } else if (Current.is(tok::question)) { if (Style.Language == FormatStyle::LK_JavaScript && Line.MustBeDeclaration && !Contexts.back().IsExpression) { // In JavaScript, `interface X { foo?(): bar; }` is an optional method // on the interface, not a ternary expression. Current.Type = TT_JsTypeOptionalQuestion; } else { Current.Type = TT_ConditionalExpr; } } else if (Current.isBinaryOperator() && (!Current.Previous || Current.Previous->isNot(tok::l_square)) && (!Current.is(tok::greater) && Style.Language != FormatStyle::LK_TextProto)) { Current.Type = TT_BinaryOperator; } else if (Current.is(tok::comment)) { if (Current.TokenText.startswith("/*")) { if (Current.TokenText.endswith("*/")) Current.Type = TT_BlockComment; else // The lexer has for some reason determined a comment here. But we // cannot really handle it, if it isn't properly terminated. Current.Tok.setKind(tok::unknown); } else { Current.Type = TT_LineComment; } } else if (Current.is(tok::r_paren)) { if (rParenEndsCast(Current)) Current.Type = TT_CastRParen; if (Current.MatchingParen && Current.Next && !Current.Next->isBinaryOperator() && !Current.Next->isOneOf(tok::semi, tok::colon, tok::l_brace, tok::comma, tok::period, tok::arrow, tok::coloncolon)) if (FormatToken *AfterParen = Current.MatchingParen->Next) { // Make sure this isn't the return type of an Obj-C block declaration if (AfterParen->Tok.isNot(tok::caret)) { if (FormatToken *BeforeParen = Current.MatchingParen->Previous) if (BeforeParen->is(tok::identifier) && !BeforeParen->is(TT_TypenameMacro) && BeforeParen->TokenText == BeforeParen->TokenText.upper() && (!BeforeParen->Previous || BeforeParen->Previous->ClosesTemplateDeclaration)) Current.Type = TT_FunctionAnnotationRParen; } } } else if (Current.is(tok::at) && Current.Next && Style.Language != FormatStyle::LK_JavaScript && Style.Language != FormatStyle::LK_Java) { // In Java & JavaScript, "@..." is a decorator or annotation. In ObjC, it // marks declarations and properties that need special formatting. switch (Current.Next->Tok.getObjCKeywordID()) { case tok::objc_interface: case tok::objc_implementation: case tok::objc_protocol: Current.Type = TT_ObjCDecl; break; case tok::objc_property: Current.Type = TT_ObjCProperty; break; default: break; } } else if (Current.is(tok::period)) { FormatToken *PreviousNoComment = Current.getPreviousNonComment(); if (PreviousNoComment && PreviousNoComment->isOneOf(tok::comma, tok::l_brace)) Current.Type = TT_DesignatedInitializerPeriod; else if (Style.Language == FormatStyle::LK_Java && Current.Previous && Current.Previous->isOneOf(TT_JavaAnnotation, TT_LeadingJavaAnnotation)) { Current.Type = Current.Previous->Type; } } else if (canBeObjCSelectorComponent(Current) && // FIXME(bug 36976): ObjC return types shouldn't use // TT_CastRParen. Current.Previous && Current.Previous->is(TT_CastRParen) && Current.Previous->MatchingParen && Current.Previous->MatchingParen->Previous && Current.Previous->MatchingParen->Previous->is( TT_ObjCMethodSpecifier)) { // This is the first part of an Objective-C selector name. (If there's no // colon after this, this is the only place which annotates the identifier // as a selector.) Current.Type = TT_SelectorName; } else if (Current.isOneOf(tok::identifier, tok::kw_const, tok::kw_noexcept) && Current.Previous && !Current.Previous->isOneOf(tok::equal, tok::at) && Line.MightBeFunctionDecl && Contexts.size() == 1) { // Line.MightBeFunctionDecl can only be true after the parentheses of a // function declaration have been found. Current.Type = TT_TrailingAnnotation; } else if ((Style.Language == FormatStyle::LK_Java || Style.Language == FormatStyle::LK_JavaScript) && Current.Previous) { if (Current.Previous->is(tok::at) && Current.isNot(Keywords.kw_interface)) { const FormatToken &AtToken = *Current.Previous; const FormatToken *Previous = AtToken.getPreviousNonComment(); if (!Previous || Previous->is(TT_LeadingJavaAnnotation)) Current.Type = TT_LeadingJavaAnnotation; else Current.Type = TT_JavaAnnotation; } else if (Current.Previous->is(tok::period) && Current.Previous->isOneOf(TT_JavaAnnotation, TT_LeadingJavaAnnotation)) { Current.Type = Current.Previous->Type; } } } /// Take a guess at whether \p Tok starts a name of a function or /// variable declaration. /// /// This is a heuristic based on whether \p Tok is an identifier following /// something that is likely a type. bool isStartOfName(const FormatToken &Tok) { if (Tok.isNot(tok::identifier) || !Tok.Previous) return false; if (Tok.Previous->isOneOf(TT_LeadingJavaAnnotation, Keywords.kw_instanceof, Keywords.kw_as)) return false; if (Style.Language == FormatStyle::LK_JavaScript && Tok.Previous->is(Keywords.kw_in)) return false; // Skip "const" as it does not have an influence on whether this is a name. FormatToken *PreviousNotConst = Tok.getPreviousNonComment(); while (PreviousNotConst && PreviousNotConst->is(tok::kw_const)) PreviousNotConst = PreviousNotConst->getPreviousNonComment(); if (!PreviousNotConst) return false; bool IsPPKeyword = PreviousNotConst->is(tok::identifier) && PreviousNotConst->Previous && PreviousNotConst->Previous->is(tok::hash); if (PreviousNotConst->is(TT_TemplateCloser)) return PreviousNotConst && PreviousNotConst->MatchingParen && PreviousNotConst->MatchingParen->Previous && PreviousNotConst->MatchingParen->Previous->isNot(tok::period) && PreviousNotConst->MatchingParen->Previous->isNot(tok::kw_template); if (PreviousNotConst->is(tok::r_paren) && PreviousNotConst->MatchingParen && PreviousNotConst->MatchingParen->Previous && PreviousNotConst->MatchingParen->Previous->is(tok::kw_decltype)) return true; return (!IsPPKeyword && PreviousNotConst->isOneOf(tok::identifier, tok::kw_auto)) || PreviousNotConst->is(TT_PointerOrReference) || PreviousNotConst->isSimpleTypeSpecifier(); } /// Determine whether ')' is ending a cast. bool rParenEndsCast(const FormatToken &Tok) { // C-style casts are only used in C++ and Java. if (!Style.isCpp() && Style.Language != FormatStyle::LK_Java) return false; // Empty parens aren't casts and there are no casts at the end of the line. if (Tok.Previous == Tok.MatchingParen || !Tok.Next || !Tok.MatchingParen) return false; FormatToken *LeftOfParens = Tok.MatchingParen->getPreviousNonComment(); if (LeftOfParens) { // If there is a closing parenthesis left of the current parentheses, // look past it as these might be chained casts. if (LeftOfParens->is(tok::r_paren)) { if (!LeftOfParens->MatchingParen || !LeftOfParens->MatchingParen->Previous) return false; LeftOfParens = LeftOfParens->MatchingParen->Previous; } // If there is an identifier (or with a few exceptions a keyword) right // before the parentheses, this is unlikely to be a cast. if (LeftOfParens->Tok.getIdentifierInfo() && !LeftOfParens->isOneOf(Keywords.kw_in, tok::kw_return, tok::kw_case, tok::kw_delete)) return false; // Certain other tokens right before the parentheses are also signals that // this cannot be a cast. if (LeftOfParens->isOneOf(tok::at, tok::r_square, TT_OverloadedOperator, TT_TemplateCloser, tok::ellipsis)) return false; } if (Tok.Next->is(tok::question)) return false; // Functions which end with decorations like volatile, noexcept are unlikely // to be casts. if (Tok.Next->isOneOf(tok::kw_noexcept, tok::kw_volatile, tok::kw_const, tok::kw_throw, tok::arrow, Keywords.kw_override, Keywords.kw_final) || isCpp11AttributeSpecifier(*Tok.Next)) return false; // As Java has no function types, a "(" after the ")" likely means that this // is a cast. if (Style.Language == FormatStyle::LK_Java && Tok.Next->is(tok::l_paren)) return true; // If a (non-string) literal follows, this is likely a cast. if (Tok.Next->isNot(tok::string_literal) && (Tok.Next->Tok.isLiteral() || Tok.Next->isOneOf(tok::kw_sizeof, tok::kw_alignof))) return true; // Heuristically try to determine whether the parentheses contain a type. bool ParensAreType = !Tok.Previous || Tok.Previous->isOneOf(TT_PointerOrReference, TT_TemplateCloser) || Tok.Previous->isSimpleTypeSpecifier(); bool ParensCouldEndDecl = Tok.Next->isOneOf(tok::equal, tok::semi, tok::l_brace, tok::greater); if (ParensAreType && !ParensCouldEndDecl) return true; // At this point, we heuristically assume that there are no casts at the // start of the line. We assume that we have found most cases where there // are by the logic above, e.g. "(void)x;". if (!LeftOfParens) return false; // Certain token types inside the parentheses mean that this can't be a // cast. for (const FormatToken *Token = Tok.MatchingParen->Next; Token != &Tok; Token = Token->Next) if (Token->is(TT_BinaryOperator)) return false; // If the following token is an identifier or 'this', this is a cast. All // cases where this can be something else are handled above. if (Tok.Next->isOneOf(tok::identifier, tok::kw_this)) return true; if (!Tok.Next->Next) return false; // If the next token after the parenthesis is a unary operator, assume // that this is cast, unless there are unexpected tokens inside the // parenthesis. bool NextIsUnary = Tok.Next->isUnaryOperator() || Tok.Next->isOneOf(tok::amp, tok::star); if (!NextIsUnary || Tok.Next->is(tok::plus) || !Tok.Next->Next->isOneOf(tok::identifier, tok::numeric_constant)) return false; // Search for unexpected tokens. for (FormatToken *Prev = Tok.Previous; Prev != Tok.MatchingParen; Prev = Prev->Previous) { if (!Prev->isOneOf(tok::kw_const, tok::identifier, tok::coloncolon)) return false; } return true; } /// Return the type of the given token assuming it is * or &. TokenType determineStarAmpUsage(const FormatToken &Tok, bool IsExpression, bool InTemplateArgument) { if (Style.Language == FormatStyle::LK_JavaScript) return TT_BinaryOperator; const FormatToken *PrevToken = Tok.getPreviousNonComment(); if (!PrevToken) return TT_UnaryOperator; const FormatToken *NextToken = Tok.getNextNonComment(); if (!NextToken || NextToken->isOneOf(tok::arrow, tok::equal, tok::kw_const, tok::kw_noexcept) || (NextToken->is(tok::l_brace) && !NextToken->getNextNonComment())) return TT_PointerOrReference; if (PrevToken->is(tok::coloncolon)) return TT_PointerOrReference; if (PrevToken->isOneOf(tok::l_paren, tok::l_square, tok::l_brace, tok::comma, tok::semi, tok::kw_return, tok::colon, tok::equal, tok::kw_delete, tok::kw_sizeof, tok::kw_throw) || PrevToken->isOneOf(TT_BinaryOperator, TT_ConditionalExpr, TT_UnaryOperator, TT_CastRParen)) return TT_UnaryOperator; if (NextToken->is(tok::l_square) && NextToken->isNot(TT_LambdaLSquare)) return TT_PointerOrReference; if (NextToken->is(tok::kw_operator) && !IsExpression) return TT_PointerOrReference; if (NextToken->isOneOf(tok::comma, tok::semi)) return TT_PointerOrReference; if (PrevToken->is(tok::r_paren) && PrevToken->MatchingParen) { FormatToken *TokenBeforeMatchingParen = PrevToken->MatchingParen->getPreviousNonComment(); if (TokenBeforeMatchingParen && TokenBeforeMatchingParen->isOneOf(tok::kw_typeof, tok::kw_decltype, TT_TypenameMacro)) return TT_PointerOrReference; } if (PrevToken->Tok.isLiteral() || PrevToken->isOneOf(tok::r_paren, tok::r_square, tok::kw_true, tok::kw_false, tok::r_brace) || NextToken->Tok.isLiteral() || NextToken->isOneOf(tok::kw_true, tok::kw_false) || NextToken->isUnaryOperator() || // If we know we're in a template argument, there are no named // declarations. Thus, having an identifier on the right-hand side // indicates a binary operator. (InTemplateArgument && NextToken->Tok.isAnyIdentifier())) return TT_BinaryOperator; // "&&(" is quite unlikely to be two successive unary "&". if (Tok.is(tok::ampamp) && NextToken && NextToken->is(tok::l_paren)) return TT_BinaryOperator; // This catches some cases where evaluation order is used as control flow: // aaa && aaa->f(); const FormatToken *NextNextToken = NextToken->getNextNonComment(); if (NextNextToken && NextNextToken->is(tok::arrow)) return TT_BinaryOperator; // It is very unlikely that we are going to find a pointer or reference type // definition on the RHS of an assignment. if (IsExpression && !Contexts.back().CaretFound) return TT_BinaryOperator; return TT_PointerOrReference; } TokenType determinePlusMinusCaretUsage(const FormatToken &Tok) { const FormatToken *PrevToken = Tok.getPreviousNonComment(); if (!PrevToken) return TT_UnaryOperator; if (PrevToken->isOneOf(TT_CastRParen, TT_UnaryOperator)) // This must be a sequence of leading unary operators. return TT_UnaryOperator; // Use heuristics to recognize unary operators. if (PrevToken->isOneOf(tok::equal, tok::l_paren, tok::comma, tok::l_square, tok::question, tok::colon, tok::kw_return, tok::kw_case, tok::at, tok::l_brace, tok::kw_throw, tok::kw_co_return, tok::kw_co_yield)) return TT_UnaryOperator; // There can't be two consecutive binary operators. if (PrevToken->is(TT_BinaryOperator)) return TT_UnaryOperator; // Fall back to marking the token as binary operator. return TT_BinaryOperator; } /// Determine whether ++/-- are pre- or post-increments/-decrements. TokenType determineIncrementUsage(const FormatToken &Tok) { const FormatToken *PrevToken = Tok.getPreviousNonComment(); if (!PrevToken || PrevToken->is(TT_CastRParen)) return TT_UnaryOperator; if (PrevToken->isOneOf(tok::r_paren, tok::r_square, tok::identifier)) return TT_TrailingUnaryOperator; return TT_UnaryOperator; } SmallVector Contexts; const FormatStyle &Style; AnnotatedLine &Line; FormatToken *CurrentToken; bool AutoFound; const AdditionalKeywords &Keywords; // Set of "<" tokens that do not open a template parameter list. If parseAngle // determines that a specific token can't be a template opener, it will make // same decision irrespective of the decisions for tokens leading up to it. // Store this information to prevent this from causing exponential runtime. llvm::SmallPtrSet NonTemplateLess; }; static const int PrecedenceUnaryOperator = prec::PointerToMember + 1; static const int PrecedenceArrowAndPeriod = prec::PointerToMember + 2; /// Parses binary expressions by inserting fake parenthesis based on /// operator precedence. class ExpressionParser { public: ExpressionParser(const FormatStyle &Style, const AdditionalKeywords &Keywords, AnnotatedLine &Line) : Style(Style), Keywords(Keywords), Current(Line.First) {} /// Parse expressions with the given operator precedence. void parse(int Precedence = 0) { // Skip 'return' and ObjC selector colons as they are not part of a binary // expression. while (Current && (Current->is(tok::kw_return) || (Current->is(tok::colon) && Current->isOneOf(TT_ObjCMethodExpr, TT_DictLiteral)))) next(); if (!Current || Precedence > PrecedenceArrowAndPeriod) return; // Conditional expressions need to be parsed separately for proper nesting. if (Precedence == prec::Conditional) { parseConditionalExpr(); return; } // Parse unary operators, which all have a higher precedence than binary // operators. if (Precedence == PrecedenceUnaryOperator) { parseUnaryOperator(); return; } FormatToken *Start = Current; FormatToken *LatestOperator = nullptr; unsigned OperatorIndex = 0; while (Current) { // Consume operators with higher precedence. parse(Precedence + 1); int CurrentPrecedence = getCurrentPrecedence(); if (Current && Current->is(TT_SelectorName) && Precedence == CurrentPrecedence) { if (LatestOperator) addFakeParenthesis(Start, prec::Level(Precedence)); Start = Current; } // At the end of the line or when an operator with higher precedence is // found, insert fake parenthesis and return. if (!Current || (Current->closesScope() && (Current->MatchingParen || Current->is(TT_TemplateString))) || (CurrentPrecedence != -1 && CurrentPrecedence < Precedence) || (CurrentPrecedence == prec::Conditional && Precedence == prec::Assignment && Current->is(tok::colon))) { break; } // Consume scopes: (), [], <> and {} if (Current->opensScope()) { // In fragment of a JavaScript template string can look like '}..${' and // thus close a scope and open a new one at the same time. while (Current && (!Current->closesScope() || Current->opensScope())) { next(); parse(); } next(); } else { // Operator found. if (CurrentPrecedence == Precedence) { if (LatestOperator) LatestOperator->NextOperator = Current; LatestOperator = Current; Current->OperatorIndex = OperatorIndex; ++OperatorIndex; } next(/*SkipPastLeadingComments=*/Precedence > 0); } } if (LatestOperator && (Current || Precedence > 0)) { // LatestOperator->LastOperator = true; if (Precedence == PrecedenceArrowAndPeriod) { // Call expressions don't have a binary operator precedence. addFakeParenthesis(Start, prec::Unknown); } else { addFakeParenthesis(Start, prec::Level(Precedence)); } } } private: /// Gets the precedence (+1) of the given token for binary operators /// and other tokens that we treat like binary operators. int getCurrentPrecedence() { if (Current) { const FormatToken *NextNonComment = Current->getNextNonComment(); if (Current->is(TT_ConditionalExpr)) return prec::Conditional; if (NextNonComment && Current->is(TT_SelectorName) && (NextNonComment->isOneOf(TT_DictLiteral, TT_JsTypeColon) || ((Style.Language == FormatStyle::LK_Proto || Style.Language == FormatStyle::LK_TextProto) && NextNonComment->is(tok::less)))) return prec::Assignment; if (Current->is(TT_JsComputedPropertyName)) return prec::Assignment; if (Current->is(TT_LambdaArrow)) return prec::Comma; if (Current->is(TT_JsFatArrow)) return prec::Assignment; if (Current->isOneOf(tok::semi, TT_InlineASMColon, TT_SelectorName) || (Current->is(tok::comment) && NextNonComment && NextNonComment->is(TT_SelectorName))) return 0; if (Current->is(TT_RangeBasedForLoopColon)) return prec::Comma; if ((Style.Language == FormatStyle::LK_Java || Style.Language == FormatStyle::LK_JavaScript) && Current->is(Keywords.kw_instanceof)) return prec::Relational; if (Style.Language == FormatStyle::LK_JavaScript && Current->isOneOf(Keywords.kw_in, Keywords.kw_as)) return prec::Relational; if (Current->is(TT_BinaryOperator) || Current->is(tok::comma)) return Current->getPrecedence(); if (Current->isOneOf(tok::period, tok::arrow)) return PrecedenceArrowAndPeriod; if ((Style.Language == FormatStyle::LK_Java || Style.Language == FormatStyle::LK_JavaScript) && Current->isOneOf(Keywords.kw_extends, Keywords.kw_implements, Keywords.kw_throws)) return 0; } return -1; } void addFakeParenthesis(FormatToken *Start, prec::Level Precedence) { Start->FakeLParens.push_back(Precedence); if (Precedence > prec::Unknown) Start->StartsBinaryExpression = true; if (Current) { FormatToken *Previous = Current->Previous; while (Previous->is(tok::comment) && Previous->Previous) Previous = Previous->Previous; ++Previous->FakeRParens; if (Precedence > prec::Unknown) Previous->EndsBinaryExpression = true; } } /// Parse unary operator expressions and surround them with fake /// parentheses if appropriate. void parseUnaryOperator() { llvm::SmallVector Tokens; while (Current && Current->is(TT_UnaryOperator)) { Tokens.push_back(Current); next(); } parse(PrecedenceArrowAndPeriod); for (FormatToken *Token : llvm::reverse(Tokens)) // The actual precedence doesn't matter. addFakeParenthesis(Token, prec::Unknown); } void parseConditionalExpr() { while (Current && Current->isTrailingComment()) { next(); } FormatToken *Start = Current; parse(prec::LogicalOr); if (!Current || !Current->is(tok::question)) return; next(); parse(prec::Assignment); if (!Current || Current->isNot(TT_ConditionalExpr)) return; next(); parse(prec::Assignment); addFakeParenthesis(Start, prec::Conditional); } void next(bool SkipPastLeadingComments = true) { if (Current) Current = Current->Next; while (Current && (Current->NewlinesBefore == 0 || SkipPastLeadingComments) && Current->isTrailingComment()) Current = Current->Next; } const FormatStyle &Style; const AdditionalKeywords &Keywords; FormatToken *Current; }; } // end anonymous namespace void TokenAnnotator::setCommentLineLevels( SmallVectorImpl &Lines) { const AnnotatedLine *NextNonCommentLine = nullptr; for (SmallVectorImpl::reverse_iterator I = Lines.rbegin(), E = Lines.rend(); I != E; ++I) { bool CommentLine = true; for (const FormatToken *Tok = (*I)->First; Tok; Tok = Tok->Next) { if (!Tok->is(tok::comment)) { CommentLine = false; break; } } // If the comment is currently aligned with the line immediately following // it, that's probably intentional and we should keep it. if (NextNonCommentLine && CommentLine && NextNonCommentLine->First->NewlinesBefore <= 1 && NextNonCommentLine->First->OriginalColumn == (*I)->First->OriginalColumn) { // Align comments for preprocessor lines with the # in column 0 if // preprocessor lines are not indented. Otherwise, align with the next // line. (*I)->Level = (Style.IndentPPDirectives != FormatStyle::PPDIS_BeforeHash && (NextNonCommentLine->Type == LT_PreprocessorDirective || NextNonCommentLine->Type == LT_ImportStatement)) ? 0 : NextNonCommentLine->Level; } else { NextNonCommentLine = (*I)->First->isNot(tok::r_brace) ? (*I) : nullptr; } setCommentLineLevels((*I)->Children); } } static unsigned maxNestingDepth(const AnnotatedLine &Line) { unsigned Result = 0; for (const auto *Tok = Line.First; Tok != nullptr; Tok = Tok->Next) Result = std::max(Result, Tok->NestingLevel); return Result; } void TokenAnnotator::annotate(AnnotatedLine &Line) { for (SmallVectorImpl::iterator I = Line.Children.begin(), E = Line.Children.end(); I != E; ++I) { annotate(**I); } AnnotatingParser Parser(Style, Line, Keywords); Line.Type = Parser.parseLine(); // With very deep nesting, ExpressionParser uses lots of stack and the // formatting algorithm is very slow. We're not going to do a good job here // anyway - it's probably generated code being formatted by mistake. // Just skip the whole line. if (maxNestingDepth(Line) > 50) Line.Type = LT_Invalid; if (Line.Type == LT_Invalid) return; ExpressionParser ExprParser(Style, Keywords, Line); ExprParser.parse(); if (Line.startsWith(TT_ObjCMethodSpecifier)) Line.Type = LT_ObjCMethodDecl; else if (Line.startsWith(TT_ObjCDecl)) Line.Type = LT_ObjCDecl; else if (Line.startsWith(TT_ObjCProperty)) Line.Type = LT_ObjCProperty; Line.First->SpacesRequiredBefore = 1; Line.First->CanBreakBefore = Line.First->MustBreakBefore; } // This function heuristically determines whether 'Current' starts the name of a // function declaration. static bool isFunctionDeclarationName(const FormatToken &Current, const AnnotatedLine &Line) { auto skipOperatorName = [](const FormatToken *Next) -> const FormatToken * { for (; Next; Next = Next->Next) { if (Next->is(TT_OverloadedOperatorLParen)) return Next; if (Next->is(TT_OverloadedOperator)) continue; if (Next->isOneOf(tok::kw_new, tok::kw_delete)) { // For 'new[]' and 'delete[]'. if (Next->Next && Next->Next->startsSequence(tok::l_square, tok::r_square)) Next = Next->Next->Next; continue; } if (Next->startsSequence(tok::l_square, tok::r_square)) { // For operator[](). Next = Next->Next; continue; } if ((Next->isSimpleTypeSpecifier() || Next->is(tok::identifier)) && Next->Next && Next->Next->isOneOf(tok::star, tok::amp, tok::ampamp)) { // For operator void*(), operator char*(), operator Foo*(). Next = Next->Next; continue; } break; } return nullptr; }; // Find parentheses of parameter list. const FormatToken *Next = Current.Next; if (Current.is(tok::kw_operator)) { if (Current.Previous && Current.Previous->is(tok::coloncolon)) return false; Next = skipOperatorName(Next); } else { if (!Current.is(TT_StartOfName) || Current.NestingLevel != 0) return false; for (; Next; Next = Next->Next) { if (Next->is(TT_TemplateOpener)) { Next = Next->MatchingParen; } else if (Next->is(tok::coloncolon)) { Next = Next->Next; if (!Next) return false; if (Next->is(tok::kw_operator)) { Next = skipOperatorName(Next->Next); break; } if (!Next->is(tok::identifier)) return false; } else if (Next->is(tok::l_paren)) { break; } else { return false; } } } // Check whether parameter list can belong to a function declaration. if (!Next || !Next->is(tok::l_paren) || !Next->MatchingParen) return false; // If the lines ends with "{", this is likely an function definition. if (Line.Last->is(tok::l_brace)) return true; if (Next->Next == Next->MatchingParen) return true; // Empty parentheses. // If there is an &/&& after the r_paren, this is likely a function. if (Next->MatchingParen->Next && Next->MatchingParen->Next->is(TT_PointerOrReference)) return true; for (const FormatToken *Tok = Next->Next; Tok && Tok != Next->MatchingParen; Tok = Tok->Next) { if (Tok->isOneOf(tok::l_paren, TT_TemplateOpener) && Tok->MatchingParen) { Tok = Tok->MatchingParen; continue; } if (Tok->is(tok::kw_const) || Tok->isSimpleTypeSpecifier() || Tok->isOneOf(TT_PointerOrReference, TT_StartOfName, tok::ellipsis)) return true; if (Tok->isOneOf(tok::l_brace, tok::string_literal, TT_ObjCMethodExpr) || Tok->Tok.isLiteral()) return false; } return false; } bool TokenAnnotator::mustBreakForReturnType(const AnnotatedLine &Line) const { assert(Line.MightBeFunctionDecl); if ((Style.AlwaysBreakAfterReturnType == FormatStyle::RTBS_TopLevel || Style.AlwaysBreakAfterReturnType == FormatStyle::RTBS_TopLevelDefinitions) && Line.Level > 0) return false; switch (Style.AlwaysBreakAfterReturnType) { case FormatStyle::RTBS_None: return false; case FormatStyle::RTBS_All: case FormatStyle::RTBS_TopLevel: return true; case FormatStyle::RTBS_AllDefinitions: case FormatStyle::RTBS_TopLevelDefinitions: return Line.mightBeFunctionDefinition(); } return false; } void TokenAnnotator::calculateFormattingInformation(AnnotatedLine &Line) { for (SmallVectorImpl::iterator I = Line.Children.begin(), E = Line.Children.end(); I != E; ++I) { calculateFormattingInformation(**I); } Line.First->TotalLength = Line.First->IsMultiline ? Style.ColumnLimit : Line.FirstStartColumn + Line.First->ColumnWidth; FormatToken *Current = Line.First->Next; bool InFunctionDecl = Line.MightBeFunctionDecl; while (Current) { if (isFunctionDeclarationName(*Current, Line)) Current->Type = TT_FunctionDeclarationName; if (Current->is(TT_LineComment)) { if (Current->Previous->BlockKind == BK_BracedInit && Current->Previous->opensScope()) Current->SpacesRequiredBefore = (Style.Cpp11BracedListStyle && !Style.SpacesInParentheses) ? 0 : 1; else Current->SpacesRequiredBefore = Style.SpacesBeforeTrailingComments; // If we find a trailing comment, iterate backwards to determine whether // it seems to relate to a specific parameter. If so, break before that // parameter to avoid changing the comment's meaning. E.g. don't move 'b' // to the previous line in: // SomeFunction(a, // b, // comment // c); if (!Current->HasUnescapedNewline) { for (FormatToken *Parameter = Current->Previous; Parameter; Parameter = Parameter->Previous) { if (Parameter->isOneOf(tok::comment, tok::r_brace)) break; if (Parameter->Previous && Parameter->Previous->is(tok::comma)) { if (!Parameter->Previous->is(TT_CtorInitializerComma) && Parameter->HasUnescapedNewline) Parameter->MustBreakBefore = true; break; } } } } else if (Current->SpacesRequiredBefore == 0 && spaceRequiredBefore(Line, *Current)) { Current->SpacesRequiredBefore = 1; } Current->MustBreakBefore = Current->MustBreakBefore || mustBreakBefore(Line, *Current); if (!Current->MustBreakBefore && InFunctionDecl && Current->is(TT_FunctionDeclarationName)) Current->MustBreakBefore = mustBreakForReturnType(Line); Current->CanBreakBefore = Current->MustBreakBefore || canBreakBefore(Line, *Current); unsigned ChildSize = 0; if (Current->Previous->Children.size() == 1) { FormatToken &LastOfChild = *Current->Previous->Children[0]->Last; ChildSize = LastOfChild.isTrailingComment() ? Style.ColumnLimit : LastOfChild.TotalLength + 1; } const FormatToken *Prev = Current->Previous; if (Current->MustBreakBefore || Prev->Children.size() > 1 || (Prev->Children.size() == 1 && Prev->Children[0]->First->MustBreakBefore) || Current->IsMultiline) Current->TotalLength = Prev->TotalLength + Style.ColumnLimit; else Current->TotalLength = Prev->TotalLength + Current->ColumnWidth + ChildSize + Current->SpacesRequiredBefore; if (Current->is(TT_CtorInitializerColon)) InFunctionDecl = false; // FIXME: Only calculate this if CanBreakBefore is true once static // initializers etc. are sorted out. // FIXME: Move magic numbers to a better place. // Reduce penalty for aligning ObjC method arguments using the colon // alignment as this is the canonical way (still prefer fitting everything // into one line if possible). Trying to fit a whole expression into one // line should not force other line breaks (e.g. when ObjC method // expression is a part of other expression). Current->SplitPenalty = splitPenalty(Line, *Current, InFunctionDecl); if (Style.Language == FormatStyle::LK_ObjC && Current->is(TT_SelectorName) && Current->ParameterIndex > 0) { if (Current->ParameterIndex == 1) Current->SplitPenalty += 5 * Current->BindingStrength; } else { Current->SplitPenalty += 20 * Current->BindingStrength; } Current = Current->Next; } calculateUnbreakableTailLengths(Line); unsigned IndentLevel = Line.Level; for (Current = Line.First; Current != nullptr; Current = Current->Next) { if (Current->Role) Current->Role->precomputeFormattingInfos(Current); if (Current->MatchingParen && Current->MatchingParen->opensBlockOrBlockTypeList(Style)) { assert(IndentLevel > 0); --IndentLevel; } Current->IndentLevel = IndentLevel; if (Current->opensBlockOrBlockTypeList(Style)) ++IndentLevel; } LLVM_DEBUG({ printDebugInfo(Line); }); } void TokenAnnotator::calculateUnbreakableTailLengths(AnnotatedLine &Line) { unsigned UnbreakableTailLength = 0; FormatToken *Current = Line.Last; while (Current) { Current->UnbreakableTailLength = UnbreakableTailLength; if (Current->CanBreakBefore || Current->isOneOf(tok::comment, tok::string_literal)) { UnbreakableTailLength = 0; } else { UnbreakableTailLength += Current->ColumnWidth + Current->SpacesRequiredBefore; } Current = Current->Previous; } } unsigned TokenAnnotator::splitPenalty(const AnnotatedLine &Line, const FormatToken &Tok, bool InFunctionDecl) { const FormatToken &Left = *Tok.Previous; const FormatToken &Right = Tok; if (Left.is(tok::semi)) return 0; if (Style.Language == FormatStyle::LK_Java) { if (Right.isOneOf(Keywords.kw_extends, Keywords.kw_throws)) return 1; if (Right.is(Keywords.kw_implements)) return 2; if (Left.is(tok::comma) && Left.NestingLevel == 0) return 3; } else if (Style.Language == FormatStyle::LK_JavaScript) { if (Right.is(Keywords.kw_function) && Left.isNot(tok::comma)) return 100; if (Left.is(TT_JsTypeColon)) return 35; if ((Left.is(TT_TemplateString) && Left.TokenText.endswith("${")) || (Right.is(TT_TemplateString) && Right.TokenText.startswith("}"))) return 100; // Prefer breaking call chains (".foo") over empty "{}", "[]" or "()". if (Left.opensScope() && Right.closesScope()) return 200; } if (Right.is(tok::identifier) && Right.Next && Right.Next->is(TT_DictLiteral)) return 1; if (Right.is(tok::l_square)) { if (Style.Language == FormatStyle::LK_Proto) return 1; if (Left.is(tok::r_square)) return 200; // Slightly prefer formatting local lambda definitions like functions. if (Right.is(TT_LambdaLSquare) && Left.is(tok::equal)) return 35; if (!Right.isOneOf(TT_ObjCMethodExpr, TT_LambdaLSquare, TT_ArrayInitializerLSquare, TT_DesignatedInitializerLSquare, TT_AttributeSquare)) return 500; } if (Left.is(tok::coloncolon) || (Right.is(tok::period) && Style.Language == FormatStyle::LK_Proto)) return 500; if (Right.isOneOf(TT_StartOfName, TT_FunctionDeclarationName) || Right.is(tok::kw_operator)) { if (Line.startsWith(tok::kw_for) && Right.PartOfMultiVariableDeclStmt) return 3; if (Left.is(TT_StartOfName)) return 110; if (InFunctionDecl && Right.NestingLevel == 0) return Style.PenaltyReturnTypeOnItsOwnLine; return 200; } if (Right.is(TT_PointerOrReference)) return 190; if (Right.is(TT_LambdaArrow)) return 110; if (Left.is(tok::equal) && Right.is(tok::l_brace)) return 160; if (Left.is(TT_CastRParen)) return 100; if (Left.isOneOf(tok::kw_class, tok::kw_struct)) return 5000; if (Left.is(tok::comment)) return 1000; if (Left.isOneOf(TT_RangeBasedForLoopColon, TT_InheritanceColon, TT_CtorInitializerColon)) return 2; if (Right.isMemberAccess()) { // Breaking before the "./->" of a chained call/member access is reasonably // cheap, as formatting those with one call per line is generally // desirable. In particular, it should be cheaper to break before the call // than it is to break inside a call's parameters, which could lead to weird // "hanging" indents. The exception is the very last "./->" to support this // frequent pattern: // // aaaaaaaa.aaaaaaaa.bbbbbbb().ccccccccccccccccccccc( // dddddddd); // // which might otherwise be blown up onto many lines. Here, clang-format // won't produce "hanging" indents anyway as there is no other trailing // call. // // Also apply higher penalty is not a call as that might lead to a wrapping // like: // // aaaaaaa // .aaaaaaaaa.bbbbbbbb(cccccccc); return !Right.NextOperator || !Right.NextOperator->Previous->closesScope() ? 150 : 35; } if (Right.is(TT_TrailingAnnotation) && (!Right.Next || Right.Next->isNot(tok::l_paren))) { // Moving trailing annotations to the next line is fine for ObjC method // declarations. if (Line.startsWith(TT_ObjCMethodSpecifier)) return 10; // Generally, breaking before a trailing annotation is bad unless it is // function-like. It seems to be especially preferable to keep standard // annotations (i.e. "const", "final" and "override") on the same line. // Use a slightly higher penalty after ")" so that annotations like // "const override" are kept together. bool is_short_annotation = Right.TokenText.size() < 10; return (Left.is(tok::r_paren) ? 100 : 120) + (is_short_annotation ? 50 : 0); } // In for-loops, prefer breaking at ',' and ';'. if (Line.startsWith(tok::kw_for) && Left.is(tok::equal)) return 4; // In Objective-C method expressions, prefer breaking before "param:" over // breaking after it. if (Right.is(TT_SelectorName)) return 0; if (Left.is(tok::colon) && Left.is(TT_ObjCMethodExpr)) return Line.MightBeFunctionDecl ? 50 : 500; // In Objective-C type declarations, avoid breaking after the category's // open paren (we'll prefer breaking after the protocol list's opening // angle bracket, if present). if (Line.Type == LT_ObjCDecl && Left.is(tok::l_paren) && Left.Previous && Left.Previous->isOneOf(tok::identifier, tok::greater)) return 500; if (Left.is(tok::l_paren) && InFunctionDecl && Style.AlignAfterOpenBracket != FormatStyle::BAS_DontAlign) return 100; if (Left.is(tok::l_paren) && Left.Previous && (Left.Previous->is(tok::kw_for) || Left.Previous->isIf())) return 1000; if (Left.is(tok::equal) && InFunctionDecl) return 110; if (Right.is(tok::r_brace)) return 1; if (Left.is(TT_TemplateOpener)) return 100; if (Left.opensScope()) { if (Style.AlignAfterOpenBracket == FormatStyle::BAS_DontAlign) return 0; if (Left.is(tok::l_brace) && !Style.Cpp11BracedListStyle) return 19; return Left.ParameterCount > 1 ? Style.PenaltyBreakBeforeFirstCallParameter : 19; } if (Left.is(TT_JavaAnnotation)) return 50; if (Left.is(TT_UnaryOperator)) return 60; if (Left.isOneOf(tok::plus, tok::comma) && Left.Previous && Left.Previous->isLabelString() && (Left.NextOperator || Left.OperatorIndex != 0)) return 50; if (Right.is(tok::plus) && Left.isLabelString() && (Right.NextOperator || Right.OperatorIndex != 0)) return 25; if (Left.is(tok::comma)) return 1; if (Right.is(tok::lessless) && Left.isLabelString() && (Right.NextOperator || Right.OperatorIndex != 1)) return 25; if (Right.is(tok::lessless)) { // Breaking at a << is really cheap. if (!Left.is(tok::r_paren) || Right.OperatorIndex > 0) // Slightly prefer to break before the first one in log-like statements. return 2; return 1; } if (Left.ClosesTemplateDeclaration) return Style.PenaltyBreakTemplateDeclaration; if (Left.is(TT_ConditionalExpr)) return prec::Conditional; prec::Level Level = Left.getPrecedence(); if (Level == prec::Unknown) Level = Right.getPrecedence(); if (Level == prec::Assignment) return Style.PenaltyBreakAssignment; if (Level != prec::Unknown) return Level; return 3; } bool TokenAnnotator::spaceRequiredBeforeParens(const FormatToken &Right) const { return Style.SpaceBeforeParens == FormatStyle::SBPO_Always || (Style.SpaceBeforeParens == FormatStyle::SBPO_NonEmptyParentheses && Right.ParameterCount > 0); } /// Returns \c true if the token is followed by a boolean condition, \c false /// otherwise. static bool isKeywordWithCondition(const FormatToken &Tok) { return Tok.isOneOf(tok::kw_if, tok::kw_for, tok::kw_while, tok::kw_switch, tok::kw_constexpr, tok::kw_catch); } bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line, const FormatToken &Left, const FormatToken &Right) { if (Left.is(tok::kw_return) && Right.isNot(tok::semi)) return true; if (Left.is(Keywords.kw_assert) && Style.Language == FormatStyle::LK_Java) return true; if (Style.ObjCSpaceAfterProperty && Line.Type == LT_ObjCProperty && Left.Tok.getObjCKeywordID() == tok::objc_property) return true; if (Right.is(tok::hashhash)) return Left.is(tok::hash); if (Left.isOneOf(tok::hashhash, tok::hash)) return Right.is(tok::hash); if ((Left.is(tok::l_paren) && Right.is(tok::r_paren)) || (Left.is(tok::l_brace) && Left.BlockKind != BK_Block && Right.is(tok::r_brace) && Right.BlockKind != BK_Block)) return Style.SpaceInEmptyParentheses; if (Style.SpacesInConditionalStatement) { if (Left.is(tok::l_paren) && Left.Previous && isKeywordWithCondition(*Left.Previous)) return true; if (Right.is(tok::r_paren) && Right.MatchingParen && Right.MatchingParen->Previous && isKeywordWithCondition(*Right.MatchingParen->Previous)) return true; } if (Left.is(tok::l_paren) || Right.is(tok::r_paren)) return (Right.is(TT_CastRParen) || (Left.MatchingParen && Left.MatchingParen->is(TT_CastRParen))) ? Style.SpacesInCStyleCastParentheses : Style.SpacesInParentheses; if (Right.isOneOf(tok::semi, tok::comma)) return false; if (Right.is(tok::less) && Line.Type == LT_ObjCDecl) { bool IsLightweightGeneric = Right.MatchingParen && Right.MatchingParen->Next && Right.MatchingParen->Next->is(tok::colon); return !IsLightweightGeneric && Style.ObjCSpaceBeforeProtocolList; } if (Right.is(tok::less) && Left.is(tok::kw_template)) return Style.SpaceAfterTemplateKeyword; if (Left.isOneOf(tok::exclaim, tok::tilde)) return false; if (Left.is(tok::at) && Right.isOneOf(tok::identifier, tok::string_literal, tok::char_constant, tok::numeric_constant, tok::l_paren, tok::l_brace, tok::kw_true, tok::kw_false)) return false; if (Left.is(tok::colon)) return !Left.is(TT_ObjCMethodExpr); if (Left.is(tok::coloncolon)) return false; if (Left.is(tok::less) || Right.isOneOf(tok::greater, tok::less)) { if (Style.Language == FormatStyle::LK_TextProto || (Style.Language == FormatStyle::LK_Proto && (Left.is(TT_DictLiteral) || Right.is(TT_DictLiteral)))) { // Format empty list as `<>`. if (Left.is(tok::less) && Right.is(tok::greater)) return false; return !Style.Cpp11BracedListStyle; } return false; } if (Right.is(tok::ellipsis)) return Left.Tok.isLiteral() || (Left.is(tok::identifier) && Left.Previous && Left.Previous->is(tok::kw_case)); if (Left.is(tok::l_square) && Right.is(tok::amp)) return Style.SpacesInSquareBrackets; if (Right.is(TT_PointerOrReference)) { if (Left.is(tok::r_paren) && Line.MightBeFunctionDecl) { if (!Left.MatchingParen) return true; FormatToken *TokenBeforeMatchingParen = Left.MatchingParen->getPreviousNonComment(); if (!TokenBeforeMatchingParen || !TokenBeforeMatchingParen->isOneOf(tok::kw_typeof, tok::kw_decltype, TT_TypenameMacro)) return true; } return (Left.Tok.isLiteral() || (!Left.isOneOf(TT_PointerOrReference, tok::l_paren) && (Style.PointerAlignment != FormatStyle::PAS_Left || (Line.IsMultiVariableDeclStmt && (Left.NestingLevel == 0 || (Left.NestingLevel == 1 && Line.First->is(tok::kw_for))))))); } if (Right.is(TT_FunctionTypeLParen) && Left.isNot(tok::l_paren) && (!Left.is(TT_PointerOrReference) || (Style.PointerAlignment != FormatStyle::PAS_Right && !Line.IsMultiVariableDeclStmt))) return true; if (Left.is(TT_PointerOrReference)) return Right.Tok.isLiteral() || Right.is(TT_BlockComment) || (Right.isOneOf(Keywords.kw_override, Keywords.kw_final) && !Right.is(TT_StartOfName)) || (Right.is(tok::l_brace) && Right.BlockKind == BK_Block) || (!Right.isOneOf(TT_PointerOrReference, TT_ArraySubscriptLSquare, tok::l_paren) && (Style.PointerAlignment != FormatStyle::PAS_Right && !Line.IsMultiVariableDeclStmt) && Left.Previous && !Left.Previous->isOneOf(tok::l_paren, tok::coloncolon, tok::l_square)); if (Right.is(tok::star) && Left.is(tok::l_paren)) return false; if (Right.isOneOf(tok::star, tok::amp, tok::ampamp) && (Left.is(tok::identifier) || Left.isSimpleTypeSpecifier()) && - Left.Previous && Left.Previous->is(tok::kw_operator)) - // Space between the type and the * - // operator void*(), operator char*(), operator Foo*() dependant - // on PointerAlignment style. + // Space between the type and the * in: + // operator void*() + // operator char*() + // operator /*comment*/ const char*() + // operator volatile /*comment*/ char*() + // operator Foo*() + // dependent on PointerAlignment style. + Left.Previous && + (Left.Previous->endsSequence(tok::kw_operator) || + Left.Previous->endsSequence(tok::kw_const, tok::kw_operator) || + Left.Previous->endsSequence(tok::kw_volatile, tok::kw_operator))) return (Style.PointerAlignment != FormatStyle::PAS_Left); const auto SpaceRequiredForArrayInitializerLSquare = [](const FormatToken &LSquareTok, const FormatStyle &Style) { return Style.SpacesInContainerLiterals || ((Style.Language == FormatStyle::LK_Proto || Style.Language == FormatStyle::LK_TextProto) && !Style.Cpp11BracedListStyle && LSquareTok.endsSequence(tok::l_square, tok::colon, TT_SelectorName)); }; if (Left.is(tok::l_square)) return (Left.is(TT_ArrayInitializerLSquare) && Right.isNot(tok::r_square) && SpaceRequiredForArrayInitializerLSquare(Left, Style)) || (Left.isOneOf(TT_ArraySubscriptLSquare, TT_StructuredBindingLSquare, TT_LambdaLSquare) && Style.SpacesInSquareBrackets && Right.isNot(tok::r_square)); if (Right.is(tok::r_square)) return Right.MatchingParen && ((Right.MatchingParen->is(TT_ArrayInitializerLSquare) && SpaceRequiredForArrayInitializerLSquare(*Right.MatchingParen, Style)) || (Style.SpacesInSquareBrackets && Right.MatchingParen->isOneOf(TT_ArraySubscriptLSquare, TT_StructuredBindingLSquare, TT_LambdaLSquare)) || Right.MatchingParen->is(TT_AttributeParen)); if (Right.is(tok::l_square) && !Right.isOneOf(TT_ObjCMethodExpr, TT_LambdaLSquare, TT_DesignatedInitializerLSquare, TT_StructuredBindingLSquare, TT_AttributeSquare) && !Left.isOneOf(tok::numeric_constant, TT_DictLiteral) && !(!Left.is(tok::r_square) && Style.SpaceBeforeSquareBrackets && Right.is(TT_ArraySubscriptLSquare))) return false; if (Left.is(tok::l_brace) && Right.is(tok::r_brace)) return !Left.Children.empty(); // No spaces in "{}". if ((Left.is(tok::l_brace) && Left.BlockKind != BK_Block) || (Right.is(tok::r_brace) && Right.MatchingParen && Right.MatchingParen->BlockKind != BK_Block)) return Style.Cpp11BracedListStyle ? Style.SpacesInParentheses : true; if (Left.is(TT_BlockComment)) // No whitespace in x(/*foo=*/1), except for JavaScript. return Style.Language == FormatStyle::LK_JavaScript || !Left.TokenText.endswith("=*/"); if (Right.is(tok::l_paren)) { if ((Left.is(tok::r_paren) && Left.is(TT_AttributeParen)) || (Left.is(tok::r_square) && Left.is(TT_AttributeSquare))) return true; return Line.Type == LT_ObjCDecl || Left.is(tok::semi) || (Style.SpaceBeforeParens != FormatStyle::SBPO_Never && (Left.isOneOf(tok::pp_elif, tok::kw_for, tok::kw_while, tok::kw_switch, tok::kw_case, TT_ForEachMacro, TT_ObjCForIn) || Left.isIf(Line.Type != LT_PreprocessorDirective) || (Left.isOneOf(tok::kw_try, Keywords.kw___except, tok::kw_catch, tok::kw_new, tok::kw_delete) && (!Left.Previous || Left.Previous->isNot(tok::period))))) || (spaceRequiredBeforeParens(Right) && (Left.is(tok::identifier) || Left.isFunctionLikeKeyword() || Left.is(tok::r_paren) || Left.isSimpleTypeSpecifier() || (Left.is(tok::r_square) && Left.MatchingParen && Left.MatchingParen->is(TT_LambdaLSquare))) && Line.Type != LT_PreprocessorDirective); } if (Left.is(tok::at) && Right.Tok.getObjCKeywordID() != tok::objc_not_keyword) return false; if (Right.is(TT_UnaryOperator)) return !Left.isOneOf(tok::l_paren, tok::l_square, tok::at) && (Left.isNot(tok::colon) || Left.isNot(TT_ObjCMethodExpr)); if ((Left.isOneOf(tok::identifier, tok::greater, tok::r_square, tok::r_paren) || Left.isSimpleTypeSpecifier()) && Right.is(tok::l_brace) && Right.getNextNonComment() && Right.BlockKind != BK_Block) return false; if (Left.is(tok::period) || Right.is(tok::period)) return false; if (Right.is(tok::hash) && Left.is(tok::identifier) && Left.TokenText == "L") return false; if (Left.is(TT_TemplateCloser) && Left.MatchingParen && Left.MatchingParen->Previous && (Left.MatchingParen->Previous->is(tok::period) || Left.MatchingParen->Previous->is(tok::coloncolon))) // Java call to generic function with explicit type: // A.>>DoSomething(); // A::>>DoSomething(); // With a Java 8 method reference. return false; if (Left.is(TT_TemplateCloser) && Right.is(tok::l_square)) return false; if (Left.is(tok::l_brace) && Left.endsSequence(TT_DictLiteral, tok::at)) // Objective-C dictionary literal -> no space after opening brace. return false; if (Right.is(tok::r_brace) && Right.MatchingParen && Right.MatchingParen->endsSequence(TT_DictLiteral, tok::at)) // Objective-C dictionary literal -> no space before closing brace. return false; if (Right.Type == TT_TrailingAnnotation && Right.isOneOf(tok::amp, tok::ampamp) && Left.isOneOf(tok::kw_const, tok::kw_volatile) && (!Right.Next || Right.Next->is(tok::semi))) // Match const and volatile ref-qualifiers without any additional // qualifiers such as // void Fn() const &; return Style.PointerAlignment != FormatStyle::PAS_Left; return true; } bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line, const FormatToken &Right) { const FormatToken &Left = *Right.Previous; if (Right.Tok.getIdentifierInfo() && Left.Tok.getIdentifierInfo()) return true; // Never ever merge two identifiers. if (Style.isCpp()) { if (Left.is(tok::kw_operator)) return Right.is(tok::coloncolon); if (Right.is(tok::l_brace) && Right.BlockKind == BK_BracedInit && !Left.opensScope() && Style.SpaceBeforeCpp11BracedList) return true; } else if (Style.Language == FormatStyle::LK_Proto || Style.Language == FormatStyle::LK_TextProto) { if (Right.is(tok::period) && Left.isOneOf(Keywords.kw_optional, Keywords.kw_required, Keywords.kw_repeated, Keywords.kw_extend)) return true; if (Right.is(tok::l_paren) && Left.isOneOf(Keywords.kw_returns, Keywords.kw_option)) return true; if (Right.isOneOf(tok::l_brace, tok::less) && Left.is(TT_SelectorName)) return true; // Slashes occur in text protocol extension syntax: [type/type] { ... }. if (Left.is(tok::slash) || Right.is(tok::slash)) return false; if (Left.MatchingParen && Left.MatchingParen->is(TT_ProtoExtensionLSquare) && Right.isOneOf(tok::l_brace, tok::less)) return !Style.Cpp11BracedListStyle; // A percent is probably part of a formatting specification, such as %lld. if (Left.is(tok::percent)) return false; // Preserve the existence of a space before a percent for cases like 0x%04x // and "%d %d" if (Left.is(tok::numeric_constant) && Right.is(tok::percent)) return Right.WhitespaceRange.getEnd() != Right.WhitespaceRange.getBegin(); } else if (Style.isCSharp()) { // space between type and variable e.g. Dictionary foo; if (Left.is(TT_TemplateCloser) && Right.is(TT_StartOfName)) return true; // space between keywords and paren e.g. "using (" if (Right.is(tok::l_paren)) if (Left.is(tok::kw_using)) return spaceRequiredBeforeParens(Left); } else if (Style.Language == FormatStyle::LK_JavaScript) { if (Left.is(TT_JsFatArrow)) return true; // for await ( ... if (Right.is(tok::l_paren) && Left.is(Keywords.kw_await) && Left.Previous && Left.Previous->is(tok::kw_for)) return true; if (Left.is(Keywords.kw_async) && Right.is(tok::l_paren) && Right.MatchingParen) { const FormatToken *Next = Right.MatchingParen->getNextNonComment(); // An async arrow function, for example: `x = async () => foo();`, // as opposed to calling a function called async: `x = async();` if (Next && Next->is(TT_JsFatArrow)) return true; } if ((Left.is(TT_TemplateString) && Left.TokenText.endswith("${")) || (Right.is(TT_TemplateString) && Right.TokenText.startswith("}"))) return false; // In tagged template literals ("html`bar baz`"), there is no space between // the tag identifier and the template string. getIdentifierInfo makes sure // that the identifier is not a pseudo keyword like `yield`, either. if (Left.is(tok::identifier) && Keywords.IsJavaScriptIdentifier(Left) && Right.is(TT_TemplateString)) return false; if (Right.is(tok::star) && Left.isOneOf(Keywords.kw_function, Keywords.kw_yield)) return false; if (Right.isOneOf(tok::l_brace, tok::l_square) && Left.isOneOf(Keywords.kw_function, Keywords.kw_yield, Keywords.kw_extends, Keywords.kw_implements)) return true; if (Right.is(tok::l_paren)) { // JS methods can use some keywords as names (e.g. `delete()`). if (Line.MustBeDeclaration && Left.Tok.getIdentifierInfo()) return false; // Valid JS method names can include keywords, e.g. `foo.delete()` or // `bar.instanceof()`. Recognize call positions by preceding period. if (Left.Previous && Left.Previous->is(tok::period) && Left.Tok.getIdentifierInfo()) return false; // Additional unary JavaScript operators that need a space after. if (Left.isOneOf(tok::kw_throw, Keywords.kw_await, Keywords.kw_typeof, tok::kw_void)) return true; } // `foo as const;` casts into a const type. if (Left.endsSequence(tok::kw_const, Keywords.kw_as)) { return false; } if ((Left.isOneOf(Keywords.kw_let, Keywords.kw_var, Keywords.kw_in, tok::kw_const) || // "of" is only a keyword if it appears after another identifier // (e.g. as "const x of y" in a for loop), or after a destructuring // operation (const [x, y] of z, const {a, b} of c). (Left.is(Keywords.kw_of) && Left.Previous && (Left.Previous->Tok.is(tok::identifier) || Left.Previous->isOneOf(tok::r_square, tok::r_brace)))) && (!Left.Previous || !Left.Previous->is(tok::period))) return true; if (Left.isOneOf(tok::kw_for, Keywords.kw_as) && Left.Previous && Left.Previous->is(tok::period) && Right.is(tok::l_paren)) return false; if (Left.is(Keywords.kw_as) && Right.isOneOf(tok::l_square, tok::l_brace, tok::l_paren)) return true; if (Left.is(tok::kw_default) && Left.Previous && Left.Previous->is(tok::kw_export)) return true; if (Left.is(Keywords.kw_is) && Right.is(tok::l_brace)) return true; if (Right.isOneOf(TT_JsTypeColon, TT_JsTypeOptionalQuestion)) return false; if (Left.is(TT_JsTypeOperator) || Right.is(TT_JsTypeOperator)) return false; if ((Left.is(tok::l_brace) || Right.is(tok::r_brace)) && Line.First->isOneOf(Keywords.kw_import, tok::kw_export)) return false; if (Left.is(tok::ellipsis)) return false; if (Left.is(TT_TemplateCloser) && !Right.isOneOf(tok::equal, tok::l_brace, tok::comma, tok::l_square, Keywords.kw_implements, Keywords.kw_extends)) // Type assertions ('expr') are not followed by whitespace. Other // locations that should have whitespace following are identified by the // above set of follower tokens. return false; if (Right.is(TT_JsNonNullAssertion)) return false; if (Left.is(TT_JsNonNullAssertion) && Right.isOneOf(Keywords.kw_as, Keywords.kw_in)) return true; // "x! as string", "x! in y" } else if (Style.Language == FormatStyle::LK_Java) { if (Left.is(tok::r_square) && Right.is(tok::l_brace)) return true; if (Left.is(Keywords.kw_synchronized) && Right.is(tok::l_paren)) return Style.SpaceBeforeParens != FormatStyle::SBPO_Never; if ((Left.isOneOf(tok::kw_static, tok::kw_public, tok::kw_private, tok::kw_protected) || Left.isOneOf(Keywords.kw_final, Keywords.kw_abstract, Keywords.kw_native)) && Right.is(TT_TemplateOpener)) return true; } if (Left.is(TT_ImplicitStringLiteral)) return Right.WhitespaceRange.getBegin() != Right.WhitespaceRange.getEnd(); if (Line.Type == LT_ObjCMethodDecl) { if (Left.is(TT_ObjCMethodSpecifier)) return true; if (Left.is(tok::r_paren) && canBeObjCSelectorComponent(Right)) // Don't space between ')' and or ')' and 'new'. 'new' is not a // keyword in Objective-C, and '+ (instancetype)new;' is a standard class // method declaration. return false; } if (Line.Type == LT_ObjCProperty && (Right.is(tok::equal) || Left.is(tok::equal))) return false; if (Right.isOneOf(TT_TrailingReturnArrow, TT_LambdaArrow) || Left.isOneOf(TT_TrailingReturnArrow, TT_LambdaArrow)) return true; if (Right.is(TT_OverloadedOperatorLParen)) return spaceRequiredBeforeParens(Right); if (Left.is(tok::comma)) return true; if (Right.is(tok::comma)) return false; if (Right.is(TT_ObjCBlockLParen)) return true; if (Right.is(TT_CtorInitializerColon)) return Style.SpaceBeforeCtorInitializerColon; if (Right.is(TT_InheritanceColon) && !Style.SpaceBeforeInheritanceColon) return false; if (Right.is(TT_RangeBasedForLoopColon) && !Style.SpaceBeforeRangeBasedForLoopColon) return false; if (Right.is(tok::colon)) { if (Line.First->isOneOf(tok::kw_case, tok::kw_default) || !Right.getNextNonComment() || Right.getNextNonComment()->is(tok::semi)) return false; if (Right.is(TT_ObjCMethodExpr)) return false; if (Left.is(tok::question)) return false; if (Right.is(TT_InlineASMColon) && Left.is(tok::coloncolon)) return false; if (Right.is(TT_DictLiteral)) return Style.SpacesInContainerLiterals; if (Right.is(TT_AttributeColon)) return false; return true; } if (Left.is(TT_UnaryOperator)) { if (!Right.is(tok::l_paren)) { // The alternative operators for ~ and ! are "compl" and "not". // If they are used instead, we do not want to combine them with // the token to the right, unless that is a left paren. if (Left.is(tok::exclaim) && Left.TokenText == "not") return true; if (Left.is(tok::tilde) && Left.TokenText == "compl") return true; // Lambda captures allow for a lone &, so "&]" needs to be properly // handled. if (Left.is(tok::amp) && Right.is(tok::r_square)) return Style.SpacesInSquareBrackets; } return (Style.SpaceAfterLogicalNot && Left.is(tok::exclaim)) || Right.is(TT_BinaryOperator); } // If the next token is a binary operator or a selector name, we have // incorrectly classified the parenthesis as a cast. FIXME: Detect correctly. if (Left.is(TT_CastRParen)) return Style.SpaceAfterCStyleCast || Right.isOneOf(TT_BinaryOperator, TT_SelectorName); if (Left.is(tok::greater) && Right.is(tok::greater)) { if (Style.Language == FormatStyle::LK_TextProto || (Style.Language == FormatStyle::LK_Proto && Left.is(TT_DictLiteral))) return !Style.Cpp11BracedListStyle; return Right.is(TT_TemplateCloser) && Left.is(TT_TemplateCloser) && (Style.Standard < FormatStyle::LS_Cpp11 || Style.SpacesInAngles); } if (Right.isOneOf(tok::arrow, tok::arrowstar, tok::periodstar) || Left.isOneOf(tok::arrow, tok::period, tok::arrowstar, tok::periodstar) || (Right.is(tok::period) && Right.isNot(TT_DesignatedInitializerPeriod))) return false; if (!Style.SpaceBeforeAssignmentOperators && Left.isNot(TT_TemplateCloser) && Right.getPrecedence() == prec::Assignment) return false; if (Style.Language == FormatStyle::LK_Java && Right.is(tok::coloncolon) && (Left.is(tok::identifier) || Left.is(tok::kw_this))) return false; if (Right.is(tok::coloncolon) && Left.is(tok::identifier)) // Generally don't remove existing spaces between an identifier and "::". // The identifier might actually be a macro name such as ALWAYS_INLINE. If // this turns out to be too lenient, add analysis of the identifier itself. return Right.WhitespaceRange.getBegin() != Right.WhitespaceRange.getEnd(); if (Right.is(tok::coloncolon) && !Left.isOneOf(tok::l_brace, tok::comment, tok::l_paren)) return (Left.is(TT_TemplateOpener) && Style.Standard < FormatStyle::LS_Cpp11) || !(Left.isOneOf(tok::l_paren, tok::r_paren, tok::l_square, tok::kw___super, TT_TemplateCloser, TT_TemplateOpener)) || (Left.is(tok ::l_paren) && Style.SpacesInParentheses); if ((Left.is(TT_TemplateOpener)) != (Right.is(TT_TemplateCloser))) return Style.SpacesInAngles; // Space before TT_StructuredBindingLSquare. if (Right.is(TT_StructuredBindingLSquare)) return !Left.isOneOf(tok::amp, tok::ampamp) || Style.PointerAlignment != FormatStyle::PAS_Right; // Space before & or && following a TT_StructuredBindingLSquare. if (Right.Next && Right.Next->is(TT_StructuredBindingLSquare) && Right.isOneOf(tok::amp, tok::ampamp)) return Style.PointerAlignment != FormatStyle::PAS_Left; if ((Right.is(TT_BinaryOperator) && !Left.is(tok::l_paren)) || (Left.isOneOf(TT_BinaryOperator, TT_ConditionalExpr) && !Right.is(tok::r_paren))) return true; if (Left.is(TT_TemplateCloser) && Right.is(tok::l_paren) && Right.isNot(TT_FunctionTypeLParen)) return spaceRequiredBeforeParens(Right); if (Right.is(TT_TemplateOpener) && Left.is(tok::r_paren) && Left.MatchingParen && Left.MatchingParen->is(TT_OverloadedOperatorLParen)) return false; if (Right.is(tok::less) && Left.isNot(tok::l_paren) && Line.startsWith(tok::hash)) return true; if (Right.is(TT_TrailingUnaryOperator)) return false; if (Left.is(TT_RegexLiteral)) return false; return spaceRequiredBetween(Line, Left, Right); } // Returns 'true' if 'Tok' is a brace we'd want to break before in Allman style. static bool isAllmanBrace(const FormatToken &Tok) { return Tok.is(tok::l_brace) && Tok.BlockKind == BK_Block && !Tok.isOneOf(TT_ObjCBlockLBrace, TT_LambdaLBrace, TT_DictLiteral); } bool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line, const FormatToken &Right) { const FormatToken &Left = *Right.Previous; if (Right.NewlinesBefore > 1 && Style.MaxEmptyLinesToKeep > 0) return true; if (Style.Language == FormatStyle::LK_JavaScript) { // FIXME: This might apply to other languages and token kinds. if (Right.is(tok::string_literal) && Left.is(tok::plus) && Left.Previous && Left.Previous->is(tok::string_literal)) return true; if (Left.is(TT_DictLiteral) && Left.is(tok::l_brace) && Line.Level == 0 && Left.Previous && Left.Previous->is(tok::equal) && Line.First->isOneOf(tok::identifier, Keywords.kw_import, tok::kw_export, tok::kw_const) && // kw_var/kw_let are pseudo-tokens that are tok::identifier, so match // above. !Line.First->isOneOf(Keywords.kw_var, Keywords.kw_let)) // Object literals on the top level of a file are treated as "enum-style". // Each key/value pair is put on a separate line, instead of bin-packing. return true; if (Left.is(tok::l_brace) && Line.Level == 0 && (Line.startsWith(tok::kw_enum) || Line.startsWith(tok::kw_const, tok::kw_enum) || Line.startsWith(tok::kw_export, tok::kw_enum) || Line.startsWith(tok::kw_export, tok::kw_const, tok::kw_enum))) // JavaScript top-level enum key/value pairs are put on separate lines // instead of bin-packing. return true; if (Right.is(tok::r_brace) && Left.is(tok::l_brace) && !Left.Children.empty()) // Support AllowShortFunctionsOnASingleLine for JavaScript. return Style.AllowShortFunctionsOnASingleLine == FormatStyle::SFS_None || Style.AllowShortFunctionsOnASingleLine == FormatStyle::SFS_Empty || (Left.NestingLevel == 0 && Line.Level == 0 && Style.AllowShortFunctionsOnASingleLine & FormatStyle::SFS_InlineOnly); } else if (Style.Language == FormatStyle::LK_Java) { if (Right.is(tok::plus) && Left.is(tok::string_literal) && Right.Next && Right.Next->is(tok::string_literal)) return true; } else if (Style.Language == FormatStyle::LK_Cpp || Style.Language == FormatStyle::LK_ObjC || Style.Language == FormatStyle::LK_Proto || Style.Language == FormatStyle::LK_TableGen || Style.Language == FormatStyle::LK_TextProto) { if (Left.isStringLiteral() && Right.isStringLiteral()) return true; } // If the last token before a '}', ']', or ')' is a comma or a trailing // comment, the intention is to insert a line break after it in order to make // shuffling around entries easier. Import statements, especially in // JavaScript, can be an exception to this rule. if (Style.JavaScriptWrapImports || Line.Type != LT_ImportStatement) { const FormatToken *BeforeClosingBrace = nullptr; if ((Left.isOneOf(tok::l_brace, TT_ArrayInitializerLSquare) || (Style.Language == FormatStyle::LK_JavaScript && Left.is(tok::l_paren))) && Left.BlockKind != BK_Block && Left.MatchingParen) BeforeClosingBrace = Left.MatchingParen->Previous; else if (Right.MatchingParen && (Right.MatchingParen->isOneOf(tok::l_brace, TT_ArrayInitializerLSquare) || (Style.Language == FormatStyle::LK_JavaScript && Right.MatchingParen->is(tok::l_paren)))) BeforeClosingBrace = &Left; if (BeforeClosingBrace && (BeforeClosingBrace->is(tok::comma) || BeforeClosingBrace->isTrailingComment())) return true; } if (Right.is(tok::comment)) return Left.BlockKind != BK_BracedInit && Left.isNot(TT_CtorInitializerColon) && (Right.NewlinesBefore > 0 && Right.HasUnescapedNewline); if (Left.isTrailingComment()) return true; if (Right.Previous->IsUnterminatedLiteral) return true; if (Right.is(tok::lessless) && Right.Next && Right.Previous->is(tok::string_literal) && Right.Next->is(tok::string_literal)) return true; if (Right.Previous->ClosesTemplateDeclaration && Right.Previous->MatchingParen && Right.Previous->MatchingParen->NestingLevel == 0 && Style.AlwaysBreakTemplateDeclarations == FormatStyle::BTDS_Yes) return true; if (Right.is(TT_CtorInitializerComma) && Style.BreakConstructorInitializers == FormatStyle::BCIS_BeforeComma && !Style.ConstructorInitializerAllOnOneLineOrOnePerLine) return true; if (Right.is(TT_CtorInitializerColon) && Style.BreakConstructorInitializers == FormatStyle::BCIS_BeforeComma && !Style.ConstructorInitializerAllOnOneLineOrOnePerLine) return true; // Break only if we have multiple inheritance. if (Style.BreakInheritanceList == FormatStyle::BILS_BeforeComma && Right.is(TT_InheritanceComma)) return true; if (Right.is(tok::string_literal) && Right.TokenText.startswith("R\"")) // Multiline raw string literals are special wrt. line breaks. The author // has made a deliberate choice and might have aligned the contents of the // string literal accordingly. Thus, we try keep existing line breaks. return Right.IsMultiline && Right.NewlinesBefore > 0; if ((Right.Previous->is(tok::l_brace) || (Right.Previous->is(tok::less) && Right.Previous->Previous && Right.Previous->Previous->is(tok::equal))) && Right.NestingLevel == 1 && Style.Language == FormatStyle::LK_Proto) { // Don't put enums or option definitions onto single lines in protocol // buffers. return true; } if (Right.is(TT_InlineASMBrace)) return Right.HasUnescapedNewline; if (isAllmanBrace(Left) || isAllmanBrace(Right)) return (Line.startsWith(tok::kw_enum) && Style.BraceWrapping.AfterEnum) || (Line.startsWith(tok::kw_typedef, tok::kw_enum) && Style.BraceWrapping.AfterEnum) || (Line.startsWith(tok::kw_class) && Style.BraceWrapping.AfterClass) || (Line.startsWith(tok::kw_struct) && Style.BraceWrapping.AfterStruct); if (Left.is(TT_ObjCBlockLBrace) && Style.AllowShortBlocksOnASingleLine == FormatStyle::SBS_Never) return true; if (Left.is(TT_LambdaLBrace)) { if (Left.MatchingParen && Left.MatchingParen->Next && Left.MatchingParen->Next->isOneOf(tok::comma, tok::r_paren) && Style.AllowShortLambdasOnASingleLine == FormatStyle::SLS_Inline) return false; if (Style.AllowShortLambdasOnASingleLine == FormatStyle::SLS_None || Style.AllowShortLambdasOnASingleLine == FormatStyle::SLS_Inline || (!Left.Children.empty() && Style.AllowShortLambdasOnASingleLine == FormatStyle::SLS_Empty)) return true; } // Put multiple C# attributes on a new line. if (Style.isCSharp() && ((Left.is(TT_AttributeSquare) && Left.is(tok::r_square)) || (Left.is(tok::r_square) && Right.is(TT_AttributeSquare) && Right.is(tok::l_square)))) return true; // Put multiple Java annotation on a new line. if ((Style.Language == FormatStyle::LK_Java || Style.Language == FormatStyle::LK_JavaScript) && Left.is(TT_LeadingJavaAnnotation) && Right.isNot(TT_LeadingJavaAnnotation) && Right.isNot(tok::l_paren) && (Line.Last->is(tok::l_brace) || Style.BreakAfterJavaFieldAnnotations)) return true; if (Right.is(TT_ProtoExtensionLSquare)) return true; // In text proto instances if a submessage contains at least 2 entries and at // least one of them is a submessage, like A { ... B { ... } ... }, // put all of the entries of A on separate lines by forcing the selector of // the submessage B to be put on a newline. // // Example: these can stay on one line: // a { scalar_1: 1 scalar_2: 2 } // a { b { key: value } } // // and these entries need to be on a new line even if putting them all in one // line is under the column limit: // a { // scalar: 1 // b { key: value } // } // // We enforce this by breaking before a submessage field that has previous // siblings, *and* breaking before a field that follows a submessage field. // // Be careful to exclude the case [proto.ext] { ... } since the `]` is // the TT_SelectorName there, but we don't want to break inside the brackets. // // Another edge case is @submessage { key: value }, which is a common // substitution placeholder. In this case we want to keep `@` and `submessage` // together. // // We ensure elsewhere that extensions are always on their own line. if ((Style.Language == FormatStyle::LK_Proto || Style.Language == FormatStyle::LK_TextProto) && Right.is(TT_SelectorName) && !Right.is(tok::r_square) && Right.Next) { // Keep `@submessage` together in: // @submessage { key: value } if (Right.Previous && Right.Previous->is(tok::at)) return false; // Look for the scope opener after selector in cases like: // selector { ... // selector: { ... // selector: @base { ... FormatToken *LBrace = Right.Next; if (LBrace && LBrace->is(tok::colon)) { LBrace = LBrace->Next; if (LBrace && LBrace->is(tok::at)) { LBrace = LBrace->Next; if (LBrace) LBrace = LBrace->Next; } } if (LBrace && // The scope opener is one of {, [, <: // selector { ... } // selector [ ... ] // selector < ... > // // In case of selector { ... }, the l_brace is TT_DictLiteral. // In case of an empty selector {}, the l_brace is not TT_DictLiteral, // so we check for immediately following r_brace. ((LBrace->is(tok::l_brace) && (LBrace->is(TT_DictLiteral) || (LBrace->Next && LBrace->Next->is(tok::r_brace)))) || LBrace->is(TT_ArrayInitializerLSquare) || LBrace->is(tok::less))) { // If Left.ParameterCount is 0, then this submessage entry is not the // first in its parent submessage, and we want to break before this entry. // If Left.ParameterCount is greater than 0, then its parent submessage // might contain 1 or more entries and we want to break before this entry // if it contains at least 2 entries. We deal with this case later by // detecting and breaking before the next entry in the parent submessage. if (Left.ParameterCount == 0) return true; // However, if this submessage is the first entry in its parent // submessage, Left.ParameterCount might be 1 in some cases. // We deal with this case later by detecting an entry // following a closing paren of this submessage. } // If this is an entry immediately following a submessage, it will be // preceded by a closing paren of that submessage, like in: // left---. .---right // v v // sub: { ... } key: value // If there was a comment between `}` an `key` above, then `key` would be // put on a new line anyways. if (Left.isOneOf(tok::r_brace, tok::greater, tok::r_square)) return true; } // Deal with lambda arguments in C++ - we want consistent line breaks whether // they happen to be at arg0, arg1 or argN. The selection is a bit nuanced // as aggressive line breaks are placed when the lambda is not the last arg. if ((Style.Language == FormatStyle::LK_Cpp || Style.Language == FormatStyle::LK_ObjC) && Left.is(tok::l_paren) && Left.BlockParameterCount > 0 && !Right.isOneOf(tok::l_paren, TT_LambdaLSquare)) { // Multiple lambdas in the same function call force line breaks. if (Left.BlockParameterCount > 1) return true; // A lambda followed by another arg forces a line break. if (!Left.Role) return false; auto Comma = Left.Role->lastComma(); if (!Comma) return false; auto Next = Comma->getNextNonComment(); if (!Next) return false; if (!Next->isOneOf(TT_LambdaLSquare, tok::l_brace, tok::caret)) return true; } return false; } bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line, const FormatToken &Right) { const FormatToken &Left = *Right.Previous; // Language-specific stuff. if (Style.Language == FormatStyle::LK_Java) { if (Left.isOneOf(Keywords.kw_throws, Keywords.kw_extends, Keywords.kw_implements)) return false; if (Right.isOneOf(Keywords.kw_throws, Keywords.kw_extends, Keywords.kw_implements)) return true; } else if (Style.Language == FormatStyle::LK_JavaScript) { const FormatToken *NonComment = Right.getPreviousNonComment(); if (NonComment && NonComment->isOneOf( tok::kw_return, Keywords.kw_yield, tok::kw_continue, tok::kw_break, tok::kw_throw, Keywords.kw_interface, Keywords.kw_type, tok::kw_static, tok::kw_public, tok::kw_private, tok::kw_protected, Keywords.kw_readonly, Keywords.kw_abstract, Keywords.kw_get, Keywords.kw_set, Keywords.kw_async, Keywords.kw_await)) return false; // Otherwise automatic semicolon insertion would trigger. if (Right.NestingLevel == 0 && (Left.Tok.getIdentifierInfo() || Left.isOneOf(tok::r_square, tok::r_paren)) && Right.isOneOf(tok::l_square, tok::l_paren)) return false; // Otherwise automatic semicolon insertion would trigger. if (Left.is(TT_JsFatArrow) && Right.is(tok::l_brace)) return false; if (Left.is(TT_JsTypeColon)) return true; // Don't wrap between ":" and "!" of a strict prop init ("field!: type;"). if (Left.is(tok::exclaim) && Right.is(tok::colon)) return false; // Look for is type annotations like: // function f(): a is B { ... } // Do not break before is in these cases. if (Right.is(Keywords.kw_is)) { const FormatToken *Next = Right.getNextNonComment(); // If `is` is followed by a colon, it's likely that it's a dict key, so // ignore it for this check. // For example this is common in Polymer: // Polymer({ // is: 'name', // ... // }); if (!Next || !Next->is(tok::colon)) return false; } if (Left.is(Keywords.kw_in)) return Style.BreakBeforeBinaryOperators == FormatStyle::BOS_None; if (Right.is(Keywords.kw_in)) return Style.BreakBeforeBinaryOperators != FormatStyle::BOS_None; if (Right.is(Keywords.kw_as)) return false; // must not break before as in 'x as type' casts if (Right.isOneOf(Keywords.kw_extends, Keywords.kw_infer)) { // extends and infer can appear as keywords in conditional types: // https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-8.html#conditional-types // do not break before them, as the expressions are subject to ASI. return false; } if (Left.is(Keywords.kw_as)) return true; if (Left.is(TT_JsNonNullAssertion)) return true; if (Left.is(Keywords.kw_declare) && Right.isOneOf(Keywords.kw_module, tok::kw_namespace, Keywords.kw_function, tok::kw_class, tok::kw_enum, Keywords.kw_interface, Keywords.kw_type, Keywords.kw_var, Keywords.kw_let, tok::kw_const)) // See grammar for 'declare' statements at: // https://github.com/Microsoft/TypeScript/blob/master/doc/spec.md#A.10 return false; if (Left.isOneOf(Keywords.kw_module, tok::kw_namespace) && Right.isOneOf(tok::identifier, tok::string_literal)) return false; // must not break in "module foo { ...}" if (Right.is(TT_TemplateString) && Right.closesScope()) return false; // Don't split tagged template literal so there is a break between the tag // identifier and template string. if (Left.is(tok::identifier) && Right.is(TT_TemplateString)) { return false; } if (Left.is(TT_TemplateString) && Left.opensScope()) return true; } if (Left.is(tok::at)) return false; if (Left.Tok.getObjCKeywordID() == tok::objc_interface) return false; if (Left.isOneOf(TT_JavaAnnotation, TT_LeadingJavaAnnotation)) return !Right.is(tok::l_paren); if (Right.is(TT_PointerOrReference)) return Line.IsMultiVariableDeclStmt || (Style.PointerAlignment == FormatStyle::PAS_Right && (!Right.Next || Right.Next->isNot(TT_FunctionDeclarationName))); if (Right.isOneOf(TT_StartOfName, TT_FunctionDeclarationName) || Right.is(tok::kw_operator)) return true; if (Left.is(TT_PointerOrReference)) return false; if (Right.isTrailingComment()) // We rely on MustBreakBefore being set correctly here as we should not // change the "binding" behavior of a comment. // The first comment in a braced lists is always interpreted as belonging to // the first list element. Otherwise, it should be placed outside of the // list. return Left.BlockKind == BK_BracedInit || (Left.is(TT_CtorInitializerColon) && Style.BreakConstructorInitializers == FormatStyle::BCIS_AfterColon); if (Left.is(tok::question) && Right.is(tok::colon)) return false; if (Right.is(TT_ConditionalExpr) || Right.is(tok::question)) return Style.BreakBeforeTernaryOperators; if (Left.is(TT_ConditionalExpr) || Left.is(tok::question)) return !Style.BreakBeforeTernaryOperators; if (Left.is(TT_InheritanceColon)) return Style.BreakInheritanceList == FormatStyle::BILS_AfterColon; if (Right.is(TT_InheritanceColon)) return Style.BreakInheritanceList != FormatStyle::BILS_AfterColon; if (Right.is(TT_ObjCMethodExpr) && !Right.is(tok::r_square) && Left.isNot(TT_SelectorName)) return true; if (Right.is(tok::colon) && !Right.isOneOf(TT_CtorInitializerColon, TT_InlineASMColon)) return false; if (Left.is(tok::colon) && Left.isOneOf(TT_DictLiteral, TT_ObjCMethodExpr)) { if (Style.Language == FormatStyle::LK_Proto || Style.Language == FormatStyle::LK_TextProto) { if (!Style.AlwaysBreakBeforeMultilineStrings && Right.isStringLiteral()) return false; // Prevent cases like: // // submessage: // { key: valueeeeeeeeeeee } // // when the snippet does not fit into one line. // Prefer: // // submessage: { // key: valueeeeeeeeeeee // } // // instead, even if it is longer by one line. // // Note that this allows allows the "{" to go over the column limit // when the column limit is just between ":" and "{", but that does // not happen too often and alternative formattings in this case are // not much better. // // The code covers the cases: // // submessage: { ... } // submessage: < ... > // repeated: [ ... ] if (((Right.is(tok::l_brace) || Right.is(tok::less)) && Right.is(TT_DictLiteral)) || Right.is(TT_ArrayInitializerLSquare)) return false; } return true; } if (Right.is(tok::r_square) && Right.MatchingParen && Right.MatchingParen->is(TT_ProtoExtensionLSquare)) return false; if (Right.is(TT_SelectorName) || (Right.is(tok::identifier) && Right.Next && Right.Next->is(TT_ObjCMethodExpr))) return Left.isNot(tok::period); // FIXME: Properly parse ObjC calls. if (Left.is(tok::r_paren) && Line.Type == LT_ObjCProperty) return true; if (Left.ClosesTemplateDeclaration || Left.is(TT_FunctionAnnotationRParen)) return true; if (Right.isOneOf(TT_RangeBasedForLoopColon, TT_OverloadedOperatorLParen, TT_OverloadedOperator)) return false; if (Left.is(TT_RangeBasedForLoopColon)) return true; if (Right.is(TT_RangeBasedForLoopColon)) return false; if (Left.is(TT_TemplateCloser) && Right.is(TT_TemplateOpener)) return true; if (Left.isOneOf(TT_TemplateCloser, TT_UnaryOperator) || Left.is(tok::kw_operator)) return false; if (Left.is(tok::equal) && !Right.isOneOf(tok::kw_default, tok::kw_delete) && Line.Type == LT_VirtualFunctionDecl && Left.NestingLevel == 0) return false; if (Left.is(tok::equal) && Right.is(tok::l_brace) && !Style.Cpp11BracedListStyle) return false; if (Left.is(tok::l_paren) && Left.is(TT_AttributeParen)) return false; if (Left.is(tok::l_paren) && Left.Previous && (Left.Previous->isOneOf(TT_BinaryOperator, TT_CastRParen))) return false; if (Right.is(TT_ImplicitStringLiteral)) return false; if (Right.is(tok::r_paren) || Right.is(TT_TemplateCloser)) return false; if (Right.is(tok::r_square) && Right.MatchingParen && Right.MatchingParen->is(TT_LambdaLSquare)) return false; // We only break before r_brace if there was a corresponding break before // the l_brace, which is tracked by BreakBeforeClosingBrace. if (Right.is(tok::r_brace)) return Right.MatchingParen && Right.MatchingParen->BlockKind == BK_Block; // Allow breaking after a trailing annotation, e.g. after a method // declaration. if (Left.is(TT_TrailingAnnotation)) return !Right.isOneOf(tok::l_brace, tok::semi, tok::equal, tok::l_paren, tok::less, tok::coloncolon); if (Right.is(tok::kw___attribute) || (Right.is(tok::l_square) && Right.is(TT_AttributeSquare))) return true; if (Left.is(tok::identifier) && Right.is(tok::string_literal)) return true; if (Right.is(tok::identifier) && Right.Next && Right.Next->is(TT_DictLiteral)) return true; if (Left.is(TT_CtorInitializerColon)) return Style.BreakConstructorInitializers == FormatStyle::BCIS_AfterColon; if (Right.is(TT_CtorInitializerColon)) return Style.BreakConstructorInitializers != FormatStyle::BCIS_AfterColon; if (Left.is(TT_CtorInitializerComma) && Style.BreakConstructorInitializers == FormatStyle::BCIS_BeforeComma) return false; if (Right.is(TT_CtorInitializerComma) && Style.BreakConstructorInitializers == FormatStyle::BCIS_BeforeComma) return true; if (Left.is(TT_InheritanceComma) && Style.BreakInheritanceList == FormatStyle::BILS_BeforeComma) return false; if (Right.is(TT_InheritanceComma) && Style.BreakInheritanceList == FormatStyle::BILS_BeforeComma) return true; if ((Left.is(tok::greater) && Right.is(tok::greater)) || (Left.is(tok::less) && Right.is(tok::less))) return false; if (Right.is(TT_BinaryOperator) && Style.BreakBeforeBinaryOperators != FormatStyle::BOS_None && (Style.BreakBeforeBinaryOperators == FormatStyle::BOS_All || Right.getPrecedence() != prec::Assignment)) return true; if (Left.is(TT_ArrayInitializerLSquare)) return true; if (Right.is(tok::kw_typename) && Left.isNot(tok::kw_const)) return true; if ((Left.isBinaryOperator() || Left.is(TT_BinaryOperator)) && !Left.isOneOf(tok::arrowstar, tok::lessless) && Style.BreakBeforeBinaryOperators != FormatStyle::BOS_All && (Style.BreakBeforeBinaryOperators == FormatStyle::BOS_None || Left.getPrecedence() == prec::Assignment)) return true; if ((Left.is(TT_AttributeSquare) && Right.is(tok::l_square)) || (Left.is(tok::r_square) && Right.is(TT_AttributeSquare))) return false; return Left.isOneOf(tok::comma, tok::coloncolon, tok::semi, tok::l_brace, tok::kw_class, tok::kw_struct, tok::comment) || Right.isMemberAccess() || Right.isOneOf(TT_TrailingReturnArrow, TT_LambdaArrow, tok::lessless, tok::colon, tok::l_square, tok::at) || (Left.is(tok::r_paren) && Right.isOneOf(tok::identifier, tok::kw_const)) || (Left.is(tok::l_paren) && !Right.is(tok::r_paren)) || (Left.is(TT_TemplateOpener) && !Right.is(TT_TemplateCloser)); } void TokenAnnotator::printDebugInfo(const AnnotatedLine &Line) { llvm::errs() << "AnnotatedTokens(L=" << Line.Level << "):\n"; const FormatToken *Tok = Line.First; while (Tok) { llvm::errs() << " M=" << Tok->MustBreakBefore << " C=" << Tok->CanBreakBefore << " T=" << getTokenTypeName(Tok->Type) << " S=" << Tok->SpacesRequiredBefore << " B=" << Tok->BlockParameterCount << " BK=" << Tok->BlockKind << " P=" << Tok->SplitPenalty << " Name=" << Tok->Tok.getName() << " L=" << Tok->TotalLength << " PPK=" << Tok->PackingKind << " FakeLParens="; for (unsigned i = 0, e = Tok->FakeLParens.size(); i != e; ++i) llvm::errs() << Tok->FakeLParens[i] << "/"; llvm::errs() << " FakeRParens=" << Tok->FakeRParens; llvm::errs() << " II=" << Tok->Tok.getIdentifierInfo(); llvm::errs() << " Text='" << Tok->TokenText << "'\n"; if (!Tok->Next) assert(Tok == Line.Last); Tok = Tok->Next; } llvm::errs() << "----\n"; } } // namespace format } // namespace clang diff --git a/contrib/llvm-project/clang/lib/Parse/ParseExpr.cpp b/contrib/llvm-project/clang/lib/Parse/ParseExpr.cpp index 1eb3ad6afd1c..ad9627a2425c 100644 --- a/contrib/llvm-project/clang/lib/Parse/ParseExpr.cpp +++ b/contrib/llvm-project/clang/lib/Parse/ParseExpr.cpp @@ -1,3448 +1,3449 @@ //===--- ParseExpr.cpp - Expression Parsing -------------------------------===// // // 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 /// Provides the Expression parsing implementation. /// /// Expressions in C99 basically consist of a bunch of binary operators with /// unary operators and other random stuff at the leaves. /// /// In the C99 grammar, these unary operators bind tightest and are represented /// as the 'cast-expression' production. Everything else is either a binary /// operator (e.g. '/') or a ternary operator ("?:"). The unary leaves are /// handled by ParseCastExpression, the higher level pieces are handled by /// ParseBinaryExpression. /// //===----------------------------------------------------------------------===// #include "clang/Parse/Parser.h" #include "clang/AST/ASTContext.h" #include "clang/AST/ExprCXX.h" #include "clang/Basic/PrettyStackTrace.h" #include "clang/Parse/RAIIObjectsForParser.h" #include "clang/Sema/DeclSpec.h" #include "clang/Sema/ParsedTemplate.h" #include "clang/Sema/Scope.h" #include "clang/Sema/TypoCorrection.h" #include "llvm/ADT/SmallVector.h" using namespace clang; /// Simple precedence-based parser for binary/ternary operators. /// /// Note: we diverge from the C99 grammar when parsing the assignment-expression /// production. C99 specifies that the LHS of an assignment operator should be /// parsed as a unary-expression, but consistency dictates that it be a /// conditional-expession. In practice, the important thing here is that the /// LHS of an assignment has to be an l-value, which productions between /// unary-expression and conditional-expression don't produce. Because we want /// consistency, we parse the LHS as a conditional-expression, then check for /// l-value-ness in semantic analysis stages. /// /// \verbatim /// pm-expression: [C++ 5.5] /// cast-expression /// pm-expression '.*' cast-expression /// pm-expression '->*' cast-expression /// /// multiplicative-expression: [C99 6.5.5] /// Note: in C++, apply pm-expression instead of cast-expression /// cast-expression /// multiplicative-expression '*' cast-expression /// multiplicative-expression '/' cast-expression /// multiplicative-expression '%' cast-expression /// /// additive-expression: [C99 6.5.6] /// multiplicative-expression /// additive-expression '+' multiplicative-expression /// additive-expression '-' multiplicative-expression /// /// shift-expression: [C99 6.5.7] /// additive-expression /// shift-expression '<<' additive-expression /// shift-expression '>>' additive-expression /// /// compare-expression: [C++20 expr.spaceship] /// shift-expression /// compare-expression '<=>' shift-expression /// /// relational-expression: [C99 6.5.8] /// compare-expression /// relational-expression '<' compare-expression /// relational-expression '>' compare-expression /// relational-expression '<=' compare-expression /// relational-expression '>=' compare-expression /// /// equality-expression: [C99 6.5.9] /// relational-expression /// equality-expression '==' relational-expression /// equality-expression '!=' relational-expression /// /// AND-expression: [C99 6.5.10] /// equality-expression /// AND-expression '&' equality-expression /// /// exclusive-OR-expression: [C99 6.5.11] /// AND-expression /// exclusive-OR-expression '^' AND-expression /// /// inclusive-OR-expression: [C99 6.5.12] /// exclusive-OR-expression /// inclusive-OR-expression '|' exclusive-OR-expression /// /// logical-AND-expression: [C99 6.5.13] /// inclusive-OR-expression /// logical-AND-expression '&&' inclusive-OR-expression /// /// logical-OR-expression: [C99 6.5.14] /// logical-AND-expression /// logical-OR-expression '||' logical-AND-expression /// /// conditional-expression: [C99 6.5.15] /// logical-OR-expression /// logical-OR-expression '?' expression ':' conditional-expression /// [GNU] logical-OR-expression '?' ':' conditional-expression /// [C++] the third operand is an assignment-expression /// /// assignment-expression: [C99 6.5.16] /// conditional-expression /// unary-expression assignment-operator assignment-expression /// [C++] throw-expression [C++ 15] /// /// assignment-operator: one of /// = *= /= %= += -= <<= >>= &= ^= |= /// /// expression: [C99 6.5.17] /// assignment-expression ...[opt] /// expression ',' assignment-expression ...[opt] /// \endverbatim ExprResult Parser::ParseExpression(TypeCastState isTypeCast) { ExprResult LHS(ParseAssignmentExpression(isTypeCast)); return ParseRHSOfBinaryExpression(LHS, prec::Comma); } /// This routine is called when the '@' is seen and consumed. /// Current token is an Identifier and is not a 'try'. This /// routine is necessary to disambiguate \@try-statement from, /// for example, \@encode-expression. /// ExprResult Parser::ParseExpressionWithLeadingAt(SourceLocation AtLoc) { ExprResult LHS(ParseObjCAtExpression(AtLoc)); return ParseRHSOfBinaryExpression(LHS, prec::Comma); } /// This routine is called when a leading '__extension__' is seen and /// consumed. This is necessary because the token gets consumed in the /// process of disambiguating between an expression and a declaration. ExprResult Parser::ParseExpressionWithLeadingExtension(SourceLocation ExtLoc) { ExprResult LHS(true); { // Silence extension warnings in the sub-expression ExtensionRAIIObject O(Diags); LHS = ParseCastExpression(AnyCastExpr); } if (!LHS.isInvalid()) LHS = Actions.ActOnUnaryOp(getCurScope(), ExtLoc, tok::kw___extension__, LHS.get()); return ParseRHSOfBinaryExpression(LHS, prec::Comma); } /// Parse an expr that doesn't include (top-level) commas. ExprResult Parser::ParseAssignmentExpression(TypeCastState isTypeCast) { if (Tok.is(tok::code_completion)) { Actions.CodeCompleteExpression(getCurScope(), PreferredType.get(Tok.getLocation())); cutOffParsing(); return ExprError(); } if (Tok.is(tok::kw_throw)) return ParseThrowExpression(); if (Tok.is(tok::kw_co_yield)) return ParseCoyieldExpression(); ExprResult LHS = ParseCastExpression(AnyCastExpr, /*isAddressOfOperand=*/false, isTypeCast); return ParseRHSOfBinaryExpression(LHS, prec::Assignment); } /// Parse an assignment expression where part of an Objective-C message /// send has already been parsed. /// /// In this case \p LBracLoc indicates the location of the '[' of the message /// send, and either \p ReceiverName or \p ReceiverExpr is non-null indicating /// the receiver of the message. /// /// Since this handles full assignment-expression's, it handles postfix /// expressions and other binary operators for these expressions as well. ExprResult Parser::ParseAssignmentExprWithObjCMessageExprStart(SourceLocation LBracLoc, SourceLocation SuperLoc, ParsedType ReceiverType, Expr *ReceiverExpr) { ExprResult R = ParseObjCMessageExpressionBody(LBracLoc, SuperLoc, ReceiverType, ReceiverExpr); R = ParsePostfixExpressionSuffix(R); return ParseRHSOfBinaryExpression(R, prec::Assignment); } ExprResult Parser::ParseConstantExpressionInExprEvalContext(TypeCastState isTypeCast) { assert(Actions.ExprEvalContexts.back().Context == Sema::ExpressionEvaluationContext::ConstantEvaluated && "Call this function only if your ExpressionEvaluationContext is " "already ConstantEvaluated"); ExprResult LHS(ParseCastExpression(AnyCastExpr, false, isTypeCast)); ExprResult Res(ParseRHSOfBinaryExpression(LHS, prec::Conditional)); return Actions.ActOnConstantExpression(Res); } ExprResult Parser::ParseConstantExpression(TypeCastState isTypeCast) { // C++03 [basic.def.odr]p2: // An expression is potentially evaluated unless it appears where an // integral constant expression is required (see 5.19) [...]. // C++98 and C++11 have no such rule, but this is only a defect in C++98. EnterExpressionEvaluationContext ConstantEvaluated( Actions, Sema::ExpressionEvaluationContext::ConstantEvaluated); return ParseConstantExpressionInExprEvalContext(isTypeCast); } ExprResult Parser::ParseCaseExpression(SourceLocation CaseLoc) { EnterExpressionEvaluationContext ConstantEvaluated( Actions, Sema::ExpressionEvaluationContext::ConstantEvaluated); ExprResult LHS(ParseCastExpression(AnyCastExpr, false, NotTypeCast)); ExprResult Res(ParseRHSOfBinaryExpression(LHS, prec::Conditional)); return Actions.ActOnCaseExpr(CaseLoc, Res); } /// Parse a constraint-expression. /// /// \verbatim /// constraint-expression: C++2a[temp.constr.decl]p1 /// logical-or-expression /// \endverbatim ExprResult Parser::ParseConstraintExpression() { EnterExpressionEvaluationContext ConstantEvaluated( Actions, Sema::ExpressionEvaluationContext::Unevaluated); ExprResult LHS(ParseCastExpression(AnyCastExpr)); ExprResult Res(ParseRHSOfBinaryExpression(LHS, prec::LogicalOr)); if (Res.isUsable() && !Actions.CheckConstraintExpression(Res.get())) { Actions.CorrectDelayedTyposInExpr(Res); return ExprError(); } return Res; } /// \brief Parse a constraint-logical-and-expression. /// /// \verbatim /// C++2a[temp.constr.decl]p1 /// constraint-logical-and-expression: /// primary-expression /// constraint-logical-and-expression '&&' primary-expression /// /// \endverbatim ExprResult Parser::ParseConstraintLogicalAndExpression(bool IsTrailingRequiresClause) { EnterExpressionEvaluationContext ConstantEvaluated( Actions, Sema::ExpressionEvaluationContext::Unevaluated); bool NotPrimaryExpression = false; auto ParsePrimary = [&] () { ExprResult E = ParseCastExpression(PrimaryExprOnly, /*isAddressOfOperand=*/false, /*isTypeCast=*/NotTypeCast, /*isVectorLiteral=*/false, &NotPrimaryExpression); if (E.isInvalid()) return ExprError(); auto RecoverFromNonPrimary = [&] (ExprResult E, bool Note) { E = ParsePostfixExpressionSuffix(E); // Use InclusiveOr, the precedence just after '&&' to not parse the // next arguments to the logical and. E = ParseRHSOfBinaryExpression(E, prec::InclusiveOr); if (!E.isInvalid()) Diag(E.get()->getExprLoc(), Note ? diag::note_unparenthesized_non_primary_expr_in_requires_clause : diag::err_unparenthesized_non_primary_expr_in_requires_clause) << FixItHint::CreateInsertion(E.get()->getBeginLoc(), "(") << FixItHint::CreateInsertion( PP.getLocForEndOfToken(E.get()->getEndLoc()), ")") << E.get()->getSourceRange(); return E; }; if (NotPrimaryExpression || // Check if the following tokens must be a part of a non-primary // expression getBinOpPrecedence(Tok.getKind(), GreaterThanIsOperator, /*CPlusPlus11=*/true) > prec::LogicalAnd || // Postfix operators other than '(' (which will be checked for in // CheckConstraintExpression). Tok.isOneOf(tok::period, tok::plusplus, tok::minusminus) || (Tok.is(tok::l_square) && !NextToken().is(tok::l_square))) { E = RecoverFromNonPrimary(E, /*Note=*/false); if (E.isInvalid()) return ExprError(); NotPrimaryExpression = false; } bool PossibleNonPrimary; bool IsConstraintExpr = Actions.CheckConstraintExpression(E.get(), Tok, &PossibleNonPrimary, IsTrailingRequiresClause); if (!IsConstraintExpr || PossibleNonPrimary) { // Atomic constraint might be an unparenthesized non-primary expression // (such as a binary operator), in which case we might get here (e.g. in // 'requires 0 + 1 && true' we would now be at '+', and parse and ignore // the rest of the addition expression). Try to parse the rest of it here. if (PossibleNonPrimary) E = RecoverFromNonPrimary(E, /*Note=*/!IsConstraintExpr); Actions.CorrectDelayedTyposInExpr(E); return ExprError(); } return E; }; ExprResult LHS = ParsePrimary(); if (LHS.isInvalid()) return ExprError(); while (Tok.is(tok::ampamp)) { SourceLocation LogicalAndLoc = ConsumeToken(); ExprResult RHS = ParsePrimary(); if (RHS.isInvalid()) { Actions.CorrectDelayedTyposInExpr(LHS); return ExprError(); } ExprResult Op = Actions.ActOnBinOp(getCurScope(), LogicalAndLoc, tok::ampamp, LHS.get(), RHS.get()); if (!Op.isUsable()) { Actions.CorrectDelayedTyposInExpr(RHS); Actions.CorrectDelayedTyposInExpr(LHS); return ExprError(); } LHS = Op; } return LHS; } /// \brief Parse a constraint-logical-or-expression. /// /// \verbatim /// C++2a[temp.constr.decl]p1 /// constraint-logical-or-expression: /// constraint-logical-and-expression /// constraint-logical-or-expression '||' /// constraint-logical-and-expression /// /// \endverbatim ExprResult Parser::ParseConstraintLogicalOrExpression(bool IsTrailingRequiresClause) { ExprResult LHS(ParseConstraintLogicalAndExpression(IsTrailingRequiresClause)); if (!LHS.isUsable()) return ExprError(); while (Tok.is(tok::pipepipe)) { SourceLocation LogicalOrLoc = ConsumeToken(); ExprResult RHS = ParseConstraintLogicalAndExpression(IsTrailingRequiresClause); if (!RHS.isUsable()) { Actions.CorrectDelayedTyposInExpr(LHS); return ExprError(); } ExprResult Op = Actions.ActOnBinOp(getCurScope(), LogicalOrLoc, tok::pipepipe, LHS.get(), RHS.get()); if (!Op.isUsable()) { Actions.CorrectDelayedTyposInExpr(RHS); Actions.CorrectDelayedTyposInExpr(LHS); return ExprError(); } LHS = Op; } return LHS; } bool Parser::isNotExpressionStart() { tok::TokenKind K = Tok.getKind(); if (K == tok::l_brace || K == tok::r_brace || K == tok::kw_for || K == tok::kw_while || K == tok::kw_if || K == tok::kw_else || K == tok::kw_goto || K == tok::kw_try) return true; // If this is a decl-specifier, we can't be at the start of an expression. return isKnownToBeDeclarationSpecifier(); } bool Parser::isFoldOperator(prec::Level Level) const { return Level > prec::Unknown && Level != prec::Conditional && Level != prec::Spaceship; } bool Parser::isFoldOperator(tok::TokenKind Kind) const { return isFoldOperator(getBinOpPrecedence(Kind, GreaterThanIsOperator, true)); } /// Parse a binary expression that starts with \p LHS and has a /// precedence of at least \p MinPrec. ExprResult Parser::ParseRHSOfBinaryExpression(ExprResult LHS, prec::Level MinPrec) { prec::Level NextTokPrec = getBinOpPrecedence(Tok.getKind(), GreaterThanIsOperator, getLangOpts().CPlusPlus11); SourceLocation ColonLoc; auto SavedType = PreferredType; while (1) { // Every iteration may rely on a preferred type for the whole expression. PreferredType = SavedType; // If this token has a lower precedence than we are allowed to parse (e.g. // because we are called recursively, or because the token is not a binop), // then we are done! if (NextTokPrec < MinPrec) return LHS; // Consume the operator, saving the operator token for error reporting. Token OpToken = Tok; ConsumeToken(); if (OpToken.is(tok::caretcaret)) { return ExprError(Diag(Tok, diag::err_opencl_logical_exclusive_or)); } // If we're potentially in a template-id, we may now be able to determine // whether we're actually in one or not. if (OpToken.isOneOf(tok::comma, tok::greater, tok::greatergreater, tok::greatergreatergreater) && checkPotentialAngleBracketDelimiter(OpToken)) return ExprError(); // Bail out when encountering a comma followed by a token which can't // possibly be the start of an expression. For instance: // int f() { return 1, } // We can't do this before consuming the comma, because // isNotExpressionStart() looks at the token stream. if (OpToken.is(tok::comma) && isNotExpressionStart()) { PP.EnterToken(Tok, /*IsReinject*/true); Tok = OpToken; return LHS; } // If the next token is an ellipsis, then this is a fold-expression. Leave // it alone so we can handle it in the paren expression. if (isFoldOperator(NextTokPrec) && Tok.is(tok::ellipsis)) { // FIXME: We can't check this via lookahead before we consume the token // because that tickles a lexer bug. PP.EnterToken(Tok, /*IsReinject*/true); Tok = OpToken; return LHS; } // In Objective-C++, alternative operator tokens can be used as keyword args // in message expressions. Unconsume the token so that it can reinterpreted // as an identifier in ParseObjCMessageExpressionBody. i.e., we support: // [foo meth:0 and:0]; // [foo not_eq]; if (getLangOpts().ObjC && getLangOpts().CPlusPlus && Tok.isOneOf(tok::colon, tok::r_square) && OpToken.getIdentifierInfo() != nullptr) { PP.EnterToken(Tok, /*IsReinject*/true); Tok = OpToken; return LHS; } // Special case handling for the ternary operator. ExprResult TernaryMiddle(true); if (NextTokPrec == prec::Conditional) { if (getLangOpts().CPlusPlus11 && Tok.is(tok::l_brace)) { // Parse a braced-init-list here for error recovery purposes. SourceLocation BraceLoc = Tok.getLocation(); TernaryMiddle = ParseBraceInitializer(); if (!TernaryMiddle.isInvalid()) { Diag(BraceLoc, diag::err_init_list_bin_op) << /*RHS*/ 1 << PP.getSpelling(OpToken) << Actions.getExprRange(TernaryMiddle.get()); TernaryMiddle = ExprError(); } } else if (Tok.isNot(tok::colon)) { // Don't parse FOO:BAR as if it were a typo for FOO::BAR. ColonProtectionRAIIObject X(*this); // Handle this production specially: // logical-OR-expression '?' expression ':' conditional-expression // In particular, the RHS of the '?' is 'expression', not // 'logical-OR-expression' as we might expect. TernaryMiddle = ParseExpression(); } else { // Special case handling of "X ? Y : Z" where Y is empty: // logical-OR-expression '?' ':' conditional-expression [GNU] TernaryMiddle = nullptr; Diag(Tok, diag::ext_gnu_conditional_expr); } if (TernaryMiddle.isInvalid()) { Actions.CorrectDelayedTyposInExpr(LHS); LHS = ExprError(); TernaryMiddle = nullptr; } if (!TryConsumeToken(tok::colon, ColonLoc)) { // Otherwise, we're missing a ':'. Assume that this was a typo that // the user forgot. If we're not in a macro expansion, we can suggest // a fixit hint. If there were two spaces before the current token, // suggest inserting the colon in between them, otherwise insert ": ". SourceLocation FILoc = Tok.getLocation(); const char *FIText = ": "; const SourceManager &SM = PP.getSourceManager(); if (FILoc.isFileID() || PP.isAtStartOfMacroExpansion(FILoc, &FILoc)) { assert(FILoc.isFileID()); bool IsInvalid = false; const char *SourcePtr = SM.getCharacterData(FILoc.getLocWithOffset(-1), &IsInvalid); if (!IsInvalid && *SourcePtr == ' ') { SourcePtr = SM.getCharacterData(FILoc.getLocWithOffset(-2), &IsInvalid); if (!IsInvalid && *SourcePtr == ' ') { FILoc = FILoc.getLocWithOffset(-1); FIText = ":"; } } } Diag(Tok, diag::err_expected) << tok::colon << FixItHint::CreateInsertion(FILoc, FIText); Diag(OpToken, diag::note_matching) << tok::question; ColonLoc = Tok.getLocation(); } } PreferredType.enterBinary(Actions, Tok.getLocation(), LHS.get(), OpToken.getKind()); // Parse another leaf here for the RHS of the operator. // ParseCastExpression works here because all RHS expressions in C have it // as a prefix, at least. However, in C++, an assignment-expression could // be a throw-expression, which is not a valid cast-expression. // Therefore we need some special-casing here. // Also note that the third operand of the conditional operator is // an assignment-expression in C++, and in C++11, we can have a // braced-init-list on the RHS of an assignment. For better diagnostics, // parse as if we were allowed braced-init-lists everywhere, and check that // they only appear on the RHS of assignments later. ExprResult RHS; bool RHSIsInitList = false; if (getLangOpts().CPlusPlus11 && Tok.is(tok::l_brace)) { RHS = ParseBraceInitializer(); RHSIsInitList = true; } else if (getLangOpts().CPlusPlus && NextTokPrec <= prec::Conditional) RHS = ParseAssignmentExpression(); else RHS = ParseCastExpression(AnyCastExpr); if (RHS.isInvalid()) { // FIXME: Errors generated by the delayed typo correction should be // printed before errors from parsing the RHS, not after. Actions.CorrectDelayedTyposInExpr(LHS); if (TernaryMiddle.isUsable()) TernaryMiddle = Actions.CorrectDelayedTyposInExpr(TernaryMiddle); LHS = ExprError(); } // Remember the precedence of this operator and get the precedence of the // operator immediately to the right of the RHS. prec::Level ThisPrec = NextTokPrec; NextTokPrec = getBinOpPrecedence(Tok.getKind(), GreaterThanIsOperator, getLangOpts().CPlusPlus11); // Assignment and conditional expressions are right-associative. bool isRightAssoc = ThisPrec == prec::Conditional || ThisPrec == prec::Assignment; // Get the precedence of the operator to the right of the RHS. If it binds // more tightly with RHS than we do, evaluate it completely first. if (ThisPrec < NextTokPrec || (ThisPrec == NextTokPrec && isRightAssoc)) { if (!RHS.isInvalid() && RHSIsInitList) { Diag(Tok, diag::err_init_list_bin_op) << /*LHS*/0 << PP.getSpelling(Tok) << Actions.getExprRange(RHS.get()); RHS = ExprError(); } // If this is left-associative, only parse things on the RHS that bind // more tightly than the current operator. If it is left-associative, it // is okay, to bind exactly as tightly. For example, compile A=B=C=D as // A=(B=(C=D)), where each paren is a level of recursion here. // The function takes ownership of the RHS. RHS = ParseRHSOfBinaryExpression(RHS, static_cast(ThisPrec + !isRightAssoc)); RHSIsInitList = false; if (RHS.isInvalid()) { // FIXME: Errors generated by the delayed typo correction should be // printed before errors from ParseRHSOfBinaryExpression, not after. Actions.CorrectDelayedTyposInExpr(LHS); if (TernaryMiddle.isUsable()) TernaryMiddle = Actions.CorrectDelayedTyposInExpr(TernaryMiddle); LHS = ExprError(); } NextTokPrec = getBinOpPrecedence(Tok.getKind(), GreaterThanIsOperator, getLangOpts().CPlusPlus11); } if (!RHS.isInvalid() && RHSIsInitList) { if (ThisPrec == prec::Assignment) { Diag(OpToken, diag::warn_cxx98_compat_generalized_initializer_lists) << Actions.getExprRange(RHS.get()); } else if (ColonLoc.isValid()) { Diag(ColonLoc, diag::err_init_list_bin_op) << /*RHS*/1 << ":" << Actions.getExprRange(RHS.get()); LHS = ExprError(); } else { Diag(OpToken, diag::err_init_list_bin_op) << /*RHS*/1 << PP.getSpelling(OpToken) << Actions.getExprRange(RHS.get()); LHS = ExprError(); } } ExprResult OrigLHS = LHS; if (!LHS.isInvalid()) { // Combine the LHS and RHS into the LHS (e.g. build AST). if (TernaryMiddle.isInvalid()) { // If we're using '>>' as an operator within a template // argument list (in C++98), suggest the addition of // parentheses so that the code remains well-formed in C++0x. if (!GreaterThanIsOperator && OpToken.is(tok::greatergreater)) SuggestParentheses(OpToken.getLocation(), diag::warn_cxx11_right_shift_in_template_arg, SourceRange(Actions.getExprRange(LHS.get()).getBegin(), Actions.getExprRange(RHS.get()).getEnd())); LHS = Actions.ActOnBinOp(getCurScope(), OpToken.getLocation(), OpToken.getKind(), LHS.get(), RHS.get()); } else { LHS = Actions.ActOnConditionalOp(OpToken.getLocation(), ColonLoc, LHS.get(), TernaryMiddle.get(), RHS.get()); } // In this case, ActOnBinOp or ActOnConditionalOp performed the // CorrectDelayedTyposInExpr check. if (!getLangOpts().CPlusPlus) continue; } // Ensure potential typos aren't left undiagnosed. if (LHS.isInvalid()) { Actions.CorrectDelayedTyposInExpr(OrigLHS); Actions.CorrectDelayedTyposInExpr(TernaryMiddle); Actions.CorrectDelayedTyposInExpr(RHS); } } } /// Parse a cast-expression, unary-expression or primary-expression, based /// on \p ExprType. /// /// \p isAddressOfOperand exists because an id-expression that is the /// operand of address-of gets special treatment due to member pointers. /// ExprResult Parser::ParseCastExpression(CastParseKind ParseKind, bool isAddressOfOperand, TypeCastState isTypeCast, bool isVectorLiteral, bool *NotPrimaryExpression) { bool NotCastExpr; ExprResult Res = ParseCastExpression(ParseKind, isAddressOfOperand, NotCastExpr, isTypeCast, isVectorLiteral, NotPrimaryExpression); if (NotCastExpr) Diag(Tok, diag::err_expected_expression); return Res; } namespace { class CastExpressionIdValidator final : public CorrectionCandidateCallback { public: CastExpressionIdValidator(Token Next, bool AllowTypes, bool AllowNonTypes) : NextToken(Next), AllowNonTypes(AllowNonTypes) { WantTypeSpecifiers = WantFunctionLikeCasts = AllowTypes; } bool ValidateCandidate(const TypoCorrection &candidate) override { NamedDecl *ND = candidate.getCorrectionDecl(); if (!ND) return candidate.isKeyword(); if (isa(ND)) return WantTypeSpecifiers; if (!AllowNonTypes || !CorrectionCandidateCallback::ValidateCandidate(candidate)) return false; if (!NextToken.isOneOf(tok::equal, tok::arrow, tok::period)) return true; for (auto *C : candidate) { NamedDecl *ND = C->getUnderlyingDecl(); if (isa(ND) && !isa(ND)) return true; } return false; } std::unique_ptr clone() override { return std::make_unique(*this); } private: Token NextToken; bool AllowNonTypes; }; } /// Parse a cast-expression, or, if \pisUnaryExpression is true, parse /// a unary-expression. /// /// \p isAddressOfOperand exists because an id-expression that is the operand /// of address-of gets special treatment due to member pointers. NotCastExpr /// is set to true if the token is not the start of a cast-expression, and no /// diagnostic is emitted in this case and no tokens are consumed. /// /// \verbatim /// cast-expression: [C99 6.5.4] /// unary-expression /// '(' type-name ')' cast-expression /// /// unary-expression: [C99 6.5.3] /// postfix-expression /// '++' unary-expression /// '--' unary-expression /// [Coro] 'co_await' cast-expression /// unary-operator cast-expression /// 'sizeof' unary-expression /// 'sizeof' '(' type-name ')' /// [C++11] 'sizeof' '...' '(' identifier ')' /// [GNU] '__alignof' unary-expression /// [GNU] '__alignof' '(' type-name ')' /// [C11] '_Alignof' '(' type-name ')' /// [C++11] 'alignof' '(' type-id ')' /// [GNU] '&&' identifier /// [C++11] 'noexcept' '(' expression ')' [C++11 5.3.7] /// [C++] new-expression /// [C++] delete-expression /// /// unary-operator: one of /// '&' '*' '+' '-' '~' '!' /// [GNU] '__extension__' '__real' '__imag' /// /// primary-expression: [C99 6.5.1] /// [C99] identifier /// [C++] id-expression /// constant /// string-literal /// [C++] boolean-literal [C++ 2.13.5] /// [C++11] 'nullptr' [C++11 2.14.7] /// [C++11] user-defined-literal /// '(' expression ')' /// [C11] generic-selection /// [C++2a] requires-expression /// '__func__' [C99 6.4.2.2] /// [GNU] '__FUNCTION__' /// [MS] '__FUNCDNAME__' /// [MS] 'L__FUNCTION__' /// [MS] '__FUNCSIG__' /// [MS] 'L__FUNCSIG__' /// [GNU] '__PRETTY_FUNCTION__' /// [GNU] '(' compound-statement ')' /// [GNU] '__builtin_va_arg' '(' assignment-expression ',' type-name ')' /// [GNU] '__builtin_offsetof' '(' type-name ',' offsetof-member-designator')' /// [GNU] '__builtin_choose_expr' '(' assign-expr ',' assign-expr ',' /// assign-expr ')' /// [GNU] '__builtin_FILE' '(' ')' /// [GNU] '__builtin_FUNCTION' '(' ')' /// [GNU] '__builtin_LINE' '(' ')' /// [CLANG] '__builtin_COLUMN' '(' ')' /// [GNU] '__builtin_types_compatible_p' '(' type-name ',' type-name ')' /// [GNU] '__null' /// [OBJC] '[' objc-message-expr ']' /// [OBJC] '\@selector' '(' objc-selector-arg ')' /// [OBJC] '\@protocol' '(' identifier ')' /// [OBJC] '\@encode' '(' type-name ')' /// [OBJC] objc-string-literal /// [C++] simple-type-specifier '(' expression-list[opt] ')' [C++ 5.2.3] /// [C++11] simple-type-specifier braced-init-list [C++11 5.2.3] /// [C++] typename-specifier '(' expression-list[opt] ')' [C++ 5.2.3] /// [C++11] typename-specifier braced-init-list [C++11 5.2.3] /// [C++] 'const_cast' '<' type-name '>' '(' expression ')' [C++ 5.2p1] /// [C++] 'dynamic_cast' '<' type-name '>' '(' expression ')' [C++ 5.2p1] /// [C++] 'reinterpret_cast' '<' type-name '>' '(' expression ')' [C++ 5.2p1] /// [C++] 'static_cast' '<' type-name '>' '(' expression ')' [C++ 5.2p1] /// [C++] 'typeid' '(' expression ')' [C++ 5.2p1] /// [C++] 'typeid' '(' type-id ')' [C++ 5.2p1] /// [C++] 'this' [C++ 9.3.2] /// [G++] unary-type-trait '(' type-id ')' /// [G++] binary-type-trait '(' type-id ',' type-id ')' [TODO] /// [EMBT] array-type-trait '(' type-id ',' integer ')' /// [clang] '^' block-literal /// /// constant: [C99 6.4.4] /// integer-constant /// floating-constant /// enumeration-constant -> identifier /// character-constant /// /// id-expression: [C++ 5.1] /// unqualified-id /// qualified-id /// /// unqualified-id: [C++ 5.1] /// identifier /// operator-function-id /// conversion-function-id /// '~' class-name /// template-id /// /// new-expression: [C++ 5.3.4] /// '::'[opt] 'new' new-placement[opt] new-type-id /// new-initializer[opt] /// '::'[opt] 'new' new-placement[opt] '(' type-id ')' /// new-initializer[opt] /// /// delete-expression: [C++ 5.3.5] /// '::'[opt] 'delete' cast-expression /// '::'[opt] 'delete' '[' ']' cast-expression /// /// [GNU/Embarcadero] unary-type-trait: /// '__is_arithmetic' /// '__is_floating_point' /// '__is_integral' /// '__is_lvalue_expr' /// '__is_rvalue_expr' /// '__is_complete_type' /// '__is_void' /// '__is_array' /// '__is_function' /// '__is_reference' /// '__is_lvalue_reference' /// '__is_rvalue_reference' /// '__is_fundamental' /// '__is_object' /// '__is_scalar' /// '__is_compound' /// '__is_pointer' /// '__is_member_object_pointer' /// '__is_member_function_pointer' /// '__is_member_pointer' /// '__is_const' /// '__is_volatile' /// '__is_trivial' /// '__is_standard_layout' /// '__is_signed' /// '__is_unsigned' /// /// [GNU] unary-type-trait: /// '__has_nothrow_assign' /// '__has_nothrow_copy' /// '__has_nothrow_constructor' /// '__has_trivial_assign' [TODO] /// '__has_trivial_copy' [TODO] /// '__has_trivial_constructor' /// '__has_trivial_destructor' /// '__has_virtual_destructor' /// '__is_abstract' [TODO] /// '__is_class' /// '__is_empty' [TODO] /// '__is_enum' /// '__is_final' /// '__is_pod' /// '__is_polymorphic' /// '__is_sealed' [MS] /// '__is_trivial' /// '__is_union' /// '__has_unique_object_representations' /// /// [Clang] unary-type-trait: /// '__is_aggregate' /// '__trivially_copyable' /// /// binary-type-trait: /// [GNU] '__is_base_of' /// [MS] '__is_convertible_to' /// '__is_convertible' /// '__is_same' /// /// [Embarcadero] array-type-trait: /// '__array_rank' /// '__array_extent' /// /// [Embarcadero] expression-trait: /// '__is_lvalue_expr' /// '__is_rvalue_expr' /// \endverbatim /// ExprResult Parser::ParseCastExpression(CastParseKind ParseKind, bool isAddressOfOperand, bool &NotCastExpr, TypeCastState isTypeCast, bool isVectorLiteral, bool *NotPrimaryExpression) { ExprResult Res; tok::TokenKind SavedKind = Tok.getKind(); auto SavedType = PreferredType; NotCastExpr = false; // This handles all of cast-expression, unary-expression, postfix-expression, // and primary-expression. We handle them together like this for efficiency // and to simplify handling of an expression starting with a '(' token: which // may be one of a parenthesized expression, cast-expression, compound literal // expression, or statement expression. // // If the parsed tokens consist of a primary-expression, the cases below // break out of the switch; at the end we call ParsePostfixExpressionSuffix // to handle the postfix expression suffixes. Cases that cannot be followed // by postfix exprs should return without invoking // ParsePostfixExpressionSuffix. switch (SavedKind) { case tok::l_paren: { // If this expression is limited to being a unary-expression, the paren can // not start a cast expression. ParenParseOption ParenExprType; switch (ParseKind) { case CastParseKind::UnaryExprOnly: if (!getLangOpts().CPlusPlus) ParenExprType = CompoundLiteral; LLVM_FALLTHROUGH; case CastParseKind::AnyCastExpr: ParenExprType = ParenParseOption::CastExpr; break; case CastParseKind::PrimaryExprOnly: ParenExprType = FoldExpr; break; } ParsedType CastTy; SourceLocation RParenLoc; Res = ParseParenExpression(ParenExprType, false/*stopIfCastExr*/, isTypeCast == IsTypeCast, CastTy, RParenLoc); if (isVectorLiteral) return Res; switch (ParenExprType) { case SimpleExpr: break; // Nothing else to do. case CompoundStmt: break; // Nothing else to do. case CompoundLiteral: // We parsed '(' type-name ')' '{' ... '}'. If any suffixes of // postfix-expression exist, parse them now. break; case CastExpr: // We have parsed the cast-expression and no postfix-expr pieces are // following. return Res; case FoldExpr: // We only parsed a fold-expression. There might be postfix-expr pieces // afterwards; parse them now. break; } break; } // primary-expression case tok::numeric_constant: // constant: integer-constant // constant: floating-constant Res = Actions.ActOnNumericConstant(Tok, /*UDLScope*/getCurScope()); ConsumeToken(); break; case tok::kw_true: case tok::kw_false: Res = ParseCXXBoolLiteral(); break; case tok::kw___objc_yes: case tok::kw___objc_no: return ParseObjCBoolLiteral(); case tok::kw_nullptr: Diag(Tok, diag::warn_cxx98_compat_nullptr); return Actions.ActOnCXXNullPtrLiteral(ConsumeToken()); case tok::annot_primary_expr: Res = getExprAnnotation(Tok); ConsumeAnnotationToken(); if (!Res.isInvalid() && Tok.is(tok::less)) checkPotentialAngleBracket(Res); break; case tok::annot_non_type: case tok::annot_non_type_dependent: case tok::annot_non_type_undeclared: { CXXScopeSpec SS; Token Replacement; Res = tryParseCXXIdExpression(SS, isAddressOfOperand, Replacement); assert(!Res.isUnset() && "should not perform typo correction on annotation token"); break; } case tok::kw___super: case tok::kw_decltype: // Annotate the token and tail recurse. if (TryAnnotateTypeOrScopeToken()) return ExprError(); assert(Tok.isNot(tok::kw_decltype) && Tok.isNot(tok::kw___super)); return ParseCastExpression(ParseKind, isAddressOfOperand, isTypeCast, isVectorLiteral, NotPrimaryExpression); case tok::identifier: { // primary-expression: identifier // unqualified-id: identifier // constant: enumeration-constant // Turn a potentially qualified name into a annot_typename or // annot_cxxscope if it would be valid. This handles things like x::y, etc. if (getLangOpts().CPlusPlus) { // Avoid the unnecessary parse-time lookup in the common case // where the syntax forbids a type. const Token &Next = NextToken(); // If this identifier was reverted from a token ID, and the next token // is a parenthesis, this is likely to be a use of a type trait. Check // those tokens. if (Next.is(tok::l_paren) && Tok.is(tok::identifier) && Tok.getIdentifierInfo()->hasRevertedTokenIDToIdentifier()) { IdentifierInfo *II = Tok.getIdentifierInfo(); // Build up the mapping of revertible type traits, for future use. if (RevertibleTypeTraits.empty()) { #define RTT_JOIN(X,Y) X##Y #define REVERTIBLE_TYPE_TRAIT(Name) \ RevertibleTypeTraits[PP.getIdentifierInfo(#Name)] \ = RTT_JOIN(tok::kw_,Name) REVERTIBLE_TYPE_TRAIT(__is_abstract); REVERTIBLE_TYPE_TRAIT(__is_aggregate); REVERTIBLE_TYPE_TRAIT(__is_arithmetic); REVERTIBLE_TYPE_TRAIT(__is_array); REVERTIBLE_TYPE_TRAIT(__is_assignable); REVERTIBLE_TYPE_TRAIT(__is_base_of); REVERTIBLE_TYPE_TRAIT(__is_class); REVERTIBLE_TYPE_TRAIT(__is_complete_type); REVERTIBLE_TYPE_TRAIT(__is_compound); REVERTIBLE_TYPE_TRAIT(__is_const); REVERTIBLE_TYPE_TRAIT(__is_constructible); REVERTIBLE_TYPE_TRAIT(__is_convertible); REVERTIBLE_TYPE_TRAIT(__is_convertible_to); REVERTIBLE_TYPE_TRAIT(__is_destructible); REVERTIBLE_TYPE_TRAIT(__is_empty); REVERTIBLE_TYPE_TRAIT(__is_enum); REVERTIBLE_TYPE_TRAIT(__is_floating_point); REVERTIBLE_TYPE_TRAIT(__is_final); REVERTIBLE_TYPE_TRAIT(__is_function); REVERTIBLE_TYPE_TRAIT(__is_fundamental); REVERTIBLE_TYPE_TRAIT(__is_integral); REVERTIBLE_TYPE_TRAIT(__is_interface_class); REVERTIBLE_TYPE_TRAIT(__is_literal); REVERTIBLE_TYPE_TRAIT(__is_lvalue_expr); REVERTIBLE_TYPE_TRAIT(__is_lvalue_reference); REVERTIBLE_TYPE_TRAIT(__is_member_function_pointer); REVERTIBLE_TYPE_TRAIT(__is_member_object_pointer); REVERTIBLE_TYPE_TRAIT(__is_member_pointer); REVERTIBLE_TYPE_TRAIT(__is_nothrow_assignable); REVERTIBLE_TYPE_TRAIT(__is_nothrow_constructible); REVERTIBLE_TYPE_TRAIT(__is_nothrow_destructible); REVERTIBLE_TYPE_TRAIT(__is_object); REVERTIBLE_TYPE_TRAIT(__is_pod); REVERTIBLE_TYPE_TRAIT(__is_pointer); REVERTIBLE_TYPE_TRAIT(__is_polymorphic); REVERTIBLE_TYPE_TRAIT(__is_reference); REVERTIBLE_TYPE_TRAIT(__is_rvalue_expr); REVERTIBLE_TYPE_TRAIT(__is_rvalue_reference); REVERTIBLE_TYPE_TRAIT(__is_same); REVERTIBLE_TYPE_TRAIT(__is_scalar); REVERTIBLE_TYPE_TRAIT(__is_sealed); REVERTIBLE_TYPE_TRAIT(__is_signed); REVERTIBLE_TYPE_TRAIT(__is_standard_layout); REVERTIBLE_TYPE_TRAIT(__is_trivial); REVERTIBLE_TYPE_TRAIT(__is_trivially_assignable); REVERTIBLE_TYPE_TRAIT(__is_trivially_constructible); REVERTIBLE_TYPE_TRAIT(__is_trivially_copyable); REVERTIBLE_TYPE_TRAIT(__is_union); REVERTIBLE_TYPE_TRAIT(__is_unsigned); REVERTIBLE_TYPE_TRAIT(__is_void); REVERTIBLE_TYPE_TRAIT(__is_volatile); #undef REVERTIBLE_TYPE_TRAIT #undef RTT_JOIN } // If we find that this is in fact the name of a type trait, // update the token kind in place and parse again to treat it as // the appropriate kind of type trait. llvm::SmallDenseMap::iterator Known = RevertibleTypeTraits.find(II); if (Known != RevertibleTypeTraits.end()) { Tok.setKind(Known->second); return ParseCastExpression(ParseKind, isAddressOfOperand, NotCastExpr, isTypeCast, isVectorLiteral, NotPrimaryExpression); } } if ((!ColonIsSacred && Next.is(tok::colon)) || Next.isOneOf(tok::coloncolon, tok::less, tok::l_paren, tok::l_brace)) { // If TryAnnotateTypeOrScopeToken annotates the token, tail recurse. if (TryAnnotateTypeOrScopeToken()) return ExprError(); if (!Tok.is(tok::identifier)) return ParseCastExpression(ParseKind, isAddressOfOperand, NotCastExpr, isTypeCast, isVectorLiteral, NotPrimaryExpression); } } // Consume the identifier so that we can see if it is followed by a '(' or // '.'. IdentifierInfo &II = *Tok.getIdentifierInfo(); SourceLocation ILoc = ConsumeToken(); // Support 'Class.property' and 'super.property' notation. if (getLangOpts().ObjC && Tok.is(tok::period) && (Actions.getTypeName(II, ILoc, getCurScope()) || // Allow the base to be 'super' if in an objc-method. (&II == Ident_super && getCurScope()->isInObjcMethodScope()))) { ConsumeToken(); if (Tok.is(tok::code_completion) && &II != Ident_super) { Actions.CodeCompleteObjCClassPropertyRefExpr( getCurScope(), II, ILoc, ExprStatementTokLoc == ILoc); cutOffParsing(); return ExprError(); } // Allow either an identifier or the keyword 'class' (in C++). if (Tok.isNot(tok::identifier) && !(getLangOpts().CPlusPlus && Tok.is(tok::kw_class))) { Diag(Tok, diag::err_expected_property_name); return ExprError(); } IdentifierInfo &PropertyName = *Tok.getIdentifierInfo(); SourceLocation PropertyLoc = ConsumeToken(); Res = Actions.ActOnClassPropertyRefExpr(II, PropertyName, ILoc, PropertyLoc); break; } // In an Objective-C method, if we have "super" followed by an identifier, // the token sequence is ill-formed. However, if there's a ':' or ']' after // that identifier, this is probably a message send with a missing open // bracket. Treat it as such. if (getLangOpts().ObjC && &II == Ident_super && !InMessageExpression && getCurScope()->isInObjcMethodScope() && ((Tok.is(tok::identifier) && (NextToken().is(tok::colon) || NextToken().is(tok::r_square))) || Tok.is(tok::code_completion))) { Res = ParseObjCMessageExpressionBody(SourceLocation(), ILoc, nullptr, nullptr); break; } // If we have an Objective-C class name followed by an identifier // and either ':' or ']', this is an Objective-C class message // send that's missing the opening '['. Recovery // appropriately. Also take this path if we're performing code // completion after an Objective-C class name. if (getLangOpts().ObjC && ((Tok.is(tok::identifier) && !InMessageExpression) || Tok.is(tok::code_completion))) { const Token& Next = NextToken(); if (Tok.is(tok::code_completion) || Next.is(tok::colon) || Next.is(tok::r_square)) if (ParsedType Typ = Actions.getTypeName(II, ILoc, getCurScope())) if (Typ.get()->isObjCObjectOrInterfaceType()) { // Fake up a Declarator to use with ActOnTypeName. DeclSpec DS(AttrFactory); DS.SetRangeStart(ILoc); DS.SetRangeEnd(ILoc); const char *PrevSpec = nullptr; unsigned DiagID; DS.SetTypeSpecType(TST_typename, ILoc, PrevSpec, DiagID, Typ, Actions.getASTContext().getPrintingPolicy()); Declarator DeclaratorInfo(DS, DeclaratorContext::TypeNameContext); TypeResult Ty = Actions.ActOnTypeName(getCurScope(), DeclaratorInfo); if (Ty.isInvalid()) break; Res = ParseObjCMessageExpressionBody(SourceLocation(), SourceLocation(), Ty.get(), nullptr); break; } } // Make sure to pass down the right value for isAddressOfOperand. if (isAddressOfOperand && isPostfixExpressionSuffixStart()) isAddressOfOperand = false; // Function designators are allowed to be undeclared (C99 6.5.1p2), so we // need to know whether or not this identifier is a function designator or // not. UnqualifiedId Name; CXXScopeSpec ScopeSpec; SourceLocation TemplateKWLoc; Token Replacement; CastExpressionIdValidator Validator( /*Next=*/Tok, /*AllowTypes=*/isTypeCast != NotTypeCast, /*AllowNonTypes=*/isTypeCast != IsTypeCast); Validator.IsAddressOfOperand = isAddressOfOperand; if (Tok.isOneOf(tok::periodstar, tok::arrowstar)) { Validator.WantExpressionKeywords = false; Validator.WantRemainingKeywords = false; } else { Validator.WantRemainingKeywords = Tok.isNot(tok::r_paren); } Name.setIdentifier(&II, ILoc); Res = Actions.ActOnIdExpression( getCurScope(), ScopeSpec, TemplateKWLoc, Name, Tok.is(tok::l_paren), isAddressOfOperand, &Validator, /*IsInlineAsmIdentifier=*/false, Tok.is(tok::r_paren) ? nullptr : &Replacement); if (!Res.isInvalid() && Res.isUnset()) { UnconsumeToken(Replacement); return ParseCastExpression(ParseKind, isAddressOfOperand, NotCastExpr, isTypeCast, /*isVectorLiteral=*/false, NotPrimaryExpression); } if (!Res.isInvalid() && Tok.is(tok::less)) checkPotentialAngleBracket(Res); break; } case tok::char_constant: // constant: character-constant case tok::wide_char_constant: case tok::utf8_char_constant: case tok::utf16_char_constant: case tok::utf32_char_constant: Res = Actions.ActOnCharacterConstant(Tok, /*UDLScope*/getCurScope()); ConsumeToken(); break; case tok::kw___func__: // primary-expression: __func__ [C99 6.4.2.2] case tok::kw___FUNCTION__: // primary-expression: __FUNCTION__ [GNU] case tok::kw___FUNCDNAME__: // primary-expression: __FUNCDNAME__ [MS] case tok::kw___FUNCSIG__: // primary-expression: __FUNCSIG__ [MS] case tok::kw_L__FUNCTION__: // primary-expression: L__FUNCTION__ [MS] case tok::kw_L__FUNCSIG__: // primary-expression: L__FUNCSIG__ [MS] case tok::kw___PRETTY_FUNCTION__: // primary-expression: __P..Y_F..N__ [GNU] Res = Actions.ActOnPredefinedExpr(Tok.getLocation(), SavedKind); ConsumeToken(); break; case tok::string_literal: // primary-expression: string-literal case tok::wide_string_literal: case tok::utf8_string_literal: case tok::utf16_string_literal: case tok::utf32_string_literal: Res = ParseStringLiteralExpression(true); break; case tok::kw__Generic: // primary-expression: generic-selection [C11 6.5.1] Res = ParseGenericSelectionExpression(); break; case tok::kw___builtin_available: return ParseAvailabilityCheckExpr(Tok.getLocation()); case tok::kw___builtin_va_arg: case tok::kw___builtin_offsetof: case tok::kw___builtin_choose_expr: case tok::kw___builtin_astype: // primary-expression: [OCL] as_type() case tok::kw___builtin_convertvector: case tok::kw___builtin_COLUMN: case tok::kw___builtin_FILE: case tok::kw___builtin_FUNCTION: case tok::kw___builtin_LINE: if (NotPrimaryExpression) *NotPrimaryExpression = true; return ParseBuiltinPrimaryExpression(); case tok::kw___null: return Actions.ActOnGNUNullExpr(ConsumeToken()); case tok::plusplus: // unary-expression: '++' unary-expression [C99] case tok::minusminus: { // unary-expression: '--' unary-expression [C99] if (NotPrimaryExpression) *NotPrimaryExpression = true; // C++ [expr.unary] has: // unary-expression: // ++ cast-expression // -- cast-expression Token SavedTok = Tok; ConsumeToken(); PreferredType.enterUnary(Actions, Tok.getLocation(), SavedTok.getKind(), SavedTok.getLocation()); // One special case is implicitly handled here: if the preceding tokens are // an ambiguous cast expression, such as "(T())++", then we recurse to // determine whether the '++' is prefix or postfix. Res = ParseCastExpression(getLangOpts().CPlusPlus ? UnaryExprOnly : AnyCastExpr, /*isAddressOfOperand*/false, NotCastExpr, NotTypeCast); if (NotCastExpr) { // If we return with NotCastExpr = true, we must not consume any tokens, // so put the token back where we found it. assert(Res.isInvalid()); UnconsumeToken(SavedTok); return ExprError(); } if (!Res.isInvalid()) Res = Actions.ActOnUnaryOp(getCurScope(), SavedTok.getLocation(), SavedKind, Res.get()); return Res; } case tok::amp: { // unary-expression: '&' cast-expression if (NotPrimaryExpression) *NotPrimaryExpression = true; // Special treatment because of member pointers SourceLocation SavedLoc = ConsumeToken(); PreferredType.enterUnary(Actions, Tok.getLocation(), tok::amp, SavedLoc); Res = ParseCastExpression(AnyCastExpr, true); if (!Res.isInvalid()) Res = Actions.ActOnUnaryOp(getCurScope(), SavedLoc, SavedKind, Res.get()); return Res; } case tok::star: // unary-expression: '*' cast-expression case tok::plus: // unary-expression: '+' cast-expression case tok::minus: // unary-expression: '-' cast-expression case tok::tilde: // unary-expression: '~' cast-expression case tok::exclaim: // unary-expression: '!' cast-expression case tok::kw___real: // unary-expression: '__real' cast-expression [GNU] case tok::kw___imag: { // unary-expression: '__imag' cast-expression [GNU] if (NotPrimaryExpression) *NotPrimaryExpression = true; SourceLocation SavedLoc = ConsumeToken(); PreferredType.enterUnary(Actions, Tok.getLocation(), SavedKind, SavedLoc); Res = ParseCastExpression(AnyCastExpr); if (!Res.isInvalid()) Res = Actions.ActOnUnaryOp(getCurScope(), SavedLoc, SavedKind, Res.get()); return Res; } case tok::kw_co_await: { // unary-expression: 'co_await' cast-expression if (NotPrimaryExpression) *NotPrimaryExpression = true; SourceLocation CoawaitLoc = ConsumeToken(); Res = ParseCastExpression(AnyCastExpr); if (!Res.isInvalid()) Res = Actions.ActOnCoawaitExpr(getCurScope(), CoawaitLoc, Res.get()); return Res; } case tok::kw___extension__:{//unary-expression:'__extension__' cast-expr [GNU] // __extension__ silences extension warnings in the subexpression. if (NotPrimaryExpression) *NotPrimaryExpression = true; ExtensionRAIIObject O(Diags); // Use RAII to do this. SourceLocation SavedLoc = ConsumeToken(); Res = ParseCastExpression(AnyCastExpr); if (!Res.isInvalid()) Res = Actions.ActOnUnaryOp(getCurScope(), SavedLoc, SavedKind, Res.get()); return Res; } case tok::kw__Alignof: // unary-expression: '_Alignof' '(' type-name ')' if (!getLangOpts().C11) Diag(Tok, diag::ext_c11_feature) << Tok.getName(); LLVM_FALLTHROUGH; case tok::kw_alignof: // unary-expression: 'alignof' '(' type-id ')' case tok::kw___alignof: // unary-expression: '__alignof' unary-expression // unary-expression: '__alignof' '(' type-name ')' case tok::kw_sizeof: // unary-expression: 'sizeof' unary-expression // unary-expression: 'sizeof' '(' type-name ')' case tok::kw_vec_step: // unary-expression: OpenCL 'vec_step' expression // unary-expression: '__builtin_omp_required_simd_align' '(' type-name ')' case tok::kw___builtin_omp_required_simd_align: if (NotPrimaryExpression) *NotPrimaryExpression = true; return ParseUnaryExprOrTypeTraitExpression(); case tok::ampamp: { // unary-expression: '&&' identifier if (NotPrimaryExpression) *NotPrimaryExpression = true; SourceLocation AmpAmpLoc = ConsumeToken(); if (Tok.isNot(tok::identifier)) return ExprError(Diag(Tok, diag::err_expected) << tok::identifier); if (getCurScope()->getFnParent() == nullptr) return ExprError(Diag(Tok, diag::err_address_of_label_outside_fn)); Diag(AmpAmpLoc, diag::ext_gnu_address_of_label); LabelDecl *LD = Actions.LookupOrCreateLabel(Tok.getIdentifierInfo(), Tok.getLocation()); Res = Actions.ActOnAddrLabel(AmpAmpLoc, Tok.getLocation(), LD); ConsumeToken(); return Res; } case tok::kw_const_cast: case tok::kw_dynamic_cast: case tok::kw_reinterpret_cast: case tok::kw_static_cast: if (NotPrimaryExpression) *NotPrimaryExpression = true; Res = ParseCXXCasts(); break; case tok::kw___builtin_bit_cast: if (NotPrimaryExpression) *NotPrimaryExpression = true; Res = ParseBuiltinBitCast(); break; case tok::kw_typeid: if (NotPrimaryExpression) *NotPrimaryExpression = true; Res = ParseCXXTypeid(); break; case tok::kw___uuidof: if (NotPrimaryExpression) *NotPrimaryExpression = true; Res = ParseCXXUuidof(); break; case tok::kw_this: Res = ParseCXXThis(); break; case tok::annot_typename: if (isStartOfObjCClassMessageMissingOpenBracket()) { ParsedType Type = getTypeAnnotation(Tok); // Fake up a Declarator to use with ActOnTypeName. DeclSpec DS(AttrFactory); DS.SetRangeStart(Tok.getLocation()); DS.SetRangeEnd(Tok.getLastLoc()); const char *PrevSpec = nullptr; unsigned DiagID; DS.SetTypeSpecType(TST_typename, Tok.getAnnotationEndLoc(), PrevSpec, DiagID, Type, Actions.getASTContext().getPrintingPolicy()); Declarator DeclaratorInfo(DS, DeclaratorContext::TypeNameContext); TypeResult Ty = Actions.ActOnTypeName(getCurScope(), DeclaratorInfo); if (Ty.isInvalid()) break; ConsumeAnnotationToken(); Res = ParseObjCMessageExpressionBody(SourceLocation(), SourceLocation(), Ty.get(), nullptr); break; } LLVM_FALLTHROUGH; case tok::annot_decltype: case tok::kw_char: case tok::kw_wchar_t: case tok::kw_char8_t: case tok::kw_char16_t: case tok::kw_char32_t: case tok::kw_bool: case tok::kw_short: case tok::kw_int: case tok::kw_long: case tok::kw___int64: case tok::kw___int128: case tok::kw_signed: case tok::kw_unsigned: case tok::kw_half: case tok::kw_float: case tok::kw_double: case tok::kw__Float16: case tok::kw___float128: case tok::kw_void: case tok::kw_typename: case tok::kw_typeof: case tok::kw___vector: #define GENERIC_IMAGE_TYPE(ImgType, Id) case tok::kw_##ImgType##_t: #include "clang/Basic/OpenCLImageTypes.def" { if (!getLangOpts().CPlusPlus) { Diag(Tok, diag::err_expected_expression); return ExprError(); } // Everything henceforth is a postfix-expression. if (NotPrimaryExpression) *NotPrimaryExpression = true; if (SavedKind == tok::kw_typename) { // postfix-expression: typename-specifier '(' expression-list[opt] ')' // typename-specifier braced-init-list if (TryAnnotateTypeOrScopeToken()) return ExprError(); if (!Actions.isSimpleTypeSpecifier(Tok.getKind())) // We are trying to parse a simple-type-specifier but might not get such // a token after error recovery. return ExprError(); } // postfix-expression: simple-type-specifier '(' expression-list[opt] ')' // simple-type-specifier braced-init-list // DeclSpec DS(AttrFactory); ParseCXXSimpleTypeSpecifier(DS); if (Tok.isNot(tok::l_paren) && (!getLangOpts().CPlusPlus11 || Tok.isNot(tok::l_brace))) return ExprError(Diag(Tok, diag::err_expected_lparen_after_type) << DS.getSourceRange()); if (Tok.is(tok::l_brace)) Diag(Tok, diag::warn_cxx98_compat_generalized_initializer_lists); Res = ParseCXXTypeConstructExpression(DS); break; } case tok::annot_cxxscope: { // [C++] id-expression: qualified-id // If TryAnnotateTypeOrScopeToken annotates the token, tail recurse. // (We can end up in this situation after tentative parsing.) if (TryAnnotateTypeOrScopeToken()) return ExprError(); if (!Tok.is(tok::annot_cxxscope)) return ParseCastExpression(ParseKind, isAddressOfOperand, NotCastExpr, isTypeCast, isVectorLiteral, NotPrimaryExpression); Token Next = NextToken(); if (Next.is(tok::annot_template_id)) { TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Next); if (TemplateId->Kind == TNK_Type_template) { // We have a qualified template-id that we know refers to a // type, translate it into a type and continue parsing as a // cast expression. CXXScopeSpec SS; ParseOptionalCXXScopeSpecifier(SS, nullptr, /*EnteringContext=*/false); AnnotateTemplateIdTokenAsType(SS); return ParseCastExpression(ParseKind, isAddressOfOperand, NotCastExpr, isTypeCast, isVectorLiteral, NotPrimaryExpression); } } // Parse as an id-expression. Res = ParseCXXIdExpression(isAddressOfOperand); break; } case tok::annot_template_id: { // [C++] template-id TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok); if (TemplateId->Kind == TNK_Type_template) { // We have a template-id that we know refers to a type, // translate it into a type and continue parsing as a cast // expression. CXXScopeSpec SS; AnnotateTemplateIdTokenAsType(SS); return ParseCastExpression(ParseKind, isAddressOfOperand, NotCastExpr, isTypeCast, isVectorLiteral, NotPrimaryExpression); } // Fall through to treat the template-id as an id-expression. LLVM_FALLTHROUGH; } case tok::kw_operator: // [C++] id-expression: operator/conversion-function-id Res = ParseCXXIdExpression(isAddressOfOperand); break; case tok::coloncolon: { // ::foo::bar -> global qualified name etc. If TryAnnotateTypeOrScopeToken // annotates the token, tail recurse. if (TryAnnotateTypeOrScopeToken()) return ExprError(); if (!Tok.is(tok::coloncolon)) return ParseCastExpression(ParseKind, isAddressOfOperand, isTypeCast, isVectorLiteral, NotPrimaryExpression); // ::new -> [C++] new-expression // ::delete -> [C++] delete-expression SourceLocation CCLoc = ConsumeToken(); if (Tok.is(tok::kw_new)) { if (NotPrimaryExpression) *NotPrimaryExpression = true; return ParseCXXNewExpression(true, CCLoc); } if (Tok.is(tok::kw_delete)) { if (NotPrimaryExpression) *NotPrimaryExpression = true; return ParseCXXDeleteExpression(true, CCLoc); } // This is not a type name or scope specifier, it is an invalid expression. Diag(CCLoc, diag::err_expected_expression); return ExprError(); } case tok::kw_new: // [C++] new-expression if (NotPrimaryExpression) *NotPrimaryExpression = true; return ParseCXXNewExpression(false, Tok.getLocation()); case tok::kw_delete: // [C++] delete-expression if (NotPrimaryExpression) *NotPrimaryExpression = true; return ParseCXXDeleteExpression(false, Tok.getLocation()); case tok::kw_requires: // [C++2a] requires-expression return ParseRequiresExpression(); case tok::kw_noexcept: { // [C++0x] 'noexcept' '(' expression ')' if (NotPrimaryExpression) *NotPrimaryExpression = true; Diag(Tok, diag::warn_cxx98_compat_noexcept_expr); SourceLocation KeyLoc = ConsumeToken(); BalancedDelimiterTracker T(*this, tok::l_paren); if (T.expectAndConsume(diag::err_expected_lparen_after, "noexcept")) return ExprError(); // C++11 [expr.unary.noexcept]p1: // The noexcept operator determines whether the evaluation of its operand, // which is an unevaluated operand, can throw an exception. EnterExpressionEvaluationContext Unevaluated( Actions, Sema::ExpressionEvaluationContext::Unevaluated); ExprResult Result = ParseExpression(); T.consumeClose(); if (!Result.isInvalid()) Result = Actions.ActOnNoexceptExpr(KeyLoc, T.getOpenLocation(), Result.get(), T.getCloseLocation()); return Result; } #define TYPE_TRAIT(N,Spelling,K) \ case tok::kw_##Spelling: #include "clang/Basic/TokenKinds.def" return ParseTypeTrait(); case tok::kw___array_rank: case tok::kw___array_extent: if (NotPrimaryExpression) *NotPrimaryExpression = true; return ParseArrayTypeTrait(); case tok::kw___is_lvalue_expr: case tok::kw___is_rvalue_expr: if (NotPrimaryExpression) *NotPrimaryExpression = true; return ParseExpressionTrait(); case tok::at: { if (NotPrimaryExpression) *NotPrimaryExpression = true; SourceLocation AtLoc = ConsumeToken(); return ParseObjCAtExpression(AtLoc); } case tok::caret: Res = ParseBlockLiteralExpression(); break; case tok::code_completion: { Actions.CodeCompleteExpression(getCurScope(), PreferredType.get(Tok.getLocation())); cutOffParsing(); return ExprError(); } case tok::l_square: if (getLangOpts().CPlusPlus11) { if (getLangOpts().ObjC) { // C++11 lambda expressions and Objective-C message sends both start with a // square bracket. There are three possibilities here: // we have a valid lambda expression, we have an invalid lambda // expression, or we have something that doesn't appear to be a lambda. // If we're in the last case, we fall back to ParseObjCMessageExpression. Res = TryParseLambdaExpression(); if (!Res.isInvalid() && !Res.get()) { // We assume Objective-C++ message expressions are not // primary-expressions. if (NotPrimaryExpression) *NotPrimaryExpression = true; Res = ParseObjCMessageExpression(); } break; } Res = ParseLambdaExpression(); break; } if (getLangOpts().ObjC) { Res = ParseObjCMessageExpression(); break; } LLVM_FALLTHROUGH; default: NotCastExpr = true; return ExprError(); } // Check to see whether Res is a function designator only. If it is and we // are compiling for OpenCL, we need to return an error as this implies // that the address of the function is being taken, which is illegal in CL. if (ParseKind == PrimaryExprOnly) // This is strictly a primary-expression - no postfix-expr pieces should be // parsed. return Res; // These can be followed by postfix-expr pieces. PreferredType = SavedType; Res = ParsePostfixExpressionSuffix(Res); if (getLangOpts().OpenCL) if (Expr *PostfixExpr = Res.get()) { QualType Ty = PostfixExpr->getType(); if (!Ty.isNull() && Ty->isFunctionType()) { Diag(PostfixExpr->getExprLoc(), diag::err_opencl_taking_function_address_parser); return ExprError(); } } return Res; } /// Once the leading part of a postfix-expression is parsed, this /// method parses any suffixes that apply. /// /// \verbatim /// postfix-expression: [C99 6.5.2] /// primary-expression /// postfix-expression '[' expression ']' /// postfix-expression '[' braced-init-list ']' /// postfix-expression '(' argument-expression-list[opt] ')' /// postfix-expression '.' identifier /// postfix-expression '->' identifier /// postfix-expression '++' /// postfix-expression '--' /// '(' type-name ')' '{' initializer-list '}' /// '(' type-name ')' '{' initializer-list ',' '}' /// /// argument-expression-list: [C99 6.5.2] /// argument-expression ...[opt] /// argument-expression-list ',' assignment-expression ...[opt] /// \endverbatim ExprResult Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { // Now that the primary-expression piece of the postfix-expression has been // parsed, see if there are any postfix-expression pieces here. SourceLocation Loc; auto SavedType = PreferredType; while (1) { // Each iteration relies on preferred type for the whole expression. PreferredType = SavedType; switch (Tok.getKind()) { case tok::code_completion: if (InMessageExpression) return LHS; Actions.CodeCompletePostfixExpression( getCurScope(), LHS, PreferredType.get(Tok.getLocation())); cutOffParsing(); return ExprError(); case tok::identifier: // If we see identifier: after an expression, and we're not already in a // message send, then this is probably a message send with a missing // opening bracket '['. if (getLangOpts().ObjC && !InMessageExpression && (NextToken().is(tok::colon) || NextToken().is(tok::r_square))) { LHS = ParseObjCMessageExpressionBody(SourceLocation(), SourceLocation(), nullptr, LHS.get()); break; } // Fall through; this isn't a message send. LLVM_FALLTHROUGH; default: // Not a postfix-expression suffix. return LHS; case tok::l_square: { // postfix-expression: p-e '[' expression ']' // If we have a array postfix expression that starts on a new line and // Objective-C is enabled, it is highly likely that the user forgot a // semicolon after the base expression and that the array postfix-expr is // actually another message send. In this case, do some look-ahead to see // if the contents of the square brackets are obviously not a valid // expression and recover by pretending there is no suffix. if (getLangOpts().ObjC && Tok.isAtStartOfLine() && isSimpleObjCMessageExpression()) return LHS; // Reject array indices starting with a lambda-expression. '[[' is // reserved for attributes. if (CheckProhibitedCXX11Attribute()) { (void)Actions.CorrectDelayedTyposInExpr(LHS); return ExprError(); } BalancedDelimiterTracker T(*this, tok::l_square); T.consumeOpen(); Loc = T.getOpenLocation(); ExprResult Idx, Length; SourceLocation ColonLoc; PreferredType.enterSubscript(Actions, Tok.getLocation(), LHS.get()); if (getLangOpts().CPlusPlus11 && Tok.is(tok::l_brace)) { Diag(Tok, diag::warn_cxx98_compat_generalized_initializer_lists); Idx = ParseBraceInitializer(); } else if (getLangOpts().OpenMP) { ColonProtectionRAIIObject RAII(*this); // Parse [: or [ expr or [ expr : if (!Tok.is(tok::colon)) { // [ expr Idx = ParseExpression(); } if (Tok.is(tok::colon)) { // Consume ':' ColonLoc = ConsumeToken(); if (Tok.isNot(tok::r_square)) Length = ParseExpression(); } } else Idx = ParseExpression(); SourceLocation RLoc = Tok.getLocation(); LHS = Actions.CorrectDelayedTyposInExpr(LHS); Idx = Actions.CorrectDelayedTyposInExpr(Idx); Length = Actions.CorrectDelayedTyposInExpr(Length); if (!LHS.isInvalid() && !Idx.isInvalid() && !Length.isInvalid() && Tok.is(tok::r_square)) { if (ColonLoc.isValid()) { LHS = Actions.ActOnOMPArraySectionExpr(LHS.get(), Loc, Idx.get(), ColonLoc, Length.get(), RLoc); } else { LHS = Actions.ActOnArraySubscriptExpr(getCurScope(), LHS.get(), Loc, Idx.get(), RLoc); } } else { LHS = ExprError(); Idx = ExprError(); } // Match the ']'. T.consumeClose(); break; } case tok::l_paren: // p-e: p-e '(' argument-expression-list[opt] ')' case tok::lesslessless: { // p-e: p-e '<<<' argument-expression-list '>>>' // '(' argument-expression-list[opt] ')' tok::TokenKind OpKind = Tok.getKind(); InMessageExpressionRAIIObject InMessage(*this, false); Expr *ExecConfig = nullptr; BalancedDelimiterTracker PT(*this, tok::l_paren); if (OpKind == tok::lesslessless) { ExprVector ExecConfigExprs; CommaLocsTy ExecConfigCommaLocs; SourceLocation OpenLoc = ConsumeToken(); if (ParseSimpleExpressionList(ExecConfigExprs, ExecConfigCommaLocs)) { (void)Actions.CorrectDelayedTyposInExpr(LHS); LHS = ExprError(); } SourceLocation CloseLoc; if (TryConsumeToken(tok::greatergreatergreater, CloseLoc)) { } else if (LHS.isInvalid()) { SkipUntil(tok::greatergreatergreater, StopAtSemi); } else { // There was an error closing the brackets Diag(Tok, diag::err_expected) << tok::greatergreatergreater; Diag(OpenLoc, diag::note_matching) << tok::lesslessless; SkipUntil(tok::greatergreatergreater, StopAtSemi); LHS = ExprError(); } if (!LHS.isInvalid()) { if (ExpectAndConsume(tok::l_paren)) LHS = ExprError(); else Loc = PrevTokLocation; } if (!LHS.isInvalid()) { ExprResult ECResult = Actions.ActOnCUDAExecConfigExpr(getCurScope(), OpenLoc, ExecConfigExprs, CloseLoc); if (ECResult.isInvalid()) LHS = ExprError(); else ExecConfig = ECResult.get(); } } else { PT.consumeOpen(); Loc = PT.getOpenLocation(); } ExprVector ArgExprs; CommaLocsTy CommaLocs; auto RunSignatureHelp = [&]() -> QualType { QualType PreferredType = Actions.ProduceCallSignatureHelp( getCurScope(), LHS.get(), ArgExprs, PT.getOpenLocation()); CalledSignatureHelp = true; return PreferredType; }; if (OpKind == tok::l_paren || !LHS.isInvalid()) { if (Tok.isNot(tok::r_paren)) { if (ParseExpressionList(ArgExprs, CommaLocs, [&] { PreferredType.enterFunctionArgument(Tok.getLocation(), RunSignatureHelp); })) { (void)Actions.CorrectDelayedTyposInExpr(LHS); // If we got an error when parsing expression list, we don't call // the CodeCompleteCall handler inside the parser. So call it here // to make sure we get overload suggestions even when we are in the // middle of a parameter. if (PP.isCodeCompletionReached() && !CalledSignatureHelp) RunSignatureHelp(); LHS = ExprError(); } else if (LHS.isInvalid()) { for (auto &E : ArgExprs) Actions.CorrectDelayedTyposInExpr(E); } } } // Match the ')'. if (LHS.isInvalid()) { SkipUntil(tok::r_paren, StopAtSemi); } else if (Tok.isNot(tok::r_paren)) { bool HadDelayedTypo = false; if (Actions.CorrectDelayedTyposInExpr(LHS).get() != LHS.get()) HadDelayedTypo = true; for (auto &E : ArgExprs) if (Actions.CorrectDelayedTyposInExpr(E).get() != E) HadDelayedTypo = true; // If there were delayed typos in the LHS or ArgExprs, call SkipUntil // instead of PT.consumeClose() to avoid emitting extra diagnostics for // the unmatched l_paren. if (HadDelayedTypo) SkipUntil(tok::r_paren, StopAtSemi); else PT.consumeClose(); LHS = ExprError(); } else { assert((ArgExprs.size() == 0 || ArgExprs.size()-1 == CommaLocs.size())&& "Unexpected number of commas!"); LHS = Actions.ActOnCallExpr(getCurScope(), LHS.get(), Loc, ArgExprs, Tok.getLocation(), ExecConfig); PT.consumeClose(); } break; } case tok::arrow: case tok::period: { // postfix-expression: p-e '->' template[opt] id-expression // postfix-expression: p-e '.' template[opt] id-expression tok::TokenKind OpKind = Tok.getKind(); SourceLocation OpLoc = ConsumeToken(); // Eat the "." or "->" token. CXXScopeSpec SS; ParsedType ObjectType; bool MayBePseudoDestructor = false; Expr* OrigLHS = !LHS.isInvalid() ? LHS.get() : nullptr; PreferredType.enterMemAccess(Actions, Tok.getLocation(), OrigLHS); if (getLangOpts().CPlusPlus && !LHS.isInvalid()) { Expr *Base = OrigLHS; const Type* BaseType = Base->getType().getTypePtrOrNull(); if (BaseType && Tok.is(tok::l_paren) && (BaseType->isFunctionType() || BaseType->isSpecificPlaceholderType(BuiltinType::BoundMember))) { Diag(OpLoc, diag::err_function_is_not_record) << OpKind << Base->getSourceRange() << FixItHint::CreateRemoval(OpLoc); return ParsePostfixExpressionSuffix(Base); } LHS = Actions.ActOnStartCXXMemberReference(getCurScope(), Base, OpLoc, OpKind, ObjectType, MayBePseudoDestructor); if (LHS.isInvalid()) break; ParseOptionalCXXScopeSpecifier(SS, ObjectType, /*EnteringContext=*/false, &MayBePseudoDestructor); if (SS.isNotEmpty()) ObjectType = nullptr; } if (Tok.is(tok::code_completion)) { tok::TokenKind CorrectedOpKind = OpKind == tok::arrow ? tok::period : tok::arrow; ExprResult CorrectedLHS(/*Invalid=*/true); if (getLangOpts().CPlusPlus && OrigLHS) { // FIXME: Creating a TentativeAnalysisScope from outside Sema is a // hack. Sema::TentativeAnalysisScope Trap(Actions); CorrectedLHS = Actions.ActOnStartCXXMemberReference( getCurScope(), OrigLHS, OpLoc, CorrectedOpKind, ObjectType, MayBePseudoDestructor); } Expr *Base = LHS.get(); Expr *CorrectedBase = CorrectedLHS.get(); if (!CorrectedBase && !getLangOpts().CPlusPlus) CorrectedBase = Base; // Code completion for a member access expression. Actions.CodeCompleteMemberReferenceExpr( getCurScope(), Base, CorrectedBase, OpLoc, OpKind == tok::arrow, Base && ExprStatementTokLoc == Base->getBeginLoc(), PreferredType.get(Tok.getLocation())); cutOffParsing(); return ExprError(); } if (MayBePseudoDestructor && !LHS.isInvalid()) { LHS = ParseCXXPseudoDestructor(LHS.get(), OpLoc, OpKind, SS, ObjectType); break; } // Either the action has told us that this cannot be a // pseudo-destructor expression (based on the type of base // expression), or we didn't see a '~' in the right place. We // can still parse a destructor name here, but in that case it // names a real destructor. // Allow explicit constructor calls in Microsoft mode. // FIXME: Add support for explicit call of template constructor. SourceLocation TemplateKWLoc; UnqualifiedId Name; if (getLangOpts().ObjC && OpKind == tok::period && Tok.is(tok::kw_class)) { // Objective-C++: // After a '.' in a member access expression, treat the keyword // 'class' as if it were an identifier. // // This hack allows property access to the 'class' method because it is // such a common method name. For other C++ keywords that are // Objective-C method names, one must use the message send syntax. IdentifierInfo *Id = Tok.getIdentifierInfo(); SourceLocation Loc = ConsumeToken(); Name.setIdentifier(Id, Loc); } else if (ParseUnqualifiedId(SS, /*EnteringContext=*/false, /*AllowDestructorName=*/true, /*AllowConstructorName=*/ getLangOpts().MicrosoftExt && SS.isNotEmpty(), /*AllowDeductionGuide=*/false, ObjectType, &TemplateKWLoc, Name)) { (void)Actions.CorrectDelayedTyposInExpr(LHS); LHS = ExprError(); } if (!LHS.isInvalid()) LHS = Actions.ActOnMemberAccessExpr(getCurScope(), LHS.get(), OpLoc, OpKind, SS, TemplateKWLoc, Name, CurParsedObjCImpl ? CurParsedObjCImpl->Dcl : nullptr); if (!LHS.isInvalid() && Tok.is(tok::less)) checkPotentialAngleBracket(LHS); break; } case tok::plusplus: // postfix-expression: postfix-expression '++' case tok::minusminus: // postfix-expression: postfix-expression '--' if (!LHS.isInvalid()) { LHS = Actions.ActOnPostfixUnaryOp(getCurScope(), Tok.getLocation(), Tok.getKind(), LHS.get()); } ConsumeToken(); break; } } } /// ParseExprAfterUnaryExprOrTypeTrait - We parsed a typeof/sizeof/alignof/ /// vec_step and we are at the start of an expression or a parenthesized /// type-id. OpTok is the operand token (typeof/sizeof/alignof). Returns the /// expression (isCastExpr == false) or the type (isCastExpr == true). /// /// \verbatim /// unary-expression: [C99 6.5.3] /// 'sizeof' unary-expression /// 'sizeof' '(' type-name ')' /// [GNU] '__alignof' unary-expression /// [GNU] '__alignof' '(' type-name ')' /// [C11] '_Alignof' '(' type-name ')' /// [C++0x] 'alignof' '(' type-id ')' /// /// [GNU] typeof-specifier: /// typeof ( expressions ) /// typeof ( type-name ) /// [GNU/C++] typeof unary-expression /// /// [OpenCL 1.1 6.11.12] vec_step built-in function: /// vec_step ( expressions ) /// vec_step ( type-name ) /// \endverbatim ExprResult Parser::ParseExprAfterUnaryExprOrTypeTrait(const Token &OpTok, bool &isCastExpr, ParsedType &CastTy, SourceRange &CastRange) { assert(OpTok.isOneOf(tok::kw_typeof, tok::kw_sizeof, tok::kw___alignof, tok::kw_alignof, tok::kw__Alignof, tok::kw_vec_step, tok::kw___builtin_omp_required_simd_align) && "Not a typeof/sizeof/alignof/vec_step expression!"); ExprResult Operand; // If the operand doesn't start with an '(', it must be an expression. if (Tok.isNot(tok::l_paren)) { // If construct allows a form without parenthesis, user may forget to put // pathenthesis around type name. if (OpTok.isOneOf(tok::kw_sizeof, tok::kw___alignof, tok::kw_alignof, tok::kw__Alignof)) { if (isTypeIdUnambiguously()) { DeclSpec DS(AttrFactory); ParseSpecifierQualifierList(DS); Declarator DeclaratorInfo(DS, DeclaratorContext::TypeNameContext); ParseDeclarator(DeclaratorInfo); SourceLocation LParenLoc = PP.getLocForEndOfToken(OpTok.getLocation()); SourceLocation RParenLoc = PP.getLocForEndOfToken(PrevTokLocation); Diag(LParenLoc, diag::err_expected_parentheses_around_typename) << OpTok.getName() << FixItHint::CreateInsertion(LParenLoc, "(") << FixItHint::CreateInsertion(RParenLoc, ")"); isCastExpr = true; return ExprEmpty(); } } isCastExpr = false; if (OpTok.is(tok::kw_typeof) && !getLangOpts().CPlusPlus) { Diag(Tok, diag::err_expected_after) << OpTok.getIdentifierInfo() << tok::l_paren; return ExprError(); } Operand = ParseCastExpression(UnaryExprOnly); } else { // If it starts with a '(', we know that it is either a parenthesized // type-name, or it is a unary-expression that starts with a compound // literal, or starts with a primary-expression that is a parenthesized // expression. ParenParseOption ExprType = CastExpr; SourceLocation LParenLoc = Tok.getLocation(), RParenLoc; Operand = ParseParenExpression(ExprType, true/*stopIfCastExpr*/, false, CastTy, RParenLoc); CastRange = SourceRange(LParenLoc, RParenLoc); // If ParseParenExpression parsed a '(typename)' sequence only, then this is // a type. if (ExprType == CastExpr) { isCastExpr = true; return ExprEmpty(); } if (getLangOpts().CPlusPlus || OpTok.isNot(tok::kw_typeof)) { // GNU typeof in C requires the expression to be parenthesized. Not so for // sizeof/alignof or in C++. Therefore, the parenthesized expression is // the start of a unary-expression, but doesn't include any postfix // pieces. Parse these now if present. if (!Operand.isInvalid()) Operand = ParsePostfixExpressionSuffix(Operand.get()); } } // If we get here, the operand to the typeof/sizeof/alignof was an expression. isCastExpr = false; return Operand; } /// Parse a sizeof or alignof expression. /// /// \verbatim /// unary-expression: [C99 6.5.3] /// 'sizeof' unary-expression /// 'sizeof' '(' type-name ')' /// [C++11] 'sizeof' '...' '(' identifier ')' /// [GNU] '__alignof' unary-expression /// [GNU] '__alignof' '(' type-name ')' /// [C11] '_Alignof' '(' type-name ')' /// [C++11] 'alignof' '(' type-id ')' /// \endverbatim ExprResult Parser::ParseUnaryExprOrTypeTraitExpression() { assert(Tok.isOneOf(tok::kw_sizeof, tok::kw___alignof, tok::kw_alignof, tok::kw__Alignof, tok::kw_vec_step, tok::kw___builtin_omp_required_simd_align) && "Not a sizeof/alignof/vec_step expression!"); Token OpTok = Tok; ConsumeToken(); // [C++11] 'sizeof' '...' '(' identifier ')' if (Tok.is(tok::ellipsis) && OpTok.is(tok::kw_sizeof)) { SourceLocation EllipsisLoc = ConsumeToken(); SourceLocation LParenLoc, RParenLoc; IdentifierInfo *Name = nullptr; SourceLocation NameLoc; if (Tok.is(tok::l_paren)) { BalancedDelimiterTracker T(*this, tok::l_paren); T.consumeOpen(); LParenLoc = T.getOpenLocation(); if (Tok.is(tok::identifier)) { Name = Tok.getIdentifierInfo(); NameLoc = ConsumeToken(); T.consumeClose(); RParenLoc = T.getCloseLocation(); if (RParenLoc.isInvalid()) RParenLoc = PP.getLocForEndOfToken(NameLoc); } else { Diag(Tok, diag::err_expected_parameter_pack); SkipUntil(tok::r_paren, StopAtSemi); } } else if (Tok.is(tok::identifier)) { Name = Tok.getIdentifierInfo(); NameLoc = ConsumeToken(); LParenLoc = PP.getLocForEndOfToken(EllipsisLoc); RParenLoc = PP.getLocForEndOfToken(NameLoc); Diag(LParenLoc, diag::err_paren_sizeof_parameter_pack) << Name << FixItHint::CreateInsertion(LParenLoc, "(") << FixItHint::CreateInsertion(RParenLoc, ")"); } else { Diag(Tok, diag::err_sizeof_parameter_pack); } if (!Name) return ExprError(); EnterExpressionEvaluationContext Unevaluated( Actions, Sema::ExpressionEvaluationContext::Unevaluated, Sema::ReuseLambdaContextDecl); return Actions.ActOnSizeofParameterPackExpr(getCurScope(), OpTok.getLocation(), *Name, NameLoc, RParenLoc); } if (OpTok.isOneOf(tok::kw_alignof, tok::kw__Alignof)) Diag(OpTok, diag::warn_cxx98_compat_alignof); EnterExpressionEvaluationContext Unevaluated( Actions, Sema::ExpressionEvaluationContext::Unevaluated, Sema::ReuseLambdaContextDecl); bool isCastExpr; ParsedType CastTy; SourceRange CastRange; ExprResult Operand = ParseExprAfterUnaryExprOrTypeTrait(OpTok, isCastExpr, CastTy, CastRange); UnaryExprOrTypeTrait ExprKind = UETT_SizeOf; if (OpTok.isOneOf(tok::kw_alignof, tok::kw__Alignof)) ExprKind = UETT_AlignOf; else if (OpTok.is(tok::kw___alignof)) ExprKind = UETT_PreferredAlignOf; else if (OpTok.is(tok::kw_vec_step)) ExprKind = UETT_VecStep; else if (OpTok.is(tok::kw___builtin_omp_required_simd_align)) ExprKind = UETT_OpenMPRequiredSimdAlign; if (isCastExpr) return Actions.ActOnUnaryExprOrTypeTraitExpr(OpTok.getLocation(), ExprKind, /*IsType=*/true, CastTy.getAsOpaquePtr(), CastRange); if (OpTok.isOneOf(tok::kw_alignof, tok::kw__Alignof)) Diag(OpTok, diag::ext_alignof_expr) << OpTok.getIdentifierInfo(); // If we get here, the operand to the sizeof/alignof was an expression. if (!Operand.isInvalid()) Operand = Actions.ActOnUnaryExprOrTypeTraitExpr(OpTok.getLocation(), ExprKind, /*IsType=*/false, Operand.get(), CastRange); return Operand; } /// ParseBuiltinPrimaryExpression /// /// \verbatim /// primary-expression: [C99 6.5.1] /// [GNU] '__builtin_va_arg' '(' assignment-expression ',' type-name ')' /// [GNU] '__builtin_offsetof' '(' type-name ',' offsetof-member-designator')' /// [GNU] '__builtin_choose_expr' '(' assign-expr ',' assign-expr ',' /// assign-expr ')' /// [GNU] '__builtin_types_compatible_p' '(' type-name ',' type-name ')' /// [GNU] '__builtin_FILE' '(' ')' /// [GNU] '__builtin_FUNCTION' '(' ')' /// [GNU] '__builtin_LINE' '(' ')' /// [CLANG] '__builtin_COLUMN' '(' ')' /// [OCL] '__builtin_astype' '(' assignment-expression ',' type-name ')' /// /// [GNU] offsetof-member-designator: /// [GNU] identifier /// [GNU] offsetof-member-designator '.' identifier /// [GNU] offsetof-member-designator '[' expression ']' /// \endverbatim ExprResult Parser::ParseBuiltinPrimaryExpression() { ExprResult Res; const IdentifierInfo *BuiltinII = Tok.getIdentifierInfo(); tok::TokenKind T = Tok.getKind(); SourceLocation StartLoc = ConsumeToken(); // Eat the builtin identifier. // All of these start with an open paren. if (Tok.isNot(tok::l_paren)) return ExprError(Diag(Tok, diag::err_expected_after) << BuiltinII << tok::l_paren); BalancedDelimiterTracker PT(*this, tok::l_paren); PT.consumeOpen(); // TODO: Build AST. switch (T) { default: llvm_unreachable("Not a builtin primary expression!"); case tok::kw___builtin_va_arg: { ExprResult Expr(ParseAssignmentExpression()); if (ExpectAndConsume(tok::comma)) { SkipUntil(tok::r_paren, StopAtSemi); Expr = ExprError(); } TypeResult Ty = ParseTypeName(); if (Tok.isNot(tok::r_paren)) { Diag(Tok, diag::err_expected) << tok::r_paren; Expr = ExprError(); } if (Expr.isInvalid() || Ty.isInvalid()) Res = ExprError(); else Res = Actions.ActOnVAArg(StartLoc, Expr.get(), Ty.get(), ConsumeParen()); break; } case tok::kw___builtin_offsetof: { SourceLocation TypeLoc = Tok.getLocation(); TypeResult Ty = ParseTypeName(); if (Ty.isInvalid()) { SkipUntil(tok::r_paren, StopAtSemi); return ExprError(); } if (ExpectAndConsume(tok::comma)) { SkipUntil(tok::r_paren, StopAtSemi); return ExprError(); } // We must have at least one identifier here. if (Tok.isNot(tok::identifier)) { Diag(Tok, diag::err_expected) << tok::identifier; SkipUntil(tok::r_paren, StopAtSemi); return ExprError(); } // Keep track of the various subcomponents we see. SmallVector Comps; Comps.push_back(Sema::OffsetOfComponent()); Comps.back().isBrackets = false; Comps.back().U.IdentInfo = Tok.getIdentifierInfo(); Comps.back().LocStart = Comps.back().LocEnd = ConsumeToken(); // FIXME: This loop leaks the index expressions on error. while (1) { if (Tok.is(tok::period)) { // offsetof-member-designator: offsetof-member-designator '.' identifier Comps.push_back(Sema::OffsetOfComponent()); Comps.back().isBrackets = false; Comps.back().LocStart = ConsumeToken(); if (Tok.isNot(tok::identifier)) { Diag(Tok, diag::err_expected) << tok::identifier; SkipUntil(tok::r_paren, StopAtSemi); return ExprError(); } Comps.back().U.IdentInfo = Tok.getIdentifierInfo(); Comps.back().LocEnd = ConsumeToken(); } else if (Tok.is(tok::l_square)) { if (CheckProhibitedCXX11Attribute()) return ExprError(); // offsetof-member-designator: offsetof-member-design '[' expression ']' Comps.push_back(Sema::OffsetOfComponent()); Comps.back().isBrackets = true; BalancedDelimiterTracker ST(*this, tok::l_square); ST.consumeOpen(); Comps.back().LocStart = ST.getOpenLocation(); Res = ParseExpression(); if (Res.isInvalid()) { SkipUntil(tok::r_paren, StopAtSemi); return Res; } Comps.back().U.E = Res.get(); ST.consumeClose(); Comps.back().LocEnd = ST.getCloseLocation(); } else { if (Tok.isNot(tok::r_paren)) { PT.consumeClose(); Res = ExprError(); } else if (Ty.isInvalid()) { Res = ExprError(); } else { PT.consumeClose(); Res = Actions.ActOnBuiltinOffsetOf(getCurScope(), StartLoc, TypeLoc, Ty.get(), Comps, PT.getCloseLocation()); } break; } } break; } case tok::kw___builtin_choose_expr: { ExprResult Cond(ParseAssignmentExpression()); if (Cond.isInvalid()) { SkipUntil(tok::r_paren, StopAtSemi); return Cond; } if (ExpectAndConsume(tok::comma)) { SkipUntil(tok::r_paren, StopAtSemi); return ExprError(); } ExprResult Expr1(ParseAssignmentExpression()); if (Expr1.isInvalid()) { SkipUntil(tok::r_paren, StopAtSemi); return Expr1; } if (ExpectAndConsume(tok::comma)) { SkipUntil(tok::r_paren, StopAtSemi); return ExprError(); } ExprResult Expr2(ParseAssignmentExpression()); if (Expr2.isInvalid()) { SkipUntil(tok::r_paren, StopAtSemi); return Expr2; } if (Tok.isNot(tok::r_paren)) { Diag(Tok, diag::err_expected) << tok::r_paren; return ExprError(); } Res = Actions.ActOnChooseExpr(StartLoc, Cond.get(), Expr1.get(), Expr2.get(), ConsumeParen()); break; } case tok::kw___builtin_astype: { // The first argument is an expression to be converted, followed by a comma. ExprResult Expr(ParseAssignmentExpression()); if (Expr.isInvalid()) { SkipUntil(tok::r_paren, StopAtSemi); return ExprError(); } if (ExpectAndConsume(tok::comma)) { SkipUntil(tok::r_paren, StopAtSemi); return ExprError(); } // Second argument is the type to bitcast to. TypeResult DestTy = ParseTypeName(); if (DestTy.isInvalid()) return ExprError(); // Attempt to consume the r-paren. if (Tok.isNot(tok::r_paren)) { Diag(Tok, diag::err_expected) << tok::r_paren; SkipUntil(tok::r_paren, StopAtSemi); return ExprError(); } Res = Actions.ActOnAsTypeExpr(Expr.get(), DestTy.get(), StartLoc, ConsumeParen()); break; } case tok::kw___builtin_convertvector: { // The first argument is an expression to be converted, followed by a comma. ExprResult Expr(ParseAssignmentExpression()); if (Expr.isInvalid()) { SkipUntil(tok::r_paren, StopAtSemi); return ExprError(); } if (ExpectAndConsume(tok::comma)) { SkipUntil(tok::r_paren, StopAtSemi); return ExprError(); } // Second argument is the type to bitcast to. TypeResult DestTy = ParseTypeName(); if (DestTy.isInvalid()) return ExprError(); // Attempt to consume the r-paren. if (Tok.isNot(tok::r_paren)) { Diag(Tok, diag::err_expected) << tok::r_paren; SkipUntil(tok::r_paren, StopAtSemi); return ExprError(); } Res = Actions.ActOnConvertVectorExpr(Expr.get(), DestTy.get(), StartLoc, ConsumeParen()); break; } case tok::kw___builtin_COLUMN: case tok::kw___builtin_FILE: case tok::kw___builtin_FUNCTION: case tok::kw___builtin_LINE: { // Attempt to consume the r-paren. if (Tok.isNot(tok::r_paren)) { Diag(Tok, diag::err_expected) << tok::r_paren; SkipUntil(tok::r_paren, StopAtSemi); return ExprError(); } SourceLocExpr::IdentKind Kind = [&] { switch (T) { case tok::kw___builtin_FILE: return SourceLocExpr::File; case tok::kw___builtin_FUNCTION: return SourceLocExpr::Function; case tok::kw___builtin_LINE: return SourceLocExpr::Line; case tok::kw___builtin_COLUMN: return SourceLocExpr::Column; default: llvm_unreachable("invalid keyword"); } }(); Res = Actions.ActOnSourceLocExpr(Kind, StartLoc, ConsumeParen()); break; } } if (Res.isInvalid()) return ExprError(); // These can be followed by postfix-expr pieces because they are // primary-expressions. return ParsePostfixExpressionSuffix(Res.get()); } /// ParseParenExpression - This parses the unit that starts with a '(' token, /// based on what is allowed by ExprType. The actual thing parsed is returned /// in ExprType. If stopIfCastExpr is true, it will only return the parsed type, /// not the parsed cast-expression. /// /// \verbatim /// primary-expression: [C99 6.5.1] /// '(' expression ')' /// [GNU] '(' compound-statement ')' (if !ParenExprOnly) /// postfix-expression: [C99 6.5.2] /// '(' type-name ')' '{' initializer-list '}' /// '(' type-name ')' '{' initializer-list ',' '}' /// cast-expression: [C99 6.5.4] /// '(' type-name ')' cast-expression /// [ARC] bridged-cast-expression /// [ARC] bridged-cast-expression: /// (__bridge type-name) cast-expression /// (__bridge_transfer type-name) cast-expression /// (__bridge_retained type-name) cast-expression /// fold-expression: [C++1z] /// '(' cast-expression fold-operator '...' ')' /// '(' '...' fold-operator cast-expression ')' /// '(' cast-expression fold-operator '...' /// fold-operator cast-expression ')' /// \endverbatim ExprResult Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr, bool isTypeCast, ParsedType &CastTy, SourceLocation &RParenLoc) { assert(Tok.is(tok::l_paren) && "Not a paren expr!"); ColonProtectionRAIIObject ColonProtection(*this, false); BalancedDelimiterTracker T(*this, tok::l_paren); if (T.consumeOpen()) return ExprError(); SourceLocation OpenLoc = T.getOpenLocation(); PreferredType.enterParenExpr(Tok.getLocation(), OpenLoc); ExprResult Result(true); bool isAmbiguousTypeId; CastTy = nullptr; if (Tok.is(tok::code_completion)) { Actions.CodeCompleteExpression( getCurScope(), PreferredType.get(Tok.getLocation()), /*IsParenthesized=*/ExprType >= CompoundLiteral); cutOffParsing(); return ExprError(); } // Diagnose use of bridge casts in non-arc mode. bool BridgeCast = (getLangOpts().ObjC && Tok.isOneOf(tok::kw___bridge, tok::kw___bridge_transfer, tok::kw___bridge_retained, tok::kw___bridge_retain)); if (BridgeCast && !getLangOpts().ObjCAutoRefCount) { if (!TryConsumeToken(tok::kw___bridge)) { StringRef BridgeCastName = Tok.getName(); SourceLocation BridgeKeywordLoc = ConsumeToken(); if (!PP.getSourceManager().isInSystemHeader(BridgeKeywordLoc)) Diag(BridgeKeywordLoc, diag::warn_arc_bridge_cast_nonarc) << BridgeCastName << FixItHint::CreateReplacement(BridgeKeywordLoc, ""); } BridgeCast = false; } // None of these cases should fall through with an invalid Result // unless they've already reported an error. if (ExprType >= CompoundStmt && Tok.is(tok::l_brace)) { Diag(Tok, diag::ext_gnu_statement_expr); if (!getCurScope()->getFnParent() && !getCurScope()->getBlockParent()) { Result = ExprError(Diag(OpenLoc, diag::err_stmtexpr_file_scope)); } else { // Find the nearest non-record decl context. Variables declared in a // statement expression behave as if they were declared in the enclosing // function, block, or other code construct. DeclContext *CodeDC = Actions.CurContext; while (CodeDC->isRecord() || isa(CodeDC)) { CodeDC = CodeDC->getParent(); assert(CodeDC && !CodeDC->isFileContext() && "statement expr not in code context"); } Sema::ContextRAII SavedContext(Actions, CodeDC, /*NewThisContext=*/false); Actions.ActOnStartStmtExpr(); StmtResult Stmt(ParseCompoundStatement(true)); ExprType = CompoundStmt; // If the substmt parsed correctly, build the AST node. if (!Stmt.isInvalid()) { - Result = Actions.ActOnStmtExpr(OpenLoc, Stmt.get(), Tok.getLocation()); + Result = Actions.ActOnStmtExpr(getCurScope(), OpenLoc, Stmt.get(), + Tok.getLocation()); } else { Actions.ActOnStmtExprError(); } } } else if (ExprType >= CompoundLiteral && BridgeCast) { tok::TokenKind tokenKind = Tok.getKind(); SourceLocation BridgeKeywordLoc = ConsumeToken(); // Parse an Objective-C ARC ownership cast expression. ObjCBridgeCastKind Kind; if (tokenKind == tok::kw___bridge) Kind = OBC_Bridge; else if (tokenKind == tok::kw___bridge_transfer) Kind = OBC_BridgeTransfer; else if (tokenKind == tok::kw___bridge_retained) Kind = OBC_BridgeRetained; else { // As a hopefully temporary workaround, allow __bridge_retain as // a synonym for __bridge_retained, but only in system headers. assert(tokenKind == tok::kw___bridge_retain); Kind = OBC_BridgeRetained; if (!PP.getSourceManager().isInSystemHeader(BridgeKeywordLoc)) Diag(BridgeKeywordLoc, diag::err_arc_bridge_retain) << FixItHint::CreateReplacement(BridgeKeywordLoc, "__bridge_retained"); } TypeResult Ty = ParseTypeName(); T.consumeClose(); ColonProtection.restore(); RParenLoc = T.getCloseLocation(); PreferredType.enterTypeCast(Tok.getLocation(), Ty.get().get()); ExprResult SubExpr = ParseCastExpression(AnyCastExpr); if (Ty.isInvalid() || SubExpr.isInvalid()) return ExprError(); return Actions.ActOnObjCBridgedCast(getCurScope(), OpenLoc, Kind, BridgeKeywordLoc, Ty.get(), RParenLoc, SubExpr.get()); } else if (ExprType >= CompoundLiteral && isTypeIdInParens(isAmbiguousTypeId)) { // Otherwise, this is a compound literal expression or cast expression. // In C++, if the type-id is ambiguous we disambiguate based on context. // If stopIfCastExpr is true the context is a typeof/sizeof/alignof // in which case we should treat it as type-id. // if stopIfCastExpr is false, we need to determine the context past the // parens, so we defer to ParseCXXAmbiguousParenExpression for that. if (isAmbiguousTypeId && !stopIfCastExpr) { ExprResult res = ParseCXXAmbiguousParenExpression(ExprType, CastTy, T, ColonProtection); RParenLoc = T.getCloseLocation(); return res; } // Parse the type declarator. DeclSpec DS(AttrFactory); ParseSpecifierQualifierList(DS); Declarator DeclaratorInfo(DS, DeclaratorContext::TypeNameContext); ParseDeclarator(DeclaratorInfo); // If our type is followed by an identifier and either ':' or ']', then // this is probably an Objective-C message send where the leading '[' is // missing. Recover as if that were the case. if (!DeclaratorInfo.isInvalidType() && Tok.is(tok::identifier) && !InMessageExpression && getLangOpts().ObjC && (NextToken().is(tok::colon) || NextToken().is(tok::r_square))) { TypeResult Ty; { InMessageExpressionRAIIObject InMessage(*this, false); Ty = Actions.ActOnTypeName(getCurScope(), DeclaratorInfo); } Result = ParseObjCMessageExpressionBody(SourceLocation(), SourceLocation(), Ty.get(), nullptr); } else { // Match the ')'. T.consumeClose(); ColonProtection.restore(); RParenLoc = T.getCloseLocation(); if (Tok.is(tok::l_brace)) { ExprType = CompoundLiteral; TypeResult Ty; { InMessageExpressionRAIIObject InMessage(*this, false); Ty = Actions.ActOnTypeName(getCurScope(), DeclaratorInfo); } return ParseCompoundLiteralExpression(Ty.get(), OpenLoc, RParenLoc); } if (Tok.is(tok::l_paren)) { // This could be OpenCL vector Literals if (getLangOpts().OpenCL) { TypeResult Ty; { InMessageExpressionRAIIObject InMessage(*this, false); Ty = Actions.ActOnTypeName(getCurScope(), DeclaratorInfo); } if(Ty.isInvalid()) { return ExprError(); } QualType QT = Ty.get().get().getCanonicalType(); if (QT->isVectorType()) { // We parsed '(' vector-type-name ')' followed by '(' // Parse the cast-expression that follows it next. // isVectorLiteral = true will make sure we don't parse any // Postfix expression yet Result = ParseCastExpression(/*isUnaryExpression=*/AnyCastExpr, /*isAddressOfOperand=*/false, /*isTypeCast=*/IsTypeCast, /*isVectorLiteral=*/true); if (!Result.isInvalid()) { Result = Actions.ActOnCastExpr(getCurScope(), OpenLoc, DeclaratorInfo, CastTy, RParenLoc, Result.get()); } // After we performed the cast we can check for postfix-expr pieces. if (!Result.isInvalid()) { Result = ParsePostfixExpressionSuffix(Result); } return Result; } } } if (ExprType == CastExpr) { // We parsed '(' type-name ')' and the thing after it wasn't a '{'. if (DeclaratorInfo.isInvalidType()) return ExprError(); // Note that this doesn't parse the subsequent cast-expression, it just // returns the parsed type to the callee. if (stopIfCastExpr) { TypeResult Ty; { InMessageExpressionRAIIObject InMessage(*this, false); Ty = Actions.ActOnTypeName(getCurScope(), DeclaratorInfo); } CastTy = Ty.get(); return ExprResult(); } // Reject the cast of super idiom in ObjC. if (Tok.is(tok::identifier) && getLangOpts().ObjC && Tok.getIdentifierInfo() == Ident_super && getCurScope()->isInObjcMethodScope() && GetLookAheadToken(1).isNot(tok::period)) { Diag(Tok.getLocation(), diag::err_illegal_super_cast) << SourceRange(OpenLoc, RParenLoc); return ExprError(); } PreferredType.enterTypeCast(Tok.getLocation(), CastTy.get()); // Parse the cast-expression that follows it next. // TODO: For cast expression with CastTy. Result = ParseCastExpression(/*isUnaryExpression=*/AnyCastExpr, /*isAddressOfOperand=*/false, /*isTypeCast=*/IsTypeCast); if (!Result.isInvalid()) { Result = Actions.ActOnCastExpr(getCurScope(), OpenLoc, DeclaratorInfo, CastTy, RParenLoc, Result.get()); } return Result; } Diag(Tok, diag::err_expected_lbrace_in_compound_literal); return ExprError(); } } else if (ExprType >= FoldExpr && Tok.is(tok::ellipsis) && isFoldOperator(NextToken().getKind())) { ExprType = FoldExpr; return ParseFoldExpression(ExprResult(), T); } else if (isTypeCast) { // Parse the expression-list. InMessageExpressionRAIIObject InMessage(*this, false); ExprVector ArgExprs; CommaLocsTy CommaLocs; if (!ParseSimpleExpressionList(ArgExprs, CommaLocs)) { // FIXME: If we ever support comma expressions as operands to // fold-expressions, we'll need to allow multiple ArgExprs here. if (ExprType >= FoldExpr && ArgExprs.size() == 1 && isFoldOperator(Tok.getKind()) && NextToken().is(tok::ellipsis)) { ExprType = FoldExpr; return ParseFoldExpression(ArgExprs[0], T); } ExprType = SimpleExpr; Result = Actions.ActOnParenListExpr(OpenLoc, Tok.getLocation(), ArgExprs); } } else { InMessageExpressionRAIIObject InMessage(*this, false); Result = ParseExpression(MaybeTypeCast); if (!getLangOpts().CPlusPlus && MaybeTypeCast && Result.isUsable()) { // Correct typos in non-C++ code earlier so that implicit-cast-like // expressions are parsed correctly. Result = Actions.CorrectDelayedTyposInExpr(Result); } if (ExprType >= FoldExpr && isFoldOperator(Tok.getKind()) && NextToken().is(tok::ellipsis)) { ExprType = FoldExpr; return ParseFoldExpression(Result, T); } ExprType = SimpleExpr; // Don't build a paren expression unless we actually match a ')'. if (!Result.isInvalid() && Tok.is(tok::r_paren)) Result = Actions.ActOnParenExpr(OpenLoc, Tok.getLocation(), Result.get()); } // Match the ')'. if (Result.isInvalid()) { SkipUntil(tok::r_paren, StopAtSemi); return ExprError(); } T.consumeClose(); RParenLoc = T.getCloseLocation(); return Result; } /// ParseCompoundLiteralExpression - We have parsed the parenthesized type-name /// and we are at the left brace. /// /// \verbatim /// postfix-expression: [C99 6.5.2] /// '(' type-name ')' '{' initializer-list '}' /// '(' type-name ')' '{' initializer-list ',' '}' /// \endverbatim ExprResult Parser::ParseCompoundLiteralExpression(ParsedType Ty, SourceLocation LParenLoc, SourceLocation RParenLoc) { assert(Tok.is(tok::l_brace) && "Not a compound literal!"); if (!getLangOpts().C99) // Compound literals don't exist in C90. Diag(LParenLoc, diag::ext_c99_compound_literal); ExprResult Result = ParseInitializer(); if (!Result.isInvalid() && Ty) return Actions.ActOnCompoundLiteral(LParenLoc, Ty, RParenLoc, Result.get()); return Result; } /// ParseStringLiteralExpression - This handles the various token types that /// form string literals, and also handles string concatenation [C99 5.1.1.2, /// translation phase #6]. /// /// \verbatim /// primary-expression: [C99 6.5.1] /// string-literal /// \verbatim ExprResult Parser::ParseStringLiteralExpression(bool AllowUserDefinedLiteral) { assert(isTokenStringLiteral() && "Not a string literal!"); // String concat. Note that keywords like __func__ and __FUNCTION__ are not // considered to be strings for concatenation purposes. SmallVector StringToks; do { StringToks.push_back(Tok); ConsumeStringToken(); } while (isTokenStringLiteral()); // Pass the set of string tokens, ready for concatenation, to the actions. return Actions.ActOnStringLiteral(StringToks, AllowUserDefinedLiteral ? getCurScope() : nullptr); } /// ParseGenericSelectionExpression - Parse a C11 generic-selection /// [C11 6.5.1.1]. /// /// \verbatim /// generic-selection: /// _Generic ( assignment-expression , generic-assoc-list ) /// generic-assoc-list: /// generic-association /// generic-assoc-list , generic-association /// generic-association: /// type-name : assignment-expression /// default : assignment-expression /// \endverbatim ExprResult Parser::ParseGenericSelectionExpression() { assert(Tok.is(tok::kw__Generic) && "_Generic keyword expected"); if (!getLangOpts().C11) Diag(Tok, diag::ext_c11_feature) << Tok.getName(); SourceLocation KeyLoc = ConsumeToken(); BalancedDelimiterTracker T(*this, tok::l_paren); if (T.expectAndConsume()) return ExprError(); ExprResult ControllingExpr; { // C11 6.5.1.1p3 "The controlling expression of a generic selection is // not evaluated." EnterExpressionEvaluationContext Unevaluated( Actions, Sema::ExpressionEvaluationContext::Unevaluated); ControllingExpr = Actions.CorrectDelayedTyposInExpr(ParseAssignmentExpression()); if (ControllingExpr.isInvalid()) { SkipUntil(tok::r_paren, StopAtSemi); return ExprError(); } } if (ExpectAndConsume(tok::comma)) { SkipUntil(tok::r_paren, StopAtSemi); return ExprError(); } SourceLocation DefaultLoc; TypeVector Types; ExprVector Exprs; do { ParsedType Ty; if (Tok.is(tok::kw_default)) { // C11 6.5.1.1p2 "A generic selection shall have no more than one default // generic association." if (!DefaultLoc.isInvalid()) { Diag(Tok, diag::err_duplicate_default_assoc); Diag(DefaultLoc, diag::note_previous_default_assoc); SkipUntil(tok::r_paren, StopAtSemi); return ExprError(); } DefaultLoc = ConsumeToken(); Ty = nullptr; } else { ColonProtectionRAIIObject X(*this); TypeResult TR = ParseTypeName(); if (TR.isInvalid()) { SkipUntil(tok::r_paren, StopAtSemi); return ExprError(); } Ty = TR.get(); } Types.push_back(Ty); if (ExpectAndConsume(tok::colon)) { SkipUntil(tok::r_paren, StopAtSemi); return ExprError(); } // FIXME: These expressions should be parsed in a potentially potentially // evaluated context. ExprResult ER( Actions.CorrectDelayedTyposInExpr(ParseAssignmentExpression())); if (ER.isInvalid()) { SkipUntil(tok::r_paren, StopAtSemi); return ExprError(); } Exprs.push_back(ER.get()); } while (TryConsumeToken(tok::comma)); T.consumeClose(); if (T.getCloseLocation().isInvalid()) return ExprError(); return Actions.ActOnGenericSelectionExpr(KeyLoc, DefaultLoc, T.getCloseLocation(), ControllingExpr.get(), Types, Exprs); } /// Parse A C++1z fold-expression after the opening paren and optional /// left-hand-side expression. /// /// \verbatim /// fold-expression: /// ( cast-expression fold-operator ... ) /// ( ... fold-operator cast-expression ) /// ( cast-expression fold-operator ... fold-operator cast-expression ) ExprResult Parser::ParseFoldExpression(ExprResult LHS, BalancedDelimiterTracker &T) { if (LHS.isInvalid()) { T.skipToEnd(); return true; } tok::TokenKind Kind = tok::unknown; SourceLocation FirstOpLoc; if (LHS.isUsable()) { Kind = Tok.getKind(); assert(isFoldOperator(Kind) && "missing fold-operator"); FirstOpLoc = ConsumeToken(); } assert(Tok.is(tok::ellipsis) && "not a fold-expression"); SourceLocation EllipsisLoc = ConsumeToken(); ExprResult RHS; if (Tok.isNot(tok::r_paren)) { if (!isFoldOperator(Tok.getKind())) return Diag(Tok.getLocation(), diag::err_expected_fold_operator); if (Kind != tok::unknown && Tok.getKind() != Kind) Diag(Tok.getLocation(), diag::err_fold_operator_mismatch) << SourceRange(FirstOpLoc); Kind = Tok.getKind(); ConsumeToken(); RHS = ParseExpression(); if (RHS.isInvalid()) { T.skipToEnd(); return true; } } Diag(EllipsisLoc, getLangOpts().CPlusPlus17 ? diag::warn_cxx14_compat_fold_expression : diag::ext_fold_expression); T.consumeClose(); return Actions.ActOnCXXFoldExpr(T.getOpenLocation(), LHS.get(), Kind, EllipsisLoc, RHS.get(), T.getCloseLocation()); } /// ParseExpressionList - Used for C/C++ (argument-)expression-list. /// /// \verbatim /// argument-expression-list: /// assignment-expression /// argument-expression-list , assignment-expression /// /// [C++] expression-list: /// [C++] assignment-expression /// [C++] expression-list , assignment-expression /// /// [C++0x] expression-list: /// [C++0x] initializer-list /// /// [C++0x] initializer-list /// [C++0x] initializer-clause ...[opt] /// [C++0x] initializer-list , initializer-clause ...[opt] /// /// [C++0x] initializer-clause: /// [C++0x] assignment-expression /// [C++0x] braced-init-list /// \endverbatim bool Parser::ParseExpressionList(SmallVectorImpl &Exprs, SmallVectorImpl &CommaLocs, llvm::function_ref ExpressionStarts) { bool SawError = false; while (1) { if (ExpressionStarts) ExpressionStarts(); ExprResult Expr; if (getLangOpts().CPlusPlus11 && Tok.is(tok::l_brace)) { Diag(Tok, diag::warn_cxx98_compat_generalized_initializer_lists); Expr = ParseBraceInitializer(); } else Expr = ParseAssignmentExpression(); if (Tok.is(tok::ellipsis)) Expr = Actions.ActOnPackExpansion(Expr.get(), ConsumeToken()); if (Expr.isInvalid()) { SkipUntil(tok::comma, tok::r_paren, StopBeforeMatch); SawError = true; } else { Exprs.push_back(Expr.get()); } if (Tok.isNot(tok::comma)) break; // Move to the next argument, remember where the comma was. Token Comma = Tok; CommaLocs.push_back(ConsumeToken()); checkPotentialAngleBracketDelimiter(Comma); } if (SawError) { // Ensure typos get diagnosed when errors were encountered while parsing the // expression list. for (auto &E : Exprs) { ExprResult Expr = Actions.CorrectDelayedTyposInExpr(E); if (Expr.isUsable()) E = Expr.get(); } } return SawError; } /// ParseSimpleExpressionList - A simple comma-separated list of expressions, /// used for misc language extensions. /// /// \verbatim /// simple-expression-list: /// assignment-expression /// simple-expression-list , assignment-expression /// \endverbatim bool Parser::ParseSimpleExpressionList(SmallVectorImpl &Exprs, SmallVectorImpl &CommaLocs) { while (1) { ExprResult Expr = ParseAssignmentExpression(); if (Expr.isInvalid()) return true; Exprs.push_back(Expr.get()); if (Tok.isNot(tok::comma)) return false; // Move to the next argument, remember where the comma was. Token Comma = Tok; CommaLocs.push_back(ConsumeToken()); checkPotentialAngleBracketDelimiter(Comma); } } /// ParseBlockId - Parse a block-id, which roughly looks like int (int x). /// /// \verbatim /// [clang] block-id: /// [clang] specifier-qualifier-list block-declarator /// \endverbatim void Parser::ParseBlockId(SourceLocation CaretLoc) { if (Tok.is(tok::code_completion)) { Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Type); return cutOffParsing(); } // Parse the specifier-qualifier-list piece. DeclSpec DS(AttrFactory); ParseSpecifierQualifierList(DS); // Parse the block-declarator. Declarator DeclaratorInfo(DS, DeclaratorContext::BlockLiteralContext); DeclaratorInfo.setFunctionDefinitionKind(FDK_Definition); ParseDeclarator(DeclaratorInfo); MaybeParseGNUAttributes(DeclaratorInfo); // Inform sema that we are starting a block. Actions.ActOnBlockArguments(CaretLoc, DeclaratorInfo, getCurScope()); } /// ParseBlockLiteralExpression - Parse a block literal, which roughly looks /// like ^(int x){ return x+1; } /// /// \verbatim /// block-literal: /// [clang] '^' block-args[opt] compound-statement /// [clang] '^' block-id compound-statement /// [clang] block-args: /// [clang] '(' parameter-list ')' /// \endverbatim ExprResult Parser::ParseBlockLiteralExpression() { assert(Tok.is(tok::caret) && "block literal starts with ^"); SourceLocation CaretLoc = ConsumeToken(); PrettyStackTraceLoc CrashInfo(PP.getSourceManager(), CaretLoc, "block literal parsing"); // Enter a scope to hold everything within the block. This includes the // argument decls, decls within the compound expression, etc. This also // allows determining whether a variable reference inside the block is // within or outside of the block. ParseScope BlockScope(this, Scope::BlockScope | Scope::FnScope | Scope::CompoundStmtScope | Scope::DeclScope); // Inform sema that we are starting a block. Actions.ActOnBlockStart(CaretLoc, getCurScope()); // Parse the return type if present. DeclSpec DS(AttrFactory); Declarator ParamInfo(DS, DeclaratorContext::BlockLiteralContext); ParamInfo.setFunctionDefinitionKind(FDK_Definition); // FIXME: Since the return type isn't actually parsed, it can't be used to // fill ParamInfo with an initial valid range, so do it manually. ParamInfo.SetSourceRange(SourceRange(Tok.getLocation(), Tok.getLocation())); // If this block has arguments, parse them. There is no ambiguity here with // the expression case, because the expression case requires a parameter list. if (Tok.is(tok::l_paren)) { ParseParenDeclarator(ParamInfo); // Parse the pieces after the identifier as if we had "int(...)". // SetIdentifier sets the source range end, but in this case we're past // that location. SourceLocation Tmp = ParamInfo.getSourceRange().getEnd(); ParamInfo.SetIdentifier(nullptr, CaretLoc); ParamInfo.SetRangeEnd(Tmp); if (ParamInfo.isInvalidType()) { // If there was an error parsing the arguments, they may have // tried to use ^(x+y) which requires an argument list. Just // skip the whole block literal. Actions.ActOnBlockError(CaretLoc, getCurScope()); return ExprError(); } MaybeParseGNUAttributes(ParamInfo); // Inform sema that we are starting a block. Actions.ActOnBlockArguments(CaretLoc, ParamInfo, getCurScope()); } else if (!Tok.is(tok::l_brace)) { ParseBlockId(CaretLoc); } else { // Otherwise, pretend we saw (void). SourceLocation NoLoc; ParamInfo.AddTypeInfo( DeclaratorChunk::getFunction(/*HasProto=*/true, /*IsAmbiguous=*/false, /*RParenLoc=*/NoLoc, /*ArgInfo=*/nullptr, /*NumParams=*/0, /*EllipsisLoc=*/NoLoc, /*RParenLoc=*/NoLoc, /*RefQualifierIsLvalueRef=*/true, /*RefQualifierLoc=*/NoLoc, /*MutableLoc=*/NoLoc, EST_None, /*ESpecRange=*/SourceRange(), /*Exceptions=*/nullptr, /*ExceptionRanges=*/nullptr, /*NumExceptions=*/0, /*NoexceptExpr=*/nullptr, /*ExceptionSpecTokens=*/nullptr, /*DeclsInPrototype=*/None, CaretLoc, CaretLoc, ParamInfo), CaretLoc); MaybeParseGNUAttributes(ParamInfo); // Inform sema that we are starting a block. Actions.ActOnBlockArguments(CaretLoc, ParamInfo, getCurScope()); } ExprResult Result(true); if (!Tok.is(tok::l_brace)) { // Saw something like: ^expr Diag(Tok, diag::err_expected_expression); Actions.ActOnBlockError(CaretLoc, getCurScope()); return ExprError(); } StmtResult Stmt(ParseCompoundStatementBody()); BlockScope.Exit(); if (!Stmt.isInvalid()) Result = Actions.ActOnBlockStmtExpr(CaretLoc, Stmt.get(), getCurScope()); else Actions.ActOnBlockError(CaretLoc, getCurScope()); return Result; } /// ParseObjCBoolLiteral - This handles the objective-c Boolean literals. /// /// '__objc_yes' /// '__objc_no' ExprResult Parser::ParseObjCBoolLiteral() { tok::TokenKind Kind = Tok.getKind(); return Actions.ActOnObjCBoolLiteral(ConsumeToken(), Kind); } /// Validate availability spec list, emitting diagnostics if necessary. Returns /// true if invalid. static bool CheckAvailabilitySpecList(Parser &P, ArrayRef AvailSpecs) { llvm::SmallSet Platforms; bool HasOtherPlatformSpec = false; bool Valid = true; for (const auto &Spec : AvailSpecs) { if (Spec.isOtherPlatformSpec()) { if (HasOtherPlatformSpec) { P.Diag(Spec.getBeginLoc(), diag::err_availability_query_repeated_star); Valid = false; } HasOtherPlatformSpec = true; continue; } bool Inserted = Platforms.insert(Spec.getPlatform()).second; if (!Inserted) { // Rule out multiple version specs referring to the same platform. // For example, we emit an error for: // @available(macos 10.10, macos 10.11, *) StringRef Platform = Spec.getPlatform(); P.Diag(Spec.getBeginLoc(), diag::err_availability_query_repeated_platform) << Spec.getEndLoc() << Platform; Valid = false; } } if (!HasOtherPlatformSpec) { SourceLocation InsertWildcardLoc = AvailSpecs.back().getEndLoc(); P.Diag(InsertWildcardLoc, diag::err_availability_query_wildcard_required) << FixItHint::CreateInsertion(InsertWildcardLoc, ", *"); return true; } return !Valid; } /// Parse availability query specification. /// /// availability-spec: /// '*' /// identifier version-tuple Optional Parser::ParseAvailabilitySpec() { if (Tok.is(tok::star)) { return AvailabilitySpec(ConsumeToken()); } else { // Parse the platform name. if (Tok.is(tok::code_completion)) { Actions.CodeCompleteAvailabilityPlatformName(); cutOffParsing(); return None; } if (Tok.isNot(tok::identifier)) { Diag(Tok, diag::err_avail_query_expected_platform_name); return None; } IdentifierLoc *PlatformIdentifier = ParseIdentifierLoc(); SourceRange VersionRange; VersionTuple Version = ParseVersionTuple(VersionRange); if (Version.empty()) return None; StringRef GivenPlatform = PlatformIdentifier->Ident->getName(); StringRef Platform = AvailabilityAttr::canonicalizePlatformName(GivenPlatform); if (AvailabilityAttr::getPrettyPlatformName(Platform).empty()) { Diag(PlatformIdentifier->Loc, diag::err_avail_query_unrecognized_platform_name) << GivenPlatform; return None; } return AvailabilitySpec(Version, Platform, PlatformIdentifier->Loc, VersionRange.getEnd()); } } ExprResult Parser::ParseAvailabilityCheckExpr(SourceLocation BeginLoc) { assert(Tok.is(tok::kw___builtin_available) || Tok.isObjCAtKeyword(tok::objc_available)); // Eat the available or __builtin_available. ConsumeToken(); BalancedDelimiterTracker Parens(*this, tok::l_paren); if (Parens.expectAndConsume()) return ExprError(); SmallVector AvailSpecs; bool HasError = false; while (true) { Optional Spec = ParseAvailabilitySpec(); if (!Spec) HasError = true; else AvailSpecs.push_back(*Spec); if (!TryConsumeToken(tok::comma)) break; } if (HasError) { SkipUntil(tok::r_paren, StopAtSemi); return ExprError(); } CheckAvailabilitySpecList(*this, AvailSpecs); if (Parens.consumeClose()) return ExprError(); return Actions.ActOnObjCAvailabilityCheckExpr(AvailSpecs, BeginLoc, Parens.getCloseLocation()); } diff --git a/contrib/llvm-project/clang/lib/Sema/SemaExpr.cpp b/contrib/llvm-project/clang/lib/Sema/SemaExpr.cpp index 29562615e588..63d8d7506d03 100644 --- a/contrib/llvm-project/clang/lib/Sema/SemaExpr.cpp +++ b/contrib/llvm-project/clang/lib/Sema/SemaExpr.cpp @@ -1,18154 +1,18162 @@ //===--- 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(SourceLocation LPLoc, Stmt *SubStmt, - SourceLocation RPLoc) { // "({..})" +ExprResult Sema::ActOnStmtExpr(Scope *S, SourceLocation LPLoc, Stmt *SubStmt, + SourceLocation RPLoc) { // "({..})" 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); + Expr *ResStmtExpr = + new (Context) StmtExpr(Compound, Ty, LPLoc, RPLoc, IsDependentContext); 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); } diff --git a/contrib/llvm-project/clang/lib/Sema/SemaExprCXX.cpp b/contrib/llvm-project/clang/lib/Sema/SemaExprCXX.cpp index 98af7fb73eca..705abdb4ce72 100644 --- a/contrib/llvm-project/clang/lib/Sema/SemaExprCXX.cpp +++ b/contrib/llvm-project/clang/lib/Sema/SemaExprCXX.cpp @@ -1,8547 +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()); + Expr *E = new (Context) + StmtExpr(CompStmt, Context.VoidTy, SourceLocation(), SourceLocation(), + CurContext->isDependentContext()); 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); } diff --git a/contrib/llvm-project/clang/lib/Sema/TreeTransform.h b/contrib/llvm-project/clang/lib/Sema/TreeTransform.h index d6105353bbdf..0892f966ac2e 100644 --- a/contrib/llvm-project/clang/lib/Sema/TreeTransform.h +++ b/contrib/llvm-project/clang/lib/Sema/TreeTransform.h @@ -1,13712 +1,13713 @@ //===------- TreeTransform.h - Semantic Tree Transformation -----*- 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 implements a semantic tree transformation that takes a given // AST and rebuilds it, possibly transforming some nodes in the process. // //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_LIB_SEMA_TREETRANSFORM_H #define LLVM_CLANG_LIB_SEMA_TREETRANSFORM_H #include "CoroutineStmtBuilder.h" #include "TypeLocBuilder.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprConcepts.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/ExprObjC.h" #include "clang/AST/ExprOpenMP.h" #include "clang/AST/OpenMPClause.h" #include "clang/AST/Stmt.h" #include "clang/AST/StmtCXX.h" #include "clang/AST/StmtObjC.h" #include "clang/AST/StmtOpenMP.h" #include "clang/Sema/Designator.h" #include "clang/Sema/Lookup.h" #include "clang/Sema/Ownership.h" #include "clang/Sema/ParsedTemplate.h" #include "clang/Sema/ScopeInfo.h" #include "clang/Sema/SemaDiagnostic.h" #include "clang/Sema/SemaInternal.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/Support/ErrorHandling.h" #include using namespace llvm::omp; namespace clang { using namespace sema; /// A semantic tree transformation that allows one to transform one /// abstract syntax tree into another. /// /// A new tree transformation is defined by creating a new subclass \c X of /// \c TreeTransform and then overriding certain operations to provide /// behavior specific to that transformation. For example, template /// instantiation is implemented as a tree transformation where the /// transformation of TemplateTypeParmType nodes involves substituting the /// template arguments for their corresponding template parameters; a similar /// transformation is performed for non-type template parameters and /// template template parameters. /// /// This tree-transformation template uses static polymorphism to allow /// subclasses to customize any of its operations. Thus, a subclass can /// override any of the transformation or rebuild operators by providing an /// operation with the same signature as the default implementation. The /// overriding function should not be virtual. /// /// Semantic tree transformations are split into two stages, either of which /// can be replaced by a subclass. The "transform" step transforms an AST node /// or the parts of an AST node using the various transformation functions, /// then passes the pieces on to the "rebuild" step, which constructs a new AST /// node of the appropriate kind from the pieces. The default transformation /// routines recursively transform the operands to composite AST nodes (e.g., /// the pointee type of a PointerType node) and, if any of those operand nodes /// were changed by the transformation, invokes the rebuild operation to create /// a new AST node. /// /// Subclasses can customize the transformation at various levels. The /// most coarse-grained transformations involve replacing TransformType(), /// TransformExpr(), TransformDecl(), TransformNestedNameSpecifierLoc(), /// TransformTemplateName(), or TransformTemplateArgument() with entirely /// new implementations. /// /// For more fine-grained transformations, subclasses can replace any of the /// \c TransformXXX functions (where XXX is the name of an AST node, e.g., /// PointerType, StmtExpr) to alter the transformation. As mentioned previously, /// replacing TransformTemplateTypeParmType() allows template instantiation /// to substitute template arguments for their corresponding template /// parameters. Additionally, subclasses can override the \c RebuildXXX /// functions to control how AST nodes are rebuilt when their operands change. /// By default, \c TreeTransform will invoke semantic analysis to rebuild /// AST nodes. However, certain other tree transformations (e.g, cloning) may /// be able to use more efficient rebuild steps. /// /// There are a handful of other functions that can be overridden, allowing one /// to avoid traversing nodes that don't need any transformation /// (\c AlreadyTransformed()), force rebuilding AST nodes even when their /// operands have not changed (\c AlwaysRebuild()), and customize the /// default locations and entity names used for type-checking /// (\c getBaseLocation(), \c getBaseEntity()). template class TreeTransform { /// Private RAII object that helps us forget and then re-remember /// the template argument corresponding to a partially-substituted parameter /// pack. class ForgetPartiallySubstitutedPackRAII { Derived &Self; TemplateArgument Old; public: ForgetPartiallySubstitutedPackRAII(Derived &Self) : Self(Self) { Old = Self.ForgetPartiallySubstitutedPack(); } ~ForgetPartiallySubstitutedPackRAII() { Self.RememberPartiallySubstitutedPack(Old); } }; protected: Sema &SemaRef; /// The set of local declarations that have been transformed, for /// cases where we are forced to build new declarations within the transformer /// rather than in the subclass (e.g., lambda closure types). llvm::DenseMap TransformedLocalDecls; public: /// Initializes a new tree transformer. TreeTransform(Sema &SemaRef) : SemaRef(SemaRef) { } /// Retrieves a reference to the derived class. Derived &getDerived() { return static_cast(*this); } /// Retrieves a reference to the derived class. const Derived &getDerived() const { return static_cast(*this); } static inline ExprResult Owned(Expr *E) { return E; } static inline StmtResult Owned(Stmt *S) { return S; } /// Retrieves a reference to the semantic analysis object used for /// this tree transform. Sema &getSema() const { return SemaRef; } /// Whether the transformation should always rebuild AST nodes, even /// if none of the children have changed. /// /// Subclasses may override this function to specify when the transformation /// should rebuild all AST nodes. /// /// We must always rebuild all AST nodes when performing variadic template /// pack expansion, in order to avoid violating the AST invariant that each /// statement node appears at most once in its containing declaration. bool AlwaysRebuild() { return SemaRef.ArgumentPackSubstitutionIndex != -1; } /// Whether the transformation is forming an expression or statement that /// replaces the original. In this case, we'll reuse mangling numbers from /// existing lambdas. bool ReplacingOriginal() { return false; } /// Returns the location of the entity being transformed, if that /// information was not available elsewhere in the AST. /// /// By default, returns no source-location information. Subclasses can /// provide an alternative implementation that provides better location /// information. SourceLocation getBaseLocation() { return SourceLocation(); } /// Returns the name of the entity being transformed, if that /// information was not available elsewhere in the AST. /// /// By default, returns an empty name. Subclasses can provide an alternative /// implementation with a more precise name. DeclarationName getBaseEntity() { return DeclarationName(); } /// Sets the "base" location and entity when that /// information is known based on another transformation. /// /// By default, the source location and entity are ignored. Subclasses can /// override this function to provide a customized implementation. void setBase(SourceLocation Loc, DeclarationName Entity) { } /// RAII object that temporarily sets the base location and entity /// used for reporting diagnostics in types. class TemporaryBase { TreeTransform &Self; SourceLocation OldLocation; DeclarationName OldEntity; public: TemporaryBase(TreeTransform &Self, SourceLocation Location, DeclarationName Entity) : Self(Self) { OldLocation = Self.getDerived().getBaseLocation(); OldEntity = Self.getDerived().getBaseEntity(); if (Location.isValid()) Self.getDerived().setBase(Location, Entity); } ~TemporaryBase() { Self.getDerived().setBase(OldLocation, OldEntity); } }; /// Determine whether the given type \p T has already been /// transformed. /// /// Subclasses can provide an alternative implementation of this routine /// to short-circuit evaluation when it is known that a given type will /// not change. For example, template instantiation need not traverse /// non-dependent types. bool AlreadyTransformed(QualType T) { return T.isNull(); } /// Determine whether the given call argument should be dropped, e.g., /// because it is a default argument. /// /// Subclasses can provide an alternative implementation of this routine to /// determine which kinds of call arguments get dropped. By default, /// CXXDefaultArgument nodes are dropped (prior to transformation). bool DropCallArgument(Expr *E) { return E->isDefaultArgument(); } /// Determine whether we should expand a pack expansion with the /// given set of parameter packs into separate arguments by repeatedly /// transforming the pattern. /// /// By default, the transformer never tries to expand pack expansions. /// Subclasses can override this routine to provide different behavior. /// /// \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 TryExpandParameterPacks(SourceLocation EllipsisLoc, SourceRange PatternRange, ArrayRef Unexpanded, bool &ShouldExpand, bool &RetainExpansion, Optional &NumExpansions) { ShouldExpand = false; return false; } /// "Forget" about the partially-substituted pack template argument, /// when performing an instantiation that must preserve the parameter pack /// use. /// /// This routine is meant to be overridden by the template instantiator. TemplateArgument ForgetPartiallySubstitutedPack() { return TemplateArgument(); } /// "Remember" the partially-substituted pack template argument /// after performing an instantiation that must preserve the parameter pack /// use. /// /// This routine is meant to be overridden by the template instantiator. void RememberPartiallySubstitutedPack(TemplateArgument Arg) { } /// Note to the derived class when a function parameter pack is /// being expanded. void ExpandingFunctionParameterPack(ParmVarDecl *Pack) { } /// Transforms the given type into another type. /// /// By default, this routine transforms a type by creating a /// TypeSourceInfo for it and delegating to the appropriate /// function. This is expensive, but we don't mind, because /// this method is deprecated anyway; all users should be /// switched to storing TypeSourceInfos. /// /// \returns the transformed type. QualType TransformType(QualType T); /// Transforms the given type-with-location into a new /// type-with-location. /// /// By default, this routine transforms a type by delegating to the /// appropriate TransformXXXType to build a new type. Subclasses /// may override this function (to take over all type /// transformations) or some set of the TransformXXXType functions /// to alter the transformation. TypeSourceInfo *TransformType(TypeSourceInfo *DI); /// Transform the given type-with-location into a new /// type, collecting location information in the given builder /// as necessary. /// QualType TransformType(TypeLocBuilder &TLB, TypeLoc TL); /// Transform a type that is permitted to produce a /// DeducedTemplateSpecializationType. /// /// This is used in the (relatively rare) contexts where it is acceptable /// for transformation to produce a class template type with deduced /// template arguments. /// @{ QualType TransformTypeWithDeducedTST(QualType T); TypeSourceInfo *TransformTypeWithDeducedTST(TypeSourceInfo *DI); /// @} /// The reason why the value of a statement is not discarded, if any. enum StmtDiscardKind { SDK_Discarded, SDK_NotDiscarded, SDK_StmtExprResult, }; /// Transform the given statement. /// /// By default, this routine transforms a statement by delegating to the /// appropriate TransformXXXStmt function to transform a specific kind of /// statement or the TransformExpr() function to transform an expression. /// Subclasses may override this function to transform statements using some /// other mechanism. /// /// \returns the transformed statement. StmtResult TransformStmt(Stmt *S, StmtDiscardKind SDK = SDK_Discarded); /// Transform the given statement. /// /// By default, this routine transforms a statement by delegating to the /// appropriate TransformOMPXXXClause function to transform a specific kind /// of clause. Subclasses may override this function to transform statements /// using some other mechanism. /// /// \returns the transformed OpenMP clause. OMPClause *TransformOMPClause(OMPClause *S); /// Transform the given attribute. /// /// By default, this routine transforms a statement by delegating to the /// appropriate TransformXXXAttr function to transform a specific kind /// of attribute. Subclasses may override this function to transform /// attributed statements using some other mechanism. /// /// \returns the transformed attribute const Attr *TransformAttr(const Attr *S); /// Transform the specified attribute. /// /// Subclasses should override the transformation of attributes with a pragma /// spelling to transform expressions stored within the attribute. /// /// \returns the transformed attribute. #define ATTR(X) #define PRAGMA_SPELLING_ATTR(X) \ const X##Attr *Transform##X##Attr(const X##Attr *R) { return R; } #include "clang/Basic/AttrList.inc" /// Transform the given expression. /// /// By default, this routine transforms an expression by delegating to the /// appropriate TransformXXXExpr function to build a new expression. /// Subclasses may override this function to transform expressions using some /// other mechanism. /// /// \returns the transformed expression. ExprResult TransformExpr(Expr *E); /// Transform the given initializer. /// /// By default, this routine transforms an initializer by stripping off the /// semantic nodes added by initialization, then passing the result to /// TransformExpr or TransformExprs. /// /// \returns the transformed initializer. ExprResult TransformInitializer(Expr *Init, bool NotCopyInit); /// Transform the given list of expressions. /// /// This routine transforms a list of expressions by invoking /// \c TransformExpr() for each subexpression. However, it also provides /// support for variadic templates by expanding any pack expansions (if the /// derived class permits such expansion) along the way. When pack expansions /// are present, the number of outputs may not equal the number of inputs. /// /// \param Inputs The set of expressions to be transformed. /// /// \param NumInputs The number of expressions in \c Inputs. /// /// \param IsCall If \c true, then this transform is being performed on /// function-call arguments, and any arguments that should be dropped, will /// be. /// /// \param Outputs The transformed input expressions will be added to this /// vector. /// /// \param ArgChanged If non-NULL, will be set \c true if any argument changed /// due to transformation. /// /// \returns true if an error occurred, false otherwise. bool TransformExprs(Expr *const *Inputs, unsigned NumInputs, bool IsCall, SmallVectorImpl &Outputs, bool *ArgChanged = nullptr); /// Transform the given declaration, which is referenced from a type /// or expression. /// /// By default, acts as the identity function on declarations, unless the /// transformer has had to transform the declaration itself. Subclasses /// may override this function to provide alternate behavior. Decl *TransformDecl(SourceLocation Loc, Decl *D) { llvm::DenseMap::iterator Known = TransformedLocalDecls.find(D); if (Known != TransformedLocalDecls.end()) return Known->second; return D; } /// Transform the specified condition. /// /// By default, this transforms the variable and expression and rebuilds /// the condition. Sema::ConditionResult TransformCondition(SourceLocation Loc, VarDecl *Var, Expr *Expr, Sema::ConditionKind Kind); /// Transform the attributes associated with the given declaration and /// place them on the new declaration. /// /// By default, this operation does nothing. Subclasses may override this /// behavior to transform attributes. void transformAttrs(Decl *Old, Decl *New) { } /// Note that a local declaration has been transformed by this /// transformer. /// /// Local declarations are typically transformed via a call to /// TransformDefinition. However, in some cases (e.g., lambda expressions), /// the transformer itself has to transform the declarations. This routine /// can be overridden by a subclass that keeps track of such mappings. void transformedLocalDecl(Decl *Old, ArrayRef New) { assert(New.size() == 1 && "must override transformedLocalDecl if performing pack expansion"); TransformedLocalDecls[Old] = New.front(); } /// Transform the definition of the given declaration. /// /// By default, invokes TransformDecl() to transform the declaration. /// Subclasses may override this function to provide alternate behavior. Decl *TransformDefinition(SourceLocation Loc, Decl *D) { return getDerived().TransformDecl(Loc, D); } /// Transform the given declaration, which was the first part of a /// nested-name-specifier in a member access expression. /// /// This specific declaration transformation only applies to the first /// identifier in a nested-name-specifier of a member access expression, e.g., /// the \c T in \c x->T::member /// /// By default, invokes TransformDecl() to transform the declaration. /// Subclasses may override this function to provide alternate behavior. NamedDecl *TransformFirstQualifierInScope(NamedDecl *D, SourceLocation Loc) { return cast_or_null(getDerived().TransformDecl(Loc, D)); } /// Transform the set of declarations in an OverloadExpr. bool TransformOverloadExprDecls(OverloadExpr *Old, bool RequiresADL, LookupResult &R); /// Transform the given nested-name-specifier with source-location /// information. /// /// By default, transforms all of the types and declarations within the /// nested-name-specifier. Subclasses may override this function to provide /// alternate behavior. NestedNameSpecifierLoc TransformNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS, QualType ObjectType = QualType(), NamedDecl *FirstQualifierInScope = nullptr); /// Transform the given declaration name. /// /// By default, transforms the types of conversion function, constructor, /// and destructor names and then (if needed) rebuilds the declaration name. /// Identifiers and selectors are returned unmodified. Sublcasses may /// override this function to provide alternate behavior. DeclarationNameInfo TransformDeclarationNameInfo(const DeclarationNameInfo &NameInfo); bool TransformRequiresExprRequirements(ArrayRef Reqs, llvm::SmallVectorImpl &Transformed); concepts::TypeRequirement * TransformTypeRequirement(concepts::TypeRequirement *Req); concepts::ExprRequirement * TransformExprRequirement(concepts::ExprRequirement *Req); concepts::NestedRequirement * TransformNestedRequirement(concepts::NestedRequirement *Req); /// Transform the given template name. /// /// \param SS The nested-name-specifier that qualifies the template /// name. This nested-name-specifier must already have been transformed. /// /// \param Name The template name to transform. /// /// \param NameLoc The source location of the template name. /// /// \param ObjectType If we're translating a template name within a member /// access expression, this is the type of the object whose member template /// is being referenced. /// /// \param FirstQualifierInScope If the first part of a nested-name-specifier /// also refers to a name within the current (lexical) scope, this is the /// declaration it refers to. /// /// By default, transforms the template name by transforming the declarations /// and nested-name-specifiers that occur within the template name. /// Subclasses may override this function to provide alternate behavior. TemplateName TransformTemplateName(CXXScopeSpec &SS, TemplateName Name, SourceLocation NameLoc, QualType ObjectType = QualType(), NamedDecl *FirstQualifierInScope = nullptr, bool AllowInjectedClassName = false); /// Transform the given template argument. /// /// By default, this operation transforms the type, expression, or /// declaration stored within the template argument and constructs a /// new template argument from the transformed result. Subclasses may /// override this function to provide alternate behavior. /// /// Returns true if there was an error. bool TransformTemplateArgument(const TemplateArgumentLoc &Input, TemplateArgumentLoc &Output, bool Uneval = false); /// Transform the given set of template arguments. /// /// By default, this operation transforms all of the template arguments /// in the input set using \c TransformTemplateArgument(), and appends /// the transformed arguments to the output list. /// /// Note that this overload of \c TransformTemplateArguments() is merely /// a convenience function. Subclasses that wish to override this behavior /// should override the iterator-based member template version. /// /// \param Inputs The set of template arguments to be transformed. /// /// \param NumInputs The number of template arguments in \p Inputs. /// /// \param Outputs The set of transformed template arguments output by this /// routine. /// /// Returns true if an error occurred. bool TransformTemplateArguments(const TemplateArgumentLoc *Inputs, unsigned NumInputs, TemplateArgumentListInfo &Outputs, bool Uneval = false) { return TransformTemplateArguments(Inputs, Inputs + NumInputs, Outputs, Uneval); } /// Transform the given set of template arguments. /// /// By default, this operation transforms all of the template arguments /// in the input set using \c TransformTemplateArgument(), and appends /// the transformed arguments to the output list. /// /// \param First An iterator to the first template argument. /// /// \param Last An iterator one step past the last template argument. /// /// \param Outputs The set of transformed template arguments output by this /// routine. /// /// Returns true if an error occurred. template bool TransformTemplateArguments(InputIterator First, InputIterator Last, TemplateArgumentListInfo &Outputs, bool Uneval = false); /// Fakes up a TemplateArgumentLoc for a given TemplateArgument. void InventTemplateArgumentLoc(const TemplateArgument &Arg, TemplateArgumentLoc &ArgLoc); /// Fakes up a TypeSourceInfo for a type. TypeSourceInfo *InventTypeSourceInfo(QualType T) { return SemaRef.Context.getTrivialTypeSourceInfo(T, getDerived().getBaseLocation()); } #define ABSTRACT_TYPELOC(CLASS, PARENT) #define TYPELOC(CLASS, PARENT) \ QualType Transform##CLASS##Type(TypeLocBuilder &TLB, CLASS##TypeLoc T); #include "clang/AST/TypeLocNodes.def" template QualType TransformFunctionProtoType(TypeLocBuilder &TLB, FunctionProtoTypeLoc TL, CXXRecordDecl *ThisContext, Qualifiers ThisTypeQuals, Fn TransformExceptionSpec); bool TransformExceptionSpec(SourceLocation Loc, FunctionProtoType::ExceptionSpecInfo &ESI, SmallVectorImpl &Exceptions, bool &Changed); StmtResult TransformSEHHandler(Stmt *Handler); QualType TransformTemplateSpecializationType(TypeLocBuilder &TLB, TemplateSpecializationTypeLoc TL, TemplateName Template); QualType TransformDependentTemplateSpecializationType(TypeLocBuilder &TLB, DependentTemplateSpecializationTypeLoc TL, TemplateName Template, CXXScopeSpec &SS); QualType TransformDependentTemplateSpecializationType( TypeLocBuilder &TLB, DependentTemplateSpecializationTypeLoc TL, NestedNameSpecifierLoc QualifierLoc); /// Transforms the parameters of a function type into the /// given vectors. /// /// The result vectors should be kept in sync; null entries in the /// variables vector are acceptable. /// /// Return true on error. bool TransformFunctionTypeParams( SourceLocation Loc, ArrayRef Params, const QualType *ParamTypes, const FunctionProtoType::ExtParameterInfo *ParamInfos, SmallVectorImpl &PTypes, SmallVectorImpl *PVars, Sema::ExtParameterInfoBuilder &PInfos); /// Transforms a single function-type parameter. Return null /// on error. /// /// \param indexAdjustment - A number to add to the parameter's /// scope index; can be negative ParmVarDecl *TransformFunctionTypeParam(ParmVarDecl *OldParm, int indexAdjustment, Optional NumExpansions, bool ExpectParameterPack); /// Transform the body of a lambda-expression. StmtResult TransformLambdaBody(LambdaExpr *E, Stmt *Body); /// Alternative implementation of TransformLambdaBody that skips transforming /// the body. StmtResult SkipLambdaBody(LambdaExpr *E, Stmt *Body); QualType TransformReferenceType(TypeLocBuilder &TLB, ReferenceTypeLoc TL); StmtResult TransformCompoundStmt(CompoundStmt *S, bool IsStmtExpr); ExprResult TransformCXXNamedCastExpr(CXXNamedCastExpr *E); TemplateParameterList *TransformTemplateParameterList( TemplateParameterList *TPL) { return TPL; } ExprResult TransformAddressOfOperand(Expr *E); ExprResult TransformDependentScopeDeclRefExpr(DependentScopeDeclRefExpr *E, bool IsAddressOfOperand, TypeSourceInfo **RecoveryTSI); ExprResult TransformParenDependentScopeDeclRefExpr( ParenExpr *PE, DependentScopeDeclRefExpr *DRE, bool IsAddressOfOperand, TypeSourceInfo **RecoveryTSI); StmtResult TransformOMPExecutableDirective(OMPExecutableDirective *S); // FIXME: We use LLVM_ATTRIBUTE_NOINLINE because inlining causes a ridiculous // amount of stack usage with clang. #define STMT(Node, Parent) \ LLVM_ATTRIBUTE_NOINLINE \ StmtResult Transform##Node(Node *S); #define VALUESTMT(Node, Parent) \ LLVM_ATTRIBUTE_NOINLINE \ StmtResult Transform##Node(Node *S, StmtDiscardKind SDK); #define EXPR(Node, Parent) \ LLVM_ATTRIBUTE_NOINLINE \ ExprResult Transform##Node(Node *E); #define ABSTRACT_STMT(Stmt) #include "clang/AST/StmtNodes.inc" #define OPENMP_CLAUSE(Name, Class) \ LLVM_ATTRIBUTE_NOINLINE \ OMPClause *Transform ## Class(Class *S); #include "clang/Basic/OpenMPKinds.def" /// Build a new qualified type given its unqualified type and type location. /// /// By default, this routine adds type qualifiers only to types that can /// have qualifiers, and silently suppresses those qualifiers that are not /// permitted. Subclasses may override this routine to provide different /// behavior. QualType RebuildQualifiedType(QualType T, QualifiedTypeLoc TL); /// Build a new pointer type given its pointee type. /// /// By default, performs semantic analysis when building the pointer type. /// Subclasses may override this routine to provide different behavior. QualType RebuildPointerType(QualType PointeeType, SourceLocation Sigil); /// Build a new block pointer type given its pointee type. /// /// By default, performs semantic analysis when building the block pointer /// type. Subclasses may override this routine to provide different behavior. QualType RebuildBlockPointerType(QualType PointeeType, SourceLocation Sigil); /// Build a new reference type given the type it references. /// /// By default, performs semantic analysis when building the /// reference type. Subclasses may override this routine to provide /// different behavior. /// /// \param LValue whether the type was written with an lvalue sigil /// or an rvalue sigil. QualType RebuildReferenceType(QualType ReferentType, bool LValue, SourceLocation Sigil); /// Build a new member pointer type given the pointee type and the /// class type it refers into. /// /// By default, performs semantic analysis when building the member pointer /// type. Subclasses may override this routine to provide different behavior. QualType RebuildMemberPointerType(QualType PointeeType, QualType ClassType, SourceLocation Sigil); QualType RebuildObjCTypeParamType(const ObjCTypeParamDecl *Decl, SourceLocation ProtocolLAngleLoc, ArrayRef Protocols, ArrayRef ProtocolLocs, SourceLocation ProtocolRAngleLoc); /// Build an Objective-C object type. /// /// By default, performs semantic analysis when building the object type. /// Subclasses may override this routine to provide different behavior. QualType RebuildObjCObjectType(QualType BaseType, SourceLocation Loc, SourceLocation TypeArgsLAngleLoc, ArrayRef TypeArgs, SourceLocation TypeArgsRAngleLoc, SourceLocation ProtocolLAngleLoc, ArrayRef Protocols, ArrayRef ProtocolLocs, SourceLocation ProtocolRAngleLoc); /// Build a new Objective-C object pointer type given the pointee type. /// /// By default, directly builds the pointer type, with no additional semantic /// analysis. QualType RebuildObjCObjectPointerType(QualType PointeeType, SourceLocation Star); /// Build a new array type given the element type, size /// modifier, size of the array (if known), size expression, and index type /// qualifiers. /// /// By default, performs semantic analysis when building the array type. /// Subclasses may override this routine to provide different behavior. /// Also by default, all of the other Rebuild*Array QualType RebuildArrayType(QualType ElementType, ArrayType::ArraySizeModifier SizeMod, const llvm::APInt *Size, Expr *SizeExpr, unsigned IndexTypeQuals, SourceRange BracketsRange); /// Build a new constant array type given the element type, size /// modifier, (known) size of the array, and index type qualifiers. /// /// By default, performs semantic analysis when building the array type. /// Subclasses may override this routine to provide different behavior. QualType RebuildConstantArrayType(QualType ElementType, ArrayType::ArraySizeModifier SizeMod, const llvm::APInt &Size, Expr *SizeExpr, unsigned IndexTypeQuals, SourceRange BracketsRange); /// Build a new incomplete array type given the element type, size /// modifier, and index type qualifiers. /// /// By default, performs semantic analysis when building the array type. /// Subclasses may override this routine to provide different behavior. QualType RebuildIncompleteArrayType(QualType ElementType, ArrayType::ArraySizeModifier SizeMod, unsigned IndexTypeQuals, SourceRange BracketsRange); /// Build a new variable-length array type given the element type, /// size modifier, size expression, and index type qualifiers. /// /// By default, performs semantic analysis when building the array type. /// Subclasses may override this routine to provide different behavior. QualType RebuildVariableArrayType(QualType ElementType, ArrayType::ArraySizeModifier SizeMod, Expr *SizeExpr, unsigned IndexTypeQuals, SourceRange BracketsRange); /// Build a new dependent-sized array type given the element type, /// size modifier, size expression, and index type qualifiers. /// /// By default, performs semantic analysis when building the array type. /// Subclasses may override this routine to provide different behavior. QualType RebuildDependentSizedArrayType(QualType ElementType, ArrayType::ArraySizeModifier SizeMod, Expr *SizeExpr, unsigned IndexTypeQuals, SourceRange BracketsRange); /// Build a new vector type given the element type and /// number of elements. /// /// By default, performs semantic analysis when building the vector type. /// Subclasses may override this routine to provide different behavior. QualType RebuildVectorType(QualType ElementType, unsigned NumElements, VectorType::VectorKind VecKind); /// Build a new potentially dependently-sized extended vector type /// given the element type and number of elements. /// /// By default, performs semantic analysis when building the vector type. /// Subclasses may override this routine to provide different behavior. QualType RebuildDependentVectorType(QualType ElementType, Expr *SizeExpr, SourceLocation AttributeLoc, VectorType::VectorKind); /// Build a new extended vector type given the element type and /// number of elements. /// /// By default, performs semantic analysis when building the vector type. /// Subclasses may override this routine to provide different behavior. QualType RebuildExtVectorType(QualType ElementType, unsigned NumElements, SourceLocation AttributeLoc); /// Build a new potentially dependently-sized extended vector type /// given the element type and number of elements. /// /// By default, performs semantic analysis when building the vector type. /// Subclasses may override this routine to provide different behavior. QualType RebuildDependentSizedExtVectorType(QualType ElementType, Expr *SizeExpr, SourceLocation AttributeLoc); /// Build a new DependentAddressSpaceType or return the pointee /// type variable with the correct address space (retrieved from /// AddrSpaceExpr) applied to it. The former will be returned in cases /// where the address space remains dependent. /// /// By default, performs semantic analysis when building the type with address /// space applied. Subclasses may override this routine to provide different /// behavior. QualType RebuildDependentAddressSpaceType(QualType PointeeType, Expr *AddrSpaceExpr, SourceLocation AttributeLoc); /// Build a new function type. /// /// By default, performs semantic analysis when building the function type. /// Subclasses may override this routine to provide different behavior. QualType RebuildFunctionProtoType(QualType T, MutableArrayRef ParamTypes, const FunctionProtoType::ExtProtoInfo &EPI); /// Build a new unprototyped function type. QualType RebuildFunctionNoProtoType(QualType ResultType); /// Rebuild an unresolved typename type, given the decl that /// the UnresolvedUsingTypenameDecl was transformed to. QualType RebuildUnresolvedUsingType(SourceLocation NameLoc, Decl *D); /// Build a new typedef type. QualType RebuildTypedefType(TypedefNameDecl *Typedef) { return SemaRef.Context.getTypeDeclType(Typedef); } /// Build a new MacroDefined type. QualType RebuildMacroQualifiedType(QualType T, const IdentifierInfo *MacroII) { return SemaRef.Context.getMacroQualifiedType(T, MacroII); } /// Build a new class/struct/union type. QualType RebuildRecordType(RecordDecl *Record) { return SemaRef.Context.getTypeDeclType(Record); } /// Build a new Enum type. QualType RebuildEnumType(EnumDecl *Enum) { return SemaRef.Context.getTypeDeclType(Enum); } /// Build a new typeof(expr) type. /// /// By default, performs semantic analysis when building the typeof type. /// Subclasses may override this routine to provide different behavior. QualType RebuildTypeOfExprType(Expr *Underlying, SourceLocation Loc); /// Build a new typeof(type) type. /// /// By default, builds a new TypeOfType with the given underlying type. QualType RebuildTypeOfType(QualType Underlying); /// Build a new unary transform type. QualType RebuildUnaryTransformType(QualType BaseType, UnaryTransformType::UTTKind UKind, SourceLocation Loc); /// Build a new C++11 decltype type. /// /// By default, performs semantic analysis when building the decltype type. /// Subclasses may override this routine to provide different behavior. QualType RebuildDecltypeType(Expr *Underlying, SourceLocation Loc); /// Build a new C++11 auto type. /// /// By default, builds a new AutoType with the given deduced type. QualType RebuildAutoType(QualType Deduced, AutoTypeKeyword Keyword, ConceptDecl *TypeConstraintConcept, ArrayRef TypeConstraintArgs) { // Note, IsDependent is always false here: we implicitly convert an 'auto' // which has been deduced to a dependent type into an undeduced 'auto', so // that we'll retry deduction after the transformation. return SemaRef.Context.getAutoType(Deduced, Keyword, /*IsDependent*/ false, /*IsPack=*/false, TypeConstraintConcept, TypeConstraintArgs); } /// By default, builds a new DeducedTemplateSpecializationType with the given /// deduced type. QualType RebuildDeducedTemplateSpecializationType(TemplateName Template, QualType Deduced) { return SemaRef.Context.getDeducedTemplateSpecializationType( Template, Deduced, /*IsDependent*/ false); } /// Build a new template specialization type. /// /// By default, performs semantic analysis when building the template /// specialization type. Subclasses may override this routine to provide /// different behavior. QualType RebuildTemplateSpecializationType(TemplateName Template, SourceLocation TemplateLoc, TemplateArgumentListInfo &Args); /// Build a new parenthesized type. /// /// By default, builds a new ParenType type from the inner type. /// Subclasses may override this routine to provide different behavior. QualType RebuildParenType(QualType InnerType) { return SemaRef.BuildParenType(InnerType); } /// Build a new qualified name type. /// /// By default, builds a new ElaboratedType type from the keyword, /// the nested-name-specifier and the named type. /// Subclasses may override this routine to provide different behavior. QualType RebuildElaboratedType(SourceLocation KeywordLoc, ElaboratedTypeKeyword Keyword, NestedNameSpecifierLoc QualifierLoc, QualType Named) { return SemaRef.Context.getElaboratedType(Keyword, QualifierLoc.getNestedNameSpecifier(), Named); } /// Build a new typename type that refers to a template-id. /// /// By default, builds a new DependentNameType type from the /// nested-name-specifier and the given type. Subclasses may override /// this routine to provide different behavior. QualType RebuildDependentTemplateSpecializationType( ElaboratedTypeKeyword Keyword, NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateKWLoc, const IdentifierInfo *Name, SourceLocation NameLoc, TemplateArgumentListInfo &Args, bool AllowInjectedClassName) { // Rebuild the template name. // TODO: avoid TemplateName abstraction CXXScopeSpec SS; SS.Adopt(QualifierLoc); TemplateName InstName = getDerived().RebuildTemplateName( SS, TemplateKWLoc, *Name, NameLoc, QualType(), nullptr, AllowInjectedClassName); if (InstName.isNull()) return QualType(); // If it's still dependent, make a dependent specialization. if (InstName.getAsDependentTemplateName()) return SemaRef.Context.getDependentTemplateSpecializationType(Keyword, QualifierLoc.getNestedNameSpecifier(), Name, Args); // Otherwise, make an elaborated type wrapping a non-dependent // specialization. QualType T = getDerived().RebuildTemplateSpecializationType(InstName, NameLoc, Args); if (T.isNull()) return QualType(); if (Keyword == ETK_None && QualifierLoc.getNestedNameSpecifier() == nullptr) return T; return SemaRef.Context.getElaboratedType(Keyword, QualifierLoc.getNestedNameSpecifier(), T); } /// Build a new typename type that refers to an identifier. /// /// By default, performs semantic analysis when building the typename type /// (or elaborated type). Subclasses may override this routine to provide /// different behavior. QualType RebuildDependentNameType(ElaboratedTypeKeyword Keyword, SourceLocation KeywordLoc, NestedNameSpecifierLoc QualifierLoc, const IdentifierInfo *Id, SourceLocation IdLoc, bool DeducedTSTContext) { CXXScopeSpec SS; SS.Adopt(QualifierLoc); if (QualifierLoc.getNestedNameSpecifier()->isDependent()) { // If the name is still dependent, just build a new dependent name type. if (!SemaRef.computeDeclContext(SS)) return SemaRef.Context.getDependentNameType(Keyword, QualifierLoc.getNestedNameSpecifier(), Id); } if (Keyword == ETK_None || Keyword == ETK_Typename) { return SemaRef.CheckTypenameType(Keyword, KeywordLoc, QualifierLoc, *Id, IdLoc, DeducedTSTContext); } TagTypeKind Kind = TypeWithKeyword::getTagTypeKindForKeyword(Keyword); // We had a dependent elaborated-type-specifier that has been transformed // into a non-dependent elaborated-type-specifier. Find the tag we're // referring to. LookupResult Result(SemaRef, Id, IdLoc, Sema::LookupTagName); DeclContext *DC = SemaRef.computeDeclContext(SS, false); if (!DC) return QualType(); if (SemaRef.RequireCompleteDeclContext(SS, DC)) return QualType(); TagDecl *Tag = nullptr; SemaRef.LookupQualifiedName(Result, DC); switch (Result.getResultKind()) { case LookupResult::NotFound: case LookupResult::NotFoundInCurrentInstantiation: break; case LookupResult::Found: Tag = Result.getAsSingle(); break; case LookupResult::FoundOverloaded: case LookupResult::FoundUnresolvedValue: llvm_unreachable("Tag lookup cannot find non-tags"); case LookupResult::Ambiguous: // Let the LookupResult structure handle ambiguities. return QualType(); } if (!Tag) { // Check where the name exists but isn't a tag type and use that to emit // better diagnostics. LookupResult Result(SemaRef, Id, IdLoc, Sema::LookupTagName); SemaRef.LookupQualifiedName(Result, DC); switch (Result.getResultKind()) { case LookupResult::Found: case LookupResult::FoundOverloaded: case LookupResult::FoundUnresolvedValue: { NamedDecl *SomeDecl = Result.getRepresentativeDecl(); Sema::NonTagKind NTK = SemaRef.getNonTagTypeDeclKind(SomeDecl, Kind); SemaRef.Diag(IdLoc, diag::err_tag_reference_non_tag) << SomeDecl << NTK << Kind; SemaRef.Diag(SomeDecl->getLocation(), diag::note_declared_at); break; } default: SemaRef.Diag(IdLoc, diag::err_not_tag_in_scope) << Kind << Id << DC << QualifierLoc.getSourceRange(); break; } return QualType(); } if (!SemaRef.isAcceptableTagRedeclaration(Tag, Kind, /*isDefinition*/false, IdLoc, Id)) { SemaRef.Diag(KeywordLoc, diag::err_use_with_wrong_tag) << Id; SemaRef.Diag(Tag->getLocation(), diag::note_previous_use); return QualType(); } // Build the elaborated-type-specifier type. QualType T = SemaRef.Context.getTypeDeclType(Tag); return SemaRef.Context.getElaboratedType(Keyword, QualifierLoc.getNestedNameSpecifier(), T); } /// Build a new pack expansion type. /// /// By default, builds a new PackExpansionType type from the given pattern. /// Subclasses may override this routine to provide different behavior. QualType RebuildPackExpansionType(QualType Pattern, SourceRange PatternRange, SourceLocation EllipsisLoc, Optional NumExpansions) { return getSema().CheckPackExpansion(Pattern, PatternRange, EllipsisLoc, NumExpansions); } /// Build a new atomic type given its value type. /// /// By default, performs semantic analysis when building the atomic type. /// Subclasses may override this routine to provide different behavior. QualType RebuildAtomicType(QualType ValueType, SourceLocation KWLoc); /// Build a new pipe type given its value type. QualType RebuildPipeType(QualType ValueType, SourceLocation KWLoc, bool isReadPipe); /// Build a new template name given a nested name specifier, a flag /// indicating whether the "template" keyword was provided, and the template /// that the template name refers to. /// /// By default, builds the new template name directly. Subclasses may override /// this routine to provide different behavior. TemplateName RebuildTemplateName(CXXScopeSpec &SS, bool TemplateKW, TemplateDecl *Template); /// Build a new template name given a nested name specifier and the /// name that is referred to as a template. /// /// By default, performs semantic analysis to determine whether the name can /// be resolved to a specific template, then builds the appropriate kind of /// template name. Subclasses may override this routine to provide different /// behavior. TemplateName RebuildTemplateName(CXXScopeSpec &SS, SourceLocation TemplateKWLoc, const IdentifierInfo &Name, SourceLocation NameLoc, QualType ObjectType, NamedDecl *FirstQualifierInScope, bool AllowInjectedClassName); /// Build a new template name given a nested name specifier and the /// overloaded operator name that is referred to as a template. /// /// By default, performs semantic analysis to determine whether the name can /// be resolved to a specific template, then builds the appropriate kind of /// template name. Subclasses may override this routine to provide different /// behavior. TemplateName RebuildTemplateName(CXXScopeSpec &SS, SourceLocation TemplateKWLoc, OverloadedOperatorKind Operator, SourceLocation NameLoc, QualType ObjectType, bool AllowInjectedClassName); /// Build a new template name given a template template parameter pack /// and the /// /// By default, performs semantic analysis to determine whether the name can /// be resolved to a specific template, then builds the appropriate kind of /// template name. Subclasses may override this routine to provide different /// behavior. TemplateName RebuildTemplateName(TemplateTemplateParmDecl *Param, const TemplateArgument &ArgPack) { return getSema().Context.getSubstTemplateTemplateParmPack(Param, ArgPack); } /// Build a new compound statement. /// /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. StmtResult RebuildCompoundStmt(SourceLocation LBraceLoc, MultiStmtArg Statements, SourceLocation RBraceLoc, bool IsStmtExpr) { return getSema().ActOnCompoundStmt(LBraceLoc, RBraceLoc, Statements, IsStmtExpr); } /// Build a new case statement. /// /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. StmtResult RebuildCaseStmt(SourceLocation CaseLoc, Expr *LHS, SourceLocation EllipsisLoc, Expr *RHS, SourceLocation ColonLoc) { return getSema().ActOnCaseStmt(CaseLoc, LHS, EllipsisLoc, RHS, ColonLoc); } /// Attach the body to a new case statement. /// /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. StmtResult RebuildCaseStmtBody(Stmt *S, Stmt *Body) { getSema().ActOnCaseStmtBody(S, Body); return S; } /// Build a new default statement. /// /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. StmtResult RebuildDefaultStmt(SourceLocation DefaultLoc, SourceLocation ColonLoc, Stmt *SubStmt) { return getSema().ActOnDefaultStmt(DefaultLoc, ColonLoc, SubStmt, /*CurScope=*/nullptr); } /// Build a new label statement. /// /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. StmtResult RebuildLabelStmt(SourceLocation IdentLoc, LabelDecl *L, SourceLocation ColonLoc, Stmt *SubStmt) { return SemaRef.ActOnLabelStmt(IdentLoc, L, ColonLoc, SubStmt); } /// Build a new label statement. /// /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. StmtResult RebuildAttributedStmt(SourceLocation AttrLoc, ArrayRef Attrs, Stmt *SubStmt) { return SemaRef.ActOnAttributedStmt(AttrLoc, Attrs, SubStmt); } /// Build a new "if" statement. /// /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. StmtResult RebuildIfStmt(SourceLocation IfLoc, bool IsConstexpr, Sema::ConditionResult Cond, Stmt *Init, Stmt *Then, SourceLocation ElseLoc, Stmt *Else) { return getSema().ActOnIfStmt(IfLoc, IsConstexpr, Init, Cond, Then, ElseLoc, Else); } /// Start building a new switch statement. /// /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. StmtResult RebuildSwitchStmtStart(SourceLocation SwitchLoc, Stmt *Init, Sema::ConditionResult Cond) { return getSema().ActOnStartOfSwitchStmt(SwitchLoc, Init, Cond); } /// Attach the body to the switch statement. /// /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. StmtResult RebuildSwitchStmtBody(SourceLocation SwitchLoc, Stmt *Switch, Stmt *Body) { return getSema().ActOnFinishSwitchStmt(SwitchLoc, Switch, Body); } /// Build a new while statement. /// /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. StmtResult RebuildWhileStmt(SourceLocation WhileLoc, Sema::ConditionResult Cond, Stmt *Body) { return getSema().ActOnWhileStmt(WhileLoc, Cond, Body); } /// Build a new do-while statement. /// /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. StmtResult RebuildDoStmt(SourceLocation DoLoc, Stmt *Body, SourceLocation WhileLoc, SourceLocation LParenLoc, Expr *Cond, SourceLocation RParenLoc) { return getSema().ActOnDoStmt(DoLoc, Body, WhileLoc, LParenLoc, Cond, RParenLoc); } /// Build a new for statement. /// /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. StmtResult RebuildForStmt(SourceLocation ForLoc, SourceLocation LParenLoc, Stmt *Init, Sema::ConditionResult Cond, Sema::FullExprArg Inc, SourceLocation RParenLoc, Stmt *Body) { return getSema().ActOnForStmt(ForLoc, LParenLoc, Init, Cond, Inc, RParenLoc, Body); } /// Build a new goto statement. /// /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. StmtResult RebuildGotoStmt(SourceLocation GotoLoc, SourceLocation LabelLoc, LabelDecl *Label) { return getSema().ActOnGotoStmt(GotoLoc, LabelLoc, Label); } /// Build a new indirect goto statement. /// /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. StmtResult RebuildIndirectGotoStmt(SourceLocation GotoLoc, SourceLocation StarLoc, Expr *Target) { return getSema().ActOnIndirectGotoStmt(GotoLoc, StarLoc, Target); } /// Build a new return statement. /// /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. StmtResult RebuildReturnStmt(SourceLocation ReturnLoc, Expr *Result) { return getSema().BuildReturnStmt(ReturnLoc, Result); } /// Build a new declaration statement. /// /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. StmtResult RebuildDeclStmt(MutableArrayRef Decls, SourceLocation StartLoc, SourceLocation EndLoc) { Sema::DeclGroupPtrTy DG = getSema().BuildDeclaratorGroup(Decls); return getSema().ActOnDeclStmt(DG, StartLoc, EndLoc); } /// Build a new inline asm statement. /// /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. StmtResult RebuildGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple, bool IsVolatile, unsigned NumOutputs, unsigned NumInputs, IdentifierInfo **Names, MultiExprArg Constraints, MultiExprArg Exprs, Expr *AsmString, MultiExprArg Clobbers, unsigned NumLabels, SourceLocation RParenLoc) { return getSema().ActOnGCCAsmStmt(AsmLoc, IsSimple, IsVolatile, NumOutputs, NumInputs, Names, Constraints, Exprs, AsmString, Clobbers, NumLabels, RParenLoc); } /// Build a new MS style inline asm statement. /// /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. StmtResult RebuildMSAsmStmt(SourceLocation AsmLoc, SourceLocation LBraceLoc, ArrayRef AsmToks, StringRef AsmString, unsigned NumOutputs, unsigned NumInputs, ArrayRef Constraints, ArrayRef Clobbers, ArrayRef Exprs, SourceLocation EndLoc) { return getSema().ActOnMSAsmStmt(AsmLoc, LBraceLoc, AsmToks, AsmString, NumOutputs, NumInputs, Constraints, Clobbers, Exprs, EndLoc); } /// Build a new co_return statement. /// /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. StmtResult RebuildCoreturnStmt(SourceLocation CoreturnLoc, Expr *Result, bool IsImplicit) { return getSema().BuildCoreturnStmt(CoreturnLoc, Result, IsImplicit); } /// Build a new co_await expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. ExprResult RebuildCoawaitExpr(SourceLocation CoawaitLoc, Expr *Result, bool IsImplicit) { return getSema().BuildResolvedCoawaitExpr(CoawaitLoc, Result, IsImplicit); } /// Build a new co_await expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. ExprResult RebuildDependentCoawaitExpr(SourceLocation CoawaitLoc, Expr *Result, UnresolvedLookupExpr *Lookup) { return getSema().BuildUnresolvedCoawaitExpr(CoawaitLoc, Result, Lookup); } /// Build a new co_yield expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. ExprResult RebuildCoyieldExpr(SourceLocation CoyieldLoc, Expr *Result) { return getSema().BuildCoyieldExpr(CoyieldLoc, Result); } StmtResult RebuildCoroutineBodyStmt(CoroutineBodyStmt::CtorArgs Args) { return getSema().BuildCoroutineBodyStmt(Args); } /// Build a new Objective-C \@try statement. /// /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. StmtResult RebuildObjCAtTryStmt(SourceLocation AtLoc, Stmt *TryBody, MultiStmtArg CatchStmts, Stmt *Finally) { return getSema().ActOnObjCAtTryStmt(AtLoc, TryBody, CatchStmts, Finally); } /// Rebuild an Objective-C exception declaration. /// /// By default, performs semantic analysis to build the new declaration. /// Subclasses may override this routine to provide different behavior. VarDecl *RebuildObjCExceptionDecl(VarDecl *ExceptionDecl, TypeSourceInfo *TInfo, QualType T) { return getSema().BuildObjCExceptionDecl(TInfo, T, ExceptionDecl->getInnerLocStart(), ExceptionDecl->getLocation(), ExceptionDecl->getIdentifier()); } /// Build a new Objective-C \@catch statement. /// /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. StmtResult RebuildObjCAtCatchStmt(SourceLocation AtLoc, SourceLocation RParenLoc, VarDecl *Var, Stmt *Body) { return getSema().ActOnObjCAtCatchStmt(AtLoc, RParenLoc, Var, Body); } /// Build a new Objective-C \@finally statement. /// /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. StmtResult RebuildObjCAtFinallyStmt(SourceLocation AtLoc, Stmt *Body) { return getSema().ActOnObjCAtFinallyStmt(AtLoc, Body); } /// Build a new Objective-C \@throw statement. /// /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. StmtResult RebuildObjCAtThrowStmt(SourceLocation AtLoc, Expr *Operand) { return getSema().BuildObjCAtThrowStmt(AtLoc, Operand); } /// Build a new OpenMP executable directive. /// /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. StmtResult RebuildOMPExecutableDirective(OpenMPDirectiveKind Kind, DeclarationNameInfo DirName, OpenMPDirectiveKind CancelRegion, ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc) { return getSema().ActOnOpenMPExecutableDirective( Kind, DirName, CancelRegion, Clauses, AStmt, StartLoc, EndLoc); } /// Build a new OpenMP 'if' clause. /// /// By default, performs semantic analysis to build the new OpenMP clause. /// Subclasses may override this routine to provide different behavior. OMPClause *RebuildOMPIfClause(OpenMPDirectiveKind NameModifier, Expr *Condition, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation NameModifierLoc, SourceLocation ColonLoc, SourceLocation EndLoc) { return getSema().ActOnOpenMPIfClause(NameModifier, Condition, StartLoc, LParenLoc, NameModifierLoc, ColonLoc, EndLoc); } /// Build a new OpenMP 'final' clause. /// /// By default, performs semantic analysis to build the new OpenMP clause. /// Subclasses may override this routine to provide different behavior. OMPClause *RebuildOMPFinalClause(Expr *Condition, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc) { return getSema().ActOnOpenMPFinalClause(Condition, StartLoc, LParenLoc, EndLoc); } /// Build a new OpenMP 'num_threads' clause. /// /// By default, performs semantic analysis to build the new OpenMP clause. /// Subclasses may override this routine to provide different behavior. OMPClause *RebuildOMPNumThreadsClause(Expr *NumThreads, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc) { return getSema().ActOnOpenMPNumThreadsClause(NumThreads, StartLoc, LParenLoc, EndLoc); } /// Build a new OpenMP 'safelen' clause. /// /// By default, performs semantic analysis to build the new OpenMP clause. /// Subclasses may override this routine to provide different behavior. OMPClause *RebuildOMPSafelenClause(Expr *Len, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc) { return getSema().ActOnOpenMPSafelenClause(Len, StartLoc, LParenLoc, EndLoc); } /// Build a new OpenMP 'simdlen' clause. /// /// By default, performs semantic analysis to build the new OpenMP clause. /// Subclasses may override this routine to provide different behavior. OMPClause *RebuildOMPSimdlenClause(Expr *Len, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc) { return getSema().ActOnOpenMPSimdlenClause(Len, StartLoc, LParenLoc, EndLoc); } /// Build a new OpenMP 'allocator' clause. /// /// By default, performs semantic analysis to build the new OpenMP clause. /// Subclasses may override this routine to provide different behavior. OMPClause *RebuildOMPAllocatorClause(Expr *A, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc) { return getSema().ActOnOpenMPAllocatorClause(A, StartLoc, LParenLoc, EndLoc); } /// Build a new OpenMP 'collapse' clause. /// /// By default, performs semantic analysis to build the new OpenMP clause. /// Subclasses may override this routine to provide different behavior. OMPClause *RebuildOMPCollapseClause(Expr *Num, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc) { return getSema().ActOnOpenMPCollapseClause(Num, StartLoc, LParenLoc, EndLoc); } /// Build a new OpenMP 'default' clause. /// /// By default, performs semantic analysis to build the new OpenMP clause. /// Subclasses may override this routine to provide different behavior. OMPClause *RebuildOMPDefaultClause(OpenMPDefaultClauseKind Kind, SourceLocation KindKwLoc, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc) { return getSema().ActOnOpenMPDefaultClause(Kind, KindKwLoc, StartLoc, LParenLoc, EndLoc); } /// Build a new OpenMP 'proc_bind' clause. /// /// By default, performs semantic analysis to build the new OpenMP clause. /// Subclasses may override this routine to provide different behavior. OMPClause *RebuildOMPProcBindClause(ProcBindKind Kind, SourceLocation KindKwLoc, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc) { return getSema().ActOnOpenMPProcBindClause(Kind, KindKwLoc, StartLoc, LParenLoc, EndLoc); } /// Build a new OpenMP 'schedule' clause. /// /// By default, performs semantic analysis to build the new OpenMP clause. /// Subclasses may override this routine to provide different behavior. OMPClause *RebuildOMPScheduleClause( OpenMPScheduleClauseModifier M1, OpenMPScheduleClauseModifier M2, OpenMPScheduleClauseKind Kind, Expr *ChunkSize, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation M1Loc, SourceLocation M2Loc, SourceLocation KindLoc, SourceLocation CommaLoc, SourceLocation EndLoc) { return getSema().ActOnOpenMPScheduleClause( M1, M2, Kind, ChunkSize, StartLoc, LParenLoc, M1Loc, M2Loc, KindLoc, CommaLoc, EndLoc); } /// Build a new OpenMP 'ordered' clause. /// /// By default, performs semantic analysis to build the new OpenMP clause. /// Subclasses may override this routine to provide different behavior. OMPClause *RebuildOMPOrderedClause(SourceLocation StartLoc, SourceLocation EndLoc, SourceLocation LParenLoc, Expr *Num) { return getSema().ActOnOpenMPOrderedClause(StartLoc, EndLoc, LParenLoc, Num); } /// Build a new OpenMP 'private' clause. /// /// By default, performs semantic analysis to build the new OpenMP clause. /// Subclasses may override this routine to provide different behavior. OMPClause *RebuildOMPPrivateClause(ArrayRef VarList, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc) { return getSema().ActOnOpenMPPrivateClause(VarList, StartLoc, LParenLoc, EndLoc); } /// Build a new OpenMP 'firstprivate' clause. /// /// By default, performs semantic analysis to build the new OpenMP clause. /// Subclasses may override this routine to provide different behavior. OMPClause *RebuildOMPFirstprivateClause(ArrayRef VarList, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc) { return getSema().ActOnOpenMPFirstprivateClause(VarList, StartLoc, LParenLoc, EndLoc); } /// Build a new OpenMP 'lastprivate' clause. /// /// By default, performs semantic analysis to build the new OpenMP clause. /// Subclasses may override this routine to provide different behavior. OMPClause *RebuildOMPLastprivateClause(ArrayRef VarList, OpenMPLastprivateModifier LPKind, SourceLocation LPKindLoc, SourceLocation ColonLoc, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc) { return getSema().ActOnOpenMPLastprivateClause( VarList, LPKind, LPKindLoc, ColonLoc, StartLoc, LParenLoc, EndLoc); } /// Build a new OpenMP 'shared' clause. /// /// By default, performs semantic analysis to build the new OpenMP clause. /// Subclasses may override this routine to provide different behavior. OMPClause *RebuildOMPSharedClause(ArrayRef VarList, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc) { return getSema().ActOnOpenMPSharedClause(VarList, StartLoc, LParenLoc, EndLoc); } /// Build a new OpenMP 'reduction' clause. /// /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. OMPClause *RebuildOMPReductionClause(ArrayRef VarList, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation ColonLoc, SourceLocation EndLoc, CXXScopeSpec &ReductionIdScopeSpec, const DeclarationNameInfo &ReductionId, ArrayRef UnresolvedReductions) { return getSema().ActOnOpenMPReductionClause( VarList, StartLoc, LParenLoc, ColonLoc, EndLoc, ReductionIdScopeSpec, ReductionId, UnresolvedReductions); } /// Build a new OpenMP 'task_reduction' clause. /// /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. OMPClause *RebuildOMPTaskReductionClause( ArrayRef VarList, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation ColonLoc, SourceLocation EndLoc, CXXScopeSpec &ReductionIdScopeSpec, const DeclarationNameInfo &ReductionId, ArrayRef UnresolvedReductions) { return getSema().ActOnOpenMPTaskReductionClause( VarList, StartLoc, LParenLoc, ColonLoc, EndLoc, ReductionIdScopeSpec, ReductionId, UnresolvedReductions); } /// Build a new OpenMP 'in_reduction' clause. /// /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. OMPClause * RebuildOMPInReductionClause(ArrayRef VarList, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation ColonLoc, SourceLocation EndLoc, CXXScopeSpec &ReductionIdScopeSpec, const DeclarationNameInfo &ReductionId, ArrayRef UnresolvedReductions) { return getSema().ActOnOpenMPInReductionClause( VarList, StartLoc, LParenLoc, ColonLoc, EndLoc, ReductionIdScopeSpec, ReductionId, UnresolvedReductions); } /// Build a new OpenMP 'linear' clause. /// /// By default, performs semantic analysis to build the new OpenMP clause. /// Subclasses may override this routine to provide different behavior. OMPClause *RebuildOMPLinearClause(ArrayRef VarList, Expr *Step, SourceLocation StartLoc, SourceLocation LParenLoc, OpenMPLinearClauseKind Modifier, SourceLocation ModifierLoc, SourceLocation ColonLoc, SourceLocation EndLoc) { return getSema().ActOnOpenMPLinearClause(VarList, Step, StartLoc, LParenLoc, Modifier, ModifierLoc, ColonLoc, EndLoc); } /// Build a new OpenMP 'aligned' clause. /// /// By default, performs semantic analysis to build the new OpenMP clause. /// Subclasses may override this routine to provide different behavior. OMPClause *RebuildOMPAlignedClause(ArrayRef VarList, Expr *Alignment, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation ColonLoc, SourceLocation EndLoc) { return getSema().ActOnOpenMPAlignedClause(VarList, Alignment, StartLoc, LParenLoc, ColonLoc, EndLoc); } /// Build a new OpenMP 'copyin' clause. /// /// By default, performs semantic analysis to build the new OpenMP clause. /// Subclasses may override this routine to provide different behavior. OMPClause *RebuildOMPCopyinClause(ArrayRef VarList, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc) { return getSema().ActOnOpenMPCopyinClause(VarList, StartLoc, LParenLoc, EndLoc); } /// Build a new OpenMP 'copyprivate' clause. /// /// By default, performs semantic analysis to build the new OpenMP clause. /// Subclasses may override this routine to provide different behavior. OMPClause *RebuildOMPCopyprivateClause(ArrayRef VarList, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc) { return getSema().ActOnOpenMPCopyprivateClause(VarList, StartLoc, LParenLoc, EndLoc); } /// Build a new OpenMP 'flush' pseudo clause. /// /// By default, performs semantic analysis to build the new OpenMP clause. /// Subclasses may override this routine to provide different behavior. OMPClause *RebuildOMPFlushClause(ArrayRef VarList, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc) { return getSema().ActOnOpenMPFlushClause(VarList, StartLoc, LParenLoc, EndLoc); } /// Build a new OpenMP 'depend' pseudo clause. /// /// By default, performs semantic analysis to build the new OpenMP clause. /// Subclasses may override this routine to provide different behavior. OMPClause * RebuildOMPDependClause(OpenMPDependClauseKind DepKind, SourceLocation DepLoc, SourceLocation ColonLoc, ArrayRef VarList, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc) { return getSema().ActOnOpenMPDependClause(DepKind, DepLoc, ColonLoc, VarList, StartLoc, LParenLoc, EndLoc); } /// Build a new OpenMP 'device' clause. /// /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. OMPClause *RebuildOMPDeviceClause(Expr *Device, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc) { return getSema().ActOnOpenMPDeviceClause(Device, StartLoc, LParenLoc, EndLoc); } /// Build a new OpenMP 'map' clause. /// /// By default, performs semantic analysis to build the new OpenMP clause. /// Subclasses may override this routine to provide different behavior. OMPClause *RebuildOMPMapClause( ArrayRef MapTypeModifiers, ArrayRef MapTypeModifiersLoc, CXXScopeSpec MapperIdScopeSpec, DeclarationNameInfo MapperId, OpenMPMapClauseKind MapType, bool IsMapTypeImplicit, SourceLocation MapLoc, SourceLocation ColonLoc, ArrayRef VarList, const OMPVarListLocTy &Locs, ArrayRef UnresolvedMappers) { return getSema().ActOnOpenMPMapClause(MapTypeModifiers, MapTypeModifiersLoc, MapperIdScopeSpec, MapperId, MapType, IsMapTypeImplicit, MapLoc, ColonLoc, VarList, Locs, UnresolvedMappers); } /// Build a new OpenMP 'allocate' clause. /// /// By default, performs semantic analysis to build the new OpenMP clause. /// Subclasses may override this routine to provide different behavior. OMPClause *RebuildOMPAllocateClause(Expr *Allocate, ArrayRef VarList, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation ColonLoc, SourceLocation EndLoc) { return getSema().ActOnOpenMPAllocateClause(Allocate, VarList, StartLoc, LParenLoc, ColonLoc, EndLoc); } /// Build a new OpenMP 'num_teams' clause. /// /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. OMPClause *RebuildOMPNumTeamsClause(Expr *NumTeams, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc) { return getSema().ActOnOpenMPNumTeamsClause(NumTeams, StartLoc, LParenLoc, EndLoc); } /// Build a new OpenMP 'thread_limit' clause. /// /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. OMPClause *RebuildOMPThreadLimitClause(Expr *ThreadLimit, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc) { return getSema().ActOnOpenMPThreadLimitClause(ThreadLimit, StartLoc, LParenLoc, EndLoc); } /// Build a new OpenMP 'priority' clause. /// /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. OMPClause *RebuildOMPPriorityClause(Expr *Priority, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc) { return getSema().ActOnOpenMPPriorityClause(Priority, StartLoc, LParenLoc, EndLoc); } /// Build a new OpenMP 'grainsize' clause. /// /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. OMPClause *RebuildOMPGrainsizeClause(Expr *Grainsize, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc) { return getSema().ActOnOpenMPGrainsizeClause(Grainsize, StartLoc, LParenLoc, EndLoc); } /// Build a new OpenMP 'num_tasks' clause. /// /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. OMPClause *RebuildOMPNumTasksClause(Expr *NumTasks, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc) { return getSema().ActOnOpenMPNumTasksClause(NumTasks, StartLoc, LParenLoc, EndLoc); } /// Build a new OpenMP 'hint' clause. /// /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. OMPClause *RebuildOMPHintClause(Expr *Hint, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc) { return getSema().ActOnOpenMPHintClause(Hint, StartLoc, LParenLoc, EndLoc); } /// Build a new OpenMP 'dist_schedule' clause. /// /// By default, performs semantic analysis to build the new OpenMP clause. /// Subclasses may override this routine to provide different behavior. OMPClause * RebuildOMPDistScheduleClause(OpenMPDistScheduleClauseKind Kind, Expr *ChunkSize, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation KindLoc, SourceLocation CommaLoc, SourceLocation EndLoc) { return getSema().ActOnOpenMPDistScheduleClause( Kind, ChunkSize, StartLoc, LParenLoc, KindLoc, CommaLoc, EndLoc); } /// Build a new OpenMP 'to' clause. /// /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. OMPClause *RebuildOMPToClause(ArrayRef VarList, CXXScopeSpec &MapperIdScopeSpec, DeclarationNameInfo &MapperId, const OMPVarListLocTy &Locs, ArrayRef UnresolvedMappers) { return getSema().ActOnOpenMPToClause(VarList, MapperIdScopeSpec, MapperId, Locs, UnresolvedMappers); } /// Build a new OpenMP 'from' clause. /// /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. OMPClause *RebuildOMPFromClause(ArrayRef VarList, CXXScopeSpec &MapperIdScopeSpec, DeclarationNameInfo &MapperId, const OMPVarListLocTy &Locs, ArrayRef UnresolvedMappers) { return getSema().ActOnOpenMPFromClause(VarList, MapperIdScopeSpec, MapperId, Locs, UnresolvedMappers); } /// Build a new OpenMP 'use_device_ptr' clause. /// /// By default, performs semantic analysis to build the new OpenMP clause. /// Subclasses may override this routine to provide different behavior. OMPClause *RebuildOMPUseDevicePtrClause(ArrayRef VarList, const OMPVarListLocTy &Locs) { return getSema().ActOnOpenMPUseDevicePtrClause(VarList, Locs); } /// Build a new OpenMP 'is_device_ptr' clause. /// /// By default, performs semantic analysis to build the new OpenMP clause. /// Subclasses may override this routine to provide different behavior. OMPClause *RebuildOMPIsDevicePtrClause(ArrayRef VarList, const OMPVarListLocTy &Locs) { return getSema().ActOnOpenMPIsDevicePtrClause(VarList, Locs); } /// Build a new OpenMP 'defaultmap' clause. /// /// By default, performs semantic analysis to build the new OpenMP clause. /// Subclasses may override this routine to provide different behavior. OMPClause *RebuildOMPDefaultmapClause(OpenMPDefaultmapClauseModifier M, OpenMPDefaultmapClauseKind Kind, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation MLoc, SourceLocation KindLoc, SourceLocation EndLoc) { return getSema().ActOnOpenMPDefaultmapClause(M, Kind, StartLoc, LParenLoc, MLoc, KindLoc, EndLoc); } /// Build a new OpenMP 'nontemporal' clause. /// /// By default, performs semantic analysis to build the new OpenMP clause. /// Subclasses may override this routine to provide different behavior. OMPClause *RebuildOMPNontemporalClause(ArrayRef VarList, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc) { return getSema().ActOnOpenMPNontemporalClause(VarList, StartLoc, LParenLoc, EndLoc); } /// Rebuild the operand to an Objective-C \@synchronized statement. /// /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. ExprResult RebuildObjCAtSynchronizedOperand(SourceLocation atLoc, Expr *object) { return getSema().ActOnObjCAtSynchronizedOperand(atLoc, object); } /// Build a new Objective-C \@synchronized statement. /// /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. StmtResult RebuildObjCAtSynchronizedStmt(SourceLocation AtLoc, Expr *Object, Stmt *Body) { return getSema().ActOnObjCAtSynchronizedStmt(AtLoc, Object, Body); } /// Build a new Objective-C \@autoreleasepool statement. /// /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. StmtResult RebuildObjCAutoreleasePoolStmt(SourceLocation AtLoc, Stmt *Body) { return getSema().ActOnObjCAutoreleasePoolStmt(AtLoc, Body); } /// Build a new Objective-C fast enumeration statement. /// /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. StmtResult RebuildObjCForCollectionStmt(SourceLocation ForLoc, Stmt *Element, Expr *Collection, SourceLocation RParenLoc, Stmt *Body) { StmtResult ForEachStmt = getSema().ActOnObjCForCollectionStmt(ForLoc, Element, Collection, RParenLoc); if (ForEachStmt.isInvalid()) return StmtError(); return getSema().FinishObjCForCollectionStmt(ForEachStmt.get(), Body); } /// Build a new C++ exception declaration. /// /// By default, performs semantic analysis to build the new decaration. /// Subclasses may override this routine to provide different behavior. VarDecl *RebuildExceptionDecl(VarDecl *ExceptionDecl, TypeSourceInfo *Declarator, SourceLocation StartLoc, SourceLocation IdLoc, IdentifierInfo *Id) { VarDecl *Var = getSema().BuildExceptionDeclaration(nullptr, Declarator, StartLoc, IdLoc, Id); if (Var) getSema().CurContext->addDecl(Var); return Var; } /// Build a new C++ catch statement. /// /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. StmtResult RebuildCXXCatchStmt(SourceLocation CatchLoc, VarDecl *ExceptionDecl, Stmt *Handler) { return Owned(new (getSema().Context) CXXCatchStmt(CatchLoc, ExceptionDecl, Handler)); } /// Build a new C++ try statement. /// /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. StmtResult RebuildCXXTryStmt(SourceLocation TryLoc, Stmt *TryBlock, ArrayRef Handlers) { return getSema().ActOnCXXTryBlock(TryLoc, TryBlock, Handlers); } /// Build a new C++0x range-based for statement. /// /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. StmtResult RebuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation CoawaitLoc, Stmt *Init, SourceLocation ColonLoc, Stmt *Range, Stmt *Begin, Stmt *End, Expr *Cond, Expr *Inc, Stmt *LoopVar, SourceLocation RParenLoc) { // If we've just learned that the range is actually an Objective-C // collection, treat this as an Objective-C fast enumeration loop. if (DeclStmt *RangeStmt = dyn_cast(Range)) { if (RangeStmt->isSingleDecl()) { if (VarDecl *RangeVar = dyn_cast(RangeStmt->getSingleDecl())) { if (RangeVar->isInvalidDecl()) return StmtError(); Expr *RangeExpr = RangeVar->getInit(); if (!RangeExpr->isTypeDependent() && RangeExpr->getType()->isObjCObjectPointerType()) { // FIXME: Support init-statements in Objective-C++20 ranged for // statement. if (Init) { return SemaRef.Diag(Init->getBeginLoc(), diag::err_objc_for_range_init_stmt) << Init->getSourceRange(); } return getSema().ActOnObjCForCollectionStmt(ForLoc, LoopVar, RangeExpr, RParenLoc); } } } } return getSema().BuildCXXForRangeStmt(ForLoc, CoawaitLoc, Init, ColonLoc, Range, Begin, End, Cond, Inc, LoopVar, RParenLoc, Sema::BFRK_Rebuild); } /// Build a new C++0x range-based for statement. /// /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. StmtResult RebuildMSDependentExistsStmt(SourceLocation KeywordLoc, bool IsIfExists, NestedNameSpecifierLoc QualifierLoc, DeclarationNameInfo NameInfo, Stmt *Nested) { return getSema().BuildMSDependentExistsStmt(KeywordLoc, IsIfExists, QualifierLoc, NameInfo, Nested); } /// Attach body to a C++0x range-based for statement. /// /// By default, performs semantic analysis to finish the new statement. /// Subclasses may override this routine to provide different behavior. StmtResult FinishCXXForRangeStmt(Stmt *ForRange, Stmt *Body) { return getSema().FinishCXXForRangeStmt(ForRange, Body); } StmtResult RebuildSEHTryStmt(bool IsCXXTry, SourceLocation TryLoc, Stmt *TryBlock, Stmt *Handler) { return getSema().ActOnSEHTryBlock(IsCXXTry, TryLoc, TryBlock, Handler); } StmtResult RebuildSEHExceptStmt(SourceLocation Loc, Expr *FilterExpr, Stmt *Block) { return getSema().ActOnSEHExceptBlock(Loc, FilterExpr, Block); } StmtResult RebuildSEHFinallyStmt(SourceLocation Loc, Stmt *Block) { return SEHFinallyStmt::Create(getSema().getASTContext(), Loc, Block); } /// Build a new predefined expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. ExprResult RebuildPredefinedExpr(SourceLocation Loc, PredefinedExpr::IdentKind IK) { return getSema().BuildPredefinedExpr(Loc, IK); } /// Build a new expression that references a declaration. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. ExprResult RebuildDeclarationNameExpr(const CXXScopeSpec &SS, LookupResult &R, bool RequiresADL) { return getSema().BuildDeclarationNameExpr(SS, R, RequiresADL); } /// Build a new expression that references a declaration. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. ExprResult RebuildDeclRefExpr(NestedNameSpecifierLoc QualifierLoc, ValueDecl *VD, const DeclarationNameInfo &NameInfo, NamedDecl *Found, TemplateArgumentListInfo *TemplateArgs) { CXXScopeSpec SS; SS.Adopt(QualifierLoc); return getSema().BuildDeclarationNameExpr(SS, NameInfo, VD, Found, TemplateArgs); } /// Build a new expression in parentheses. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. ExprResult RebuildParenExpr(Expr *SubExpr, SourceLocation LParen, SourceLocation RParen) { return getSema().ActOnParenExpr(LParen, RParen, SubExpr); } /// Build a new pseudo-destructor expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. ExprResult RebuildCXXPseudoDestructorExpr(Expr *Base, SourceLocation OperatorLoc, bool isArrow, CXXScopeSpec &SS, TypeSourceInfo *ScopeType, SourceLocation CCLoc, SourceLocation TildeLoc, PseudoDestructorTypeStorage Destroyed); /// Build a new unary operator expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. ExprResult RebuildUnaryOperator(SourceLocation OpLoc, UnaryOperatorKind Opc, Expr *SubExpr) { return getSema().BuildUnaryOp(/*Scope=*/nullptr, OpLoc, Opc, SubExpr); } /// Build a new builtin offsetof expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. ExprResult RebuildOffsetOfExpr(SourceLocation OperatorLoc, TypeSourceInfo *Type, ArrayRef Components, SourceLocation RParenLoc) { return getSema().BuildBuiltinOffsetOf(OperatorLoc, Type, Components, RParenLoc); } /// Build a new sizeof, alignof or vec_step expression with a /// type argument. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. ExprResult RebuildUnaryExprOrTypeTrait(TypeSourceInfo *TInfo, SourceLocation OpLoc, UnaryExprOrTypeTrait ExprKind, SourceRange R) { return getSema().CreateUnaryExprOrTypeTraitExpr(TInfo, OpLoc, ExprKind, R); } /// Build a new sizeof, alignof or vec step expression with an /// expression argument. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. ExprResult RebuildUnaryExprOrTypeTrait(Expr *SubExpr, SourceLocation OpLoc, UnaryExprOrTypeTrait ExprKind, SourceRange R) { ExprResult Result = getSema().CreateUnaryExprOrTypeTraitExpr(SubExpr, OpLoc, ExprKind); if (Result.isInvalid()) return ExprError(); return Result; } /// Build a new array subscript expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. ExprResult RebuildArraySubscriptExpr(Expr *LHS, SourceLocation LBracketLoc, Expr *RHS, SourceLocation RBracketLoc) { return getSema().ActOnArraySubscriptExpr(/*Scope=*/nullptr, LHS, LBracketLoc, RHS, RBracketLoc); } /// Build a new array section expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. ExprResult RebuildOMPArraySectionExpr(Expr *Base, SourceLocation LBracketLoc, Expr *LowerBound, SourceLocation ColonLoc, Expr *Length, SourceLocation RBracketLoc) { return getSema().ActOnOMPArraySectionExpr(Base, LBracketLoc, LowerBound, ColonLoc, Length, RBracketLoc); } /// Build a new call expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. ExprResult RebuildCallExpr(Expr *Callee, SourceLocation LParenLoc, MultiExprArg Args, SourceLocation RParenLoc, Expr *ExecConfig = nullptr) { return getSema().BuildCallExpr(/*Scope=*/nullptr, Callee, LParenLoc, Args, RParenLoc, ExecConfig); } /// Build a new member access expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. ExprResult RebuildMemberExpr(Expr *Base, SourceLocation OpLoc, bool isArrow, NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateKWLoc, const DeclarationNameInfo &MemberNameInfo, ValueDecl *Member, NamedDecl *FoundDecl, const TemplateArgumentListInfo *ExplicitTemplateArgs, NamedDecl *FirstQualifierInScope) { ExprResult BaseResult = getSema().PerformMemberExprBaseConversion(Base, isArrow); if (!Member->getDeclName()) { // We have a reference to an unnamed field. This is always the // base of an anonymous struct/union member access, i.e. the // field is always of record type. assert(Member->getType()->isRecordType() && "unnamed member not of record type?"); BaseResult = getSema().PerformObjectMemberConversion(BaseResult.get(), QualifierLoc.getNestedNameSpecifier(), FoundDecl, Member); if (BaseResult.isInvalid()) return ExprError(); Base = BaseResult.get(); CXXScopeSpec EmptySS; return getSema().BuildFieldReferenceExpr( Base, isArrow, OpLoc, EmptySS, cast(Member), DeclAccessPair::make(FoundDecl, FoundDecl->getAccess()), MemberNameInfo); } CXXScopeSpec SS; SS.Adopt(QualifierLoc); Base = BaseResult.get(); QualType BaseType = Base->getType(); if (isArrow && !BaseType->isPointerType()) return ExprError(); // FIXME: this involves duplicating earlier analysis in a lot of // cases; we should avoid this when possible. LookupResult R(getSema(), MemberNameInfo, Sema::LookupMemberName); R.addDecl(FoundDecl); R.resolveKind(); return getSema().BuildMemberReferenceExpr(Base, BaseType, OpLoc, isArrow, SS, TemplateKWLoc, FirstQualifierInScope, R, ExplicitTemplateArgs, /*S*/nullptr); } /// Build a new binary operator expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. ExprResult RebuildBinaryOperator(SourceLocation OpLoc, BinaryOperatorKind Opc, Expr *LHS, Expr *RHS) { return getSema().BuildBinOp(/*Scope=*/nullptr, OpLoc, Opc, LHS, RHS); } /// Build a new rewritten operator expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. ExprResult RebuildCXXRewrittenBinaryOperator( SourceLocation OpLoc, BinaryOperatorKind Opcode, const UnresolvedSetImpl &UnqualLookups, Expr *LHS, Expr *RHS) { return getSema().CreateOverloadedBinOp(OpLoc, Opcode, UnqualLookups, LHS, RHS, /*RequiresADL*/false); } /// Build a new conditional operator expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. ExprResult RebuildConditionalOperator(Expr *Cond, SourceLocation QuestionLoc, Expr *LHS, SourceLocation ColonLoc, Expr *RHS) { return getSema().ActOnConditionalOp(QuestionLoc, ColonLoc, Cond, LHS, RHS); } /// Build a new C-style cast expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. ExprResult RebuildCStyleCastExpr(SourceLocation LParenLoc, TypeSourceInfo *TInfo, SourceLocation RParenLoc, Expr *SubExpr) { return getSema().BuildCStyleCastExpr(LParenLoc, TInfo, RParenLoc, SubExpr); } /// Build a new compound literal expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. ExprResult RebuildCompoundLiteralExpr(SourceLocation LParenLoc, TypeSourceInfo *TInfo, SourceLocation RParenLoc, Expr *Init) { return getSema().BuildCompoundLiteralExpr(LParenLoc, TInfo, RParenLoc, Init); } /// Build a new extended vector element access expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. ExprResult RebuildExtVectorElementExpr(Expr *Base, SourceLocation OpLoc, SourceLocation AccessorLoc, IdentifierInfo &Accessor) { CXXScopeSpec SS; DeclarationNameInfo NameInfo(&Accessor, AccessorLoc); return getSema().BuildMemberReferenceExpr(Base, Base->getType(), OpLoc, /*IsArrow*/ false, SS, SourceLocation(), /*FirstQualifierInScope*/ nullptr, NameInfo, /* TemplateArgs */ nullptr, /*S*/ nullptr); } /// Build a new initializer list expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. ExprResult RebuildInitList(SourceLocation LBraceLoc, MultiExprArg Inits, SourceLocation RBraceLoc) { return SemaRef.BuildInitList(LBraceLoc, Inits, RBraceLoc); } /// Build a new designated initializer expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. ExprResult RebuildDesignatedInitExpr(Designation &Desig, MultiExprArg ArrayExprs, SourceLocation EqualOrColonLoc, bool GNUSyntax, Expr *Init) { ExprResult Result = SemaRef.ActOnDesignatedInitializer(Desig, EqualOrColonLoc, GNUSyntax, Init); if (Result.isInvalid()) return ExprError(); return Result; } /// Build a new value-initialized expression. /// /// By default, builds the implicit value initialization without performing /// any semantic analysis. Subclasses may override this routine to provide /// different behavior. ExprResult RebuildImplicitValueInitExpr(QualType T) { return new (SemaRef.Context) ImplicitValueInitExpr(T); } /// Build a new \c va_arg expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. ExprResult RebuildVAArgExpr(SourceLocation BuiltinLoc, Expr *SubExpr, TypeSourceInfo *TInfo, SourceLocation RParenLoc) { return getSema().BuildVAArgExpr(BuiltinLoc, SubExpr, TInfo, RParenLoc); } /// Build a new expression list in parentheses. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. ExprResult RebuildParenListExpr(SourceLocation LParenLoc, MultiExprArg SubExprs, SourceLocation RParenLoc) { return getSema().ActOnParenListExpr(LParenLoc, RParenLoc, SubExprs); } /// Build a new address-of-label expression. /// /// By default, performs semantic analysis, using the name of the label /// rather than attempting to map the label statement itself. /// Subclasses may override this routine to provide different behavior. ExprResult RebuildAddrLabelExpr(SourceLocation AmpAmpLoc, SourceLocation LabelLoc, LabelDecl *Label) { return getSema().ActOnAddrLabel(AmpAmpLoc, LabelLoc, Label); } /// Build a new GNU statement expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. - ExprResult RebuildStmtExpr(SourceLocation LParenLoc, - Stmt *SubStmt, - SourceLocation RParenLoc) { - return getSema().ActOnStmtExpr(LParenLoc, SubStmt, RParenLoc); + ExprResult RebuildStmtExpr(SourceLocation LParenLoc, Stmt *SubStmt, + SourceLocation RParenLoc) { + return getSema().ActOnStmtExpr(nullptr, LParenLoc, SubStmt, RParenLoc); } /// Build a new __builtin_choose_expr expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. ExprResult RebuildChooseExpr(SourceLocation BuiltinLoc, Expr *Cond, Expr *LHS, Expr *RHS, SourceLocation RParenLoc) { return SemaRef.ActOnChooseExpr(BuiltinLoc, Cond, LHS, RHS, RParenLoc); } /// Build a new generic selection expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. ExprResult RebuildGenericSelectionExpr(SourceLocation KeyLoc, SourceLocation DefaultLoc, SourceLocation RParenLoc, Expr *ControllingExpr, ArrayRef Types, ArrayRef Exprs) { return getSema().CreateGenericSelectionExpr(KeyLoc, DefaultLoc, RParenLoc, ControllingExpr, Types, Exprs); } /// Build a new overloaded operator call expression. /// /// By default, performs semantic analysis to build the new expression. /// The semantic analysis provides the behavior of template instantiation, /// copying with transformations that turn what looks like an overloaded /// operator call into a use of a builtin operator, performing /// argument-dependent lookup, etc. Subclasses may override this routine to /// provide different behavior. ExprResult RebuildCXXOperatorCallExpr(OverloadedOperatorKind Op, SourceLocation OpLoc, Expr *Callee, Expr *First, Expr *Second); /// Build a new C++ "named" cast expression, such as static_cast or /// reinterpret_cast. /// /// By default, this routine dispatches to one of the more-specific routines /// for a particular named case, e.g., RebuildCXXStaticCastExpr(). /// Subclasses may override this routine to provide different behavior. ExprResult RebuildCXXNamedCastExpr(SourceLocation OpLoc, Stmt::StmtClass Class, SourceLocation LAngleLoc, TypeSourceInfo *TInfo, SourceLocation RAngleLoc, SourceLocation LParenLoc, Expr *SubExpr, SourceLocation RParenLoc) { switch (Class) { case Stmt::CXXStaticCastExprClass: return getDerived().RebuildCXXStaticCastExpr(OpLoc, LAngleLoc, TInfo, RAngleLoc, LParenLoc, SubExpr, RParenLoc); case Stmt::CXXDynamicCastExprClass: return getDerived().RebuildCXXDynamicCastExpr(OpLoc, LAngleLoc, TInfo, RAngleLoc, LParenLoc, SubExpr, RParenLoc); case Stmt::CXXReinterpretCastExprClass: return getDerived().RebuildCXXReinterpretCastExpr(OpLoc, LAngleLoc, TInfo, RAngleLoc, LParenLoc, SubExpr, RParenLoc); case Stmt::CXXConstCastExprClass: return getDerived().RebuildCXXConstCastExpr(OpLoc, LAngleLoc, TInfo, RAngleLoc, LParenLoc, SubExpr, RParenLoc); default: llvm_unreachable("Invalid C++ named cast"); } } /// Build a new C++ static_cast expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. ExprResult RebuildCXXStaticCastExpr(SourceLocation OpLoc, SourceLocation LAngleLoc, TypeSourceInfo *TInfo, SourceLocation RAngleLoc, SourceLocation LParenLoc, Expr *SubExpr, SourceLocation RParenLoc) { return getSema().BuildCXXNamedCast(OpLoc, tok::kw_static_cast, TInfo, SubExpr, SourceRange(LAngleLoc, RAngleLoc), SourceRange(LParenLoc, RParenLoc)); } /// Build a new C++ dynamic_cast expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. ExprResult RebuildCXXDynamicCastExpr(SourceLocation OpLoc, SourceLocation LAngleLoc, TypeSourceInfo *TInfo, SourceLocation RAngleLoc, SourceLocation LParenLoc, Expr *SubExpr, SourceLocation RParenLoc) { return getSema().BuildCXXNamedCast(OpLoc, tok::kw_dynamic_cast, TInfo, SubExpr, SourceRange(LAngleLoc, RAngleLoc), SourceRange(LParenLoc, RParenLoc)); } /// Build a new C++ reinterpret_cast expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. ExprResult RebuildCXXReinterpretCastExpr(SourceLocation OpLoc, SourceLocation LAngleLoc, TypeSourceInfo *TInfo, SourceLocation RAngleLoc, SourceLocation LParenLoc, Expr *SubExpr, SourceLocation RParenLoc) { return getSema().BuildCXXNamedCast(OpLoc, tok::kw_reinterpret_cast, TInfo, SubExpr, SourceRange(LAngleLoc, RAngleLoc), SourceRange(LParenLoc, RParenLoc)); } /// Build a new C++ const_cast expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. ExprResult RebuildCXXConstCastExpr(SourceLocation OpLoc, SourceLocation LAngleLoc, TypeSourceInfo *TInfo, SourceLocation RAngleLoc, SourceLocation LParenLoc, Expr *SubExpr, SourceLocation RParenLoc) { return getSema().BuildCXXNamedCast(OpLoc, tok::kw_const_cast, TInfo, SubExpr, SourceRange(LAngleLoc, RAngleLoc), SourceRange(LParenLoc, RParenLoc)); } /// Build a new C++ functional-style cast expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. ExprResult RebuildCXXFunctionalCastExpr(TypeSourceInfo *TInfo, SourceLocation LParenLoc, Expr *Sub, SourceLocation RParenLoc, bool ListInitialization) { return getSema().BuildCXXTypeConstructExpr(TInfo, LParenLoc, MultiExprArg(&Sub, 1), RParenLoc, ListInitialization); } /// Build a new C++ __builtin_bit_cast expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. ExprResult RebuildBuiltinBitCastExpr(SourceLocation KWLoc, TypeSourceInfo *TSI, Expr *Sub, SourceLocation RParenLoc) { return getSema().BuildBuiltinBitCastExpr(KWLoc, TSI, Sub, RParenLoc); } /// Build a new C++ typeid(type) expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. ExprResult RebuildCXXTypeidExpr(QualType TypeInfoType, SourceLocation TypeidLoc, TypeSourceInfo *Operand, SourceLocation RParenLoc) { return getSema().BuildCXXTypeId(TypeInfoType, TypeidLoc, Operand, RParenLoc); } /// Build a new C++ typeid(expr) expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. ExprResult RebuildCXXTypeidExpr(QualType TypeInfoType, SourceLocation TypeidLoc, Expr *Operand, SourceLocation RParenLoc) { return getSema().BuildCXXTypeId(TypeInfoType, TypeidLoc, Operand, RParenLoc); } /// Build a new C++ __uuidof(type) expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. ExprResult RebuildCXXUuidofExpr(QualType TypeInfoType, SourceLocation TypeidLoc, TypeSourceInfo *Operand, SourceLocation RParenLoc) { return getSema().BuildCXXUuidof(TypeInfoType, TypeidLoc, Operand, RParenLoc); } /// Build a new C++ __uuidof(expr) expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. ExprResult RebuildCXXUuidofExpr(QualType TypeInfoType, SourceLocation TypeidLoc, Expr *Operand, SourceLocation RParenLoc) { return getSema().BuildCXXUuidof(TypeInfoType, TypeidLoc, Operand, RParenLoc); } /// Build a new C++ "this" expression. /// /// By default, builds a new "this" expression without performing any /// semantic analysis. Subclasses may override this routine to provide /// different behavior. ExprResult RebuildCXXThisExpr(SourceLocation ThisLoc, QualType ThisType, bool isImplicit) { return getSema().BuildCXXThisExpr(ThisLoc, ThisType, isImplicit); } /// Build a new C++ throw expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. ExprResult RebuildCXXThrowExpr(SourceLocation ThrowLoc, Expr *Sub, bool IsThrownVariableInScope) { return getSema().BuildCXXThrow(ThrowLoc, Sub, IsThrownVariableInScope); } /// Build a new C++ default-argument expression. /// /// By default, builds a new default-argument expression, which does not /// require any semantic analysis. Subclasses may override this routine to /// provide different behavior. ExprResult RebuildCXXDefaultArgExpr(SourceLocation Loc, ParmVarDecl *Param) { return CXXDefaultArgExpr::Create(getSema().Context, Loc, Param, getSema().CurContext); } /// Build a new C++11 default-initialization expression. /// /// By default, builds a new default field initialization expression, which /// does not require any semantic analysis. Subclasses may override this /// routine to provide different behavior. ExprResult RebuildCXXDefaultInitExpr(SourceLocation Loc, FieldDecl *Field) { return CXXDefaultInitExpr::Create(getSema().Context, Loc, Field, getSema().CurContext); } /// Build a new C++ zero-initialization expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. ExprResult RebuildCXXScalarValueInitExpr(TypeSourceInfo *TSInfo, SourceLocation LParenLoc, SourceLocation RParenLoc) { return getSema().BuildCXXTypeConstructExpr( TSInfo, LParenLoc, None, RParenLoc, /*ListInitialization=*/false); } /// Build a new C++ "new" expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. ExprResult RebuildCXXNewExpr(SourceLocation StartLoc, bool UseGlobal, SourceLocation PlacementLParen, MultiExprArg PlacementArgs, SourceLocation PlacementRParen, SourceRange TypeIdParens, QualType AllocatedType, TypeSourceInfo *AllocatedTypeInfo, Optional ArraySize, SourceRange DirectInitRange, Expr *Initializer) { return getSema().BuildCXXNew(StartLoc, UseGlobal, PlacementLParen, PlacementArgs, PlacementRParen, TypeIdParens, AllocatedType, AllocatedTypeInfo, ArraySize, DirectInitRange, Initializer); } /// Build a new C++ "delete" expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. ExprResult RebuildCXXDeleteExpr(SourceLocation StartLoc, bool IsGlobalDelete, bool IsArrayForm, Expr *Operand) { return getSema().ActOnCXXDelete(StartLoc, IsGlobalDelete, IsArrayForm, Operand); } /// Build a new type trait expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. ExprResult RebuildTypeTrait(TypeTrait Trait, SourceLocation StartLoc, ArrayRef Args, SourceLocation RParenLoc) { return getSema().BuildTypeTrait(Trait, StartLoc, Args, RParenLoc); } /// Build a new array type trait expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. ExprResult RebuildArrayTypeTrait(ArrayTypeTrait Trait, SourceLocation StartLoc, TypeSourceInfo *TSInfo, Expr *DimExpr, SourceLocation RParenLoc) { return getSema().BuildArrayTypeTrait(Trait, StartLoc, TSInfo, DimExpr, RParenLoc); } /// Build a new expression trait expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. ExprResult RebuildExpressionTrait(ExpressionTrait Trait, SourceLocation StartLoc, Expr *Queried, SourceLocation RParenLoc) { return getSema().BuildExpressionTrait(Trait, StartLoc, Queried, RParenLoc); } /// Build a new (previously unresolved) declaration reference /// expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. ExprResult RebuildDependentScopeDeclRefExpr( NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateKWLoc, const DeclarationNameInfo &NameInfo, const TemplateArgumentListInfo *TemplateArgs, bool IsAddressOfOperand, TypeSourceInfo **RecoveryTSI) { CXXScopeSpec SS; SS.Adopt(QualifierLoc); if (TemplateArgs || TemplateKWLoc.isValid()) return getSema().BuildQualifiedTemplateIdExpr(SS, TemplateKWLoc, NameInfo, TemplateArgs); return getSema().BuildQualifiedDeclarationNameExpr( SS, NameInfo, IsAddressOfOperand, /*S*/nullptr, RecoveryTSI); } /// Build a new template-id expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. ExprResult RebuildTemplateIdExpr(const CXXScopeSpec &SS, SourceLocation TemplateKWLoc, LookupResult &R, bool RequiresADL, const TemplateArgumentListInfo *TemplateArgs) { return getSema().BuildTemplateIdExpr(SS, TemplateKWLoc, R, RequiresADL, TemplateArgs); } /// Build a new object-construction expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. ExprResult RebuildCXXConstructExpr(QualType T, SourceLocation Loc, CXXConstructorDecl *Constructor, bool IsElidable, MultiExprArg Args, bool HadMultipleCandidates, bool ListInitialization, bool StdInitListInitialization, bool RequiresZeroInit, CXXConstructExpr::ConstructionKind ConstructKind, SourceRange ParenRange) { SmallVector ConvertedArgs; if (getSema().CompleteConstructorCall(Constructor, Args, Loc, ConvertedArgs)) return ExprError(); return getSema().BuildCXXConstructExpr(Loc, T, Constructor, IsElidable, ConvertedArgs, HadMultipleCandidates, ListInitialization, StdInitListInitialization, RequiresZeroInit, ConstructKind, ParenRange); } /// Build a new implicit construction via inherited constructor /// expression. ExprResult RebuildCXXInheritedCtorInitExpr(QualType T, SourceLocation Loc, CXXConstructorDecl *Constructor, bool ConstructsVBase, bool InheritedFromVBase) { return new (getSema().Context) CXXInheritedCtorInitExpr( Loc, T, Constructor, ConstructsVBase, InheritedFromVBase); } /// Build a new object-construction expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. ExprResult RebuildCXXTemporaryObjectExpr(TypeSourceInfo *TSInfo, SourceLocation LParenOrBraceLoc, MultiExprArg Args, SourceLocation RParenOrBraceLoc, bool ListInitialization) { return getSema().BuildCXXTypeConstructExpr( TSInfo, LParenOrBraceLoc, Args, RParenOrBraceLoc, ListInitialization); } /// Build a new object-construction expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. ExprResult RebuildCXXUnresolvedConstructExpr(TypeSourceInfo *TSInfo, SourceLocation LParenLoc, MultiExprArg Args, SourceLocation RParenLoc, bool ListInitialization) { return getSema().BuildCXXTypeConstructExpr(TSInfo, LParenLoc, Args, RParenLoc, ListInitialization); } /// Build a new member reference expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. ExprResult RebuildCXXDependentScopeMemberExpr(Expr *BaseE, QualType BaseType, bool IsArrow, SourceLocation OperatorLoc, NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateKWLoc, NamedDecl *FirstQualifierInScope, const DeclarationNameInfo &MemberNameInfo, const TemplateArgumentListInfo *TemplateArgs) { CXXScopeSpec SS; SS.Adopt(QualifierLoc); return SemaRef.BuildMemberReferenceExpr(BaseE, BaseType, OperatorLoc, IsArrow, SS, TemplateKWLoc, FirstQualifierInScope, MemberNameInfo, TemplateArgs, /*S*/nullptr); } /// Build a new member reference expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. ExprResult RebuildUnresolvedMemberExpr(Expr *BaseE, QualType BaseType, SourceLocation OperatorLoc, bool IsArrow, NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateKWLoc, NamedDecl *FirstQualifierInScope, LookupResult &R, const TemplateArgumentListInfo *TemplateArgs) { CXXScopeSpec SS; SS.Adopt(QualifierLoc); return SemaRef.BuildMemberReferenceExpr(BaseE, BaseType, OperatorLoc, IsArrow, SS, TemplateKWLoc, FirstQualifierInScope, R, TemplateArgs, /*S*/nullptr); } /// Build a new noexcept expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. ExprResult RebuildCXXNoexceptExpr(SourceRange Range, Expr *Arg) { return SemaRef.BuildCXXNoexceptExpr(Range.getBegin(), Arg, Range.getEnd()); } /// Build a new expression to compute the length of a parameter pack. ExprResult RebuildSizeOfPackExpr(SourceLocation OperatorLoc, NamedDecl *Pack, SourceLocation PackLoc, SourceLocation RParenLoc, Optional Length, ArrayRef PartialArgs) { return SizeOfPackExpr::Create(SemaRef.Context, OperatorLoc, Pack, PackLoc, RParenLoc, Length, PartialArgs); } /// Build a new expression representing a call to a source location /// builtin. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. ExprResult RebuildSourceLocExpr(SourceLocExpr::IdentKind Kind, SourceLocation BuiltinLoc, SourceLocation RPLoc, DeclContext *ParentContext) { return getSema().BuildSourceLocExpr(Kind, BuiltinLoc, RPLoc, ParentContext); } /// Build a new Objective-C boxed expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. ExprResult RebuildConceptSpecializationExpr(NestedNameSpecifierLoc NNS, SourceLocation TemplateKWLoc, DeclarationNameInfo ConceptNameInfo, NamedDecl *FoundDecl, ConceptDecl *NamedConcept, TemplateArgumentListInfo *TALI) { CXXScopeSpec SS; SS.Adopt(NNS); ExprResult Result = getSema().CheckConceptTemplateId(SS, TemplateKWLoc, ConceptNameInfo, FoundDecl, NamedConcept, TALI); if (Result.isInvalid()) return ExprError(); return Result; } /// \brief Build a new requires expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. ExprResult RebuildRequiresExpr(SourceLocation RequiresKWLoc, RequiresExprBodyDecl *Body, ArrayRef LocalParameters, ArrayRef Requirements, SourceLocation ClosingBraceLoc) { return RequiresExpr::Create(SemaRef.Context, RequiresKWLoc, Body, LocalParameters, Requirements, ClosingBraceLoc); } concepts::TypeRequirement * RebuildTypeRequirement( concepts::Requirement::SubstitutionDiagnostic *SubstDiag) { return SemaRef.BuildTypeRequirement(SubstDiag); } concepts::TypeRequirement *RebuildTypeRequirement(TypeSourceInfo *T) { return SemaRef.BuildTypeRequirement(T); } concepts::ExprRequirement * RebuildExprRequirement( concepts::Requirement::SubstitutionDiagnostic *SubstDiag, bool IsSimple, SourceLocation NoexceptLoc, concepts::ExprRequirement::ReturnTypeRequirement Ret) { return SemaRef.BuildExprRequirement(SubstDiag, IsSimple, NoexceptLoc, std::move(Ret)); } concepts::ExprRequirement * RebuildExprRequirement(Expr *E, bool IsSimple, SourceLocation NoexceptLoc, concepts::ExprRequirement::ReturnTypeRequirement Ret) { return SemaRef.BuildExprRequirement(E, IsSimple, NoexceptLoc, std::move(Ret)); } concepts::NestedRequirement * RebuildNestedRequirement( concepts::Requirement::SubstitutionDiagnostic *SubstDiag) { return SemaRef.BuildNestedRequirement(SubstDiag); } concepts::NestedRequirement *RebuildNestedRequirement(Expr *Constraint) { return SemaRef.BuildNestedRequirement(Constraint); } /// \brief Build a new Objective-C boxed expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. ExprResult RebuildObjCBoxedExpr(SourceRange SR, Expr *ValueExpr) { return getSema().BuildObjCBoxedExpr(SR, ValueExpr); } /// Build a new Objective-C array literal. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. ExprResult RebuildObjCArrayLiteral(SourceRange Range, Expr **Elements, unsigned NumElements) { return getSema().BuildObjCArrayLiteral(Range, MultiExprArg(Elements, NumElements)); } ExprResult RebuildObjCSubscriptRefExpr(SourceLocation RB, Expr *Base, Expr *Key, ObjCMethodDecl *getterMethod, ObjCMethodDecl *setterMethod) { return getSema().BuildObjCSubscriptExpression(RB, Base, Key, getterMethod, setterMethod); } /// Build a new Objective-C dictionary literal. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. ExprResult RebuildObjCDictionaryLiteral(SourceRange Range, MutableArrayRef Elements) { return getSema().BuildObjCDictionaryLiteral(Range, Elements); } /// Build a new Objective-C \@encode expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. ExprResult RebuildObjCEncodeExpr(SourceLocation AtLoc, TypeSourceInfo *EncodeTypeInfo, SourceLocation RParenLoc) { return SemaRef.BuildObjCEncodeExpression(AtLoc, EncodeTypeInfo, RParenLoc); } /// Build a new Objective-C class message. ExprResult RebuildObjCMessageExpr(TypeSourceInfo *ReceiverTypeInfo, Selector Sel, ArrayRef SelectorLocs, ObjCMethodDecl *Method, SourceLocation LBracLoc, MultiExprArg Args, SourceLocation RBracLoc) { return SemaRef.BuildClassMessage(ReceiverTypeInfo, ReceiverTypeInfo->getType(), /*SuperLoc=*/SourceLocation(), Sel, Method, LBracLoc, SelectorLocs, RBracLoc, Args); } /// Build a new Objective-C instance message. ExprResult RebuildObjCMessageExpr(Expr *Receiver, Selector Sel, ArrayRef SelectorLocs, ObjCMethodDecl *Method, SourceLocation LBracLoc, MultiExprArg Args, SourceLocation RBracLoc) { return SemaRef.BuildInstanceMessage(Receiver, Receiver->getType(), /*SuperLoc=*/SourceLocation(), Sel, Method, LBracLoc, SelectorLocs, RBracLoc, Args); } /// Build a new Objective-C instance/class message to 'super'. ExprResult RebuildObjCMessageExpr(SourceLocation SuperLoc, Selector Sel, ArrayRef SelectorLocs, QualType SuperType, ObjCMethodDecl *Method, SourceLocation LBracLoc, MultiExprArg Args, SourceLocation RBracLoc) { return Method->isInstanceMethod() ? SemaRef.BuildInstanceMessage(nullptr, SuperType, SuperLoc, Sel, Method, LBracLoc, SelectorLocs, RBracLoc, Args) : SemaRef.BuildClassMessage(nullptr, SuperType, SuperLoc, Sel, Method, LBracLoc, SelectorLocs, RBracLoc, Args); } /// Build a new Objective-C ivar reference expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. ExprResult RebuildObjCIvarRefExpr(Expr *BaseArg, ObjCIvarDecl *Ivar, SourceLocation IvarLoc, bool IsArrow, bool IsFreeIvar) { CXXScopeSpec SS; DeclarationNameInfo NameInfo(Ivar->getDeclName(), IvarLoc); ExprResult Result = getSema().BuildMemberReferenceExpr( BaseArg, BaseArg->getType(), /*FIXME:*/ IvarLoc, IsArrow, SS, SourceLocation(), /*FirstQualifierInScope=*/nullptr, NameInfo, /*TemplateArgs=*/nullptr, /*S=*/nullptr); if (IsFreeIvar && Result.isUsable()) cast(Result.get())->setIsFreeIvar(IsFreeIvar); return Result; } /// Build a new Objective-C property reference expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. ExprResult RebuildObjCPropertyRefExpr(Expr *BaseArg, ObjCPropertyDecl *Property, SourceLocation PropertyLoc) { CXXScopeSpec SS; DeclarationNameInfo NameInfo(Property->getDeclName(), PropertyLoc); return getSema().BuildMemberReferenceExpr(BaseArg, BaseArg->getType(), /*FIXME:*/PropertyLoc, /*IsArrow=*/false, SS, SourceLocation(), /*FirstQualifierInScope=*/nullptr, NameInfo, /*TemplateArgs=*/nullptr, /*S=*/nullptr); } /// Build a new Objective-C property reference expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. ExprResult RebuildObjCPropertyRefExpr(Expr *Base, QualType T, ObjCMethodDecl *Getter, ObjCMethodDecl *Setter, SourceLocation PropertyLoc) { // Since these expressions can only be value-dependent, we do not // need to perform semantic analysis again. return Owned( new (getSema().Context) ObjCPropertyRefExpr(Getter, Setter, T, VK_LValue, OK_ObjCProperty, PropertyLoc, Base)); } /// Build a new Objective-C "isa" expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. ExprResult RebuildObjCIsaExpr(Expr *BaseArg, SourceLocation IsaLoc, SourceLocation OpLoc, bool IsArrow) { CXXScopeSpec SS; DeclarationNameInfo NameInfo(&getSema().Context.Idents.get("isa"), IsaLoc); return getSema().BuildMemberReferenceExpr(BaseArg, BaseArg->getType(), OpLoc, IsArrow, SS, SourceLocation(), /*FirstQualifierInScope=*/nullptr, NameInfo, /*TemplateArgs=*/nullptr, /*S=*/nullptr); } /// Build a new shuffle vector expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. ExprResult RebuildShuffleVectorExpr(SourceLocation BuiltinLoc, MultiExprArg SubExprs, SourceLocation RParenLoc) { // Find the declaration for __builtin_shufflevector const IdentifierInfo &Name = SemaRef.Context.Idents.get("__builtin_shufflevector"); TranslationUnitDecl *TUDecl = SemaRef.Context.getTranslationUnitDecl(); DeclContext::lookup_result Lookup = TUDecl->lookup(DeclarationName(&Name)); assert(!Lookup.empty() && "No __builtin_shufflevector?"); // Build a reference to the __builtin_shufflevector builtin FunctionDecl *Builtin = cast(Lookup.front()); Expr *Callee = new (SemaRef.Context) DeclRefExpr(SemaRef.Context, Builtin, false, SemaRef.Context.BuiltinFnTy, VK_RValue, BuiltinLoc); QualType CalleePtrTy = SemaRef.Context.getPointerType(Builtin->getType()); Callee = SemaRef.ImpCastExprToType(Callee, CalleePtrTy, CK_BuiltinFnToFnPtr).get(); // Build the CallExpr ExprResult TheCall = CallExpr::Create( SemaRef.Context, Callee, SubExprs, Builtin->getCallResultType(), Expr::getValueKindForType(Builtin->getReturnType()), RParenLoc); // Type-check the __builtin_shufflevector expression. return SemaRef.SemaBuiltinShuffleVector(cast(TheCall.get())); } /// Build a new convert vector expression. ExprResult RebuildConvertVectorExpr(SourceLocation BuiltinLoc, Expr *SrcExpr, TypeSourceInfo *DstTInfo, SourceLocation RParenLoc) { return SemaRef.SemaConvertVectorExpr(SrcExpr, DstTInfo, BuiltinLoc, RParenLoc); } /// Build a new template argument pack expansion. /// /// By default, performs semantic analysis to build a new pack expansion /// for a template argument. Subclasses may override this routine to provide /// different behavior. TemplateArgumentLoc RebuildPackExpansion(TemplateArgumentLoc Pattern, SourceLocation EllipsisLoc, Optional NumExpansions) { switch (Pattern.getArgument().getKind()) { case TemplateArgument::Expression: { ExprResult Result = getSema().CheckPackExpansion(Pattern.getSourceExpression(), EllipsisLoc, NumExpansions); if (Result.isInvalid()) return TemplateArgumentLoc(); return TemplateArgumentLoc(Result.get(), Result.get()); } case TemplateArgument::Template: return TemplateArgumentLoc(TemplateArgument( Pattern.getArgument().getAsTemplate(), NumExpansions), Pattern.getTemplateQualifierLoc(), Pattern.getTemplateNameLoc(), EllipsisLoc); case TemplateArgument::Null: case TemplateArgument::Integral: case TemplateArgument::Declaration: case TemplateArgument::Pack: case TemplateArgument::TemplateExpansion: case TemplateArgument::NullPtr: llvm_unreachable("Pack expansion pattern has no parameter packs"); case TemplateArgument::Type: if (TypeSourceInfo *Expansion = getSema().CheckPackExpansion(Pattern.getTypeSourceInfo(), EllipsisLoc, NumExpansions)) return TemplateArgumentLoc(TemplateArgument(Expansion->getType()), Expansion); break; } return TemplateArgumentLoc(); } /// Build a new expression pack expansion. /// /// By default, performs semantic analysis to build a new pack expansion /// for an expression. Subclasses may override this routine to provide /// different behavior. ExprResult RebuildPackExpansion(Expr *Pattern, SourceLocation EllipsisLoc, Optional NumExpansions) { return getSema().CheckPackExpansion(Pattern, EllipsisLoc, NumExpansions); } /// Build a new C++1z fold-expression. /// /// By default, performs semantic analysis in order to build a new fold /// expression. ExprResult RebuildCXXFoldExpr(SourceLocation LParenLoc, Expr *LHS, BinaryOperatorKind Operator, SourceLocation EllipsisLoc, Expr *RHS, SourceLocation RParenLoc, Optional NumExpansions) { return getSema().BuildCXXFoldExpr(LParenLoc, LHS, Operator, EllipsisLoc, RHS, RParenLoc, NumExpansions); } /// Build an empty C++1z fold-expression with the given operator. /// /// By default, produces the fallback value for the fold-expression, or /// produce an error if there is no fallback value. ExprResult RebuildEmptyCXXFoldExpr(SourceLocation EllipsisLoc, BinaryOperatorKind Operator) { return getSema().BuildEmptyCXXFoldExpr(EllipsisLoc, Operator); } /// Build a new atomic operation expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. ExprResult RebuildAtomicExpr(SourceLocation BuiltinLoc, MultiExprArg SubExprs, AtomicExpr::AtomicOp Op, SourceLocation RParenLoc) { // Use this for all of the locations, since we don't know the difference // between the call and the expr at this point. SourceRange Range{BuiltinLoc, RParenLoc}; return getSema().BuildAtomicExpr(Range, Range, RParenLoc, SubExprs, Op, Sema::AtomicArgumentOrder::AST); } private: TypeLoc TransformTypeInObjectScope(TypeLoc TL, QualType ObjectType, NamedDecl *FirstQualifierInScope, CXXScopeSpec &SS); TypeSourceInfo *TransformTypeInObjectScope(TypeSourceInfo *TSInfo, QualType ObjectType, NamedDecl *FirstQualifierInScope, CXXScopeSpec &SS); TypeSourceInfo *TransformTSIInObjectScope(TypeLoc TL, QualType ObjectType, NamedDecl *FirstQualifierInScope, CXXScopeSpec &SS); QualType TransformDependentNameType(TypeLocBuilder &TLB, DependentNameTypeLoc TL, bool DeducibleTSTContext); }; template StmtResult TreeTransform::TransformStmt(Stmt *S, StmtDiscardKind SDK) { if (!S) return S; switch (S->getStmtClass()) { case Stmt::NoStmtClass: break; // Transform individual statement nodes // Pass SDK into statements that can produce a value #define STMT(Node, Parent) \ case Stmt::Node##Class: return getDerived().Transform##Node(cast(S)); #define VALUESTMT(Node, Parent) \ case Stmt::Node##Class: \ return getDerived().Transform##Node(cast(S), SDK); #define ABSTRACT_STMT(Node) #define EXPR(Node, Parent) #include "clang/AST/StmtNodes.inc" // Transform expressions by calling TransformExpr. #define STMT(Node, Parent) #define ABSTRACT_STMT(Stmt) #define EXPR(Node, Parent) case Stmt::Node##Class: #include "clang/AST/StmtNodes.inc" { ExprResult E = getDerived().TransformExpr(cast(S)); if (SDK == SDK_StmtExprResult) E = getSema().ActOnStmtExprResult(E); return getSema().ActOnExprStmt(E, SDK == SDK_Discarded); } } return S; } template OMPClause *TreeTransform::TransformOMPClause(OMPClause *S) { if (!S) return S; switch (S->getClauseKind()) { default: break; // Transform individual clause nodes #define OPENMP_CLAUSE(Name, Class) \ case OMPC_ ## Name : \ return getDerived().Transform ## Class(cast(S)); #include "clang/Basic/OpenMPKinds.def" } return S; } template ExprResult TreeTransform::TransformExpr(Expr *E) { if (!E) return E; switch (E->getStmtClass()) { case Stmt::NoStmtClass: break; #define STMT(Node, Parent) case Stmt::Node##Class: break; #define ABSTRACT_STMT(Stmt) #define EXPR(Node, Parent) \ case Stmt::Node##Class: return getDerived().Transform##Node(cast(E)); #include "clang/AST/StmtNodes.inc" } return E; } template ExprResult TreeTransform::TransformInitializer(Expr *Init, bool NotCopyInit) { // Initializers are instantiated like expressions, except that various outer // layers are stripped. if (!Init) return Init; if (auto *FE = dyn_cast(Init)) Init = FE->getSubExpr(); if (auto *AIL = dyn_cast(Init)) Init = AIL->getCommonExpr(); if (MaterializeTemporaryExpr *MTE = dyn_cast(Init)) Init = MTE->getSubExpr(); while (CXXBindTemporaryExpr *Binder = dyn_cast(Init)) Init = Binder->getSubExpr(); if (ImplicitCastExpr *ICE = dyn_cast(Init)) Init = ICE->getSubExprAsWritten(); if (CXXStdInitializerListExpr *ILE = dyn_cast(Init)) return TransformInitializer(ILE->getSubExpr(), NotCopyInit); // If this is copy-initialization, we only need to reconstruct // InitListExprs. Other forms of copy-initialization will be a no-op if // the initializer is already the right type. CXXConstructExpr *Construct = dyn_cast(Init); if (!NotCopyInit && !(Construct && Construct->isListInitialization())) return getDerived().TransformExpr(Init); // Revert value-initialization back to empty parens. if (CXXScalarValueInitExpr *VIE = dyn_cast(Init)) { SourceRange Parens = VIE->getSourceRange(); return getDerived().RebuildParenListExpr(Parens.getBegin(), None, Parens.getEnd()); } // FIXME: We shouldn't build ImplicitValueInitExprs for direct-initialization. if (isa(Init)) return getDerived().RebuildParenListExpr(SourceLocation(), None, SourceLocation()); // Revert initialization by constructor back to a parenthesized or braced list // of expressions. Any other form of initializer can just be reused directly. if (!Construct || isa(Construct)) return getDerived().TransformExpr(Init); // If the initialization implicitly converted an initializer list to a // std::initializer_list object, unwrap the std::initializer_list too. if (Construct && Construct->isStdInitListInitialization()) return TransformInitializer(Construct->getArg(0), NotCopyInit); // Enter a list-init context if this was list initialization. EnterExpressionEvaluationContext Context( getSema(), EnterExpressionEvaluationContext::InitList, Construct->isListInitialization()); SmallVector NewArgs; bool ArgChanged = false; if (getDerived().TransformExprs(Construct->getArgs(), Construct->getNumArgs(), /*IsCall*/true, NewArgs, &ArgChanged)) return ExprError(); // If this was list initialization, revert to syntactic list form. if (Construct->isListInitialization()) return getDerived().RebuildInitList(Construct->getBeginLoc(), NewArgs, Construct->getEndLoc()); // Build a ParenListExpr to represent anything else. SourceRange Parens = Construct->getParenOrBraceRange(); if (Parens.isInvalid()) { // This was a variable declaration's initialization for which no initializer // was specified. assert(NewArgs.empty() && "no parens or braces but have direct init with arguments?"); return ExprEmpty(); } return getDerived().RebuildParenListExpr(Parens.getBegin(), NewArgs, Parens.getEnd()); } template bool TreeTransform::TransformExprs(Expr *const *Inputs, unsigned NumInputs, bool IsCall, SmallVectorImpl &Outputs, bool *ArgChanged) { for (unsigned I = 0; I != NumInputs; ++I) { // If requested, drop call arguments that need to be dropped. if (IsCall && getDerived().DropCallArgument(Inputs[I])) { if (ArgChanged) *ArgChanged = true; break; } if (PackExpansionExpr *Expansion = dyn_cast(Inputs[I])) { Expr *Pattern = Expansion->getPattern(); SmallVector Unexpanded; getSema().collectUnexpandedParameterPacks(Pattern, Unexpanded); assert(!Unexpanded.empty() && "Pack expansion without parameter packs?"); // Determine whether the set of unexpanded parameter packs can and should // be expanded. bool Expand = true; bool RetainExpansion = false; Optional OrigNumExpansions = Expansion->getNumExpansions(); Optional NumExpansions = OrigNumExpansions; if (getDerived().TryExpandParameterPacks(Expansion->getEllipsisLoc(), Pattern->getSourceRange(), Unexpanded, Expand, RetainExpansion, NumExpansions)) return true; if (!Expand) { // The transform has determined that we should perform a simple // transformation on the pack expansion, producing another pack // expansion. Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), -1); ExprResult OutPattern = getDerived().TransformExpr(Pattern); if (OutPattern.isInvalid()) return true; ExprResult Out = getDerived().RebuildPackExpansion(OutPattern.get(), Expansion->getEllipsisLoc(), NumExpansions); if (Out.isInvalid()) return true; if (ArgChanged) *ArgChanged = true; Outputs.push_back(Out.get()); continue; } // Record right away that the argument was changed. This needs // to happen even if the array expands to nothing. if (ArgChanged) *ArgChanged = true; // The transform has determined that we should perform an elementwise // expansion of the pattern. Do so. for (unsigned I = 0; I != *NumExpansions; ++I) { Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), I); ExprResult Out = getDerived().TransformExpr(Pattern); if (Out.isInvalid()) return true; if (Out.get()->containsUnexpandedParameterPack()) { Out = getDerived().RebuildPackExpansion( Out.get(), Expansion->getEllipsisLoc(), OrigNumExpansions); if (Out.isInvalid()) return true; } Outputs.push_back(Out.get()); } // If we're supposed to retain a pack expansion, do so by temporarily // forgetting the partially-substituted parameter pack. if (RetainExpansion) { ForgetPartiallySubstitutedPackRAII Forget(getDerived()); ExprResult Out = getDerived().TransformExpr(Pattern); if (Out.isInvalid()) return true; Out = getDerived().RebuildPackExpansion( Out.get(), Expansion->getEllipsisLoc(), OrigNumExpansions); if (Out.isInvalid()) return true; Outputs.push_back(Out.get()); } continue; } ExprResult Result = IsCall ? getDerived().TransformInitializer(Inputs[I], /*DirectInit*/false) : getDerived().TransformExpr(Inputs[I]); if (Result.isInvalid()) return true; if (Result.get() != Inputs[I] && ArgChanged) *ArgChanged = true; Outputs.push_back(Result.get()); } return false; } template Sema::ConditionResult TreeTransform::TransformCondition( SourceLocation Loc, VarDecl *Var, Expr *Expr, Sema::ConditionKind Kind) { if (Var) { VarDecl *ConditionVar = cast_or_null( getDerived().TransformDefinition(Var->getLocation(), Var)); if (!ConditionVar) return Sema::ConditionError(); return getSema().ActOnConditionVariable(ConditionVar, Loc, Kind); } if (Expr) { ExprResult CondExpr = getDerived().TransformExpr(Expr); if (CondExpr.isInvalid()) return Sema::ConditionError(); return getSema().ActOnCondition(nullptr, Loc, CondExpr.get(), Kind); } return Sema::ConditionResult(); } template NestedNameSpecifierLoc TreeTransform::TransformNestedNameSpecifierLoc( NestedNameSpecifierLoc NNS, QualType ObjectType, NamedDecl *FirstQualifierInScope) { SmallVector Qualifiers; for (NestedNameSpecifierLoc Qualifier = NNS; Qualifier; Qualifier = Qualifier.getPrefix()) Qualifiers.push_back(Qualifier); CXXScopeSpec SS; while (!Qualifiers.empty()) { NestedNameSpecifierLoc Q = Qualifiers.pop_back_val(); NestedNameSpecifier *QNNS = Q.getNestedNameSpecifier(); switch (QNNS->getKind()) { case NestedNameSpecifier::Identifier: { Sema::NestedNameSpecInfo IdInfo(QNNS->getAsIdentifier(), Q.getLocalBeginLoc(), Q.getLocalEndLoc(), ObjectType); if (SemaRef.BuildCXXNestedNameSpecifier(/*Scope=*/nullptr, IdInfo, false, SS, FirstQualifierInScope, false)) return NestedNameSpecifierLoc(); } break; case NestedNameSpecifier::Namespace: { NamespaceDecl *NS = cast_or_null( getDerived().TransformDecl( Q.getLocalBeginLoc(), QNNS->getAsNamespace())); SS.Extend(SemaRef.Context, NS, Q.getLocalBeginLoc(), Q.getLocalEndLoc()); break; } case NestedNameSpecifier::NamespaceAlias: { NamespaceAliasDecl *Alias = cast_or_null( getDerived().TransformDecl(Q.getLocalBeginLoc(), QNNS->getAsNamespaceAlias())); SS.Extend(SemaRef.Context, Alias, Q.getLocalBeginLoc(), Q.getLocalEndLoc()); break; } case NestedNameSpecifier::Global: // There is no meaningful transformation that one could perform on the // global scope. SS.MakeGlobal(SemaRef.Context, Q.getBeginLoc()); break; case NestedNameSpecifier::Super: { CXXRecordDecl *RD = cast_or_null(getDerived().TransformDecl( SourceLocation(), QNNS->getAsRecordDecl())); SS.MakeSuper(SemaRef.Context, RD, Q.getBeginLoc(), Q.getEndLoc()); break; } case NestedNameSpecifier::TypeSpecWithTemplate: case NestedNameSpecifier::TypeSpec: { TypeLoc TL = TransformTypeInObjectScope(Q.getTypeLoc(), ObjectType, FirstQualifierInScope, SS); if (!TL) return NestedNameSpecifierLoc(); if (TL.getType()->isDependentType() || TL.getType()->isRecordType() || (SemaRef.getLangOpts().CPlusPlus11 && TL.getType()->isEnumeralType())) { assert(!TL.getType().hasLocalQualifiers() && "Can't get cv-qualifiers here"); if (TL.getType()->isEnumeralType()) SemaRef.Diag(TL.getBeginLoc(), diag::warn_cxx98_compat_enum_nested_name_spec); SS.Extend(SemaRef.Context, /*FIXME:*/SourceLocation(), TL, Q.getLocalEndLoc()); break; } // If the nested-name-specifier is an invalid type def, don't emit an // error because a previous error should have already been emitted. TypedefTypeLoc TTL = TL.getAs(); if (!TTL || !TTL.getTypedefNameDecl()->isInvalidDecl()) { SemaRef.Diag(TL.getBeginLoc(), diag::err_nested_name_spec_non_tag) << TL.getType() << SS.getRange(); } return NestedNameSpecifierLoc(); } } // The qualifier-in-scope and object type only apply to the leftmost entity. FirstQualifierInScope = nullptr; ObjectType = QualType(); } // Don't rebuild the nested-name-specifier if we don't have to. if (SS.getScopeRep() == NNS.getNestedNameSpecifier() && !getDerived().AlwaysRebuild()) return NNS; // If we can re-use the source-location data from the original // nested-name-specifier, do so. if (SS.location_size() == NNS.getDataLength() && memcmp(SS.location_data(), NNS.getOpaqueData(), SS.location_size()) == 0) return NestedNameSpecifierLoc(SS.getScopeRep(), NNS.getOpaqueData()); // Allocate new nested-name-specifier location information. return SS.getWithLocInContext(SemaRef.Context); } template DeclarationNameInfo TreeTransform ::TransformDeclarationNameInfo(const DeclarationNameInfo &NameInfo) { DeclarationName Name = NameInfo.getName(); if (!Name) return DeclarationNameInfo(); switch (Name.getNameKind()) { case DeclarationName::Identifier: case DeclarationName::ObjCZeroArgSelector: case DeclarationName::ObjCOneArgSelector: case DeclarationName::ObjCMultiArgSelector: case DeclarationName::CXXOperatorName: case DeclarationName::CXXLiteralOperatorName: case DeclarationName::CXXUsingDirective: return NameInfo; case DeclarationName::CXXDeductionGuideName: { TemplateDecl *OldTemplate = Name.getCXXDeductionGuideTemplate(); TemplateDecl *NewTemplate = cast_or_null( getDerived().TransformDecl(NameInfo.getLoc(), OldTemplate)); if (!NewTemplate) return DeclarationNameInfo(); DeclarationNameInfo NewNameInfo(NameInfo); NewNameInfo.setName( SemaRef.Context.DeclarationNames.getCXXDeductionGuideName(NewTemplate)); return NewNameInfo; } case DeclarationName::CXXConstructorName: case DeclarationName::CXXDestructorName: case DeclarationName::CXXConversionFunctionName: { TypeSourceInfo *NewTInfo; CanQualType NewCanTy; if (TypeSourceInfo *OldTInfo = NameInfo.getNamedTypeInfo()) { NewTInfo = getDerived().TransformType(OldTInfo); if (!NewTInfo) return DeclarationNameInfo(); NewCanTy = SemaRef.Context.getCanonicalType(NewTInfo->getType()); } else { NewTInfo = nullptr; TemporaryBase Rebase(*this, NameInfo.getLoc(), Name); QualType NewT = getDerived().TransformType(Name.getCXXNameType()); if (NewT.isNull()) return DeclarationNameInfo(); NewCanTy = SemaRef.Context.getCanonicalType(NewT); } DeclarationName NewName = SemaRef.Context.DeclarationNames.getCXXSpecialName(Name.getNameKind(), NewCanTy); DeclarationNameInfo NewNameInfo(NameInfo); NewNameInfo.setName(NewName); NewNameInfo.setNamedTypeInfo(NewTInfo); return NewNameInfo; } } llvm_unreachable("Unknown name kind."); } template TemplateName TreeTransform::TransformTemplateName(CXXScopeSpec &SS, TemplateName Name, SourceLocation NameLoc, QualType ObjectType, NamedDecl *FirstQualifierInScope, bool AllowInjectedClassName) { if (QualifiedTemplateName *QTN = Name.getAsQualifiedTemplateName()) { TemplateDecl *Template = QTN->getTemplateDecl(); assert(Template && "qualified template name must refer to a template"); TemplateDecl *TransTemplate = cast_or_null(getDerived().TransformDecl(NameLoc, Template)); if (!TransTemplate) return TemplateName(); if (!getDerived().AlwaysRebuild() && SS.getScopeRep() == QTN->getQualifier() && TransTemplate == Template) return Name; return getDerived().RebuildTemplateName(SS, QTN->hasTemplateKeyword(), TransTemplate); } if (DependentTemplateName *DTN = Name.getAsDependentTemplateName()) { if (SS.getScopeRep()) { // These apply to the scope specifier, not the template. ObjectType = QualType(); FirstQualifierInScope = nullptr; } if (!getDerived().AlwaysRebuild() && SS.getScopeRep() == DTN->getQualifier() && ObjectType.isNull()) return Name; // FIXME: Preserve the location of the "template" keyword. SourceLocation TemplateKWLoc = NameLoc; if (DTN->isIdentifier()) { return getDerived().RebuildTemplateName(SS, TemplateKWLoc, *DTN->getIdentifier(), NameLoc, ObjectType, FirstQualifierInScope, AllowInjectedClassName); } return getDerived().RebuildTemplateName(SS, TemplateKWLoc, DTN->getOperator(), NameLoc, ObjectType, AllowInjectedClassName); } if (TemplateDecl *Template = Name.getAsTemplateDecl()) { TemplateDecl *TransTemplate = cast_or_null(getDerived().TransformDecl(NameLoc, Template)); if (!TransTemplate) return TemplateName(); if (!getDerived().AlwaysRebuild() && TransTemplate == Template) return Name; return TemplateName(TransTemplate); } if (SubstTemplateTemplateParmPackStorage *SubstPack = Name.getAsSubstTemplateTemplateParmPack()) { TemplateTemplateParmDecl *TransParam = cast_or_null( getDerived().TransformDecl(NameLoc, SubstPack->getParameterPack())); if (!TransParam) return TemplateName(); if (!getDerived().AlwaysRebuild() && TransParam == SubstPack->getParameterPack()) return Name; return getDerived().RebuildTemplateName(TransParam, SubstPack->getArgumentPack()); } // These should be getting filtered out before they reach the AST. llvm_unreachable("overloaded function decl survived to here"); } template void TreeTransform::InventTemplateArgumentLoc( const TemplateArgument &Arg, TemplateArgumentLoc &Output) { SourceLocation Loc = getDerived().getBaseLocation(); switch (Arg.getKind()) { case TemplateArgument::Null: llvm_unreachable("null template argument in TreeTransform"); break; case TemplateArgument::Type: Output = TemplateArgumentLoc(Arg, SemaRef.Context.getTrivialTypeSourceInfo(Arg.getAsType(), Loc)); break; case TemplateArgument::Template: case TemplateArgument::TemplateExpansion: { NestedNameSpecifierLocBuilder Builder; TemplateName Template = Arg.getAsTemplateOrTemplatePattern(); if (DependentTemplateName *DTN = Template.getAsDependentTemplateName()) Builder.MakeTrivial(SemaRef.Context, DTN->getQualifier(), Loc); else if (QualifiedTemplateName *QTN = Template.getAsQualifiedTemplateName()) Builder.MakeTrivial(SemaRef.Context, QTN->getQualifier(), Loc); if (Arg.getKind() == TemplateArgument::Template) Output = TemplateArgumentLoc(Arg, Builder.getWithLocInContext(SemaRef.Context), Loc); else Output = TemplateArgumentLoc(Arg, Builder.getWithLocInContext(SemaRef.Context), Loc, Loc); break; } case TemplateArgument::Expression: Output = TemplateArgumentLoc(Arg, Arg.getAsExpr()); break; case TemplateArgument::Declaration: case TemplateArgument::Integral: case TemplateArgument::Pack: case TemplateArgument::NullPtr: Output = TemplateArgumentLoc(Arg, TemplateArgumentLocInfo()); break; } } template bool TreeTransform::TransformTemplateArgument( const TemplateArgumentLoc &Input, TemplateArgumentLoc &Output, bool Uneval) { const TemplateArgument &Arg = Input.getArgument(); switch (Arg.getKind()) { case TemplateArgument::Null: case TemplateArgument::Integral: case TemplateArgument::Pack: case TemplateArgument::Declaration: case TemplateArgument::NullPtr: llvm_unreachable("Unexpected TemplateArgument"); case TemplateArgument::Type: { TypeSourceInfo *DI = Input.getTypeSourceInfo(); if (!DI) DI = InventTypeSourceInfo(Input.getArgument().getAsType()); DI = getDerived().TransformType(DI); if (!DI) return true; Output = TemplateArgumentLoc(TemplateArgument(DI->getType()), DI); return false; } case TemplateArgument::Template: { NestedNameSpecifierLoc QualifierLoc = Input.getTemplateQualifierLoc(); if (QualifierLoc) { QualifierLoc = getDerived().TransformNestedNameSpecifierLoc(QualifierLoc); if (!QualifierLoc) return true; } CXXScopeSpec SS; SS.Adopt(QualifierLoc); TemplateName Template = getDerived().TransformTemplateName(SS, Arg.getAsTemplate(), Input.getTemplateNameLoc()); if (Template.isNull()) return true; Output = TemplateArgumentLoc(TemplateArgument(Template), QualifierLoc, Input.getTemplateNameLoc()); return false; } case TemplateArgument::TemplateExpansion: llvm_unreachable("Caller should expand pack expansions"); case TemplateArgument::Expression: { // Template argument expressions are constant expressions. EnterExpressionEvaluationContext Unevaluated( getSema(), Uneval ? Sema::ExpressionEvaluationContext::Unevaluated : Sema::ExpressionEvaluationContext::ConstantEvaluated, /*LambdaContextDecl=*/nullptr, /*ExprContext=*/ Sema::ExpressionEvaluationContextRecord::EK_TemplateArgument); Expr *InputExpr = Input.getSourceExpression(); if (!InputExpr) InputExpr = Input.getArgument().getAsExpr(); ExprResult E = getDerived().TransformExpr(InputExpr); E = SemaRef.ActOnConstantExpression(E); if (E.isInvalid()) return true; Output = TemplateArgumentLoc(TemplateArgument(E.get()), E.get()); return false; } } // Work around bogus GCC warning return true; } /// Iterator adaptor that invents template argument location information /// for each of the template arguments in its underlying iterator. template class TemplateArgumentLocInventIterator { TreeTransform &Self; InputIterator Iter; public: typedef TemplateArgumentLoc value_type; typedef TemplateArgumentLoc reference; typedef typename std::iterator_traits::difference_type difference_type; typedef std::input_iterator_tag iterator_category; class pointer { TemplateArgumentLoc Arg; public: explicit pointer(TemplateArgumentLoc Arg) : Arg(Arg) { } const TemplateArgumentLoc *operator->() const { return &Arg; } }; TemplateArgumentLocInventIterator() { } explicit TemplateArgumentLocInventIterator(TreeTransform &Self, InputIterator Iter) : Self(Self), Iter(Iter) { } TemplateArgumentLocInventIterator &operator++() { ++Iter; return *this; } TemplateArgumentLocInventIterator operator++(int) { TemplateArgumentLocInventIterator Old(*this); ++(*this); return Old; } reference operator*() const { TemplateArgumentLoc Result; Self.InventTemplateArgumentLoc(*Iter, Result); return Result; } pointer operator->() const { return pointer(**this); } friend bool operator==(const TemplateArgumentLocInventIterator &X, const TemplateArgumentLocInventIterator &Y) { return X.Iter == Y.Iter; } friend bool operator!=(const TemplateArgumentLocInventIterator &X, const TemplateArgumentLocInventIterator &Y) { return X.Iter != Y.Iter; } }; template template bool TreeTransform::TransformTemplateArguments( InputIterator First, InputIterator Last, TemplateArgumentListInfo &Outputs, bool Uneval) { for (; First != Last; ++First) { TemplateArgumentLoc Out; TemplateArgumentLoc In = *First; if (In.getArgument().getKind() == TemplateArgument::Pack) { // Unpack argument packs, which we translate them into separate // arguments. // FIXME: We could do much better if we could guarantee that the // TemplateArgumentLocInfo for the pack expansion would be usable for // all of the template arguments in the argument pack. typedef TemplateArgumentLocInventIterator PackLocIterator; if (TransformTemplateArguments(PackLocIterator(*this, In.getArgument().pack_begin()), PackLocIterator(*this, In.getArgument().pack_end()), Outputs, Uneval)) return true; continue; } if (In.getArgument().isPackExpansion()) { // We have a pack expansion, for which we will be substituting into // the pattern. SourceLocation Ellipsis; Optional OrigNumExpansions; TemplateArgumentLoc Pattern = getSema().getTemplateArgumentPackExpansionPattern( In, Ellipsis, OrigNumExpansions); SmallVector Unexpanded; getSema().collectUnexpandedParameterPacks(Pattern, Unexpanded); assert(!Unexpanded.empty() && "Pack expansion without parameter packs?"); // Determine whether the set of unexpanded parameter packs can and should // be expanded. bool Expand = true; bool RetainExpansion = false; Optional NumExpansions = OrigNumExpansions; if (getDerived().TryExpandParameterPacks(Ellipsis, Pattern.getSourceRange(), Unexpanded, Expand, RetainExpansion, NumExpansions)) return true; if (!Expand) { // The transform has determined that we should perform a simple // transformation on the pack expansion, producing another pack // expansion. TemplateArgumentLoc OutPattern; Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), -1); if (getDerived().TransformTemplateArgument(Pattern, OutPattern, Uneval)) return true; Out = getDerived().RebuildPackExpansion(OutPattern, Ellipsis, NumExpansions); if (Out.getArgument().isNull()) return true; Outputs.addArgument(Out); continue; } // The transform has determined that we should perform an elementwise // expansion of the pattern. Do so. for (unsigned I = 0; I != *NumExpansions; ++I) { Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), I); if (getDerived().TransformTemplateArgument(Pattern, Out, Uneval)) return true; if (Out.getArgument().containsUnexpandedParameterPack()) { Out = getDerived().RebuildPackExpansion(Out, Ellipsis, OrigNumExpansions); if (Out.getArgument().isNull()) return true; } Outputs.addArgument(Out); } // If we're supposed to retain a pack expansion, do so by temporarily // forgetting the partially-substituted parameter pack. if (RetainExpansion) { ForgetPartiallySubstitutedPackRAII Forget(getDerived()); if (getDerived().TransformTemplateArgument(Pattern, Out, Uneval)) return true; Out = getDerived().RebuildPackExpansion(Out, Ellipsis, OrigNumExpansions); if (Out.getArgument().isNull()) return true; Outputs.addArgument(Out); } continue; } // The simple case: if (getDerived().TransformTemplateArgument(In, Out, Uneval)) return true; Outputs.addArgument(Out); } return false; } //===----------------------------------------------------------------------===// // Type transformation //===----------------------------------------------------------------------===// template QualType TreeTransform::TransformType(QualType T) { if (getDerived().AlreadyTransformed(T)) return T; // Temporary workaround. All of these transformations should // eventually turn into transformations on TypeLocs. TypeSourceInfo *DI = getSema().Context.getTrivialTypeSourceInfo(T, getDerived().getBaseLocation()); TypeSourceInfo *NewDI = getDerived().TransformType(DI); if (!NewDI) return QualType(); return NewDI->getType(); } template TypeSourceInfo *TreeTransform::TransformType(TypeSourceInfo *DI) { // Refine the base location to the type's location. TemporaryBase Rebase(*this, DI->getTypeLoc().getBeginLoc(), getDerived().getBaseEntity()); if (getDerived().AlreadyTransformed(DI->getType())) return DI; TypeLocBuilder TLB; TypeLoc TL = DI->getTypeLoc(); TLB.reserve(TL.getFullDataSize()); QualType Result = getDerived().TransformType(TLB, TL); if (Result.isNull()) return nullptr; return TLB.getTypeSourceInfo(SemaRef.Context, Result); } template QualType TreeTransform::TransformType(TypeLocBuilder &TLB, TypeLoc T) { switch (T.getTypeLocClass()) { #define ABSTRACT_TYPELOC(CLASS, PARENT) #define TYPELOC(CLASS, PARENT) \ case TypeLoc::CLASS: \ return getDerived().Transform##CLASS##Type(TLB, \ T.castAs()); #include "clang/AST/TypeLocNodes.def" } llvm_unreachable("unhandled type loc!"); } template QualType TreeTransform::TransformTypeWithDeducedTST(QualType T) { if (!isa(T)) return TransformType(T); if (getDerived().AlreadyTransformed(T)) return T; TypeSourceInfo *DI = getSema().Context.getTrivialTypeSourceInfo(T, getDerived().getBaseLocation()); TypeSourceInfo *NewDI = getDerived().TransformTypeWithDeducedTST(DI); return NewDI ? NewDI->getType() : QualType(); } template TypeSourceInfo * TreeTransform::TransformTypeWithDeducedTST(TypeSourceInfo *DI) { if (!isa(DI->getType())) return TransformType(DI); // Refine the base location to the type's location. TemporaryBase Rebase(*this, DI->getTypeLoc().getBeginLoc(), getDerived().getBaseEntity()); if (getDerived().AlreadyTransformed(DI->getType())) return DI; TypeLocBuilder TLB; TypeLoc TL = DI->getTypeLoc(); TLB.reserve(TL.getFullDataSize()); auto QTL = TL.getAs(); if (QTL) TL = QTL.getUnqualifiedLoc(); auto DNTL = TL.castAs(); QualType Result = getDerived().TransformDependentNameType( TLB, DNTL, /*DeducedTSTContext*/true); if (Result.isNull()) return nullptr; if (QTL) { Result = getDerived().RebuildQualifiedType(Result, QTL); if (Result.isNull()) return nullptr; TLB.TypeWasModifiedSafely(Result); } return TLB.getTypeSourceInfo(SemaRef.Context, Result); } template QualType TreeTransform::TransformQualifiedType(TypeLocBuilder &TLB, QualifiedTypeLoc T) { QualType Result = getDerived().TransformType(TLB, T.getUnqualifiedLoc()); if (Result.isNull()) return QualType(); Result = getDerived().RebuildQualifiedType(Result, T); if (Result.isNull()) return QualType(); // RebuildQualifiedType might have updated the type, but not in a way // that invalidates the TypeLoc. (There's no location information for // qualifiers.) TLB.TypeWasModifiedSafely(Result); return Result; } template QualType TreeTransform::RebuildQualifiedType(QualType T, QualifiedTypeLoc TL) { SourceLocation Loc = TL.getBeginLoc(); Qualifiers Quals = TL.getType().getLocalQualifiers(); if (((T.getAddressSpace() != LangAS::Default && Quals.getAddressSpace() != LangAS::Default)) && T.getAddressSpace() != Quals.getAddressSpace()) { SemaRef.Diag(Loc, diag::err_address_space_mismatch_templ_inst) << TL.getType() << T; return QualType(); } // C++ [dcl.fct]p7: // [When] adding cv-qualifications on top of the function type [...] the // cv-qualifiers are ignored. if (T->isFunctionType()) { T = SemaRef.getASTContext().getAddrSpaceQualType(T, Quals.getAddressSpace()); return T; } // C++ [dcl.ref]p1: // when the cv-qualifiers are introduced through the use of a typedef-name // or decltype-specifier [...] the cv-qualifiers are ignored. // Note that [dcl.ref]p1 lists all cases in which cv-qualifiers can be // applied to a reference type. if (T->isReferenceType()) { // The only qualifier that applies to a reference type is restrict. if (!Quals.hasRestrict()) return T; Quals = Qualifiers::fromCVRMask(Qualifiers::Restrict); } // Suppress Objective-C lifetime qualifiers if they don't make sense for the // resulting type. if (Quals.hasObjCLifetime()) { if (!T->isObjCLifetimeType() && !T->isDependentType()) Quals.removeObjCLifetime(); else if (T.getObjCLifetime()) { // Objective-C ARC: // A lifetime qualifier applied to a substituted template parameter // overrides the lifetime qualifier from the template argument. const AutoType *AutoTy; if (const SubstTemplateTypeParmType *SubstTypeParam = dyn_cast(T)) { QualType Replacement = SubstTypeParam->getReplacementType(); Qualifiers Qs = Replacement.getQualifiers(); Qs.removeObjCLifetime(); Replacement = SemaRef.Context.getQualifiedType( Replacement.getUnqualifiedType(), Qs); T = SemaRef.Context.getSubstTemplateTypeParmType( SubstTypeParam->getReplacedParameter(), Replacement); } else if ((AutoTy = dyn_cast(T)) && AutoTy->isDeduced()) { // 'auto' types behave the same way as template parameters. QualType Deduced = AutoTy->getDeducedType(); Qualifiers Qs = Deduced.getQualifiers(); Qs.removeObjCLifetime(); Deduced = SemaRef.Context.getQualifiedType(Deduced.getUnqualifiedType(), Qs); T = SemaRef.Context.getAutoType(Deduced, AutoTy->getKeyword(), AutoTy->isDependentType(), /*isPack=*/false, AutoTy->getTypeConstraintConcept(), AutoTy->getTypeConstraintArguments()); } else { // Otherwise, complain about the addition of a qualifier to an // already-qualified type. // FIXME: Why is this check not in Sema::BuildQualifiedType? SemaRef.Diag(Loc, diag::err_attr_objc_ownership_redundant) << T; Quals.removeObjCLifetime(); } } } return SemaRef.BuildQualifiedType(T, Loc, Quals); } template TypeLoc TreeTransform::TransformTypeInObjectScope(TypeLoc TL, QualType ObjectType, NamedDecl *UnqualLookup, CXXScopeSpec &SS) { if (getDerived().AlreadyTransformed(TL.getType())) return TL; TypeSourceInfo *TSI = TransformTSIInObjectScope(TL, ObjectType, UnqualLookup, SS); if (TSI) return TSI->getTypeLoc(); return TypeLoc(); } template TypeSourceInfo * TreeTransform::TransformTypeInObjectScope(TypeSourceInfo *TSInfo, QualType ObjectType, NamedDecl *UnqualLookup, CXXScopeSpec &SS) { if (getDerived().AlreadyTransformed(TSInfo->getType())) return TSInfo; return TransformTSIInObjectScope(TSInfo->getTypeLoc(), ObjectType, UnqualLookup, SS); } template TypeSourceInfo *TreeTransform::TransformTSIInObjectScope( TypeLoc TL, QualType ObjectType, NamedDecl *UnqualLookup, CXXScopeSpec &SS) { QualType T = TL.getType(); assert(!getDerived().AlreadyTransformed(T)); TypeLocBuilder TLB; QualType Result; if (isa(T)) { TemplateSpecializationTypeLoc SpecTL = TL.castAs(); TemplateName Template = getDerived().TransformTemplateName( SS, SpecTL.getTypePtr()->getTemplateName(), SpecTL.getTemplateNameLoc(), ObjectType, UnqualLookup, /*AllowInjectedClassName*/true); if (Template.isNull()) return nullptr; Result = getDerived().TransformTemplateSpecializationType(TLB, SpecTL, Template); } else if (isa(T)) { DependentTemplateSpecializationTypeLoc SpecTL = TL.castAs(); TemplateName Template = getDerived().RebuildTemplateName(SS, SpecTL.getTemplateKeywordLoc(), *SpecTL.getTypePtr()->getIdentifier(), SpecTL.getTemplateNameLoc(), ObjectType, UnqualLookup, /*AllowInjectedClassName*/true); if (Template.isNull()) return nullptr; Result = getDerived().TransformDependentTemplateSpecializationType(TLB, SpecTL, Template, SS); } else { // Nothing special needs to be done for these. Result = getDerived().TransformType(TLB, TL); } if (Result.isNull()) return nullptr; return TLB.getTypeSourceInfo(SemaRef.Context, Result); } template static inline QualType TransformTypeSpecType(TypeLocBuilder &TLB, TyLoc T) { TyLoc NewT = TLB.push(T.getType()); NewT.setNameLoc(T.getNameLoc()); return T.getType(); } template QualType TreeTransform::TransformBuiltinType(TypeLocBuilder &TLB, BuiltinTypeLoc T) { BuiltinTypeLoc NewT = TLB.push(T.getType()); NewT.setBuiltinLoc(T.getBuiltinLoc()); if (T.needsExtraLocalData()) NewT.getWrittenBuiltinSpecs() = T.getWrittenBuiltinSpecs(); return T.getType(); } template QualType TreeTransform::TransformComplexType(TypeLocBuilder &TLB, ComplexTypeLoc T) { // FIXME: recurse? return TransformTypeSpecType(TLB, T); } template QualType TreeTransform::TransformAdjustedType(TypeLocBuilder &TLB, AdjustedTypeLoc TL) { // Adjustments applied during transformation are handled elsewhere. return getDerived().TransformType(TLB, TL.getOriginalLoc()); } template QualType TreeTransform::TransformDecayedType(TypeLocBuilder &TLB, DecayedTypeLoc TL) { QualType OriginalType = getDerived().TransformType(TLB, TL.getOriginalLoc()); if (OriginalType.isNull()) return QualType(); QualType Result = TL.getType(); if (getDerived().AlwaysRebuild() || OriginalType != TL.getOriginalLoc().getType()) Result = SemaRef.Context.getDecayedType(OriginalType); TLB.push(Result); // Nothing to set for DecayedTypeLoc. return Result; } template QualType TreeTransform::TransformPointerType(TypeLocBuilder &TLB, PointerTypeLoc TL) { QualType PointeeType = getDerived().TransformType(TLB, TL.getPointeeLoc()); if (PointeeType.isNull()) return QualType(); QualType Result = TL.getType(); if (PointeeType->getAs()) { // A dependent pointer type 'T *' has is being transformed such // that an Objective-C class type is being replaced for 'T'. The // resulting pointer type is an ObjCObjectPointerType, not a // PointerType. Result = SemaRef.Context.getObjCObjectPointerType(PointeeType); ObjCObjectPointerTypeLoc NewT = TLB.push(Result); NewT.setStarLoc(TL.getStarLoc()); return Result; } if (getDerived().AlwaysRebuild() || PointeeType != TL.getPointeeLoc().getType()) { Result = getDerived().RebuildPointerType(PointeeType, TL.getSigilLoc()); if (Result.isNull()) return QualType(); } // Objective-C ARC can add lifetime qualifiers to the type that we're // pointing to. TLB.TypeWasModifiedSafely(Result->getPointeeType()); PointerTypeLoc NewT = TLB.push(Result); NewT.setSigilLoc(TL.getSigilLoc()); return Result; } template QualType TreeTransform::TransformBlockPointerType(TypeLocBuilder &TLB, BlockPointerTypeLoc TL) { QualType PointeeType = getDerived().TransformType(TLB, TL.getPointeeLoc()); if (PointeeType.isNull()) return QualType(); QualType Result = TL.getType(); if (getDerived().AlwaysRebuild() || PointeeType != TL.getPointeeLoc().getType()) { Result = getDerived().RebuildBlockPointerType(PointeeType, TL.getSigilLoc()); if (Result.isNull()) return QualType(); } BlockPointerTypeLoc NewT = TLB.push(Result); NewT.setSigilLoc(TL.getSigilLoc()); return Result; } /// Transforms a reference type. Note that somewhat paradoxically we /// don't care whether the type itself is an l-value type or an r-value /// type; we only care if the type was *written* as an l-value type /// or an r-value type. template QualType TreeTransform::TransformReferenceType(TypeLocBuilder &TLB, ReferenceTypeLoc TL) { const ReferenceType *T = TL.getTypePtr(); // Note that this works with the pointee-as-written. QualType PointeeType = getDerived().TransformType(TLB, TL.getPointeeLoc()); if (PointeeType.isNull()) return QualType(); QualType Result = TL.getType(); if (getDerived().AlwaysRebuild() || PointeeType != T->getPointeeTypeAsWritten()) { Result = getDerived().RebuildReferenceType(PointeeType, T->isSpelledAsLValue(), TL.getSigilLoc()); if (Result.isNull()) return QualType(); } // Objective-C ARC can add lifetime qualifiers to the type that we're // referring to. TLB.TypeWasModifiedSafely( Result->castAs()->getPointeeTypeAsWritten()); // r-value references can be rebuilt as l-value references. ReferenceTypeLoc NewTL; if (isa(Result)) NewTL = TLB.push(Result); else NewTL = TLB.push(Result); NewTL.setSigilLoc(TL.getSigilLoc()); return Result; } template QualType TreeTransform::TransformLValueReferenceType(TypeLocBuilder &TLB, LValueReferenceTypeLoc TL) { return TransformReferenceType(TLB, TL); } template QualType TreeTransform::TransformRValueReferenceType(TypeLocBuilder &TLB, RValueReferenceTypeLoc TL) { return TransformReferenceType(TLB, TL); } template QualType TreeTransform::TransformMemberPointerType(TypeLocBuilder &TLB, MemberPointerTypeLoc TL) { QualType PointeeType = getDerived().TransformType(TLB, TL.getPointeeLoc()); if (PointeeType.isNull()) return QualType(); TypeSourceInfo* OldClsTInfo = TL.getClassTInfo(); TypeSourceInfo *NewClsTInfo = nullptr; if (OldClsTInfo) { NewClsTInfo = getDerived().TransformType(OldClsTInfo); if (!NewClsTInfo) return QualType(); } const MemberPointerType *T = TL.getTypePtr(); QualType OldClsType = QualType(T->getClass(), 0); QualType NewClsType; if (NewClsTInfo) NewClsType = NewClsTInfo->getType(); else { NewClsType = getDerived().TransformType(OldClsType); if (NewClsType.isNull()) return QualType(); } QualType Result = TL.getType(); if (getDerived().AlwaysRebuild() || PointeeType != T->getPointeeType() || NewClsType != OldClsType) { Result = getDerived().RebuildMemberPointerType(PointeeType, NewClsType, TL.getStarLoc()); if (Result.isNull()) return QualType(); } // If we had to adjust the pointee type when building a member pointer, make // sure to push TypeLoc info for it. const MemberPointerType *MPT = Result->getAs(); if (MPT && PointeeType != MPT->getPointeeType()) { assert(isa(MPT->getPointeeType())); TLB.push(MPT->getPointeeType()); } MemberPointerTypeLoc NewTL = TLB.push(Result); NewTL.setSigilLoc(TL.getSigilLoc()); NewTL.setClassTInfo(NewClsTInfo); return Result; } template QualType TreeTransform::TransformConstantArrayType(TypeLocBuilder &TLB, ConstantArrayTypeLoc TL) { const ConstantArrayType *T = TL.getTypePtr(); QualType ElementType = getDerived().TransformType(TLB, TL.getElementLoc()); if (ElementType.isNull()) return QualType(); // Prefer the expression from the TypeLoc; the other may have been uniqued. Expr *OldSize = TL.getSizeExpr(); if (!OldSize) OldSize = const_cast(T->getSizeExpr()); Expr *NewSize = nullptr; if (OldSize) { EnterExpressionEvaluationContext Unevaluated( SemaRef, Sema::ExpressionEvaluationContext::ConstantEvaluated); NewSize = getDerived().TransformExpr(OldSize).template getAs(); NewSize = SemaRef.ActOnConstantExpression(NewSize).get(); } QualType Result = TL.getType(); if (getDerived().AlwaysRebuild() || ElementType != T->getElementType() || (T->getSizeExpr() && NewSize != OldSize)) { Result = getDerived().RebuildConstantArrayType(ElementType, T->getSizeModifier(), T->getSize(), NewSize, T->getIndexTypeCVRQualifiers(), TL.getBracketsRange()); if (Result.isNull()) return QualType(); } // We might have either a ConstantArrayType or a VariableArrayType now: // a ConstantArrayType is allowed to have an element type which is a // VariableArrayType if the type is dependent. Fortunately, all array // types have the same location layout. ArrayTypeLoc NewTL = TLB.push(Result); NewTL.setLBracketLoc(TL.getLBracketLoc()); NewTL.setRBracketLoc(TL.getRBracketLoc()); NewTL.setSizeExpr(NewSize); return Result; } template QualType TreeTransform::TransformIncompleteArrayType( TypeLocBuilder &TLB, IncompleteArrayTypeLoc TL) { const IncompleteArrayType *T = TL.getTypePtr(); QualType ElementType = getDerived().TransformType(TLB, TL.getElementLoc()); if (ElementType.isNull()) return QualType(); QualType Result = TL.getType(); if (getDerived().AlwaysRebuild() || ElementType != T->getElementType()) { Result = getDerived().RebuildIncompleteArrayType(ElementType, T->getSizeModifier(), T->getIndexTypeCVRQualifiers(), TL.getBracketsRange()); if (Result.isNull()) return QualType(); } IncompleteArrayTypeLoc NewTL = TLB.push(Result); NewTL.setLBracketLoc(TL.getLBracketLoc()); NewTL.setRBracketLoc(TL.getRBracketLoc()); NewTL.setSizeExpr(nullptr); return Result; } template QualType TreeTransform::TransformVariableArrayType(TypeLocBuilder &TLB, VariableArrayTypeLoc TL) { const VariableArrayType *T = TL.getTypePtr(); QualType ElementType = getDerived().TransformType(TLB, TL.getElementLoc()); if (ElementType.isNull()) return QualType(); ExprResult SizeResult; { EnterExpressionEvaluationContext Context( SemaRef, Sema::ExpressionEvaluationContext::PotentiallyEvaluated); SizeResult = getDerived().TransformExpr(T->getSizeExpr()); } if (SizeResult.isInvalid()) return QualType(); SizeResult = SemaRef.ActOnFinishFullExpr(SizeResult.get(), /*DiscardedValue*/ false); if (SizeResult.isInvalid()) return QualType(); Expr *Size = SizeResult.get(); QualType Result = TL.getType(); if (getDerived().AlwaysRebuild() || ElementType != T->getElementType() || Size != T->getSizeExpr()) { Result = getDerived().RebuildVariableArrayType(ElementType, T->getSizeModifier(), Size, T->getIndexTypeCVRQualifiers(), TL.getBracketsRange()); if (Result.isNull()) return QualType(); } // We might have constant size array now, but fortunately it has the same // location layout. ArrayTypeLoc NewTL = TLB.push(Result); NewTL.setLBracketLoc(TL.getLBracketLoc()); NewTL.setRBracketLoc(TL.getRBracketLoc()); NewTL.setSizeExpr(Size); return Result; } template QualType TreeTransform::TransformDependentSizedArrayType(TypeLocBuilder &TLB, DependentSizedArrayTypeLoc TL) { const DependentSizedArrayType *T = TL.getTypePtr(); QualType ElementType = getDerived().TransformType(TLB, TL.getElementLoc()); if (ElementType.isNull()) return QualType(); // Array bounds are constant expressions. EnterExpressionEvaluationContext Unevaluated( SemaRef, Sema::ExpressionEvaluationContext::ConstantEvaluated); // Prefer the expression from the TypeLoc; the other may have been uniqued. Expr *origSize = TL.getSizeExpr(); if (!origSize) origSize = T->getSizeExpr(); ExprResult sizeResult = getDerived().TransformExpr(origSize); sizeResult = SemaRef.ActOnConstantExpression(sizeResult); if (sizeResult.isInvalid()) return QualType(); Expr *size = sizeResult.get(); QualType Result = TL.getType(); if (getDerived().AlwaysRebuild() || ElementType != T->getElementType() || size != origSize) { Result = getDerived().RebuildDependentSizedArrayType(ElementType, T->getSizeModifier(), size, T->getIndexTypeCVRQualifiers(), TL.getBracketsRange()); if (Result.isNull()) return QualType(); } // We might have any sort of array type now, but fortunately they // all have the same location layout. ArrayTypeLoc NewTL = TLB.push(Result); NewTL.setLBracketLoc(TL.getLBracketLoc()); NewTL.setRBracketLoc(TL.getRBracketLoc()); NewTL.setSizeExpr(size); return Result; } template QualType TreeTransform::TransformDependentVectorType( TypeLocBuilder &TLB, DependentVectorTypeLoc TL) { const DependentVectorType *T = TL.getTypePtr(); QualType ElementType = getDerived().TransformType(T->getElementType()); if (ElementType.isNull()) return QualType(); EnterExpressionEvaluationContext Unevaluated( SemaRef, Sema::ExpressionEvaluationContext::ConstantEvaluated); ExprResult Size = getDerived().TransformExpr(T->getSizeExpr()); Size = SemaRef.ActOnConstantExpression(Size); if (Size.isInvalid()) return QualType(); QualType Result = TL.getType(); if (getDerived().AlwaysRebuild() || ElementType != T->getElementType() || Size.get() != T->getSizeExpr()) { Result = getDerived().RebuildDependentVectorType( ElementType, Size.get(), T->getAttributeLoc(), T->getVectorKind()); if (Result.isNull()) return QualType(); } // Result might be dependent or not. if (isa(Result)) { DependentVectorTypeLoc NewTL = TLB.push(Result); NewTL.setNameLoc(TL.getNameLoc()); } else { VectorTypeLoc NewTL = TLB.push(Result); NewTL.setNameLoc(TL.getNameLoc()); } return Result; } template QualType TreeTransform::TransformDependentSizedExtVectorType( TypeLocBuilder &TLB, DependentSizedExtVectorTypeLoc TL) { const DependentSizedExtVectorType *T = TL.getTypePtr(); // FIXME: ext vector locs should be nested QualType ElementType = getDerived().TransformType(T->getElementType()); if (ElementType.isNull()) return QualType(); // Vector sizes are constant expressions. EnterExpressionEvaluationContext Unevaluated( SemaRef, Sema::ExpressionEvaluationContext::ConstantEvaluated); ExprResult Size = getDerived().TransformExpr(T->getSizeExpr()); Size = SemaRef.ActOnConstantExpression(Size); if (Size.isInvalid()) return QualType(); QualType Result = TL.getType(); if (getDerived().AlwaysRebuild() || ElementType != T->getElementType() || Size.get() != T->getSizeExpr()) { Result = getDerived().RebuildDependentSizedExtVectorType(ElementType, Size.get(), T->getAttributeLoc()); if (Result.isNull()) return QualType(); } // Result might be dependent or not. if (isa(Result)) { DependentSizedExtVectorTypeLoc NewTL = TLB.push(Result); NewTL.setNameLoc(TL.getNameLoc()); } else { ExtVectorTypeLoc NewTL = TLB.push(Result); NewTL.setNameLoc(TL.getNameLoc()); } return Result; } template QualType TreeTransform::TransformDependentAddressSpaceType( TypeLocBuilder &TLB, DependentAddressSpaceTypeLoc TL) { const DependentAddressSpaceType *T = TL.getTypePtr(); QualType pointeeType = getDerived().TransformType(T->getPointeeType()); if (pointeeType.isNull()) return QualType(); // Address spaces are constant expressions. EnterExpressionEvaluationContext Unevaluated( SemaRef, Sema::ExpressionEvaluationContext::ConstantEvaluated); ExprResult AddrSpace = getDerived().TransformExpr(T->getAddrSpaceExpr()); AddrSpace = SemaRef.ActOnConstantExpression(AddrSpace); if (AddrSpace.isInvalid()) return QualType(); QualType Result = TL.getType(); if (getDerived().AlwaysRebuild() || pointeeType != T->getPointeeType() || AddrSpace.get() != T->getAddrSpaceExpr()) { Result = getDerived().RebuildDependentAddressSpaceType( pointeeType, AddrSpace.get(), T->getAttributeLoc()); if (Result.isNull()) return QualType(); } // Result might be dependent or not. if (isa(Result)) { DependentAddressSpaceTypeLoc NewTL = TLB.push(Result); NewTL.setAttrOperandParensRange(TL.getAttrOperandParensRange()); NewTL.setAttrExprOperand(TL.getAttrExprOperand()); NewTL.setAttrNameLoc(TL.getAttrNameLoc()); } else { TypeSourceInfo *DI = getSema().Context.getTrivialTypeSourceInfo( Result, getDerived().getBaseLocation()); TransformType(TLB, DI->getTypeLoc()); } return Result; } template QualType TreeTransform::TransformVectorType(TypeLocBuilder &TLB, VectorTypeLoc TL) { const VectorType *T = TL.getTypePtr(); QualType ElementType = getDerived().TransformType(T->getElementType()); if (ElementType.isNull()) return QualType(); QualType Result = TL.getType(); if (getDerived().AlwaysRebuild() || ElementType != T->getElementType()) { Result = getDerived().RebuildVectorType(ElementType, T->getNumElements(), T->getVectorKind()); if (Result.isNull()) return QualType(); } VectorTypeLoc NewTL = TLB.push(Result); NewTL.setNameLoc(TL.getNameLoc()); return Result; } template QualType TreeTransform::TransformExtVectorType(TypeLocBuilder &TLB, ExtVectorTypeLoc TL) { const VectorType *T = TL.getTypePtr(); QualType ElementType = getDerived().TransformType(T->getElementType()); if (ElementType.isNull()) return QualType(); QualType Result = TL.getType(); if (getDerived().AlwaysRebuild() || ElementType != T->getElementType()) { Result = getDerived().RebuildExtVectorType(ElementType, T->getNumElements(), /*FIXME*/ SourceLocation()); if (Result.isNull()) return QualType(); } ExtVectorTypeLoc NewTL = TLB.push(Result); NewTL.setNameLoc(TL.getNameLoc()); return Result; } template ParmVarDecl *TreeTransform::TransformFunctionTypeParam( ParmVarDecl *OldParm, int indexAdjustment, Optional NumExpansions, bool ExpectParameterPack) { TypeSourceInfo *OldDI = OldParm->getTypeSourceInfo(); TypeSourceInfo *NewDI = nullptr; if (NumExpansions && isa(OldDI->getType())) { // If we're substituting into a pack expansion type and we know the // length we want to expand to, just substitute for the pattern. TypeLoc OldTL = OldDI->getTypeLoc(); PackExpansionTypeLoc OldExpansionTL = OldTL.castAs(); TypeLocBuilder TLB; TypeLoc NewTL = OldDI->getTypeLoc(); TLB.reserve(NewTL.getFullDataSize()); QualType Result = getDerived().TransformType(TLB, OldExpansionTL.getPatternLoc()); if (Result.isNull()) return nullptr; Result = RebuildPackExpansionType(Result, OldExpansionTL.getPatternLoc().getSourceRange(), OldExpansionTL.getEllipsisLoc(), NumExpansions); if (Result.isNull()) return nullptr; PackExpansionTypeLoc NewExpansionTL = TLB.push(Result); NewExpansionTL.setEllipsisLoc(OldExpansionTL.getEllipsisLoc()); NewDI = TLB.getTypeSourceInfo(SemaRef.Context, Result); } else NewDI = getDerived().TransformType(OldDI); if (!NewDI) return nullptr; if (NewDI == OldDI && indexAdjustment == 0) return OldParm; ParmVarDecl *newParm = ParmVarDecl::Create(SemaRef.Context, OldParm->getDeclContext(), OldParm->getInnerLocStart(), OldParm->getLocation(), OldParm->getIdentifier(), NewDI->getType(), NewDI, OldParm->getStorageClass(), /* DefArg */ nullptr); newParm->setScopeInfo(OldParm->getFunctionScopeDepth(), OldParm->getFunctionScopeIndex() + indexAdjustment); return newParm; } template bool TreeTransform::TransformFunctionTypeParams( SourceLocation Loc, ArrayRef Params, const QualType *ParamTypes, const FunctionProtoType::ExtParameterInfo *ParamInfos, SmallVectorImpl &OutParamTypes, SmallVectorImpl *PVars, Sema::ExtParameterInfoBuilder &PInfos) { int indexAdjustment = 0; unsigned NumParams = Params.size(); for (unsigned i = 0; i != NumParams; ++i) { if (ParmVarDecl *OldParm = Params[i]) { assert(OldParm->getFunctionScopeIndex() == i); Optional NumExpansions; ParmVarDecl *NewParm = nullptr; if (OldParm->isParameterPack()) { // We have a function parameter pack that may need to be expanded. SmallVector Unexpanded; // Find the parameter packs that could be expanded. TypeLoc TL = OldParm->getTypeSourceInfo()->getTypeLoc(); PackExpansionTypeLoc ExpansionTL = TL.castAs(); TypeLoc Pattern = ExpansionTL.getPatternLoc(); SemaRef.collectUnexpandedParameterPacks(Pattern, Unexpanded); // Determine whether we should expand the parameter packs. bool ShouldExpand = false; bool RetainExpansion = false; Optional OrigNumExpansions; if (Unexpanded.size() > 0) { OrigNumExpansions = ExpansionTL.getTypePtr()->getNumExpansions(); NumExpansions = OrigNumExpansions; if (getDerived().TryExpandParameterPacks(ExpansionTL.getEllipsisLoc(), Pattern.getSourceRange(), Unexpanded, ShouldExpand, RetainExpansion, NumExpansions)) { return true; } } else { #ifndef NDEBUG const AutoType *AT = Pattern.getType().getTypePtr()->getContainedAutoType(); assert((AT && (!AT->isDeduced() || AT->getDeducedType().isNull())) && "Could not find parameter packs or undeduced auto type!"); #endif } if (ShouldExpand) { // Expand the function parameter pack into multiple, separate // parameters. getDerived().ExpandingFunctionParameterPack(OldParm); for (unsigned I = 0; I != *NumExpansions; ++I) { Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), I); ParmVarDecl *NewParm = getDerived().TransformFunctionTypeParam(OldParm, indexAdjustment++, OrigNumExpansions, /*ExpectParameterPack=*/false); if (!NewParm) return true; if (ParamInfos) PInfos.set(OutParamTypes.size(), ParamInfos[i]); OutParamTypes.push_back(NewParm->getType()); if (PVars) PVars->push_back(NewParm); } // If we're supposed to retain a pack expansion, do so by temporarily // forgetting the partially-substituted parameter pack. if (RetainExpansion) { ForgetPartiallySubstitutedPackRAII Forget(getDerived()); ParmVarDecl *NewParm = getDerived().TransformFunctionTypeParam(OldParm, indexAdjustment++, OrigNumExpansions, /*ExpectParameterPack=*/false); if (!NewParm) return true; if (ParamInfos) PInfos.set(OutParamTypes.size(), ParamInfos[i]); OutParamTypes.push_back(NewParm->getType()); if (PVars) PVars->push_back(NewParm); } // The next parameter should have the same adjustment as the // last thing we pushed, but we post-incremented indexAdjustment // on every push. Also, if we push nothing, the adjustment should // go down by one. indexAdjustment--; // We're done with the pack expansion. continue; } // We'll substitute the parameter now without expanding the pack // expansion. Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), -1); NewParm = getDerived().TransformFunctionTypeParam(OldParm, indexAdjustment, NumExpansions, /*ExpectParameterPack=*/true); assert(NewParm->isParameterPack() && "Parameter pack no longer a parameter pack after " "transformation."); } else { NewParm = getDerived().TransformFunctionTypeParam( OldParm, indexAdjustment, None, /*ExpectParameterPack=*/ false); } if (!NewParm) return true; if (ParamInfos) PInfos.set(OutParamTypes.size(), ParamInfos[i]); OutParamTypes.push_back(NewParm->getType()); if (PVars) PVars->push_back(NewParm); continue; } // Deal with the possibility that we don't have a parameter // declaration for this parameter. QualType OldType = ParamTypes[i]; bool IsPackExpansion = false; Optional NumExpansions; QualType NewType; if (const PackExpansionType *Expansion = dyn_cast(OldType)) { // We have a function parameter pack that may need to be expanded. QualType Pattern = Expansion->getPattern(); SmallVector Unexpanded; getSema().collectUnexpandedParameterPacks(Pattern, Unexpanded); // Determine whether we should expand the parameter packs. bool ShouldExpand = false; bool RetainExpansion = false; if (getDerived().TryExpandParameterPacks(Loc, SourceRange(), Unexpanded, ShouldExpand, RetainExpansion, NumExpansions)) { return true; } if (ShouldExpand) { // Expand the function parameter pack into multiple, separate // parameters. for (unsigned I = 0; I != *NumExpansions; ++I) { Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), I); QualType NewType = getDerived().TransformType(Pattern); if (NewType.isNull()) return true; if (NewType->containsUnexpandedParameterPack()) { NewType = getSema().getASTContext().getPackExpansionType(NewType, None); if (NewType.isNull()) return true; } if (ParamInfos) PInfos.set(OutParamTypes.size(), ParamInfos[i]); OutParamTypes.push_back(NewType); if (PVars) PVars->push_back(nullptr); } // We're done with the pack expansion. continue; } // If we're supposed to retain a pack expansion, do so by temporarily // forgetting the partially-substituted parameter pack. if (RetainExpansion) { ForgetPartiallySubstitutedPackRAII Forget(getDerived()); QualType NewType = getDerived().TransformType(Pattern); if (NewType.isNull()) return true; if (ParamInfos) PInfos.set(OutParamTypes.size(), ParamInfos[i]); OutParamTypes.push_back(NewType); if (PVars) PVars->push_back(nullptr); } // We'll substitute the parameter now without expanding the pack // expansion. OldType = Expansion->getPattern(); IsPackExpansion = true; Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), -1); NewType = getDerived().TransformType(OldType); } else { NewType = getDerived().TransformType(OldType); } if (NewType.isNull()) return true; if (IsPackExpansion) NewType = getSema().Context.getPackExpansionType(NewType, NumExpansions); if (ParamInfos) PInfos.set(OutParamTypes.size(), ParamInfos[i]); OutParamTypes.push_back(NewType); if (PVars) PVars->push_back(nullptr); } #ifndef NDEBUG if (PVars) { for (unsigned i = 0, e = PVars->size(); i != e; ++i) if (ParmVarDecl *parm = (*PVars)[i]) assert(parm->getFunctionScopeIndex() == i); } #endif return false; } template QualType TreeTransform::TransformFunctionProtoType(TypeLocBuilder &TLB, FunctionProtoTypeLoc TL) { SmallVector ExceptionStorage; TreeTransform *This = this; // Work around gcc.gnu.org/PR56135. return getDerived().TransformFunctionProtoType( TLB, TL, nullptr, Qualifiers(), [&](FunctionProtoType::ExceptionSpecInfo &ESI, bool &Changed) { return This->TransformExceptionSpec(TL.getBeginLoc(), ESI, ExceptionStorage, Changed); }); } template template QualType TreeTransform::TransformFunctionProtoType( TypeLocBuilder &TLB, FunctionProtoTypeLoc TL, CXXRecordDecl *ThisContext, Qualifiers ThisTypeQuals, Fn TransformExceptionSpec) { // Transform the parameters and return type. // // We are required to instantiate the params and return type in source order. // When the function has a trailing return type, we instantiate the // parameters before the return type, since the return type can then refer // to the parameters themselves (via decltype, sizeof, etc.). // SmallVector ParamTypes; SmallVector ParamDecls; Sema::ExtParameterInfoBuilder ExtParamInfos; const FunctionProtoType *T = TL.getTypePtr(); QualType ResultType; if (T->hasTrailingReturn()) { if (getDerived().TransformFunctionTypeParams( TL.getBeginLoc(), TL.getParams(), TL.getTypePtr()->param_type_begin(), T->getExtParameterInfosOrNull(), ParamTypes, &ParamDecls, ExtParamInfos)) return QualType(); { // C++11 [expr.prim.general]p3: // If a declaration declares a member function or member function // template of a class X, the expression this is a prvalue of type // "pointer to cv-qualifier-seq X" between the optional cv-qualifer-seq // and the end of the function-definition, member-declarator, or // declarator. Sema::CXXThisScopeRAII ThisScope(SemaRef, ThisContext, ThisTypeQuals); ResultType = getDerived().TransformType(TLB, TL.getReturnLoc()); if (ResultType.isNull()) return QualType(); } } else { ResultType = getDerived().TransformType(TLB, TL.getReturnLoc()); if (ResultType.isNull()) return QualType(); if (getDerived().TransformFunctionTypeParams( TL.getBeginLoc(), TL.getParams(), TL.getTypePtr()->param_type_begin(), T->getExtParameterInfosOrNull(), ParamTypes, &ParamDecls, ExtParamInfos)) return QualType(); } FunctionProtoType::ExtProtoInfo EPI = T->getExtProtoInfo(); bool EPIChanged = false; if (TransformExceptionSpec(EPI.ExceptionSpec, EPIChanged)) return QualType(); // Handle extended parameter information. if (auto NewExtParamInfos = ExtParamInfos.getPointerOrNull(ParamTypes.size())) { if (!EPI.ExtParameterInfos || llvm::makeArrayRef(EPI.ExtParameterInfos, TL.getNumParams()) != llvm::makeArrayRef(NewExtParamInfos, ParamTypes.size())) { EPIChanged = true; } EPI.ExtParameterInfos = NewExtParamInfos; } else if (EPI.ExtParameterInfos) { EPIChanged = true; EPI.ExtParameterInfos = nullptr; } QualType Result = TL.getType(); if (getDerived().AlwaysRebuild() || ResultType != T->getReturnType() || T->getParamTypes() != llvm::makeArrayRef(ParamTypes) || EPIChanged) { Result = getDerived().RebuildFunctionProtoType(ResultType, ParamTypes, EPI); if (Result.isNull()) return QualType(); } FunctionProtoTypeLoc NewTL = TLB.push(Result); NewTL.setLocalRangeBegin(TL.getLocalRangeBegin()); NewTL.setLParenLoc(TL.getLParenLoc()); NewTL.setRParenLoc(TL.getRParenLoc()); NewTL.setExceptionSpecRange(TL.getExceptionSpecRange()); NewTL.setLocalRangeEnd(TL.getLocalRangeEnd()); for (unsigned i = 0, e = NewTL.getNumParams(); i != e; ++i) NewTL.setParam(i, ParamDecls[i]); return Result; } template bool TreeTransform::TransformExceptionSpec( SourceLocation Loc, FunctionProtoType::ExceptionSpecInfo &ESI, SmallVectorImpl &Exceptions, bool &Changed) { assert(ESI.Type != EST_Uninstantiated && ESI.Type != EST_Unevaluated); // Instantiate a dynamic noexcept expression, if any. if (isComputedNoexcept(ESI.Type)) { EnterExpressionEvaluationContext Unevaluated( getSema(), Sema::ExpressionEvaluationContext::ConstantEvaluated); ExprResult NoexceptExpr = getDerived().TransformExpr(ESI.NoexceptExpr); if (NoexceptExpr.isInvalid()) return true; ExceptionSpecificationType EST = ESI.Type; NoexceptExpr = getSema().ActOnNoexceptSpec(Loc, NoexceptExpr.get(), EST); if (NoexceptExpr.isInvalid()) return true; if (ESI.NoexceptExpr != NoexceptExpr.get() || EST != ESI.Type) Changed = true; ESI.NoexceptExpr = NoexceptExpr.get(); ESI.Type = EST; } if (ESI.Type != EST_Dynamic) return false; // Instantiate a dynamic exception specification's type. for (QualType T : ESI.Exceptions) { if (const PackExpansionType *PackExpansion = T->getAs()) { Changed = true; // We have a pack expansion. Instantiate it. SmallVector Unexpanded; SemaRef.collectUnexpandedParameterPacks(PackExpansion->getPattern(), Unexpanded); assert(!Unexpanded.empty() && "Pack expansion without parameter packs?"); // Determine whether the set of unexpanded parameter packs can and // should // be expanded. bool Expand = false; bool RetainExpansion = false; Optional NumExpansions = PackExpansion->getNumExpansions(); // FIXME: Track the location of the ellipsis (and track source location // information for the types in the exception specification in general). if (getDerived().TryExpandParameterPacks( Loc, SourceRange(), Unexpanded, Expand, RetainExpansion, NumExpansions)) return true; if (!Expand) { // We can't expand this pack expansion into separate arguments yet; // just substitute into the pattern and create a new pack expansion // type. Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), -1); QualType U = getDerived().TransformType(PackExpansion->getPattern()); if (U.isNull()) return true; U = SemaRef.Context.getPackExpansionType(U, NumExpansions); Exceptions.push_back(U); continue; } // Substitute into the pack expansion pattern for each slice of the // pack. for (unsigned ArgIdx = 0; ArgIdx != *NumExpansions; ++ArgIdx) { Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), ArgIdx); QualType U = getDerived().TransformType(PackExpansion->getPattern()); if (U.isNull() || SemaRef.CheckSpecifiedExceptionType(U, Loc)) return true; Exceptions.push_back(U); } } else { QualType U = getDerived().TransformType(T); if (U.isNull() || SemaRef.CheckSpecifiedExceptionType(U, Loc)) return true; if (T != U) Changed = true; Exceptions.push_back(U); } } ESI.Exceptions = Exceptions; if (ESI.Exceptions.empty()) ESI.Type = EST_DynamicNone; return false; } template QualType TreeTransform::TransformFunctionNoProtoType( TypeLocBuilder &TLB, FunctionNoProtoTypeLoc TL) { const FunctionNoProtoType *T = TL.getTypePtr(); QualType ResultType = getDerived().TransformType(TLB, TL.getReturnLoc()); if (ResultType.isNull()) return QualType(); QualType Result = TL.getType(); if (getDerived().AlwaysRebuild() || ResultType != T->getReturnType()) Result = getDerived().RebuildFunctionNoProtoType(ResultType); FunctionNoProtoTypeLoc NewTL = TLB.push(Result); NewTL.setLocalRangeBegin(TL.getLocalRangeBegin()); NewTL.setLParenLoc(TL.getLParenLoc()); NewTL.setRParenLoc(TL.getRParenLoc()); NewTL.setLocalRangeEnd(TL.getLocalRangeEnd()); return Result; } template QualType TreeTransform::TransformUnresolvedUsingType(TypeLocBuilder &TLB, UnresolvedUsingTypeLoc TL) { const UnresolvedUsingType *T = TL.getTypePtr(); Decl *D = getDerived().TransformDecl(TL.getNameLoc(), T->getDecl()); if (!D) return QualType(); QualType Result = TL.getType(); if (getDerived().AlwaysRebuild() || D != T->getDecl()) { Result = getDerived().RebuildUnresolvedUsingType(TL.getNameLoc(), D); if (Result.isNull()) return QualType(); } // We might get an arbitrary type spec type back. We should at // least always get a type spec type, though. TypeSpecTypeLoc NewTL = TLB.pushTypeSpec(Result); NewTL.setNameLoc(TL.getNameLoc()); return Result; } template QualType TreeTransform::TransformTypedefType(TypeLocBuilder &TLB, TypedefTypeLoc TL) { const TypedefType *T = TL.getTypePtr(); TypedefNameDecl *Typedef = cast_or_null(getDerived().TransformDecl(TL.getNameLoc(), T->getDecl())); if (!Typedef) return QualType(); QualType Result = TL.getType(); if (getDerived().AlwaysRebuild() || Typedef != T->getDecl()) { Result = getDerived().RebuildTypedefType(Typedef); if (Result.isNull()) return QualType(); } TypedefTypeLoc NewTL = TLB.push(Result); NewTL.setNameLoc(TL.getNameLoc()); return Result; } template QualType TreeTransform::TransformTypeOfExprType(TypeLocBuilder &TLB, TypeOfExprTypeLoc TL) { // typeof expressions are not potentially evaluated contexts EnterExpressionEvaluationContext Unevaluated( SemaRef, Sema::ExpressionEvaluationContext::Unevaluated, Sema::ReuseLambdaContextDecl); ExprResult E = getDerived().TransformExpr(TL.getUnderlyingExpr()); if (E.isInvalid()) return QualType(); E = SemaRef.HandleExprEvaluationContextForTypeof(E.get()); if (E.isInvalid()) return QualType(); QualType Result = TL.getType(); if (getDerived().AlwaysRebuild() || E.get() != TL.getUnderlyingExpr()) { Result = getDerived().RebuildTypeOfExprType(E.get(), TL.getTypeofLoc()); if (Result.isNull()) return QualType(); } else E.get(); TypeOfExprTypeLoc NewTL = TLB.push(Result); NewTL.setTypeofLoc(TL.getTypeofLoc()); NewTL.setLParenLoc(TL.getLParenLoc()); NewTL.setRParenLoc(TL.getRParenLoc()); return Result; } template QualType TreeTransform::TransformTypeOfType(TypeLocBuilder &TLB, TypeOfTypeLoc TL) { TypeSourceInfo* Old_Under_TI = TL.getUnderlyingTInfo(); TypeSourceInfo* New_Under_TI = getDerived().TransformType(Old_Under_TI); if (!New_Under_TI) return QualType(); QualType Result = TL.getType(); if (getDerived().AlwaysRebuild() || New_Under_TI != Old_Under_TI) { Result = getDerived().RebuildTypeOfType(New_Under_TI->getType()); if (Result.isNull()) return QualType(); } TypeOfTypeLoc NewTL = TLB.push(Result); NewTL.setTypeofLoc(TL.getTypeofLoc()); NewTL.setLParenLoc(TL.getLParenLoc()); NewTL.setRParenLoc(TL.getRParenLoc()); NewTL.setUnderlyingTInfo(New_Under_TI); return Result; } template QualType TreeTransform::TransformDecltypeType(TypeLocBuilder &TLB, DecltypeTypeLoc TL) { const DecltypeType *T = TL.getTypePtr(); // decltype expressions are not potentially evaluated contexts EnterExpressionEvaluationContext Unevaluated( SemaRef, Sema::ExpressionEvaluationContext::Unevaluated, nullptr, Sema::ExpressionEvaluationContextRecord::EK_Decltype); ExprResult E = getDerived().TransformExpr(T->getUnderlyingExpr()); if (E.isInvalid()) return QualType(); E = getSema().ActOnDecltypeExpression(E.get()); if (E.isInvalid()) return QualType(); QualType Result = TL.getType(); if (getDerived().AlwaysRebuild() || E.get() != T->getUnderlyingExpr()) { Result = getDerived().RebuildDecltypeType(E.get(), TL.getNameLoc()); if (Result.isNull()) return QualType(); } else E.get(); DecltypeTypeLoc NewTL = TLB.push(Result); NewTL.setNameLoc(TL.getNameLoc()); return Result; } template QualType TreeTransform::TransformUnaryTransformType( TypeLocBuilder &TLB, UnaryTransformTypeLoc TL) { QualType Result = TL.getType(); if (Result->isDependentType()) { const UnaryTransformType *T = TL.getTypePtr(); QualType NewBase = getDerived().TransformType(TL.getUnderlyingTInfo())->getType(); Result = getDerived().RebuildUnaryTransformType(NewBase, T->getUTTKind(), TL.getKWLoc()); if (Result.isNull()) return QualType(); } UnaryTransformTypeLoc NewTL = TLB.push(Result); NewTL.setKWLoc(TL.getKWLoc()); NewTL.setParensRange(TL.getParensRange()); NewTL.setUnderlyingTInfo(TL.getUnderlyingTInfo()); return Result; } template QualType TreeTransform::TransformDeducedTemplateSpecializationType( TypeLocBuilder &TLB, DeducedTemplateSpecializationTypeLoc TL) { const DeducedTemplateSpecializationType *T = TL.getTypePtr(); CXXScopeSpec SS; TemplateName TemplateName = getDerived().TransformTemplateName( SS, T->getTemplateName(), TL.getTemplateNameLoc()); if (TemplateName.isNull()) return QualType(); QualType OldDeduced = T->getDeducedType(); QualType NewDeduced; if (!OldDeduced.isNull()) { NewDeduced = getDerived().TransformType(OldDeduced); if (NewDeduced.isNull()) return QualType(); } QualType Result = getDerived().RebuildDeducedTemplateSpecializationType( TemplateName, NewDeduced); if (Result.isNull()) return QualType(); DeducedTemplateSpecializationTypeLoc NewTL = TLB.push(Result); NewTL.setTemplateNameLoc(TL.getTemplateNameLoc()); return Result; } template QualType TreeTransform::TransformRecordType(TypeLocBuilder &TLB, RecordTypeLoc TL) { const RecordType *T = TL.getTypePtr(); RecordDecl *Record = cast_or_null(getDerived().TransformDecl(TL.getNameLoc(), T->getDecl())); if (!Record) return QualType(); QualType Result = TL.getType(); if (getDerived().AlwaysRebuild() || Record != T->getDecl()) { Result = getDerived().RebuildRecordType(Record); if (Result.isNull()) return QualType(); } RecordTypeLoc NewTL = TLB.push(Result); NewTL.setNameLoc(TL.getNameLoc()); return Result; } template QualType TreeTransform::TransformEnumType(TypeLocBuilder &TLB, EnumTypeLoc TL) { const EnumType *T = TL.getTypePtr(); EnumDecl *Enum = cast_or_null(getDerived().TransformDecl(TL.getNameLoc(), T->getDecl())); if (!Enum) return QualType(); QualType Result = TL.getType(); if (getDerived().AlwaysRebuild() || Enum != T->getDecl()) { Result = getDerived().RebuildEnumType(Enum); if (Result.isNull()) return QualType(); } EnumTypeLoc NewTL = TLB.push(Result); NewTL.setNameLoc(TL.getNameLoc()); return Result; } template QualType TreeTransform::TransformInjectedClassNameType( TypeLocBuilder &TLB, InjectedClassNameTypeLoc TL) { Decl *D = getDerived().TransformDecl(TL.getNameLoc(), TL.getTypePtr()->getDecl()); if (!D) return QualType(); QualType T = SemaRef.Context.getTypeDeclType(cast(D)); TLB.pushTypeSpec(T).setNameLoc(TL.getNameLoc()); return T; } template QualType TreeTransform::TransformTemplateTypeParmType( TypeLocBuilder &TLB, TemplateTypeParmTypeLoc TL) { return TransformTypeSpecType(TLB, TL); } template QualType TreeTransform::TransformSubstTemplateTypeParmType( TypeLocBuilder &TLB, SubstTemplateTypeParmTypeLoc TL) { const SubstTemplateTypeParmType *T = TL.getTypePtr(); // Substitute into the replacement type, which itself might involve something // that needs to be transformed. This only tends to occur with default // template arguments of template template parameters. TemporaryBase Rebase(*this, TL.getNameLoc(), DeclarationName()); QualType Replacement = getDerived().TransformType(T->getReplacementType()); if (Replacement.isNull()) return QualType(); // Always canonicalize the replacement type. Replacement = SemaRef.Context.getCanonicalType(Replacement); QualType Result = SemaRef.Context.getSubstTemplateTypeParmType(T->getReplacedParameter(), Replacement); // Propagate type-source information. SubstTemplateTypeParmTypeLoc NewTL = TLB.push(Result); NewTL.setNameLoc(TL.getNameLoc()); return Result; } template QualType TreeTransform::TransformSubstTemplateTypeParmPackType( TypeLocBuilder &TLB, SubstTemplateTypeParmPackTypeLoc TL) { return TransformTypeSpecType(TLB, TL); } template QualType TreeTransform::TransformTemplateSpecializationType( TypeLocBuilder &TLB, TemplateSpecializationTypeLoc TL) { const TemplateSpecializationType *T = TL.getTypePtr(); // The nested-name-specifier never matters in a TemplateSpecializationType, // because we can't have a dependent nested-name-specifier anyway. CXXScopeSpec SS; TemplateName Template = getDerived().TransformTemplateName(SS, T->getTemplateName(), TL.getTemplateNameLoc()); if (Template.isNull()) return QualType(); return getDerived().TransformTemplateSpecializationType(TLB, TL, Template); } template QualType TreeTransform::TransformAtomicType(TypeLocBuilder &TLB, AtomicTypeLoc TL) { QualType ValueType = getDerived().TransformType(TLB, TL.getValueLoc()); if (ValueType.isNull()) return QualType(); QualType Result = TL.getType(); if (getDerived().AlwaysRebuild() || ValueType != TL.getValueLoc().getType()) { Result = getDerived().RebuildAtomicType(ValueType, TL.getKWLoc()); if (Result.isNull()) return QualType(); } AtomicTypeLoc NewTL = TLB.push(Result); NewTL.setKWLoc(TL.getKWLoc()); NewTL.setLParenLoc(TL.getLParenLoc()); NewTL.setRParenLoc(TL.getRParenLoc()); return Result; } template QualType TreeTransform::TransformPipeType(TypeLocBuilder &TLB, PipeTypeLoc TL) { QualType ValueType = getDerived().TransformType(TLB, TL.getValueLoc()); if (ValueType.isNull()) return QualType(); QualType Result = TL.getType(); if (getDerived().AlwaysRebuild() || ValueType != TL.getValueLoc().getType()) { const PipeType *PT = Result->castAs(); bool isReadPipe = PT->isReadOnly(); Result = getDerived().RebuildPipeType(ValueType, TL.getKWLoc(), isReadPipe); if (Result.isNull()) return QualType(); } PipeTypeLoc NewTL = TLB.push(Result); NewTL.setKWLoc(TL.getKWLoc()); return Result; } /// Simple iterator that traverses the template arguments in a /// container that provides a \c getArgLoc() member function. /// /// This iterator is intended to be used with the iterator form of /// \c TreeTransform::TransformTemplateArguments(). template class TemplateArgumentLocContainerIterator { ArgLocContainer *Container; unsigned Index; public: typedef TemplateArgumentLoc value_type; typedef TemplateArgumentLoc reference; typedef int difference_type; typedef std::input_iterator_tag iterator_category; class pointer { TemplateArgumentLoc Arg; public: explicit pointer(TemplateArgumentLoc Arg) : Arg(Arg) { } const TemplateArgumentLoc *operator->() const { return &Arg; } }; TemplateArgumentLocContainerIterator() {} TemplateArgumentLocContainerIterator(ArgLocContainer &Container, unsigned Index) : Container(&Container), Index(Index) { } TemplateArgumentLocContainerIterator &operator++() { ++Index; return *this; } TemplateArgumentLocContainerIterator operator++(int) { TemplateArgumentLocContainerIterator Old(*this); ++(*this); return Old; } TemplateArgumentLoc operator*() const { return Container->getArgLoc(Index); } pointer operator->() const { return pointer(Container->getArgLoc(Index)); } friend bool operator==(const TemplateArgumentLocContainerIterator &X, const TemplateArgumentLocContainerIterator &Y) { return X.Container == Y.Container && X.Index == Y.Index; } friend bool operator!=(const TemplateArgumentLocContainerIterator &X, const TemplateArgumentLocContainerIterator &Y) { return !(X == Y); } }; template QualType TreeTransform::TransformAutoType(TypeLocBuilder &TLB, AutoTypeLoc TL) { const AutoType *T = TL.getTypePtr(); QualType OldDeduced = T->getDeducedType(); QualType NewDeduced; if (!OldDeduced.isNull()) { NewDeduced = getDerived().TransformType(OldDeduced); if (NewDeduced.isNull()) return QualType(); } ConceptDecl *NewCD = nullptr; TemplateArgumentListInfo NewTemplateArgs; NestedNameSpecifierLoc NewNestedNameSpec; if (TL.getTypePtr()->isConstrained()) { NewCD = cast_or_null( getDerived().TransformDecl( TL.getConceptNameLoc(), TL.getTypePtr()->getTypeConstraintConcept())); NewTemplateArgs.setLAngleLoc(TL.getLAngleLoc()); NewTemplateArgs.setRAngleLoc(TL.getRAngleLoc()); typedef TemplateArgumentLocContainerIterator ArgIterator; if (getDerived().TransformTemplateArguments(ArgIterator(TL, 0), ArgIterator(TL, TL.getNumArgs()), NewTemplateArgs)) return QualType(); if (TL.getNestedNameSpecifierLoc()) { NewNestedNameSpec = getDerived().TransformNestedNameSpecifierLoc( TL.getNestedNameSpecifierLoc()); if (!NewNestedNameSpec) return QualType(); } } QualType Result = TL.getType(); if (getDerived().AlwaysRebuild() || NewDeduced != OldDeduced || T->isDependentType()) { llvm::SmallVector NewArgList; NewArgList.reserve(NewArgList.size()); for (const auto &ArgLoc : NewTemplateArgs.arguments()) NewArgList.push_back(ArgLoc.getArgument()); Result = getDerived().RebuildAutoType(NewDeduced, T->getKeyword(), NewCD, NewArgList); if (Result.isNull()) return QualType(); } AutoTypeLoc NewTL = TLB.push(Result); NewTL.setNameLoc(TL.getNameLoc()); NewTL.setNestedNameSpecifierLoc(NewNestedNameSpec); NewTL.setTemplateKWLoc(TL.getTemplateKWLoc()); NewTL.setConceptNameLoc(TL.getConceptNameLoc()); NewTL.setFoundDecl(TL.getFoundDecl()); NewTL.setLAngleLoc(TL.getLAngleLoc()); NewTL.setRAngleLoc(TL.getRAngleLoc()); for (unsigned I = 0; I < TL.getNumArgs(); ++I) NewTL.setArgLocInfo(I, NewTemplateArgs.arguments()[I].getLocInfo()); return Result; } template QualType TreeTransform::TransformTemplateSpecializationType( TypeLocBuilder &TLB, TemplateSpecializationTypeLoc TL, TemplateName Template) { TemplateArgumentListInfo NewTemplateArgs; NewTemplateArgs.setLAngleLoc(TL.getLAngleLoc()); NewTemplateArgs.setRAngleLoc(TL.getRAngleLoc()); typedef TemplateArgumentLocContainerIterator ArgIterator; if (getDerived().TransformTemplateArguments(ArgIterator(TL, 0), ArgIterator(TL, TL.getNumArgs()), NewTemplateArgs)) return QualType(); // FIXME: maybe don't rebuild if all the template arguments are the same. QualType Result = getDerived().RebuildTemplateSpecializationType(Template, TL.getTemplateNameLoc(), NewTemplateArgs); if (!Result.isNull()) { // Specializations of template template parameters are represented as // TemplateSpecializationTypes, and substitution of type alias templates // within a dependent context can transform them into // DependentTemplateSpecializationTypes. if (isa(Result)) { DependentTemplateSpecializationTypeLoc NewTL = TLB.push(Result); NewTL.setElaboratedKeywordLoc(SourceLocation()); NewTL.setQualifierLoc(NestedNameSpecifierLoc()); NewTL.setTemplateKeywordLoc(TL.getTemplateKeywordLoc()); NewTL.setTemplateNameLoc(TL.getTemplateNameLoc()); NewTL.setLAngleLoc(TL.getLAngleLoc()); NewTL.setRAngleLoc(TL.getRAngleLoc()); for (unsigned i = 0, e = NewTemplateArgs.size(); i != e; ++i) NewTL.setArgLocInfo(i, NewTemplateArgs[i].getLocInfo()); return Result; } TemplateSpecializationTypeLoc NewTL = TLB.push(Result); NewTL.setTemplateKeywordLoc(TL.getTemplateKeywordLoc()); NewTL.setTemplateNameLoc(TL.getTemplateNameLoc()); NewTL.setLAngleLoc(TL.getLAngleLoc()); NewTL.setRAngleLoc(TL.getRAngleLoc()); for (unsigned i = 0, e = NewTemplateArgs.size(); i != e; ++i) NewTL.setArgLocInfo(i, NewTemplateArgs[i].getLocInfo()); } return Result; } template QualType TreeTransform::TransformDependentTemplateSpecializationType( TypeLocBuilder &TLB, DependentTemplateSpecializationTypeLoc TL, TemplateName Template, CXXScopeSpec &SS) { TemplateArgumentListInfo NewTemplateArgs; NewTemplateArgs.setLAngleLoc(TL.getLAngleLoc()); NewTemplateArgs.setRAngleLoc(TL.getRAngleLoc()); typedef TemplateArgumentLocContainerIterator< DependentTemplateSpecializationTypeLoc> ArgIterator; if (getDerived().TransformTemplateArguments(ArgIterator(TL, 0), ArgIterator(TL, TL.getNumArgs()), NewTemplateArgs)) return QualType(); // FIXME: maybe don't rebuild if all the template arguments are the same. if (DependentTemplateName *DTN = Template.getAsDependentTemplateName()) { QualType Result = getSema().Context.getDependentTemplateSpecializationType( TL.getTypePtr()->getKeyword(), DTN->getQualifier(), DTN->getIdentifier(), NewTemplateArgs); DependentTemplateSpecializationTypeLoc NewTL = TLB.push(Result); NewTL.setElaboratedKeywordLoc(TL.getElaboratedKeywordLoc()); NewTL.setQualifierLoc(SS.getWithLocInContext(SemaRef.Context)); NewTL.setTemplateKeywordLoc(TL.getTemplateKeywordLoc()); NewTL.setTemplateNameLoc(TL.getTemplateNameLoc()); NewTL.setLAngleLoc(TL.getLAngleLoc()); NewTL.setRAngleLoc(TL.getRAngleLoc()); for (unsigned i = 0, e = NewTemplateArgs.size(); i != e; ++i) NewTL.setArgLocInfo(i, NewTemplateArgs[i].getLocInfo()); return Result; } QualType Result = getDerived().RebuildTemplateSpecializationType(Template, TL.getTemplateNameLoc(), NewTemplateArgs); if (!Result.isNull()) { /// FIXME: Wrap this in an elaborated-type-specifier? TemplateSpecializationTypeLoc NewTL = TLB.push(Result); NewTL.setTemplateKeywordLoc(TL.getTemplateKeywordLoc()); NewTL.setTemplateNameLoc(TL.getTemplateNameLoc()); NewTL.setLAngleLoc(TL.getLAngleLoc()); NewTL.setRAngleLoc(TL.getRAngleLoc()); for (unsigned i = 0, e = NewTemplateArgs.size(); i != e; ++i) NewTL.setArgLocInfo(i, NewTemplateArgs[i].getLocInfo()); } return Result; } template QualType TreeTransform::TransformElaboratedType(TypeLocBuilder &TLB, ElaboratedTypeLoc TL) { const ElaboratedType *T = TL.getTypePtr(); NestedNameSpecifierLoc QualifierLoc; // NOTE: the qualifier in an ElaboratedType is optional. if (TL.getQualifierLoc()) { QualifierLoc = getDerived().TransformNestedNameSpecifierLoc(TL.getQualifierLoc()); if (!QualifierLoc) return QualType(); } QualType NamedT = getDerived().TransformType(TLB, TL.getNamedTypeLoc()); if (NamedT.isNull()) return QualType(); // C++0x [dcl.type.elab]p2: // If the identifier resolves to a typedef-name or the simple-template-id // resolves to an alias template specialization, the // elaborated-type-specifier is ill-formed. if (T->getKeyword() != ETK_None && T->getKeyword() != ETK_Typename) { if (const TemplateSpecializationType *TST = NamedT->getAs()) { TemplateName Template = TST->getTemplateName(); if (TypeAliasTemplateDecl *TAT = dyn_cast_or_null( Template.getAsTemplateDecl())) { SemaRef.Diag(TL.getNamedTypeLoc().getBeginLoc(), diag::err_tag_reference_non_tag) << TAT << Sema::NTK_TypeAliasTemplate << ElaboratedType::getTagTypeKindForKeyword(T->getKeyword()); SemaRef.Diag(TAT->getLocation(), diag::note_declared_at); } } } QualType Result = TL.getType(); if (getDerived().AlwaysRebuild() || QualifierLoc != TL.getQualifierLoc() || NamedT != T->getNamedType()) { Result = getDerived().RebuildElaboratedType(TL.getElaboratedKeywordLoc(), T->getKeyword(), QualifierLoc, NamedT); if (Result.isNull()) return QualType(); } ElaboratedTypeLoc NewTL = TLB.push(Result); NewTL.setElaboratedKeywordLoc(TL.getElaboratedKeywordLoc()); NewTL.setQualifierLoc(QualifierLoc); return Result; } template QualType TreeTransform::TransformAttributedType( TypeLocBuilder &TLB, AttributedTypeLoc TL) { const AttributedType *oldType = TL.getTypePtr(); QualType modifiedType = getDerived().TransformType(TLB, TL.getModifiedLoc()); if (modifiedType.isNull()) return QualType(); // oldAttr can be null if we started with a QualType rather than a TypeLoc. const Attr *oldAttr = TL.getAttr(); const Attr *newAttr = oldAttr ? getDerived().TransformAttr(oldAttr) : nullptr; if (oldAttr && !newAttr) return QualType(); QualType result = TL.getType(); // FIXME: dependent operand expressions? if (getDerived().AlwaysRebuild() || modifiedType != oldType->getModifiedType()) { // TODO: this is really lame; we should really be rebuilding the // equivalent type from first principles. QualType equivalentType = getDerived().TransformType(oldType->getEquivalentType()); if (equivalentType.isNull()) return QualType(); // Check whether we can add nullability; it is only represented as // type sugar, and therefore cannot be diagnosed in any other way. if (auto nullability = oldType->getImmediateNullability()) { if (!modifiedType->canHaveNullability()) { SemaRef.Diag(TL.getAttr()->getLocation(), diag::err_nullability_nonpointer) << DiagNullabilityKind(*nullability, false) << modifiedType; return QualType(); } } result = SemaRef.Context.getAttributedType(TL.getAttrKind(), modifiedType, equivalentType); } AttributedTypeLoc newTL = TLB.push(result); newTL.setAttr(newAttr); return result; } template QualType TreeTransform::TransformParenType(TypeLocBuilder &TLB, ParenTypeLoc TL) { QualType Inner = getDerived().TransformType(TLB, TL.getInnerLoc()); if (Inner.isNull()) return QualType(); QualType Result = TL.getType(); if (getDerived().AlwaysRebuild() || Inner != TL.getInnerLoc().getType()) { Result = getDerived().RebuildParenType(Inner); if (Result.isNull()) return QualType(); } ParenTypeLoc NewTL = TLB.push(Result); NewTL.setLParenLoc(TL.getLParenLoc()); NewTL.setRParenLoc(TL.getRParenLoc()); return Result; } template QualType TreeTransform::TransformMacroQualifiedType(TypeLocBuilder &TLB, MacroQualifiedTypeLoc TL) { QualType Inner = getDerived().TransformType(TLB, TL.getInnerLoc()); if (Inner.isNull()) return QualType(); QualType Result = TL.getType(); if (getDerived().AlwaysRebuild() || Inner != TL.getInnerLoc().getType()) { Result = getDerived().RebuildMacroQualifiedType(Inner, TL.getMacroIdentifier()); if (Result.isNull()) return QualType(); } MacroQualifiedTypeLoc NewTL = TLB.push(Result); NewTL.setExpansionLoc(TL.getExpansionLoc()); return Result; } template QualType TreeTransform::TransformDependentNameType( TypeLocBuilder &TLB, DependentNameTypeLoc TL) { return TransformDependentNameType(TLB, TL, false); } template QualType TreeTransform::TransformDependentNameType( TypeLocBuilder &TLB, DependentNameTypeLoc TL, bool DeducedTSTContext) { const DependentNameType *T = TL.getTypePtr(); NestedNameSpecifierLoc QualifierLoc = getDerived().TransformNestedNameSpecifierLoc(TL.getQualifierLoc()); if (!QualifierLoc) return QualType(); QualType Result = getDerived().RebuildDependentNameType(T->getKeyword(), TL.getElaboratedKeywordLoc(), QualifierLoc, T->getIdentifier(), TL.getNameLoc(), DeducedTSTContext); if (Result.isNull()) return QualType(); if (const ElaboratedType* ElabT = Result->getAs()) { QualType NamedT = ElabT->getNamedType(); TLB.pushTypeSpec(NamedT).setNameLoc(TL.getNameLoc()); ElaboratedTypeLoc NewTL = TLB.push(Result); NewTL.setElaboratedKeywordLoc(TL.getElaboratedKeywordLoc()); NewTL.setQualifierLoc(QualifierLoc); } else { DependentNameTypeLoc NewTL = TLB.push(Result); NewTL.setElaboratedKeywordLoc(TL.getElaboratedKeywordLoc()); NewTL.setQualifierLoc(QualifierLoc); NewTL.setNameLoc(TL.getNameLoc()); } return Result; } template QualType TreeTransform:: TransformDependentTemplateSpecializationType(TypeLocBuilder &TLB, DependentTemplateSpecializationTypeLoc TL) { NestedNameSpecifierLoc QualifierLoc; if (TL.getQualifierLoc()) { QualifierLoc = getDerived().TransformNestedNameSpecifierLoc(TL.getQualifierLoc()); if (!QualifierLoc) return QualType(); } return getDerived() .TransformDependentTemplateSpecializationType(TLB, TL, QualifierLoc); } template QualType TreeTransform:: TransformDependentTemplateSpecializationType(TypeLocBuilder &TLB, DependentTemplateSpecializationTypeLoc TL, NestedNameSpecifierLoc QualifierLoc) { const DependentTemplateSpecializationType *T = TL.getTypePtr(); TemplateArgumentListInfo NewTemplateArgs; NewTemplateArgs.setLAngleLoc(TL.getLAngleLoc()); NewTemplateArgs.setRAngleLoc(TL.getRAngleLoc()); typedef TemplateArgumentLocContainerIterator< DependentTemplateSpecializationTypeLoc> ArgIterator; if (getDerived().TransformTemplateArguments(ArgIterator(TL, 0), ArgIterator(TL, TL.getNumArgs()), NewTemplateArgs)) return QualType(); QualType Result = getDerived().RebuildDependentTemplateSpecializationType( T->getKeyword(), QualifierLoc, TL.getTemplateKeywordLoc(), T->getIdentifier(), TL.getTemplateNameLoc(), NewTemplateArgs, /*AllowInjectedClassName*/ false); if (Result.isNull()) return QualType(); if (const ElaboratedType *ElabT = dyn_cast(Result)) { QualType NamedT = ElabT->getNamedType(); // Copy information relevant to the template specialization. TemplateSpecializationTypeLoc NamedTL = TLB.push(NamedT); NamedTL.setTemplateKeywordLoc(TL.getTemplateKeywordLoc()); NamedTL.setTemplateNameLoc(TL.getTemplateNameLoc()); NamedTL.setLAngleLoc(TL.getLAngleLoc()); NamedTL.setRAngleLoc(TL.getRAngleLoc()); for (unsigned I = 0, E = NewTemplateArgs.size(); I != E; ++I) NamedTL.setArgLocInfo(I, NewTemplateArgs[I].getLocInfo()); // Copy information relevant to the elaborated type. ElaboratedTypeLoc NewTL = TLB.push(Result); NewTL.setElaboratedKeywordLoc(TL.getElaboratedKeywordLoc()); NewTL.setQualifierLoc(QualifierLoc); } else if (isa(Result)) { DependentTemplateSpecializationTypeLoc SpecTL = TLB.push(Result); SpecTL.setElaboratedKeywordLoc(TL.getElaboratedKeywordLoc()); SpecTL.setQualifierLoc(QualifierLoc); SpecTL.setTemplateKeywordLoc(TL.getTemplateKeywordLoc()); SpecTL.setTemplateNameLoc(TL.getTemplateNameLoc()); SpecTL.setLAngleLoc(TL.getLAngleLoc()); SpecTL.setRAngleLoc(TL.getRAngleLoc()); for (unsigned I = 0, E = NewTemplateArgs.size(); I != E; ++I) SpecTL.setArgLocInfo(I, NewTemplateArgs[I].getLocInfo()); } else { TemplateSpecializationTypeLoc SpecTL = TLB.push(Result); SpecTL.setTemplateKeywordLoc(TL.getTemplateKeywordLoc()); SpecTL.setTemplateNameLoc(TL.getTemplateNameLoc()); SpecTL.setLAngleLoc(TL.getLAngleLoc()); SpecTL.setRAngleLoc(TL.getRAngleLoc()); for (unsigned I = 0, E = NewTemplateArgs.size(); I != E; ++I) SpecTL.setArgLocInfo(I, NewTemplateArgs[I].getLocInfo()); } return Result; } template QualType TreeTransform::TransformPackExpansionType(TypeLocBuilder &TLB, PackExpansionTypeLoc TL) { QualType Pattern = getDerived().TransformType(TLB, TL.getPatternLoc()); if (Pattern.isNull()) return QualType(); QualType Result = TL.getType(); if (getDerived().AlwaysRebuild() || Pattern != TL.getPatternLoc().getType()) { Result = getDerived().RebuildPackExpansionType(Pattern, TL.getPatternLoc().getSourceRange(), TL.getEllipsisLoc(), TL.getTypePtr()->getNumExpansions()); if (Result.isNull()) return QualType(); } PackExpansionTypeLoc NewT = TLB.push(Result); NewT.setEllipsisLoc(TL.getEllipsisLoc()); return Result; } template QualType TreeTransform::TransformObjCInterfaceType(TypeLocBuilder &TLB, ObjCInterfaceTypeLoc TL) { // ObjCInterfaceType is never dependent. TLB.pushFullCopy(TL); return TL.getType(); } template QualType TreeTransform::TransformObjCTypeParamType(TypeLocBuilder &TLB, ObjCTypeParamTypeLoc TL) { const ObjCTypeParamType *T = TL.getTypePtr(); ObjCTypeParamDecl *OTP = cast_or_null( getDerived().TransformDecl(T->getDecl()->getLocation(), T->getDecl())); if (!OTP) return QualType(); QualType Result = TL.getType(); if (getDerived().AlwaysRebuild() || OTP != T->getDecl()) { Result = getDerived().RebuildObjCTypeParamType(OTP, TL.getProtocolLAngleLoc(), llvm::makeArrayRef(TL.getTypePtr()->qual_begin(), TL.getNumProtocols()), TL.getProtocolLocs(), TL.getProtocolRAngleLoc()); if (Result.isNull()) return QualType(); } ObjCTypeParamTypeLoc NewTL = TLB.push(Result); if (TL.getNumProtocols()) { NewTL.setProtocolLAngleLoc(TL.getProtocolLAngleLoc()); for (unsigned i = 0, n = TL.getNumProtocols(); i != n; ++i) NewTL.setProtocolLoc(i, TL.getProtocolLoc(i)); NewTL.setProtocolRAngleLoc(TL.getProtocolRAngleLoc()); } return Result; } template QualType TreeTransform::TransformObjCObjectType(TypeLocBuilder &TLB, ObjCObjectTypeLoc TL) { // Transform base type. QualType BaseType = getDerived().TransformType(TLB, TL.getBaseLoc()); if (BaseType.isNull()) return QualType(); bool AnyChanged = BaseType != TL.getBaseLoc().getType(); // Transform type arguments. SmallVector NewTypeArgInfos; for (unsigned i = 0, n = TL.getNumTypeArgs(); i != n; ++i) { TypeSourceInfo *TypeArgInfo = TL.getTypeArgTInfo(i); TypeLoc TypeArgLoc = TypeArgInfo->getTypeLoc(); QualType TypeArg = TypeArgInfo->getType(); if (auto PackExpansionLoc = TypeArgLoc.getAs()) { AnyChanged = true; // We have a pack expansion. Instantiate it. const auto *PackExpansion = PackExpansionLoc.getType() ->castAs(); SmallVector Unexpanded; SemaRef.collectUnexpandedParameterPacks(PackExpansion->getPattern(), Unexpanded); assert(!Unexpanded.empty() && "Pack expansion without parameter packs?"); // Determine whether the set of unexpanded parameter packs can // and should be expanded. TypeLoc PatternLoc = PackExpansionLoc.getPatternLoc(); bool Expand = false; bool RetainExpansion = false; Optional NumExpansions = PackExpansion->getNumExpansions(); if (getDerived().TryExpandParameterPacks( PackExpansionLoc.getEllipsisLoc(), PatternLoc.getSourceRange(), Unexpanded, Expand, RetainExpansion, NumExpansions)) return QualType(); if (!Expand) { // We can't expand this pack expansion into separate arguments yet; // just substitute into the pattern and create a new pack expansion // type. Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), -1); TypeLocBuilder TypeArgBuilder; TypeArgBuilder.reserve(PatternLoc.getFullDataSize()); QualType NewPatternType = getDerived().TransformType(TypeArgBuilder, PatternLoc); if (NewPatternType.isNull()) return QualType(); QualType NewExpansionType = SemaRef.Context.getPackExpansionType( NewPatternType, NumExpansions); auto NewExpansionLoc = TLB.push(NewExpansionType); NewExpansionLoc.setEllipsisLoc(PackExpansionLoc.getEllipsisLoc()); NewTypeArgInfos.push_back( TypeArgBuilder.getTypeSourceInfo(SemaRef.Context, NewExpansionType)); continue; } // Substitute into the pack expansion pattern for each slice of the // pack. for (unsigned ArgIdx = 0; ArgIdx != *NumExpansions; ++ArgIdx) { Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), ArgIdx); TypeLocBuilder TypeArgBuilder; TypeArgBuilder.reserve(PatternLoc.getFullDataSize()); QualType NewTypeArg = getDerived().TransformType(TypeArgBuilder, PatternLoc); if (NewTypeArg.isNull()) return QualType(); NewTypeArgInfos.push_back( TypeArgBuilder.getTypeSourceInfo(SemaRef.Context, NewTypeArg)); } continue; } TypeLocBuilder TypeArgBuilder; TypeArgBuilder.reserve(TypeArgLoc.getFullDataSize()); QualType NewTypeArg = getDerived().TransformType(TypeArgBuilder, TypeArgLoc); if (NewTypeArg.isNull()) return QualType(); // If nothing changed, just keep the old TypeSourceInfo. if (NewTypeArg == TypeArg) { NewTypeArgInfos.push_back(TypeArgInfo); continue; } NewTypeArgInfos.push_back( TypeArgBuilder.getTypeSourceInfo(SemaRef.Context, NewTypeArg)); AnyChanged = true; } QualType Result = TL.getType(); if (getDerived().AlwaysRebuild() || AnyChanged) { // Rebuild the type. Result = getDerived().RebuildObjCObjectType( BaseType, TL.getBeginLoc(), TL.getTypeArgsLAngleLoc(), NewTypeArgInfos, TL.getTypeArgsRAngleLoc(), TL.getProtocolLAngleLoc(), llvm::makeArrayRef(TL.getTypePtr()->qual_begin(), TL.getNumProtocols()), TL.getProtocolLocs(), TL.getProtocolRAngleLoc()); if (Result.isNull()) return QualType(); } ObjCObjectTypeLoc NewT = TLB.push(Result); NewT.setHasBaseTypeAsWritten(true); NewT.setTypeArgsLAngleLoc(TL.getTypeArgsLAngleLoc()); for (unsigned i = 0, n = TL.getNumTypeArgs(); i != n; ++i) NewT.setTypeArgTInfo(i, NewTypeArgInfos[i]); NewT.setTypeArgsRAngleLoc(TL.getTypeArgsRAngleLoc()); NewT.setProtocolLAngleLoc(TL.getProtocolLAngleLoc()); for (unsigned i = 0, n = TL.getNumProtocols(); i != n; ++i) NewT.setProtocolLoc(i, TL.getProtocolLoc(i)); NewT.setProtocolRAngleLoc(TL.getProtocolRAngleLoc()); return Result; } template QualType TreeTransform::TransformObjCObjectPointerType(TypeLocBuilder &TLB, ObjCObjectPointerTypeLoc TL) { QualType PointeeType = getDerived().TransformType(TLB, TL.getPointeeLoc()); if (PointeeType.isNull()) return QualType(); QualType Result = TL.getType(); if (getDerived().AlwaysRebuild() || PointeeType != TL.getPointeeLoc().getType()) { Result = getDerived().RebuildObjCObjectPointerType(PointeeType, TL.getStarLoc()); if (Result.isNull()) return QualType(); } ObjCObjectPointerTypeLoc NewT = TLB.push(Result); NewT.setStarLoc(TL.getStarLoc()); return Result; } //===----------------------------------------------------------------------===// // Statement transformation //===----------------------------------------------------------------------===// template StmtResult TreeTransform::TransformNullStmt(NullStmt *S) { return S; } template StmtResult TreeTransform::TransformCompoundStmt(CompoundStmt *S) { return getDerived().TransformCompoundStmt(S, false); } template StmtResult TreeTransform::TransformCompoundStmt(CompoundStmt *S, bool IsStmtExpr) { Sema::CompoundScopeRAII CompoundScope(getSema()); const Stmt *ExprResult = S->getStmtExprResult(); bool SubStmtInvalid = false; bool SubStmtChanged = false; SmallVector Statements; for (auto *B : S->body()) { StmtResult Result = getDerived().TransformStmt( B, IsStmtExpr && B == ExprResult ? SDK_StmtExprResult : SDK_Discarded); if (Result.isInvalid()) { // Immediately fail if this was a DeclStmt, since it's very // likely that this will cause problems for future statements. if (isa(B)) return StmtError(); // Otherwise, just keep processing substatements and fail later. SubStmtInvalid = true; continue; } SubStmtChanged = SubStmtChanged || Result.get() != B; Statements.push_back(Result.getAs()); } if (SubStmtInvalid) return StmtError(); if (!getDerived().AlwaysRebuild() && !SubStmtChanged) return S; return getDerived().RebuildCompoundStmt(S->getLBracLoc(), Statements, S->getRBracLoc(), IsStmtExpr); } template StmtResult TreeTransform::TransformCaseStmt(CaseStmt *S) { ExprResult LHS, RHS; { EnterExpressionEvaluationContext Unevaluated( SemaRef, Sema::ExpressionEvaluationContext::ConstantEvaluated); // Transform the left-hand case value. LHS = getDerived().TransformExpr(S->getLHS()); LHS = SemaRef.ActOnCaseExpr(S->getCaseLoc(), LHS); if (LHS.isInvalid()) return StmtError(); // Transform the right-hand case value (for the GNU case-range extension). RHS = getDerived().TransformExpr(S->getRHS()); RHS = SemaRef.ActOnCaseExpr(S->getCaseLoc(), RHS); if (RHS.isInvalid()) return StmtError(); } // Build the case statement. // Case statements are always rebuilt so that they will attached to their // transformed switch statement. StmtResult Case = getDerived().RebuildCaseStmt(S->getCaseLoc(), LHS.get(), S->getEllipsisLoc(), RHS.get(), S->getColonLoc()); if (Case.isInvalid()) return StmtError(); // Transform the statement following the case StmtResult SubStmt = getDerived().TransformStmt(S->getSubStmt()); if (SubStmt.isInvalid()) return StmtError(); // Attach the body to the case statement return getDerived().RebuildCaseStmtBody(Case.get(), SubStmt.get()); } template StmtResult TreeTransform::TransformDefaultStmt(DefaultStmt *S) { // Transform the statement following the default case StmtResult SubStmt = getDerived().TransformStmt(S->getSubStmt()); if (SubStmt.isInvalid()) return StmtError(); // Default statements are always rebuilt return getDerived().RebuildDefaultStmt(S->getDefaultLoc(), S->getColonLoc(), SubStmt.get()); } template StmtResult TreeTransform::TransformLabelStmt(LabelStmt *S, StmtDiscardKind SDK) { StmtResult SubStmt = getDerived().TransformStmt(S->getSubStmt(), SDK); if (SubStmt.isInvalid()) return StmtError(); Decl *LD = getDerived().TransformDecl(S->getDecl()->getLocation(), S->getDecl()); if (!LD) return StmtError(); // If we're transforming "in-place" (we're not creating new local // declarations), assume we're replacing the old label statement // and clear out the reference to it. if (LD == S->getDecl()) S->getDecl()->setStmt(nullptr); // FIXME: Pass the real colon location in. return getDerived().RebuildLabelStmt(S->getIdentLoc(), cast(LD), SourceLocation(), SubStmt.get()); } template const Attr *TreeTransform::TransformAttr(const Attr *R) { if (!R) return R; switch (R->getKind()) { // Transform attributes with a pragma spelling by calling TransformXXXAttr. #define ATTR(X) #define PRAGMA_SPELLING_ATTR(X) \ case attr::X: \ return getDerived().Transform##X##Attr(cast(R)); #include "clang/Basic/AttrList.inc" default: return R; } } template StmtResult TreeTransform::TransformAttributedStmt(AttributedStmt *S, StmtDiscardKind SDK) { bool AttrsChanged = false; SmallVector Attrs; // Visit attributes and keep track if any are transformed. for (const auto *I : S->getAttrs()) { const Attr *R = getDerived().TransformAttr(I); AttrsChanged |= (I != R); Attrs.push_back(R); } StmtResult SubStmt = getDerived().TransformStmt(S->getSubStmt(), SDK); if (SubStmt.isInvalid()) return StmtError(); if (SubStmt.get() == S->getSubStmt() && !AttrsChanged) return S; return getDerived().RebuildAttributedStmt(S->getAttrLoc(), Attrs, SubStmt.get()); } template StmtResult TreeTransform::TransformIfStmt(IfStmt *S) { // Transform the initialization statement StmtResult Init = getDerived().TransformStmt(S->getInit()); if (Init.isInvalid()) return StmtError(); // Transform the condition Sema::ConditionResult Cond = getDerived().TransformCondition( S->getIfLoc(), S->getConditionVariable(), S->getCond(), S->isConstexpr() ? Sema::ConditionKind::ConstexprIf : Sema::ConditionKind::Boolean); if (Cond.isInvalid()) return StmtError(); // If this is a constexpr if, determine which arm we should instantiate. llvm::Optional ConstexprConditionValue; if (S->isConstexpr()) ConstexprConditionValue = Cond.getKnownValue(); // Transform the "then" branch. StmtResult Then; if (!ConstexprConditionValue || *ConstexprConditionValue) { Then = getDerived().TransformStmt(S->getThen()); if (Then.isInvalid()) return StmtError(); } else { Then = new (getSema().Context) NullStmt(S->getThen()->getBeginLoc()); } // Transform the "else" branch. StmtResult Else; if (!ConstexprConditionValue || !*ConstexprConditionValue) { Else = getDerived().TransformStmt(S->getElse()); if (Else.isInvalid()) return StmtError(); } if (!getDerived().AlwaysRebuild() && Init.get() == S->getInit() && Cond.get() == std::make_pair(S->getConditionVariable(), S->getCond()) && Then.get() == S->getThen() && Else.get() == S->getElse()) return S; return getDerived().RebuildIfStmt(S->getIfLoc(), S->isConstexpr(), Cond, Init.get(), Then.get(), S->getElseLoc(), Else.get()); } template StmtResult TreeTransform::TransformSwitchStmt(SwitchStmt *S) { // Transform the initialization statement StmtResult Init = getDerived().TransformStmt(S->getInit()); if (Init.isInvalid()) return StmtError(); // Transform the condition. Sema::ConditionResult Cond = getDerived().TransformCondition( S->getSwitchLoc(), S->getConditionVariable(), S->getCond(), Sema::ConditionKind::Switch); if (Cond.isInvalid()) return StmtError(); // Rebuild the switch statement. StmtResult Switch = getDerived().RebuildSwitchStmtStart(S->getSwitchLoc(), Init.get(), Cond); if (Switch.isInvalid()) return StmtError(); // Transform the body of the switch statement. StmtResult Body = getDerived().TransformStmt(S->getBody()); if (Body.isInvalid()) return StmtError(); // Complete the switch statement. return getDerived().RebuildSwitchStmtBody(S->getSwitchLoc(), Switch.get(), Body.get()); } template StmtResult TreeTransform::TransformWhileStmt(WhileStmt *S) { // Transform the condition Sema::ConditionResult Cond = getDerived().TransformCondition( S->getWhileLoc(), S->getConditionVariable(), S->getCond(), Sema::ConditionKind::Boolean); if (Cond.isInvalid()) return StmtError(); // Transform the body StmtResult Body = getDerived().TransformStmt(S->getBody()); if (Body.isInvalid()) return StmtError(); if (!getDerived().AlwaysRebuild() && Cond.get() == std::make_pair(S->getConditionVariable(), S->getCond()) && Body.get() == S->getBody()) return Owned(S); return getDerived().RebuildWhileStmt(S->getWhileLoc(), Cond, Body.get()); } template StmtResult TreeTransform::TransformDoStmt(DoStmt *S) { // Transform the body StmtResult Body = getDerived().TransformStmt(S->getBody()); if (Body.isInvalid()) return StmtError(); // Transform the condition ExprResult Cond = getDerived().TransformExpr(S->getCond()); if (Cond.isInvalid()) return StmtError(); if (!getDerived().AlwaysRebuild() && Cond.get() == S->getCond() && Body.get() == S->getBody()) return S; return getDerived().RebuildDoStmt(S->getDoLoc(), Body.get(), S->getWhileLoc(), /*FIXME:*/S->getWhileLoc(), Cond.get(), S->getRParenLoc()); } template StmtResult TreeTransform::TransformForStmt(ForStmt *S) { if (getSema().getLangOpts().OpenMP) getSema().startOpenMPLoop(); // Transform the initialization statement StmtResult Init = getDerived().TransformStmt(S->getInit()); if (Init.isInvalid()) return StmtError(); // In OpenMP loop region loop control variable must be captured and be // private. Perform analysis of first part (if any). if (getSema().getLangOpts().OpenMP && Init.isUsable()) getSema().ActOnOpenMPLoopInitialization(S->getForLoc(), Init.get()); // Transform the condition Sema::ConditionResult Cond = getDerived().TransformCondition( S->getForLoc(), S->getConditionVariable(), S->getCond(), Sema::ConditionKind::Boolean); if (Cond.isInvalid()) return StmtError(); // Transform the increment ExprResult Inc = getDerived().TransformExpr(S->getInc()); if (Inc.isInvalid()) return StmtError(); Sema::FullExprArg FullInc(getSema().MakeFullDiscardedValueExpr(Inc.get())); if (S->getInc() && !FullInc.get()) return StmtError(); // Transform the body StmtResult Body = getDerived().TransformStmt(S->getBody()); if (Body.isInvalid()) return StmtError(); if (!getDerived().AlwaysRebuild() && Init.get() == S->getInit() && Cond.get() == std::make_pair(S->getConditionVariable(), S->getCond()) && Inc.get() == S->getInc() && Body.get() == S->getBody()) return S; return getDerived().RebuildForStmt(S->getForLoc(), S->getLParenLoc(), Init.get(), Cond, FullInc, S->getRParenLoc(), Body.get()); } template StmtResult TreeTransform::TransformGotoStmt(GotoStmt *S) { Decl *LD = getDerived().TransformDecl(S->getLabel()->getLocation(), S->getLabel()); if (!LD) return StmtError(); // Goto statements must always be rebuilt, to resolve the label. return getDerived().RebuildGotoStmt(S->getGotoLoc(), S->getLabelLoc(), cast(LD)); } template StmtResult TreeTransform::TransformIndirectGotoStmt(IndirectGotoStmt *S) { ExprResult Target = getDerived().TransformExpr(S->getTarget()); if (Target.isInvalid()) return StmtError(); Target = SemaRef.MaybeCreateExprWithCleanups(Target.get()); if (!getDerived().AlwaysRebuild() && Target.get() == S->getTarget()) return S; return getDerived().RebuildIndirectGotoStmt(S->getGotoLoc(), S->getStarLoc(), Target.get()); } template StmtResult TreeTransform::TransformContinueStmt(ContinueStmt *S) { return S; } template StmtResult TreeTransform::TransformBreakStmt(BreakStmt *S) { return S; } template StmtResult TreeTransform::TransformReturnStmt(ReturnStmt *S) { ExprResult Result = getDerived().TransformInitializer(S->getRetValue(), /*NotCopyInit*/false); if (Result.isInvalid()) return StmtError(); // FIXME: We always rebuild the return statement because there is no way // to tell whether the return type of the function has changed. return getDerived().RebuildReturnStmt(S->getReturnLoc(), Result.get()); } template StmtResult TreeTransform::TransformDeclStmt(DeclStmt *S) { bool DeclChanged = false; SmallVector Decls; for (auto *D : S->decls()) { Decl *Transformed = getDerived().TransformDefinition(D->getLocation(), D); if (!Transformed) return StmtError(); if (Transformed != D) DeclChanged = true; Decls.push_back(Transformed); } if (!getDerived().AlwaysRebuild() && !DeclChanged) return S; return getDerived().RebuildDeclStmt(Decls, S->getBeginLoc(), S->getEndLoc()); } template StmtResult TreeTransform::TransformGCCAsmStmt(GCCAsmStmt *S) { SmallVector Constraints; SmallVector Exprs; SmallVector Names; ExprResult AsmString; SmallVector Clobbers; bool ExprsChanged = false; // Go through the outputs. for (unsigned I = 0, E = S->getNumOutputs(); I != E; ++I) { Names.push_back(S->getOutputIdentifier(I)); // No need to transform the constraint literal. Constraints.push_back(S->getOutputConstraintLiteral(I)); // Transform the output expr. Expr *OutputExpr = S->getOutputExpr(I); ExprResult Result = getDerived().TransformExpr(OutputExpr); if (Result.isInvalid()) return StmtError(); ExprsChanged |= Result.get() != OutputExpr; Exprs.push_back(Result.get()); } // Go through the inputs. for (unsigned I = 0, E = S->getNumInputs(); I != E; ++I) { Names.push_back(S->getInputIdentifier(I)); // No need to transform the constraint literal. Constraints.push_back(S->getInputConstraintLiteral(I)); // Transform the input expr. Expr *InputExpr = S->getInputExpr(I); ExprResult Result = getDerived().TransformExpr(InputExpr); if (Result.isInvalid()) return StmtError(); ExprsChanged |= Result.get() != InputExpr; Exprs.push_back(Result.get()); } // Go through the Labels. for (unsigned I = 0, E = S->getNumLabels(); I != E; ++I) { Names.push_back(S->getLabelIdentifier(I)); ExprResult Result = getDerived().TransformExpr(S->getLabelExpr(I)); if (Result.isInvalid()) return StmtError(); ExprsChanged |= Result.get() != S->getLabelExpr(I); Exprs.push_back(Result.get()); } if (!getDerived().AlwaysRebuild() && !ExprsChanged) return S; // Go through the clobbers. for (unsigned I = 0, E = S->getNumClobbers(); I != E; ++I) Clobbers.push_back(S->getClobberStringLiteral(I)); // No need to transform the asm string literal. AsmString = S->getAsmString(); return getDerived().RebuildGCCAsmStmt(S->getAsmLoc(), S->isSimple(), S->isVolatile(), S->getNumOutputs(), S->getNumInputs(), Names.data(), Constraints, Exprs, AsmString.get(), Clobbers, S->getNumLabels(), S->getRParenLoc()); } template StmtResult TreeTransform::TransformMSAsmStmt(MSAsmStmt *S) { ArrayRef AsmToks = llvm::makeArrayRef(S->getAsmToks(), S->getNumAsmToks()); bool HadError = false, HadChange = false; ArrayRef SrcExprs = S->getAllExprs(); SmallVector TransformedExprs; TransformedExprs.reserve(SrcExprs.size()); for (unsigned i = 0, e = SrcExprs.size(); i != e; ++i) { ExprResult Result = getDerived().TransformExpr(SrcExprs[i]); if (!Result.isUsable()) { HadError = true; } else { HadChange |= (Result.get() != SrcExprs[i]); TransformedExprs.push_back(Result.get()); } } if (HadError) return StmtError(); if (!HadChange && !getDerived().AlwaysRebuild()) return Owned(S); return getDerived().RebuildMSAsmStmt(S->getAsmLoc(), S->getLBraceLoc(), AsmToks, S->getAsmString(), S->getNumOutputs(), S->getNumInputs(), S->getAllConstraints(), S->getClobbers(), TransformedExprs, S->getEndLoc()); } // C++ Coroutines TS template StmtResult TreeTransform::TransformCoroutineBodyStmt(CoroutineBodyStmt *S) { auto *ScopeInfo = SemaRef.getCurFunction(); auto *FD = cast(SemaRef.CurContext); assert(FD && ScopeInfo && !ScopeInfo->CoroutinePromise && ScopeInfo->NeedsCoroutineSuspends && ScopeInfo->CoroutineSuspends.first == nullptr && ScopeInfo->CoroutineSuspends.second == nullptr && "expected clean scope info"); // Set that we have (possibly-invalid) suspend points before we do anything // that may fail. ScopeInfo->setNeedsCoroutineSuspends(false); // We re-build the coroutine promise object (and the coroutine parameters its // type and constructor depend on) based on the types used in our current // function. We must do so, and set it on the current FunctionScopeInfo, // before attempting to transform the other parts of the coroutine body // statement, such as the implicit suspend statements (because those // statements reference the FunctionScopeInfo::CoroutinePromise). if (!SemaRef.buildCoroutineParameterMoves(FD->getLocation())) return StmtError(); auto *Promise = SemaRef.buildCoroutinePromise(FD->getLocation()); if (!Promise) return StmtError(); getDerived().transformedLocalDecl(S->getPromiseDecl(), {Promise}); ScopeInfo->CoroutinePromise = Promise; // Transform the implicit coroutine statements constructed using dependent // types during the previous parse: initial and final suspensions, the return // object, and others. We also transform the coroutine function's body. StmtResult InitSuspend = getDerived().TransformStmt(S->getInitSuspendStmt()); if (InitSuspend.isInvalid()) return StmtError(); StmtResult FinalSuspend = getDerived().TransformStmt(S->getFinalSuspendStmt()); if (FinalSuspend.isInvalid()) return StmtError(); ScopeInfo->setCoroutineSuspends(InitSuspend.get(), FinalSuspend.get()); assert(isa(InitSuspend.get()) && isa(FinalSuspend.get())); StmtResult BodyRes = getDerived().TransformStmt(S->getBody()); if (BodyRes.isInvalid()) return StmtError(); CoroutineStmtBuilder Builder(SemaRef, *FD, *ScopeInfo, BodyRes.get()); if (Builder.isInvalid()) return StmtError(); Expr *ReturnObject = S->getReturnValueInit(); assert(ReturnObject && "the return object is expected to be valid"); ExprResult Res = getDerived().TransformInitializer(ReturnObject, /*NoCopyInit*/ false); if (Res.isInvalid()) return StmtError(); Builder.ReturnValue = Res.get(); // If during the previous parse the coroutine still had a dependent promise // statement, we may need to build some implicit coroutine statements // (such as exception and fallthrough handlers) for the first time. if (S->hasDependentPromiseType()) { // We can only build these statements, however, if the current promise type // is not dependent. if (!Promise->getType()->isDependentType()) { assert(!S->getFallthroughHandler() && !S->getExceptionHandler() && !S->getReturnStmtOnAllocFailure() && !S->getDeallocate() && "these nodes should not have been built yet"); if (!Builder.buildDependentStatements()) return StmtError(); } } else { if (auto *OnFallthrough = S->getFallthroughHandler()) { StmtResult Res = getDerived().TransformStmt(OnFallthrough); if (Res.isInvalid()) return StmtError(); Builder.OnFallthrough = Res.get(); } if (auto *OnException = S->getExceptionHandler()) { StmtResult Res = getDerived().TransformStmt(OnException); if (Res.isInvalid()) return StmtError(); Builder.OnException = Res.get(); } if (auto *OnAllocFailure = S->getReturnStmtOnAllocFailure()) { StmtResult Res = getDerived().TransformStmt(OnAllocFailure); if (Res.isInvalid()) return StmtError(); Builder.ReturnStmtOnAllocFailure = Res.get(); } // Transform any additional statements we may have already built assert(S->getAllocate() && S->getDeallocate() && "allocation and deallocation calls must already be built"); ExprResult AllocRes = getDerived().TransformExpr(S->getAllocate()); if (AllocRes.isInvalid()) return StmtError(); Builder.Allocate = AllocRes.get(); ExprResult DeallocRes = getDerived().TransformExpr(S->getDeallocate()); if (DeallocRes.isInvalid()) return StmtError(); Builder.Deallocate = DeallocRes.get(); assert(S->getResultDecl() && "ResultDecl must already be built"); StmtResult ResultDecl = getDerived().TransformStmt(S->getResultDecl()); if (ResultDecl.isInvalid()) return StmtError(); Builder.ResultDecl = ResultDecl.get(); if (auto *ReturnStmt = S->getReturnStmt()) { StmtResult Res = getDerived().TransformStmt(ReturnStmt); if (Res.isInvalid()) return StmtError(); Builder.ReturnStmt = Res.get(); } } return getDerived().RebuildCoroutineBodyStmt(Builder); } template StmtResult TreeTransform::TransformCoreturnStmt(CoreturnStmt *S) { ExprResult Result = getDerived().TransformInitializer(S->getOperand(), /*NotCopyInit*/false); if (Result.isInvalid()) return StmtError(); // Always rebuild; we don't know if this needs to be injected into a new // context or if the promise type has changed. return getDerived().RebuildCoreturnStmt(S->getKeywordLoc(), Result.get(), S->isImplicit()); } template ExprResult TreeTransform::TransformCoawaitExpr(CoawaitExpr *E) { ExprResult Result = getDerived().TransformInitializer(E->getOperand(), /*NotCopyInit*/false); if (Result.isInvalid()) return ExprError(); // Always rebuild; we don't know if this needs to be injected into a new // context or if the promise type has changed. return getDerived().RebuildCoawaitExpr(E->getKeywordLoc(), Result.get(), E->isImplicit()); } template ExprResult TreeTransform::TransformDependentCoawaitExpr(DependentCoawaitExpr *E) { ExprResult OperandResult = getDerived().TransformInitializer(E->getOperand(), /*NotCopyInit*/ false); if (OperandResult.isInvalid()) return ExprError(); ExprResult LookupResult = getDerived().TransformUnresolvedLookupExpr( E->getOperatorCoawaitLookup()); if (LookupResult.isInvalid()) return ExprError(); // Always rebuild; we don't know if this needs to be injected into a new // context or if the promise type has changed. return getDerived().RebuildDependentCoawaitExpr( E->getKeywordLoc(), OperandResult.get(), cast(LookupResult.get())); } template ExprResult TreeTransform::TransformCoyieldExpr(CoyieldExpr *E) { ExprResult Result = getDerived().TransformInitializer(E->getOperand(), /*NotCopyInit*/false); if (Result.isInvalid()) return ExprError(); // Always rebuild; we don't know if this needs to be injected into a new // context or if the promise type has changed. return getDerived().RebuildCoyieldExpr(E->getKeywordLoc(), Result.get()); } // Objective-C Statements. template StmtResult TreeTransform::TransformObjCAtTryStmt(ObjCAtTryStmt *S) { // Transform the body of the @try. StmtResult TryBody = getDerived().TransformStmt(S->getTryBody()); if (TryBody.isInvalid()) return StmtError(); // Transform the @catch statements (if present). bool AnyCatchChanged = false; SmallVector CatchStmts; for (unsigned I = 0, N = S->getNumCatchStmts(); I != N; ++I) { StmtResult Catch = getDerived().TransformStmt(S->getCatchStmt(I)); if (Catch.isInvalid()) return StmtError(); if (Catch.get() != S->getCatchStmt(I)) AnyCatchChanged = true; CatchStmts.push_back(Catch.get()); } // Transform the @finally statement (if present). StmtResult Finally; if (S->getFinallyStmt()) { Finally = getDerived().TransformStmt(S->getFinallyStmt()); if (Finally.isInvalid()) return StmtError(); } // If nothing changed, just retain this statement. if (!getDerived().AlwaysRebuild() && TryBody.get() == S->getTryBody() && !AnyCatchChanged && Finally.get() == S->getFinallyStmt()) return S; // Build a new statement. return getDerived().RebuildObjCAtTryStmt(S->getAtTryLoc(), TryBody.get(), CatchStmts, Finally.get()); } template StmtResult TreeTransform::TransformObjCAtCatchStmt(ObjCAtCatchStmt *S) { // Transform the @catch parameter, if there is one. VarDecl *Var = nullptr; if (VarDecl *FromVar = S->getCatchParamDecl()) { TypeSourceInfo *TSInfo = nullptr; if (FromVar->getTypeSourceInfo()) { TSInfo = getDerived().TransformType(FromVar->getTypeSourceInfo()); if (!TSInfo) return StmtError(); } QualType T; if (TSInfo) T = TSInfo->getType(); else { T = getDerived().TransformType(FromVar->getType()); if (T.isNull()) return StmtError(); } Var = getDerived().RebuildObjCExceptionDecl(FromVar, TSInfo, T); if (!Var) return StmtError(); } StmtResult Body = getDerived().TransformStmt(S->getCatchBody()); if (Body.isInvalid()) return StmtError(); return getDerived().RebuildObjCAtCatchStmt(S->getAtCatchLoc(), S->getRParenLoc(), Var, Body.get()); } template StmtResult TreeTransform::TransformObjCAtFinallyStmt(ObjCAtFinallyStmt *S) { // Transform the body. StmtResult Body = getDerived().TransformStmt(S->getFinallyBody()); if (Body.isInvalid()) return StmtError(); // If nothing changed, just retain this statement. if (!getDerived().AlwaysRebuild() && Body.get() == S->getFinallyBody()) return S; // Build a new statement. return getDerived().RebuildObjCAtFinallyStmt(S->getAtFinallyLoc(), Body.get()); } template StmtResult TreeTransform::TransformObjCAtThrowStmt(ObjCAtThrowStmt *S) { ExprResult Operand; if (S->getThrowExpr()) { Operand = getDerived().TransformExpr(S->getThrowExpr()); if (Operand.isInvalid()) return StmtError(); } if (!getDerived().AlwaysRebuild() && Operand.get() == S->getThrowExpr()) return S; return getDerived().RebuildObjCAtThrowStmt(S->getThrowLoc(), Operand.get()); } template StmtResult TreeTransform::TransformObjCAtSynchronizedStmt( ObjCAtSynchronizedStmt *S) { // Transform the object we are locking. ExprResult Object = getDerived().TransformExpr(S->getSynchExpr()); if (Object.isInvalid()) return StmtError(); Object = getDerived().RebuildObjCAtSynchronizedOperand(S->getAtSynchronizedLoc(), Object.get()); if (Object.isInvalid()) return StmtError(); // Transform the body. StmtResult Body = getDerived().TransformStmt(S->getSynchBody()); if (Body.isInvalid()) return StmtError(); // If nothing change, just retain the current statement. if (!getDerived().AlwaysRebuild() && Object.get() == S->getSynchExpr() && Body.get() == S->getSynchBody()) return S; // Build a new statement. return getDerived().RebuildObjCAtSynchronizedStmt(S->getAtSynchronizedLoc(), Object.get(), Body.get()); } template StmtResult TreeTransform::TransformObjCAutoreleasePoolStmt( ObjCAutoreleasePoolStmt *S) { // Transform the body. StmtResult Body = getDerived().TransformStmt(S->getSubStmt()); if (Body.isInvalid()) return StmtError(); // If nothing changed, just retain this statement. if (!getDerived().AlwaysRebuild() && Body.get() == S->getSubStmt()) return S; // Build a new statement. return getDerived().RebuildObjCAutoreleasePoolStmt( S->getAtLoc(), Body.get()); } template StmtResult TreeTransform::TransformObjCForCollectionStmt( ObjCForCollectionStmt *S) { // Transform the element statement. StmtResult Element = getDerived().TransformStmt(S->getElement(), SDK_NotDiscarded); if (Element.isInvalid()) return StmtError(); // Transform the collection expression. ExprResult Collection = getDerived().TransformExpr(S->getCollection()); if (Collection.isInvalid()) return StmtError(); // Transform the body. StmtResult Body = getDerived().TransformStmt(S->getBody()); if (Body.isInvalid()) return StmtError(); // If nothing changed, just retain this statement. if (!getDerived().AlwaysRebuild() && Element.get() == S->getElement() && Collection.get() == S->getCollection() && Body.get() == S->getBody()) return S; // Build a new statement. return getDerived().RebuildObjCForCollectionStmt(S->getForLoc(), Element.get(), Collection.get(), S->getRParenLoc(), Body.get()); } template StmtResult TreeTransform::TransformCXXCatchStmt(CXXCatchStmt *S) { // Transform the exception declaration, if any. VarDecl *Var = nullptr; if (VarDecl *ExceptionDecl = S->getExceptionDecl()) { TypeSourceInfo *T = getDerived().TransformType(ExceptionDecl->getTypeSourceInfo()); if (!T) return StmtError(); Var = getDerived().RebuildExceptionDecl( ExceptionDecl, T, ExceptionDecl->getInnerLocStart(), ExceptionDecl->getLocation(), ExceptionDecl->getIdentifier()); if (!Var || Var->isInvalidDecl()) return StmtError(); } // Transform the actual exception handler. StmtResult Handler = getDerived().TransformStmt(S->getHandlerBlock()); if (Handler.isInvalid()) return StmtError(); if (!getDerived().AlwaysRebuild() && !Var && Handler.get() == S->getHandlerBlock()) return S; return getDerived().RebuildCXXCatchStmt(S->getCatchLoc(), Var, Handler.get()); } template StmtResult TreeTransform::TransformCXXTryStmt(CXXTryStmt *S) { // Transform the try block itself. StmtResult TryBlock = getDerived().TransformCompoundStmt(S->getTryBlock()); if (TryBlock.isInvalid()) return StmtError(); // Transform the handlers. bool HandlerChanged = false; SmallVector Handlers; for (unsigned I = 0, N = S->getNumHandlers(); I != N; ++I) { StmtResult Handler = getDerived().TransformCXXCatchStmt(S->getHandler(I)); if (Handler.isInvalid()) return StmtError(); HandlerChanged = HandlerChanged || Handler.get() != S->getHandler(I); Handlers.push_back(Handler.getAs()); } if (!getDerived().AlwaysRebuild() && TryBlock.get() == S->getTryBlock() && !HandlerChanged) return S; return getDerived().RebuildCXXTryStmt(S->getTryLoc(), TryBlock.get(), Handlers); } template StmtResult TreeTransform::TransformCXXForRangeStmt(CXXForRangeStmt *S) { StmtResult Init = S->getInit() ? getDerived().TransformStmt(S->getInit()) : StmtResult(); if (Init.isInvalid()) return StmtError(); StmtResult Range = getDerived().TransformStmt(S->getRangeStmt()); if (Range.isInvalid()) return StmtError(); StmtResult Begin = getDerived().TransformStmt(S->getBeginStmt()); if (Begin.isInvalid()) return StmtError(); StmtResult End = getDerived().TransformStmt(S->getEndStmt()); if (End.isInvalid()) return StmtError(); ExprResult Cond = getDerived().TransformExpr(S->getCond()); if (Cond.isInvalid()) return StmtError(); if (Cond.get()) Cond = SemaRef.CheckBooleanCondition(S->getColonLoc(), Cond.get()); if (Cond.isInvalid()) return StmtError(); if (Cond.get()) Cond = SemaRef.MaybeCreateExprWithCleanups(Cond.get()); ExprResult Inc = getDerived().TransformExpr(S->getInc()); if (Inc.isInvalid()) return StmtError(); if (Inc.get()) Inc = SemaRef.MaybeCreateExprWithCleanups(Inc.get()); StmtResult LoopVar = getDerived().TransformStmt(S->getLoopVarStmt()); if (LoopVar.isInvalid()) return StmtError(); StmtResult NewStmt = S; if (getDerived().AlwaysRebuild() || Init.get() != S->getInit() || Range.get() != S->getRangeStmt() || Begin.get() != S->getBeginStmt() || End.get() != S->getEndStmt() || Cond.get() != S->getCond() || Inc.get() != S->getInc() || LoopVar.get() != S->getLoopVarStmt()) { NewStmt = getDerived().RebuildCXXForRangeStmt(S->getForLoc(), S->getCoawaitLoc(), Init.get(), S->getColonLoc(), Range.get(), Begin.get(), End.get(), Cond.get(), Inc.get(), LoopVar.get(), S->getRParenLoc()); if (NewStmt.isInvalid()) return StmtError(); } StmtResult Body = getDerived().TransformStmt(S->getBody()); if (Body.isInvalid()) return StmtError(); // Body has changed but we didn't rebuild the for-range statement. Rebuild // it now so we have a new statement to attach the body to. if (Body.get() != S->getBody() && NewStmt.get() == S) { NewStmt = getDerived().RebuildCXXForRangeStmt(S->getForLoc(), S->getCoawaitLoc(), Init.get(), S->getColonLoc(), Range.get(), Begin.get(), End.get(), Cond.get(), Inc.get(), LoopVar.get(), S->getRParenLoc()); if (NewStmt.isInvalid()) return StmtError(); } if (NewStmt.get() == S) return S; return FinishCXXForRangeStmt(NewStmt.get(), Body.get()); } template StmtResult TreeTransform::TransformMSDependentExistsStmt( MSDependentExistsStmt *S) { // Transform the nested-name-specifier, if any. NestedNameSpecifierLoc QualifierLoc; if (S->getQualifierLoc()) { QualifierLoc = getDerived().TransformNestedNameSpecifierLoc(S->getQualifierLoc()); if (!QualifierLoc) return StmtError(); } // Transform the declaration name. DeclarationNameInfo NameInfo = S->getNameInfo(); if (NameInfo.getName()) { NameInfo = getDerived().TransformDeclarationNameInfo(NameInfo); if (!NameInfo.getName()) return StmtError(); } // Check whether anything changed. if (!getDerived().AlwaysRebuild() && QualifierLoc == S->getQualifierLoc() && NameInfo.getName() == S->getNameInfo().getName()) return S; // Determine whether this name exists, if we can. CXXScopeSpec SS; SS.Adopt(QualifierLoc); bool Dependent = false; switch (getSema().CheckMicrosoftIfExistsSymbol(/*S=*/nullptr, SS, NameInfo)) { case Sema::IER_Exists: if (S->isIfExists()) break; return new (getSema().Context) NullStmt(S->getKeywordLoc()); case Sema::IER_DoesNotExist: if (S->isIfNotExists()) break; return new (getSema().Context) NullStmt(S->getKeywordLoc()); case Sema::IER_Dependent: Dependent = true; break; case Sema::IER_Error: return StmtError(); } // We need to continue with the instantiation, so do so now. StmtResult SubStmt = getDerived().TransformCompoundStmt(S->getSubStmt()); if (SubStmt.isInvalid()) return StmtError(); // If we have resolved the name, just transform to the substatement. if (!Dependent) return SubStmt; // The name is still dependent, so build a dependent expression again. return getDerived().RebuildMSDependentExistsStmt(S->getKeywordLoc(), S->isIfExists(), QualifierLoc, NameInfo, SubStmt.get()); } template ExprResult TreeTransform::TransformMSPropertyRefExpr(MSPropertyRefExpr *E) { NestedNameSpecifierLoc QualifierLoc; if (E->getQualifierLoc()) { QualifierLoc = getDerived().TransformNestedNameSpecifierLoc(E->getQualifierLoc()); if (!QualifierLoc) return ExprError(); } MSPropertyDecl *PD = cast_or_null( getDerived().TransformDecl(E->getMemberLoc(), E->getPropertyDecl())); if (!PD) return ExprError(); ExprResult Base = getDerived().TransformExpr(E->getBaseExpr()); if (Base.isInvalid()) return ExprError(); return new (SemaRef.getASTContext()) MSPropertyRefExpr(Base.get(), PD, E->isArrow(), SemaRef.getASTContext().PseudoObjectTy, VK_LValue, QualifierLoc, E->getMemberLoc()); } template ExprResult TreeTransform::TransformMSPropertySubscriptExpr( MSPropertySubscriptExpr *E) { auto BaseRes = getDerived().TransformExpr(E->getBase()); if (BaseRes.isInvalid()) return ExprError(); auto IdxRes = getDerived().TransformExpr(E->getIdx()); if (IdxRes.isInvalid()) return ExprError(); if (!getDerived().AlwaysRebuild() && BaseRes.get() == E->getBase() && IdxRes.get() == E->getIdx()) return E; return getDerived().RebuildArraySubscriptExpr( BaseRes.get(), SourceLocation(), IdxRes.get(), E->getRBracketLoc()); } template StmtResult TreeTransform::TransformSEHTryStmt(SEHTryStmt *S) { StmtResult TryBlock = getDerived().TransformCompoundStmt(S->getTryBlock()); if (TryBlock.isInvalid()) return StmtError(); StmtResult Handler = getDerived().TransformSEHHandler(S->getHandler()); if (Handler.isInvalid()) return StmtError(); if (!getDerived().AlwaysRebuild() && TryBlock.get() == S->getTryBlock() && Handler.get() == S->getHandler()) return S; return getDerived().RebuildSEHTryStmt(S->getIsCXXTry(), S->getTryLoc(), TryBlock.get(), Handler.get()); } template StmtResult TreeTransform::TransformSEHFinallyStmt(SEHFinallyStmt *S) { StmtResult Block = getDerived().TransformCompoundStmt(S->getBlock()); if (Block.isInvalid()) return StmtError(); return getDerived().RebuildSEHFinallyStmt(S->getFinallyLoc(), Block.get()); } template StmtResult TreeTransform::TransformSEHExceptStmt(SEHExceptStmt *S) { ExprResult FilterExpr = getDerived().TransformExpr(S->getFilterExpr()); if (FilterExpr.isInvalid()) return StmtError(); StmtResult Block = getDerived().TransformCompoundStmt(S->getBlock()); if (Block.isInvalid()) return StmtError(); return getDerived().RebuildSEHExceptStmt(S->getExceptLoc(), FilterExpr.get(), Block.get()); } template StmtResult TreeTransform::TransformSEHHandler(Stmt *Handler) { if (isa(Handler)) return getDerived().TransformSEHFinallyStmt(cast(Handler)); else return getDerived().TransformSEHExceptStmt(cast(Handler)); } template StmtResult TreeTransform::TransformSEHLeaveStmt(SEHLeaveStmt *S) { return S; } //===----------------------------------------------------------------------===// // OpenMP directive transformation //===----------------------------------------------------------------------===// template StmtResult TreeTransform::TransformOMPExecutableDirective( OMPExecutableDirective *D) { // Transform the clauses llvm::SmallVector TClauses; ArrayRef Clauses = D->clauses(); TClauses.reserve(Clauses.size()); for (ArrayRef::iterator I = Clauses.begin(), E = Clauses.end(); I != E; ++I) { if (*I) { getDerived().getSema().StartOpenMPClause((*I)->getClauseKind()); OMPClause *Clause = getDerived().TransformOMPClause(*I); getDerived().getSema().EndOpenMPClause(); if (Clause) TClauses.push_back(Clause); } else { TClauses.push_back(nullptr); } } StmtResult AssociatedStmt; if (D->hasAssociatedStmt() && D->getAssociatedStmt()) { getDerived().getSema().ActOnOpenMPRegionStart(D->getDirectiveKind(), /*CurScope=*/nullptr); StmtResult Body; { Sema::CompoundScopeRAII CompoundScope(getSema()); Stmt *CS = D->getInnermostCapturedStmt()->getCapturedStmt(); Body = getDerived().TransformStmt(CS); } AssociatedStmt = getDerived().getSema().ActOnOpenMPRegionEnd(Body, TClauses); if (AssociatedStmt.isInvalid()) { return StmtError(); } } if (TClauses.size() != Clauses.size()) { return StmtError(); } // Transform directive name for 'omp critical' directive. DeclarationNameInfo DirName; if (D->getDirectiveKind() == OMPD_critical) { DirName = cast(D)->getDirectiveName(); DirName = getDerived().TransformDeclarationNameInfo(DirName); } OpenMPDirectiveKind CancelRegion = OMPD_unknown; if (D->getDirectiveKind() == OMPD_cancellation_point) { CancelRegion = cast(D)->getCancelRegion(); } else if (D->getDirectiveKind() == OMPD_cancel) { CancelRegion = cast(D)->getCancelRegion(); } return getDerived().RebuildOMPExecutableDirective( D->getDirectiveKind(), DirName, CancelRegion, TClauses, AssociatedStmt.get(), D->getBeginLoc(), D->getEndLoc()); } template StmtResult TreeTransform::TransformOMPParallelDirective(OMPParallelDirective *D) { DeclarationNameInfo DirName; getDerived().getSema().StartOpenMPDSABlock(OMPD_parallel, DirName, nullptr, D->getBeginLoc()); StmtResult Res = getDerived().TransformOMPExecutableDirective(D); getDerived().getSema().EndOpenMPDSABlock(Res.get()); return Res; } template StmtResult TreeTransform::TransformOMPSimdDirective(OMPSimdDirective *D) { DeclarationNameInfo DirName; getDerived().getSema().StartOpenMPDSABlock(OMPD_simd, DirName, nullptr, D->getBeginLoc()); StmtResult Res = getDerived().TransformOMPExecutableDirective(D); getDerived().getSema().EndOpenMPDSABlock(Res.get()); return Res; } template StmtResult TreeTransform::TransformOMPForDirective(OMPForDirective *D) { DeclarationNameInfo DirName; getDerived().getSema().StartOpenMPDSABlock(OMPD_for, DirName, nullptr, D->getBeginLoc()); StmtResult Res = getDerived().TransformOMPExecutableDirective(D); getDerived().getSema().EndOpenMPDSABlock(Res.get()); return Res; } template StmtResult TreeTransform::TransformOMPForSimdDirective(OMPForSimdDirective *D) { DeclarationNameInfo DirName; getDerived().getSema().StartOpenMPDSABlock(OMPD_for_simd, DirName, nullptr, D->getBeginLoc()); StmtResult Res = getDerived().TransformOMPExecutableDirective(D); getDerived().getSema().EndOpenMPDSABlock(Res.get()); return Res; } template StmtResult TreeTransform::TransformOMPSectionsDirective(OMPSectionsDirective *D) { DeclarationNameInfo DirName; getDerived().getSema().StartOpenMPDSABlock(OMPD_sections, DirName, nullptr, D->getBeginLoc()); StmtResult Res = getDerived().TransformOMPExecutableDirective(D); getDerived().getSema().EndOpenMPDSABlock(Res.get()); return Res; } template StmtResult TreeTransform::TransformOMPSectionDirective(OMPSectionDirective *D) { DeclarationNameInfo DirName; getDerived().getSema().StartOpenMPDSABlock(OMPD_section, DirName, nullptr, D->getBeginLoc()); StmtResult Res = getDerived().TransformOMPExecutableDirective(D); getDerived().getSema().EndOpenMPDSABlock(Res.get()); return Res; } template StmtResult TreeTransform::TransformOMPSingleDirective(OMPSingleDirective *D) { DeclarationNameInfo DirName; getDerived().getSema().StartOpenMPDSABlock(OMPD_single, DirName, nullptr, D->getBeginLoc()); StmtResult Res = getDerived().TransformOMPExecutableDirective(D); getDerived().getSema().EndOpenMPDSABlock(Res.get()); return Res; } template StmtResult TreeTransform::TransformOMPMasterDirective(OMPMasterDirective *D) { DeclarationNameInfo DirName; getDerived().getSema().StartOpenMPDSABlock(OMPD_master, DirName, nullptr, D->getBeginLoc()); StmtResult Res = getDerived().TransformOMPExecutableDirective(D); getDerived().getSema().EndOpenMPDSABlock(Res.get()); return Res; } template StmtResult TreeTransform::TransformOMPCriticalDirective(OMPCriticalDirective *D) { getDerived().getSema().StartOpenMPDSABlock( OMPD_critical, D->getDirectiveName(), nullptr, D->getBeginLoc()); StmtResult Res = getDerived().TransformOMPExecutableDirective(D); getDerived().getSema().EndOpenMPDSABlock(Res.get()); return Res; } template StmtResult TreeTransform::TransformOMPParallelForDirective( OMPParallelForDirective *D) { DeclarationNameInfo DirName; getDerived().getSema().StartOpenMPDSABlock(OMPD_parallel_for, DirName, nullptr, D->getBeginLoc()); StmtResult Res = getDerived().TransformOMPExecutableDirective(D); getDerived().getSema().EndOpenMPDSABlock(Res.get()); return Res; } template StmtResult TreeTransform::TransformOMPParallelForSimdDirective( OMPParallelForSimdDirective *D) { DeclarationNameInfo DirName; getDerived().getSema().StartOpenMPDSABlock(OMPD_parallel_for_simd, DirName, nullptr, D->getBeginLoc()); StmtResult Res = getDerived().TransformOMPExecutableDirective(D); getDerived().getSema().EndOpenMPDSABlock(Res.get()); return Res; } template StmtResult TreeTransform::TransformOMPParallelMasterDirective( OMPParallelMasterDirective *D) { DeclarationNameInfo DirName; getDerived().getSema().StartOpenMPDSABlock(OMPD_parallel_master, DirName, nullptr, D->getBeginLoc()); StmtResult Res = getDerived().TransformOMPExecutableDirective(D); getDerived().getSema().EndOpenMPDSABlock(Res.get()); return Res; } template StmtResult TreeTransform::TransformOMPParallelSectionsDirective( OMPParallelSectionsDirective *D) { DeclarationNameInfo DirName; getDerived().getSema().StartOpenMPDSABlock(OMPD_parallel_sections, DirName, nullptr, D->getBeginLoc()); StmtResult Res = getDerived().TransformOMPExecutableDirective(D); getDerived().getSema().EndOpenMPDSABlock(Res.get()); return Res; } template StmtResult TreeTransform::TransformOMPTaskDirective(OMPTaskDirective *D) { DeclarationNameInfo DirName; getDerived().getSema().StartOpenMPDSABlock(OMPD_task, DirName, nullptr, D->getBeginLoc()); StmtResult Res = getDerived().TransformOMPExecutableDirective(D); getDerived().getSema().EndOpenMPDSABlock(Res.get()); return Res; } template StmtResult TreeTransform::TransformOMPTaskyieldDirective( OMPTaskyieldDirective *D) { DeclarationNameInfo DirName; getDerived().getSema().StartOpenMPDSABlock(OMPD_taskyield, DirName, nullptr, D->getBeginLoc()); StmtResult Res = getDerived().TransformOMPExecutableDirective(D); getDerived().getSema().EndOpenMPDSABlock(Res.get()); return Res; } template StmtResult TreeTransform::TransformOMPBarrierDirective(OMPBarrierDirective *D) { DeclarationNameInfo DirName; getDerived().getSema().StartOpenMPDSABlock(OMPD_barrier, DirName, nullptr, D->getBeginLoc()); StmtResult Res = getDerived().TransformOMPExecutableDirective(D); getDerived().getSema().EndOpenMPDSABlock(Res.get()); return Res; } template StmtResult TreeTransform::TransformOMPTaskwaitDirective(OMPTaskwaitDirective *D) { DeclarationNameInfo DirName; getDerived().getSema().StartOpenMPDSABlock(OMPD_taskwait, DirName, nullptr, D->getBeginLoc()); StmtResult Res = getDerived().TransformOMPExecutableDirective(D); getDerived().getSema().EndOpenMPDSABlock(Res.get()); return Res; } template StmtResult TreeTransform::TransformOMPTaskgroupDirective( OMPTaskgroupDirective *D) { DeclarationNameInfo DirName; getDerived().getSema().StartOpenMPDSABlock(OMPD_taskgroup, DirName, nullptr, D->getBeginLoc()); StmtResult Res = getDerived().TransformOMPExecutableDirective(D); getDerived().getSema().EndOpenMPDSABlock(Res.get()); return Res; } template StmtResult TreeTransform::TransformOMPFlushDirective(OMPFlushDirective *D) { DeclarationNameInfo DirName; getDerived().getSema().StartOpenMPDSABlock(OMPD_flush, DirName, nullptr, D->getBeginLoc()); StmtResult Res = getDerived().TransformOMPExecutableDirective(D); getDerived().getSema().EndOpenMPDSABlock(Res.get()); return Res; } template StmtResult TreeTransform::TransformOMPOrderedDirective(OMPOrderedDirective *D) { DeclarationNameInfo DirName; getDerived().getSema().StartOpenMPDSABlock(OMPD_ordered, DirName, nullptr, D->getBeginLoc()); StmtResult Res = getDerived().TransformOMPExecutableDirective(D); getDerived().getSema().EndOpenMPDSABlock(Res.get()); return Res; } template StmtResult TreeTransform::TransformOMPAtomicDirective(OMPAtomicDirective *D) { DeclarationNameInfo DirName; getDerived().getSema().StartOpenMPDSABlock(OMPD_atomic, DirName, nullptr, D->getBeginLoc()); StmtResult Res = getDerived().TransformOMPExecutableDirective(D); getDerived().getSema().EndOpenMPDSABlock(Res.get()); return Res; } template StmtResult TreeTransform::TransformOMPTargetDirective(OMPTargetDirective *D) { DeclarationNameInfo DirName; getDerived().getSema().StartOpenMPDSABlock(OMPD_target, DirName, nullptr, D->getBeginLoc()); StmtResult Res = getDerived().TransformOMPExecutableDirective(D); getDerived().getSema().EndOpenMPDSABlock(Res.get()); return Res; } template StmtResult TreeTransform::TransformOMPTargetDataDirective( OMPTargetDataDirective *D) { DeclarationNameInfo DirName; getDerived().getSema().StartOpenMPDSABlock(OMPD_target_data, DirName, nullptr, D->getBeginLoc()); StmtResult Res = getDerived().TransformOMPExecutableDirective(D); getDerived().getSema().EndOpenMPDSABlock(Res.get()); return Res; } template StmtResult TreeTransform::TransformOMPTargetEnterDataDirective( OMPTargetEnterDataDirective *D) { DeclarationNameInfo DirName; getDerived().getSema().StartOpenMPDSABlock(OMPD_target_enter_data, DirName, nullptr, D->getBeginLoc()); StmtResult Res = getDerived().TransformOMPExecutableDirective(D); getDerived().getSema().EndOpenMPDSABlock(Res.get()); return Res; } template StmtResult TreeTransform::TransformOMPTargetExitDataDirective( OMPTargetExitDataDirective *D) { DeclarationNameInfo DirName; getDerived().getSema().StartOpenMPDSABlock(OMPD_target_exit_data, DirName, nullptr, D->getBeginLoc()); StmtResult Res = getDerived().TransformOMPExecutableDirective(D); getDerived().getSema().EndOpenMPDSABlock(Res.get()); return Res; } template StmtResult TreeTransform::TransformOMPTargetParallelDirective( OMPTargetParallelDirective *D) { DeclarationNameInfo DirName; getDerived().getSema().StartOpenMPDSABlock(OMPD_target_parallel, DirName, nullptr, D->getBeginLoc()); StmtResult Res = getDerived().TransformOMPExecutableDirective(D); getDerived().getSema().EndOpenMPDSABlock(Res.get()); return Res; } template StmtResult TreeTransform::TransformOMPTargetParallelForDirective( OMPTargetParallelForDirective *D) { DeclarationNameInfo DirName; getDerived().getSema().StartOpenMPDSABlock(OMPD_target_parallel_for, DirName, nullptr, D->getBeginLoc()); StmtResult Res = getDerived().TransformOMPExecutableDirective(D); getDerived().getSema().EndOpenMPDSABlock(Res.get()); return Res; } template StmtResult TreeTransform::TransformOMPTargetUpdateDirective( OMPTargetUpdateDirective *D) { DeclarationNameInfo DirName; getDerived().getSema().StartOpenMPDSABlock(OMPD_target_update, DirName, nullptr, D->getBeginLoc()); StmtResult Res = getDerived().TransformOMPExecutableDirective(D); getDerived().getSema().EndOpenMPDSABlock(Res.get()); return Res; } template StmtResult TreeTransform::TransformOMPTeamsDirective(OMPTeamsDirective *D) { DeclarationNameInfo DirName; getDerived().getSema().StartOpenMPDSABlock(OMPD_teams, DirName, nullptr, D->getBeginLoc()); StmtResult Res = getDerived().TransformOMPExecutableDirective(D); getDerived().getSema().EndOpenMPDSABlock(Res.get()); return Res; } template StmtResult TreeTransform::TransformOMPCancellationPointDirective( OMPCancellationPointDirective *D) { DeclarationNameInfo DirName; getDerived().getSema().StartOpenMPDSABlock(OMPD_cancellation_point, DirName, nullptr, D->getBeginLoc()); StmtResult Res = getDerived().TransformOMPExecutableDirective(D); getDerived().getSema().EndOpenMPDSABlock(Res.get()); return Res; } template StmtResult TreeTransform::TransformOMPCancelDirective(OMPCancelDirective *D) { DeclarationNameInfo DirName; getDerived().getSema().StartOpenMPDSABlock(OMPD_cancel, DirName, nullptr, D->getBeginLoc()); StmtResult Res = getDerived().TransformOMPExecutableDirective(D); getDerived().getSema().EndOpenMPDSABlock(Res.get()); return Res; } template StmtResult TreeTransform::TransformOMPTaskLoopDirective(OMPTaskLoopDirective *D) { DeclarationNameInfo DirName; getDerived().getSema().StartOpenMPDSABlock(OMPD_taskloop, DirName, nullptr, D->getBeginLoc()); StmtResult Res = getDerived().TransformOMPExecutableDirective(D); getDerived().getSema().EndOpenMPDSABlock(Res.get()); return Res; } template StmtResult TreeTransform::TransformOMPTaskLoopSimdDirective( OMPTaskLoopSimdDirective *D) { DeclarationNameInfo DirName; getDerived().getSema().StartOpenMPDSABlock(OMPD_taskloop_simd, DirName, nullptr, D->getBeginLoc()); StmtResult Res = getDerived().TransformOMPExecutableDirective(D); getDerived().getSema().EndOpenMPDSABlock(Res.get()); return Res; } template StmtResult TreeTransform::TransformOMPMasterTaskLoopDirective( OMPMasterTaskLoopDirective *D) { DeclarationNameInfo DirName; getDerived().getSema().StartOpenMPDSABlock(OMPD_master_taskloop, DirName, nullptr, D->getBeginLoc()); StmtResult Res = getDerived().TransformOMPExecutableDirective(D); getDerived().getSema().EndOpenMPDSABlock(Res.get()); return Res; } template StmtResult TreeTransform::TransformOMPMasterTaskLoopSimdDirective( OMPMasterTaskLoopSimdDirective *D) { DeclarationNameInfo DirName; getDerived().getSema().StartOpenMPDSABlock(OMPD_master_taskloop_simd, DirName, nullptr, D->getBeginLoc()); StmtResult Res = getDerived().TransformOMPExecutableDirective(D); getDerived().getSema().EndOpenMPDSABlock(Res.get()); return Res; } template StmtResult TreeTransform::TransformOMPParallelMasterTaskLoopDirective( OMPParallelMasterTaskLoopDirective *D) { DeclarationNameInfo DirName; getDerived().getSema().StartOpenMPDSABlock( OMPD_parallel_master_taskloop, DirName, nullptr, D->getBeginLoc()); StmtResult Res = getDerived().TransformOMPExecutableDirective(D); getDerived().getSema().EndOpenMPDSABlock(Res.get()); return Res; } template StmtResult TreeTransform::TransformOMPParallelMasterTaskLoopSimdDirective( OMPParallelMasterTaskLoopSimdDirective *D) { DeclarationNameInfo DirName; getDerived().getSema().StartOpenMPDSABlock( OMPD_parallel_master_taskloop_simd, DirName, nullptr, D->getBeginLoc()); StmtResult Res = getDerived().TransformOMPExecutableDirective(D); getDerived().getSema().EndOpenMPDSABlock(Res.get()); return Res; } template StmtResult TreeTransform::TransformOMPDistributeDirective( OMPDistributeDirective *D) { DeclarationNameInfo DirName; getDerived().getSema().StartOpenMPDSABlock(OMPD_distribute, DirName, nullptr, D->getBeginLoc()); StmtResult Res = getDerived().TransformOMPExecutableDirective(D); getDerived().getSema().EndOpenMPDSABlock(Res.get()); return Res; } template StmtResult TreeTransform::TransformOMPDistributeParallelForDirective( OMPDistributeParallelForDirective *D) { DeclarationNameInfo DirName; getDerived().getSema().StartOpenMPDSABlock( OMPD_distribute_parallel_for, DirName, nullptr, D->getBeginLoc()); StmtResult Res = getDerived().TransformOMPExecutableDirective(D); getDerived().getSema().EndOpenMPDSABlock(Res.get()); return Res; } template StmtResult TreeTransform::TransformOMPDistributeParallelForSimdDirective( OMPDistributeParallelForSimdDirective *D) { DeclarationNameInfo DirName; getDerived().getSema().StartOpenMPDSABlock( OMPD_distribute_parallel_for_simd, DirName, nullptr, D->getBeginLoc()); StmtResult Res = getDerived().TransformOMPExecutableDirective(D); getDerived().getSema().EndOpenMPDSABlock(Res.get()); return Res; } template StmtResult TreeTransform::TransformOMPDistributeSimdDirective( OMPDistributeSimdDirective *D) { DeclarationNameInfo DirName; getDerived().getSema().StartOpenMPDSABlock(OMPD_distribute_simd, DirName, nullptr, D->getBeginLoc()); StmtResult Res = getDerived().TransformOMPExecutableDirective(D); getDerived().getSema().EndOpenMPDSABlock(Res.get()); return Res; } template StmtResult TreeTransform::TransformOMPTargetParallelForSimdDirective( OMPTargetParallelForSimdDirective *D) { DeclarationNameInfo DirName; getDerived().getSema().StartOpenMPDSABlock( OMPD_target_parallel_for_simd, DirName, nullptr, D->getBeginLoc()); StmtResult Res = getDerived().TransformOMPExecutableDirective(D); getDerived().getSema().EndOpenMPDSABlock(Res.get()); return Res; } template StmtResult TreeTransform::TransformOMPTargetSimdDirective( OMPTargetSimdDirective *D) { DeclarationNameInfo DirName; getDerived().getSema().StartOpenMPDSABlock(OMPD_target_simd, DirName, nullptr, D->getBeginLoc()); StmtResult Res = getDerived().TransformOMPExecutableDirective(D); getDerived().getSema().EndOpenMPDSABlock(Res.get()); return Res; } template StmtResult TreeTransform::TransformOMPTeamsDistributeDirective( OMPTeamsDistributeDirective *D) { DeclarationNameInfo DirName; getDerived().getSema().StartOpenMPDSABlock(OMPD_teams_distribute, DirName, nullptr, D->getBeginLoc()); StmtResult Res = getDerived().TransformOMPExecutableDirective(D); getDerived().getSema().EndOpenMPDSABlock(Res.get()); return Res; } template StmtResult TreeTransform::TransformOMPTeamsDistributeSimdDirective( OMPTeamsDistributeSimdDirective *D) { DeclarationNameInfo DirName; getDerived().getSema().StartOpenMPDSABlock( OMPD_teams_distribute_simd, DirName, nullptr, D->getBeginLoc()); StmtResult Res = getDerived().TransformOMPExecutableDirective(D); getDerived().getSema().EndOpenMPDSABlock(Res.get()); return Res; } template StmtResult TreeTransform::TransformOMPTeamsDistributeParallelForSimdDirective( OMPTeamsDistributeParallelForSimdDirective *D) { DeclarationNameInfo DirName; getDerived().getSema().StartOpenMPDSABlock( OMPD_teams_distribute_parallel_for_simd, DirName, nullptr, D->getBeginLoc()); StmtResult Res = getDerived().TransformOMPExecutableDirective(D); getDerived().getSema().EndOpenMPDSABlock(Res.get()); return Res; } template StmtResult TreeTransform::TransformOMPTeamsDistributeParallelForDirective( OMPTeamsDistributeParallelForDirective *D) { DeclarationNameInfo DirName; getDerived().getSema().StartOpenMPDSABlock( OMPD_teams_distribute_parallel_for, DirName, nullptr, D->getBeginLoc()); StmtResult Res = getDerived().TransformOMPExecutableDirective(D); getDerived().getSema().EndOpenMPDSABlock(Res.get()); return Res; } template StmtResult TreeTransform::TransformOMPTargetTeamsDirective( OMPTargetTeamsDirective *D) { DeclarationNameInfo DirName; getDerived().getSema().StartOpenMPDSABlock(OMPD_target_teams, DirName, nullptr, D->getBeginLoc()); auto Res = getDerived().TransformOMPExecutableDirective(D); getDerived().getSema().EndOpenMPDSABlock(Res.get()); return Res; } template StmtResult TreeTransform::TransformOMPTargetTeamsDistributeDirective( OMPTargetTeamsDistributeDirective *D) { DeclarationNameInfo DirName; getDerived().getSema().StartOpenMPDSABlock( OMPD_target_teams_distribute, DirName, nullptr, D->getBeginLoc()); auto Res = getDerived().TransformOMPExecutableDirective(D); getDerived().getSema().EndOpenMPDSABlock(Res.get()); return Res; } template StmtResult TreeTransform::TransformOMPTargetTeamsDistributeParallelForDirective( OMPTargetTeamsDistributeParallelForDirective *D) { DeclarationNameInfo DirName; getDerived().getSema().StartOpenMPDSABlock( OMPD_target_teams_distribute_parallel_for, DirName, nullptr, D->getBeginLoc()); auto Res = getDerived().TransformOMPExecutableDirective(D); getDerived().getSema().EndOpenMPDSABlock(Res.get()); return Res; } template StmtResult TreeTransform:: TransformOMPTargetTeamsDistributeParallelForSimdDirective( OMPTargetTeamsDistributeParallelForSimdDirective *D) { DeclarationNameInfo DirName; getDerived().getSema().StartOpenMPDSABlock( OMPD_target_teams_distribute_parallel_for_simd, DirName, nullptr, D->getBeginLoc()); auto Res = getDerived().TransformOMPExecutableDirective(D); getDerived().getSema().EndOpenMPDSABlock(Res.get()); return Res; } template StmtResult TreeTransform::TransformOMPTargetTeamsDistributeSimdDirective( OMPTargetTeamsDistributeSimdDirective *D) { DeclarationNameInfo DirName; getDerived().getSema().StartOpenMPDSABlock( OMPD_target_teams_distribute_simd, DirName, nullptr, D->getBeginLoc()); auto Res = getDerived().TransformOMPExecutableDirective(D); getDerived().getSema().EndOpenMPDSABlock(Res.get()); return Res; } //===----------------------------------------------------------------------===// // OpenMP clause transformation //===----------------------------------------------------------------------===// template OMPClause *TreeTransform::TransformOMPIfClause(OMPIfClause *C) { ExprResult Cond = getDerived().TransformExpr(C->getCondition()); if (Cond.isInvalid()) return nullptr; return getDerived().RebuildOMPIfClause( C->getNameModifier(), Cond.get(), C->getBeginLoc(), C->getLParenLoc(), C->getNameModifierLoc(), C->getColonLoc(), C->getEndLoc()); } template OMPClause *TreeTransform::TransformOMPFinalClause(OMPFinalClause *C) { ExprResult Cond = getDerived().TransformExpr(C->getCondition()); if (Cond.isInvalid()) return nullptr; return getDerived().RebuildOMPFinalClause(Cond.get(), C->getBeginLoc(), C->getLParenLoc(), C->getEndLoc()); } template OMPClause * TreeTransform::TransformOMPNumThreadsClause(OMPNumThreadsClause *C) { ExprResult NumThreads = getDerived().TransformExpr(C->getNumThreads()); if (NumThreads.isInvalid()) return nullptr; return getDerived().RebuildOMPNumThreadsClause( NumThreads.get(), C->getBeginLoc(), C->getLParenLoc(), C->getEndLoc()); } template OMPClause * TreeTransform::TransformOMPSafelenClause(OMPSafelenClause *C) { ExprResult E = getDerived().TransformExpr(C->getSafelen()); if (E.isInvalid()) return nullptr; return getDerived().RebuildOMPSafelenClause( E.get(), C->getBeginLoc(), C->getLParenLoc(), C->getEndLoc()); } template OMPClause * TreeTransform::TransformOMPAllocatorClause(OMPAllocatorClause *C) { ExprResult E = getDerived().TransformExpr(C->getAllocator()); if (E.isInvalid()) return nullptr; return getDerived().RebuildOMPAllocatorClause( E.get(), C->getBeginLoc(), C->getLParenLoc(), C->getEndLoc()); } template OMPClause * TreeTransform::TransformOMPSimdlenClause(OMPSimdlenClause *C) { ExprResult E = getDerived().TransformExpr(C->getSimdlen()); if (E.isInvalid()) return nullptr; return getDerived().RebuildOMPSimdlenClause( E.get(), C->getBeginLoc(), C->getLParenLoc(), C->getEndLoc()); } template OMPClause * TreeTransform::TransformOMPCollapseClause(OMPCollapseClause *C) { ExprResult E = getDerived().TransformExpr(C->getNumForLoops()); if (E.isInvalid()) return nullptr; return getDerived().RebuildOMPCollapseClause( E.get(), C->getBeginLoc(), C->getLParenLoc(), C->getEndLoc()); } template OMPClause * TreeTransform::TransformOMPDefaultClause(OMPDefaultClause *C) { return getDerived().RebuildOMPDefaultClause( C->getDefaultKind(), C->getDefaultKindKwLoc(), C->getBeginLoc(), C->getLParenLoc(), C->getEndLoc()); } template OMPClause * TreeTransform::TransformOMPProcBindClause(OMPProcBindClause *C) { return getDerived().RebuildOMPProcBindClause( C->getProcBindKind(), C->getProcBindKindKwLoc(), C->getBeginLoc(), C->getLParenLoc(), C->getEndLoc()); } template OMPClause * TreeTransform::TransformOMPScheduleClause(OMPScheduleClause *C) { ExprResult E = getDerived().TransformExpr(C->getChunkSize()); if (E.isInvalid()) return nullptr; return getDerived().RebuildOMPScheduleClause( C->getFirstScheduleModifier(), C->getSecondScheduleModifier(), C->getScheduleKind(), E.get(), C->getBeginLoc(), C->getLParenLoc(), C->getFirstScheduleModifierLoc(), C->getSecondScheduleModifierLoc(), C->getScheduleKindLoc(), C->getCommaLoc(), C->getEndLoc()); } template OMPClause * TreeTransform::TransformOMPOrderedClause(OMPOrderedClause *C) { ExprResult E; if (auto *Num = C->getNumForLoops()) { E = getDerived().TransformExpr(Num); if (E.isInvalid()) return nullptr; } return getDerived().RebuildOMPOrderedClause(C->getBeginLoc(), C->getEndLoc(), C->getLParenLoc(), E.get()); } template OMPClause * TreeTransform::TransformOMPNowaitClause(OMPNowaitClause *C) { // No need to rebuild this clause, no template-dependent parameters. return C; } template OMPClause * TreeTransform::TransformOMPUntiedClause(OMPUntiedClause *C) { // No need to rebuild this clause, no template-dependent parameters. return C; } template OMPClause * TreeTransform::TransformOMPMergeableClause(OMPMergeableClause *C) { // No need to rebuild this clause, no template-dependent parameters. return C; } template OMPClause *TreeTransform::TransformOMPReadClause(OMPReadClause *C) { // No need to rebuild this clause, no template-dependent parameters. return C; } template OMPClause *TreeTransform::TransformOMPWriteClause(OMPWriteClause *C) { // No need to rebuild this clause, no template-dependent parameters. return C; } template OMPClause * TreeTransform::TransformOMPUpdateClause(OMPUpdateClause *C) { // No need to rebuild this clause, no template-dependent parameters. return C; } template OMPClause * TreeTransform::TransformOMPCaptureClause(OMPCaptureClause *C) { // No need to rebuild this clause, no template-dependent parameters. return C; } template OMPClause * TreeTransform::TransformOMPSeqCstClause(OMPSeqCstClause *C) { // No need to rebuild this clause, no template-dependent parameters. return C; } template OMPClause * TreeTransform::TransformOMPThreadsClause(OMPThreadsClause *C) { // No need to rebuild this clause, no template-dependent parameters. return C; } template OMPClause *TreeTransform::TransformOMPSIMDClause(OMPSIMDClause *C) { // No need to rebuild this clause, no template-dependent parameters. return C; } template OMPClause * TreeTransform::TransformOMPNogroupClause(OMPNogroupClause *C) { // No need to rebuild this clause, no template-dependent parameters. return C; } template OMPClause *TreeTransform::TransformOMPUnifiedAddressClause( OMPUnifiedAddressClause *C) { llvm_unreachable("unified_address clause cannot appear in dependent context"); } template OMPClause *TreeTransform::TransformOMPUnifiedSharedMemoryClause( OMPUnifiedSharedMemoryClause *C) { llvm_unreachable( "unified_shared_memory clause cannot appear in dependent context"); } template OMPClause *TreeTransform::TransformOMPReverseOffloadClause( OMPReverseOffloadClause *C) { llvm_unreachable("reverse_offload clause cannot appear in dependent context"); } template OMPClause *TreeTransform::TransformOMPDynamicAllocatorsClause( OMPDynamicAllocatorsClause *C) { llvm_unreachable( "dynamic_allocators clause cannot appear in dependent context"); } template OMPClause *TreeTransform::TransformOMPAtomicDefaultMemOrderClause( OMPAtomicDefaultMemOrderClause *C) { llvm_unreachable( "atomic_default_mem_order clause cannot appear in dependent context"); } template OMPClause * TreeTransform::TransformOMPPrivateClause(OMPPrivateClause *C) { llvm::SmallVector Vars; Vars.reserve(C->varlist_size()); for (auto *VE : C->varlists()) { ExprResult EVar = getDerived().TransformExpr(cast(VE)); if (EVar.isInvalid()) return nullptr; Vars.push_back(EVar.get()); } return getDerived().RebuildOMPPrivateClause( Vars, C->getBeginLoc(), C->getLParenLoc(), C->getEndLoc()); } template OMPClause *TreeTransform::TransformOMPFirstprivateClause( OMPFirstprivateClause *C) { llvm::SmallVector Vars; Vars.reserve(C->varlist_size()); for (auto *VE : C->varlists()) { ExprResult EVar = getDerived().TransformExpr(cast(VE)); if (EVar.isInvalid()) return nullptr; Vars.push_back(EVar.get()); } return getDerived().RebuildOMPFirstprivateClause( Vars, C->getBeginLoc(), C->getLParenLoc(), C->getEndLoc()); } template OMPClause * TreeTransform::TransformOMPLastprivateClause(OMPLastprivateClause *C) { llvm::SmallVector Vars; Vars.reserve(C->varlist_size()); for (auto *VE : C->varlists()) { ExprResult EVar = getDerived().TransformExpr(cast(VE)); if (EVar.isInvalid()) return nullptr; Vars.push_back(EVar.get()); } return getDerived().RebuildOMPLastprivateClause( Vars, C->getKind(), C->getKindLoc(), C->getColonLoc(), C->getBeginLoc(), C->getLParenLoc(), C->getEndLoc()); } template OMPClause * TreeTransform::TransformOMPSharedClause(OMPSharedClause *C) { llvm::SmallVector Vars; Vars.reserve(C->varlist_size()); for (auto *VE : C->varlists()) { ExprResult EVar = getDerived().TransformExpr(cast(VE)); if (EVar.isInvalid()) return nullptr; Vars.push_back(EVar.get()); } return getDerived().RebuildOMPSharedClause(Vars, C->getBeginLoc(), C->getLParenLoc(), C->getEndLoc()); } template OMPClause * TreeTransform::TransformOMPReductionClause(OMPReductionClause *C) { llvm::SmallVector Vars; Vars.reserve(C->varlist_size()); for (auto *VE : C->varlists()) { ExprResult EVar = getDerived().TransformExpr(cast(VE)); if (EVar.isInvalid()) return nullptr; Vars.push_back(EVar.get()); } CXXScopeSpec ReductionIdScopeSpec; ReductionIdScopeSpec.Adopt(C->getQualifierLoc()); DeclarationNameInfo NameInfo = C->getNameInfo(); if (NameInfo.getName()) { NameInfo = getDerived().TransformDeclarationNameInfo(NameInfo); if (!NameInfo.getName()) return nullptr; } // Build a list of all UDR decls with the same names ranged by the Scopes. // The Scope boundary is a duplication of the previous decl. llvm::SmallVector UnresolvedReductions; for (auto *E : C->reduction_ops()) { // Transform all the decls. if (E) { auto *ULE = cast(E); UnresolvedSet<8> Decls; for (auto *D : ULE->decls()) { NamedDecl *InstD = cast(getDerived().TransformDecl(E->getExprLoc(), D)); Decls.addDecl(InstD, InstD->getAccess()); } UnresolvedReductions.push_back( UnresolvedLookupExpr::Create( SemaRef.Context, /*NamingClass=*/nullptr, ReductionIdScopeSpec.getWithLocInContext(SemaRef.Context), NameInfo, /*ADL=*/true, ULE->isOverloaded(), Decls.begin(), Decls.end())); } else UnresolvedReductions.push_back(nullptr); } return getDerived().RebuildOMPReductionClause( Vars, C->getBeginLoc(), C->getLParenLoc(), C->getColonLoc(), C->getEndLoc(), ReductionIdScopeSpec, NameInfo, UnresolvedReductions); } template OMPClause *TreeTransform::TransformOMPTaskReductionClause( OMPTaskReductionClause *C) { llvm::SmallVector Vars; Vars.reserve(C->varlist_size()); for (auto *VE : C->varlists()) { ExprResult EVar = getDerived().TransformExpr(cast(VE)); if (EVar.isInvalid()) return nullptr; Vars.push_back(EVar.get()); } CXXScopeSpec ReductionIdScopeSpec; ReductionIdScopeSpec.Adopt(C->getQualifierLoc()); DeclarationNameInfo NameInfo = C->getNameInfo(); if (NameInfo.getName()) { NameInfo = getDerived().TransformDeclarationNameInfo(NameInfo); if (!NameInfo.getName()) return nullptr; } // Build a list of all UDR decls with the same names ranged by the Scopes. // The Scope boundary is a duplication of the previous decl. llvm::SmallVector UnresolvedReductions; for (auto *E : C->reduction_ops()) { // Transform all the decls. if (E) { auto *ULE = cast(E); UnresolvedSet<8> Decls; for (auto *D : ULE->decls()) { NamedDecl *InstD = cast(getDerived().TransformDecl(E->getExprLoc(), D)); Decls.addDecl(InstD, InstD->getAccess()); } UnresolvedReductions.push_back(UnresolvedLookupExpr::Create( SemaRef.Context, /*NamingClass=*/nullptr, ReductionIdScopeSpec.getWithLocInContext(SemaRef.Context), NameInfo, /*ADL=*/true, ULE->isOverloaded(), Decls.begin(), Decls.end())); } else UnresolvedReductions.push_back(nullptr); } return getDerived().RebuildOMPTaskReductionClause( Vars, C->getBeginLoc(), C->getLParenLoc(), C->getColonLoc(), C->getEndLoc(), ReductionIdScopeSpec, NameInfo, UnresolvedReductions); } template OMPClause * TreeTransform::TransformOMPInReductionClause(OMPInReductionClause *C) { llvm::SmallVector Vars; Vars.reserve(C->varlist_size()); for (auto *VE : C->varlists()) { ExprResult EVar = getDerived().TransformExpr(cast(VE)); if (EVar.isInvalid()) return nullptr; Vars.push_back(EVar.get()); } CXXScopeSpec ReductionIdScopeSpec; ReductionIdScopeSpec.Adopt(C->getQualifierLoc()); DeclarationNameInfo NameInfo = C->getNameInfo(); if (NameInfo.getName()) { NameInfo = getDerived().TransformDeclarationNameInfo(NameInfo); if (!NameInfo.getName()) return nullptr; } // Build a list of all UDR decls with the same names ranged by the Scopes. // The Scope boundary is a duplication of the previous decl. llvm::SmallVector UnresolvedReductions; for (auto *E : C->reduction_ops()) { // Transform all the decls. if (E) { auto *ULE = cast(E); UnresolvedSet<8> Decls; for (auto *D : ULE->decls()) { NamedDecl *InstD = cast(getDerived().TransformDecl(E->getExprLoc(), D)); Decls.addDecl(InstD, InstD->getAccess()); } UnresolvedReductions.push_back(UnresolvedLookupExpr::Create( SemaRef.Context, /*NamingClass=*/nullptr, ReductionIdScopeSpec.getWithLocInContext(SemaRef.Context), NameInfo, /*ADL=*/true, ULE->isOverloaded(), Decls.begin(), Decls.end())); } else UnresolvedReductions.push_back(nullptr); } return getDerived().RebuildOMPInReductionClause( Vars, C->getBeginLoc(), C->getLParenLoc(), C->getColonLoc(), C->getEndLoc(), ReductionIdScopeSpec, NameInfo, UnresolvedReductions); } template OMPClause * TreeTransform::TransformOMPLinearClause(OMPLinearClause *C) { llvm::SmallVector Vars; Vars.reserve(C->varlist_size()); for (auto *VE : C->varlists()) { ExprResult EVar = getDerived().TransformExpr(cast(VE)); if (EVar.isInvalid()) return nullptr; Vars.push_back(EVar.get()); } ExprResult Step = getDerived().TransformExpr(C->getStep()); if (Step.isInvalid()) return nullptr; return getDerived().RebuildOMPLinearClause( Vars, Step.get(), C->getBeginLoc(), C->getLParenLoc(), C->getModifier(), C->getModifierLoc(), C->getColonLoc(), C->getEndLoc()); } template OMPClause * TreeTransform::TransformOMPAlignedClause(OMPAlignedClause *C) { llvm::SmallVector Vars; Vars.reserve(C->varlist_size()); for (auto *VE : C->varlists()) { ExprResult EVar = getDerived().TransformExpr(cast(VE)); if (EVar.isInvalid()) return nullptr; Vars.push_back(EVar.get()); } ExprResult Alignment = getDerived().TransformExpr(C->getAlignment()); if (Alignment.isInvalid()) return nullptr; return getDerived().RebuildOMPAlignedClause( Vars, Alignment.get(), C->getBeginLoc(), C->getLParenLoc(), C->getColonLoc(), C->getEndLoc()); } template OMPClause * TreeTransform::TransformOMPCopyinClause(OMPCopyinClause *C) { llvm::SmallVector Vars; Vars.reserve(C->varlist_size()); for (auto *VE : C->varlists()) { ExprResult EVar = getDerived().TransformExpr(cast(VE)); if (EVar.isInvalid()) return nullptr; Vars.push_back(EVar.get()); } return getDerived().RebuildOMPCopyinClause(Vars, C->getBeginLoc(), C->getLParenLoc(), C->getEndLoc()); } template OMPClause * TreeTransform::TransformOMPCopyprivateClause(OMPCopyprivateClause *C) { llvm::SmallVector Vars; Vars.reserve(C->varlist_size()); for (auto *VE : C->varlists()) { ExprResult EVar = getDerived().TransformExpr(cast(VE)); if (EVar.isInvalid()) return nullptr; Vars.push_back(EVar.get()); } return getDerived().RebuildOMPCopyprivateClause( Vars, C->getBeginLoc(), C->getLParenLoc(), C->getEndLoc()); } template OMPClause *TreeTransform::TransformOMPFlushClause(OMPFlushClause *C) { llvm::SmallVector Vars; Vars.reserve(C->varlist_size()); for (auto *VE : C->varlists()) { ExprResult EVar = getDerived().TransformExpr(cast(VE)); if (EVar.isInvalid()) return nullptr; Vars.push_back(EVar.get()); } return getDerived().RebuildOMPFlushClause(Vars, C->getBeginLoc(), C->getLParenLoc(), C->getEndLoc()); } template OMPClause * TreeTransform::TransformOMPDependClause(OMPDependClause *C) { llvm::SmallVector Vars; Vars.reserve(C->varlist_size()); for (auto *VE : C->varlists()) { ExprResult EVar = getDerived().TransformExpr(cast(VE)); if (EVar.isInvalid()) return nullptr; Vars.push_back(EVar.get()); } return getDerived().RebuildOMPDependClause( C->getDependencyKind(), C->getDependencyLoc(), C->getColonLoc(), Vars, C->getBeginLoc(), C->getLParenLoc(), C->getEndLoc()); } template OMPClause * TreeTransform::TransformOMPDeviceClause(OMPDeviceClause *C) { ExprResult E = getDerived().TransformExpr(C->getDevice()); if (E.isInvalid()) return nullptr; return getDerived().RebuildOMPDeviceClause(E.get(), C->getBeginLoc(), C->getLParenLoc(), C->getEndLoc()); } template bool transformOMPMappableExprListClause( TreeTransform &TT, OMPMappableExprListClause *C, llvm::SmallVectorImpl &Vars, CXXScopeSpec &MapperIdScopeSpec, DeclarationNameInfo &MapperIdInfo, llvm::SmallVectorImpl &UnresolvedMappers) { // Transform expressions in the list. Vars.reserve(C->varlist_size()); for (auto *VE : C->varlists()) { ExprResult EVar = TT.getDerived().TransformExpr(cast(VE)); if (EVar.isInvalid()) return true; Vars.push_back(EVar.get()); } // Transform mapper scope specifier and identifier. NestedNameSpecifierLoc QualifierLoc; if (C->getMapperQualifierLoc()) { QualifierLoc = TT.getDerived().TransformNestedNameSpecifierLoc( C->getMapperQualifierLoc()); if (!QualifierLoc) return true; } MapperIdScopeSpec.Adopt(QualifierLoc); MapperIdInfo = C->getMapperIdInfo(); if (MapperIdInfo.getName()) { MapperIdInfo = TT.getDerived().TransformDeclarationNameInfo(MapperIdInfo); if (!MapperIdInfo.getName()) return true; } // Build a list of all candidate OMPDeclareMapperDecls, which is provided by // the previous user-defined mapper lookup in dependent environment. for (auto *E : C->mapperlists()) { // Transform all the decls. if (E) { auto *ULE = cast(E); UnresolvedSet<8> Decls; for (auto *D : ULE->decls()) { NamedDecl *InstD = cast(TT.getDerived().TransformDecl(E->getExprLoc(), D)); Decls.addDecl(InstD, InstD->getAccess()); } UnresolvedMappers.push_back(UnresolvedLookupExpr::Create( TT.getSema().Context, /*NamingClass=*/nullptr, MapperIdScopeSpec.getWithLocInContext(TT.getSema().Context), MapperIdInfo, /*ADL=*/true, ULE->isOverloaded(), Decls.begin(), Decls.end())); } else { UnresolvedMappers.push_back(nullptr); } } return false; } template OMPClause *TreeTransform::TransformOMPMapClause(OMPMapClause *C) { OMPVarListLocTy Locs(C->getBeginLoc(), C->getLParenLoc(), C->getEndLoc()); llvm::SmallVector Vars; CXXScopeSpec MapperIdScopeSpec; DeclarationNameInfo MapperIdInfo; llvm::SmallVector UnresolvedMappers; if (transformOMPMappableExprListClause( *this, C, Vars, MapperIdScopeSpec, MapperIdInfo, UnresolvedMappers)) return nullptr; return getDerived().RebuildOMPMapClause( C->getMapTypeModifiers(), C->getMapTypeModifiersLoc(), MapperIdScopeSpec, MapperIdInfo, C->getMapType(), C->isImplicitMapType(), C->getMapLoc(), C->getColonLoc(), Vars, Locs, UnresolvedMappers); } template OMPClause * TreeTransform::TransformOMPAllocateClause(OMPAllocateClause *C) { Expr *Allocator = C->getAllocator(); if (Allocator) { ExprResult AllocatorRes = getDerived().TransformExpr(Allocator); if (AllocatorRes.isInvalid()) return nullptr; Allocator = AllocatorRes.get(); } llvm::SmallVector Vars; Vars.reserve(C->varlist_size()); for (auto *VE : C->varlists()) { ExprResult EVar = getDerived().TransformExpr(cast(VE)); if (EVar.isInvalid()) return nullptr; Vars.push_back(EVar.get()); } return getDerived().RebuildOMPAllocateClause( Allocator, Vars, C->getBeginLoc(), C->getLParenLoc(), C->getColonLoc(), C->getEndLoc()); } template OMPClause * TreeTransform::TransformOMPNumTeamsClause(OMPNumTeamsClause *C) { ExprResult E = getDerived().TransformExpr(C->getNumTeams()); if (E.isInvalid()) return nullptr; return getDerived().RebuildOMPNumTeamsClause( E.get(), C->getBeginLoc(), C->getLParenLoc(), C->getEndLoc()); } template OMPClause * TreeTransform::TransformOMPThreadLimitClause(OMPThreadLimitClause *C) { ExprResult E = getDerived().TransformExpr(C->getThreadLimit()); if (E.isInvalid()) return nullptr; return getDerived().RebuildOMPThreadLimitClause( E.get(), C->getBeginLoc(), C->getLParenLoc(), C->getEndLoc()); } template OMPClause * TreeTransform::TransformOMPPriorityClause(OMPPriorityClause *C) { ExprResult E = getDerived().TransformExpr(C->getPriority()); if (E.isInvalid()) return nullptr; return getDerived().RebuildOMPPriorityClause( E.get(), C->getBeginLoc(), C->getLParenLoc(), C->getEndLoc()); } template OMPClause * TreeTransform::TransformOMPGrainsizeClause(OMPGrainsizeClause *C) { ExprResult E = getDerived().TransformExpr(C->getGrainsize()); if (E.isInvalid()) return nullptr; return getDerived().RebuildOMPGrainsizeClause( E.get(), C->getBeginLoc(), C->getLParenLoc(), C->getEndLoc()); } template OMPClause * TreeTransform::TransformOMPNumTasksClause(OMPNumTasksClause *C) { ExprResult E = getDerived().TransformExpr(C->getNumTasks()); if (E.isInvalid()) return nullptr; return getDerived().RebuildOMPNumTasksClause( E.get(), C->getBeginLoc(), C->getLParenLoc(), C->getEndLoc()); } template OMPClause *TreeTransform::TransformOMPHintClause(OMPHintClause *C) { ExprResult E = getDerived().TransformExpr(C->getHint()); if (E.isInvalid()) return nullptr; return getDerived().RebuildOMPHintClause(E.get(), C->getBeginLoc(), C->getLParenLoc(), C->getEndLoc()); } template OMPClause *TreeTransform::TransformOMPDistScheduleClause( OMPDistScheduleClause *C) { ExprResult E = getDerived().TransformExpr(C->getChunkSize()); if (E.isInvalid()) return nullptr; return getDerived().RebuildOMPDistScheduleClause( C->getDistScheduleKind(), E.get(), C->getBeginLoc(), C->getLParenLoc(), C->getDistScheduleKindLoc(), C->getCommaLoc(), C->getEndLoc()); } template OMPClause * TreeTransform::TransformOMPDefaultmapClause(OMPDefaultmapClause *C) { // Rebuild Defaultmap Clause since we need to invoke the checking of // defaultmap(none:variable-category) after template initialization. return getDerived().RebuildOMPDefaultmapClause(C->getDefaultmapModifier(), C->getDefaultmapKind(), C->getBeginLoc(), C->getLParenLoc(), C->getDefaultmapModifierLoc(), C->getDefaultmapKindLoc(), C->getEndLoc()); } template OMPClause *TreeTransform::TransformOMPToClause(OMPToClause *C) { OMPVarListLocTy Locs(C->getBeginLoc(), C->getLParenLoc(), C->getEndLoc()); llvm::SmallVector Vars; CXXScopeSpec MapperIdScopeSpec; DeclarationNameInfo MapperIdInfo; llvm::SmallVector UnresolvedMappers; if (transformOMPMappableExprListClause( *this, C, Vars, MapperIdScopeSpec, MapperIdInfo, UnresolvedMappers)) return nullptr; return getDerived().RebuildOMPToClause(Vars, MapperIdScopeSpec, MapperIdInfo, Locs, UnresolvedMappers); } template OMPClause *TreeTransform::TransformOMPFromClause(OMPFromClause *C) { OMPVarListLocTy Locs(C->getBeginLoc(), C->getLParenLoc(), C->getEndLoc()); llvm::SmallVector Vars; CXXScopeSpec MapperIdScopeSpec; DeclarationNameInfo MapperIdInfo; llvm::SmallVector UnresolvedMappers; if (transformOMPMappableExprListClause( *this, C, Vars, MapperIdScopeSpec, MapperIdInfo, UnresolvedMappers)) return nullptr; return getDerived().RebuildOMPFromClause( Vars, MapperIdScopeSpec, MapperIdInfo, Locs, UnresolvedMappers); } template OMPClause *TreeTransform::TransformOMPUseDevicePtrClause( OMPUseDevicePtrClause *C) { llvm::SmallVector Vars; Vars.reserve(C->varlist_size()); for (auto *VE : C->varlists()) { ExprResult EVar = getDerived().TransformExpr(cast(VE)); if (EVar.isInvalid()) return nullptr; Vars.push_back(EVar.get()); } OMPVarListLocTy Locs(C->getBeginLoc(), C->getLParenLoc(), C->getEndLoc()); return getDerived().RebuildOMPUseDevicePtrClause(Vars, Locs); } template OMPClause * TreeTransform::TransformOMPIsDevicePtrClause(OMPIsDevicePtrClause *C) { llvm::SmallVector Vars; Vars.reserve(C->varlist_size()); for (auto *VE : C->varlists()) { ExprResult EVar = getDerived().TransformExpr(cast(VE)); if (EVar.isInvalid()) return nullptr; Vars.push_back(EVar.get()); } OMPVarListLocTy Locs(C->getBeginLoc(), C->getLParenLoc(), C->getEndLoc()); return getDerived().RebuildOMPIsDevicePtrClause(Vars, Locs); } template OMPClause * TreeTransform::TransformOMPNontemporalClause(OMPNontemporalClause *C) { llvm::SmallVector Vars; Vars.reserve(C->varlist_size()); for (auto *VE : C->varlists()) { ExprResult EVar = getDerived().TransformExpr(cast(VE)); if (EVar.isInvalid()) return nullptr; Vars.push_back(EVar.get()); } return getDerived().RebuildOMPNontemporalClause( Vars, C->getBeginLoc(), C->getLParenLoc(), C->getEndLoc()); } //===----------------------------------------------------------------------===// // Expression transformation //===----------------------------------------------------------------------===// template ExprResult TreeTransform::TransformConstantExpr(ConstantExpr *E) { return TransformExpr(E->getSubExpr()); } template ExprResult TreeTransform::TransformPredefinedExpr(PredefinedExpr *E) { if (!E->isTypeDependent()) return E; return getDerived().RebuildPredefinedExpr(E->getLocation(), E->getIdentKind()); } template ExprResult TreeTransform::TransformDeclRefExpr(DeclRefExpr *E) { NestedNameSpecifierLoc QualifierLoc; if (E->getQualifierLoc()) { QualifierLoc = getDerived().TransformNestedNameSpecifierLoc(E->getQualifierLoc()); if (!QualifierLoc) return ExprError(); } ValueDecl *ND = cast_or_null(getDerived().TransformDecl(E->getLocation(), E->getDecl())); if (!ND) return ExprError(); NamedDecl *Found = ND; if (E->getFoundDecl() != E->getDecl()) { Found = cast_or_null( getDerived().TransformDecl(E->getLocation(), E->getFoundDecl())); if (!Found) return ExprError(); } DeclarationNameInfo NameInfo = E->getNameInfo(); if (NameInfo.getName()) { NameInfo = getDerived().TransformDeclarationNameInfo(NameInfo); if (!NameInfo.getName()) return ExprError(); } if (!getDerived().AlwaysRebuild() && QualifierLoc == E->getQualifierLoc() && ND == E->getDecl() && Found == E->getFoundDecl() && NameInfo.getName() == E->getDecl()->getDeclName() && !E->hasExplicitTemplateArgs()) { // Mark it referenced in the new context regardless. // FIXME: this is a bit instantiation-specific. SemaRef.MarkDeclRefReferenced(E); return E; } TemplateArgumentListInfo TransArgs, *TemplateArgs = nullptr; if (E->hasExplicitTemplateArgs()) { TemplateArgs = &TransArgs; TransArgs.setLAngleLoc(E->getLAngleLoc()); TransArgs.setRAngleLoc(E->getRAngleLoc()); if (getDerived().TransformTemplateArguments(E->getTemplateArgs(), E->getNumTemplateArgs(), TransArgs)) return ExprError(); } return getDerived().RebuildDeclRefExpr(QualifierLoc, ND, NameInfo, Found, TemplateArgs); } template ExprResult TreeTransform::TransformIntegerLiteral(IntegerLiteral *E) { return E; } template ExprResult TreeTransform::TransformFixedPointLiteral( FixedPointLiteral *E) { return E; } template ExprResult TreeTransform::TransformFloatingLiteral(FloatingLiteral *E) { return E; } template ExprResult TreeTransform::TransformImaginaryLiteral(ImaginaryLiteral *E) { return E; } template ExprResult TreeTransform::TransformStringLiteral(StringLiteral *E) { return E; } template ExprResult TreeTransform::TransformCharacterLiteral(CharacterLiteral *E) { return E; } template ExprResult TreeTransform::TransformUserDefinedLiteral(UserDefinedLiteral *E) { if (FunctionDecl *FD = E->getDirectCallee()) SemaRef.MarkFunctionReferenced(E->getBeginLoc(), FD); return SemaRef.MaybeBindToTemporary(E); } template ExprResult TreeTransform::TransformGenericSelectionExpr(GenericSelectionExpr *E) { ExprResult ControllingExpr = getDerived().TransformExpr(E->getControllingExpr()); if (ControllingExpr.isInvalid()) return ExprError(); SmallVector AssocExprs; SmallVector AssocTypes; for (const GenericSelectionExpr::Association Assoc : E->associations()) { TypeSourceInfo *TSI = Assoc.getTypeSourceInfo(); if (TSI) { TypeSourceInfo *AssocType = getDerived().TransformType(TSI); if (!AssocType) return ExprError(); AssocTypes.push_back(AssocType); } else { AssocTypes.push_back(nullptr); } ExprResult AssocExpr = getDerived().TransformExpr(Assoc.getAssociationExpr()); if (AssocExpr.isInvalid()) return ExprError(); AssocExprs.push_back(AssocExpr.get()); } return getDerived().RebuildGenericSelectionExpr(E->getGenericLoc(), E->getDefaultLoc(), E->getRParenLoc(), ControllingExpr.get(), AssocTypes, AssocExprs); } template ExprResult TreeTransform::TransformParenExpr(ParenExpr *E) { ExprResult SubExpr = getDerived().TransformExpr(E->getSubExpr()); if (SubExpr.isInvalid()) return ExprError(); if (!getDerived().AlwaysRebuild() && SubExpr.get() == E->getSubExpr()) return E; return getDerived().RebuildParenExpr(SubExpr.get(), E->getLParen(), E->getRParen()); } /// The operand of a unary address-of operator has special rules: it's /// allowed to refer to a non-static member of a class even if there's no 'this' /// object available. template ExprResult TreeTransform::TransformAddressOfOperand(Expr *E) { if (DependentScopeDeclRefExpr *DRE = dyn_cast(E)) return getDerived().TransformDependentScopeDeclRefExpr(DRE, true, nullptr); else return getDerived().TransformExpr(E); } template ExprResult TreeTransform::TransformUnaryOperator(UnaryOperator *E) { ExprResult SubExpr; if (E->getOpcode() == UO_AddrOf) SubExpr = TransformAddressOfOperand(E->getSubExpr()); else SubExpr = TransformExpr(E->getSubExpr()); if (SubExpr.isInvalid()) return ExprError(); if (!getDerived().AlwaysRebuild() && SubExpr.get() == E->getSubExpr()) return E; return getDerived().RebuildUnaryOperator(E->getOperatorLoc(), E->getOpcode(), SubExpr.get()); } template ExprResult TreeTransform::TransformOffsetOfExpr(OffsetOfExpr *E) { // Transform the type. TypeSourceInfo *Type = getDerived().TransformType(E->getTypeSourceInfo()); if (!Type) return ExprError(); // Transform all of the components into components similar to what the // parser uses. // FIXME: It would be slightly more efficient in the non-dependent case to // just map FieldDecls, rather than requiring the rebuilder to look for // the fields again. However, __builtin_offsetof is rare enough in // template code that we don't care. bool ExprChanged = false; typedef Sema::OffsetOfComponent Component; SmallVector Components; for (unsigned I = 0, N = E->getNumComponents(); I != N; ++I) { const OffsetOfNode &ON = E->getComponent(I); Component Comp; Comp.isBrackets = true; Comp.LocStart = ON.getSourceRange().getBegin(); Comp.LocEnd = ON.getSourceRange().getEnd(); switch (ON.getKind()) { case OffsetOfNode::Array: { Expr *FromIndex = E->getIndexExpr(ON.getArrayExprIndex()); ExprResult Index = getDerived().TransformExpr(FromIndex); if (Index.isInvalid()) return ExprError(); ExprChanged = ExprChanged || Index.get() != FromIndex; Comp.isBrackets = true; Comp.U.E = Index.get(); break; } case OffsetOfNode::Field: case OffsetOfNode::Identifier: Comp.isBrackets = false; Comp.U.IdentInfo = ON.getFieldName(); if (!Comp.U.IdentInfo) continue; break; case OffsetOfNode::Base: // Will be recomputed during the rebuild. continue; } Components.push_back(Comp); } // If nothing changed, retain the existing expression. if (!getDerived().AlwaysRebuild() && Type == E->getTypeSourceInfo() && !ExprChanged) return E; // Build a new offsetof expression. return getDerived().RebuildOffsetOfExpr(E->getOperatorLoc(), Type, Components, E->getRParenLoc()); } template ExprResult TreeTransform::TransformOpaqueValueExpr(OpaqueValueExpr *E) { assert((!E->getSourceExpr() || getDerived().AlreadyTransformed(E->getType())) && "opaque value expression requires transformation"); return E; } template ExprResult TreeTransform::TransformTypoExpr(TypoExpr *E) { return E; } template ExprResult TreeTransform::TransformPseudoObjectExpr(PseudoObjectExpr *E) { // Rebuild the syntactic form. The original syntactic form has // opaque-value expressions in it, so strip those away and rebuild // the result. This is a really awful way of doing this, but the // better solution (rebuilding the semantic expressions and // rebinding OVEs as necessary) doesn't work; we'd need // TreeTransform to not strip away implicit conversions. Expr *newSyntacticForm = SemaRef.recreateSyntacticForm(E); ExprResult result = getDerived().TransformExpr(newSyntacticForm); if (result.isInvalid()) return ExprError(); // If that gives us a pseudo-object result back, the pseudo-object // expression must have been an lvalue-to-rvalue conversion which we // should reapply. if (result.get()->hasPlaceholderType(BuiltinType::PseudoObject)) result = SemaRef.checkPseudoObjectRValue(result.get()); return result; } template ExprResult TreeTransform::TransformUnaryExprOrTypeTraitExpr( UnaryExprOrTypeTraitExpr *E) { if (E->isArgumentType()) { TypeSourceInfo *OldT = E->getArgumentTypeInfo(); TypeSourceInfo *NewT = getDerived().TransformType(OldT); if (!NewT) return ExprError(); if (!getDerived().AlwaysRebuild() && OldT == NewT) return E; return getDerived().RebuildUnaryExprOrTypeTrait(NewT, E->getOperatorLoc(), E->getKind(), E->getSourceRange()); } // C++0x [expr.sizeof]p1: // The operand is either an expression, which is an unevaluated operand // [...] EnterExpressionEvaluationContext Unevaluated( SemaRef, Sema::ExpressionEvaluationContext::Unevaluated, Sema::ReuseLambdaContextDecl); // Try to recover if we have something like sizeof(T::X) where X is a type. // Notably, there must be *exactly* one set of parens if X is a type. TypeSourceInfo *RecoveryTSI = nullptr; ExprResult SubExpr; auto *PE = dyn_cast(E->getArgumentExpr()); if (auto *DRE = PE ? dyn_cast(PE->getSubExpr()) : nullptr) SubExpr = getDerived().TransformParenDependentScopeDeclRefExpr( PE, DRE, false, &RecoveryTSI); else SubExpr = getDerived().TransformExpr(E->getArgumentExpr()); if (RecoveryTSI) { return getDerived().RebuildUnaryExprOrTypeTrait( RecoveryTSI, E->getOperatorLoc(), E->getKind(), E->getSourceRange()); } else if (SubExpr.isInvalid()) return ExprError(); if (!getDerived().AlwaysRebuild() && SubExpr.get() == E->getArgumentExpr()) return E; return getDerived().RebuildUnaryExprOrTypeTrait(SubExpr.get(), E->getOperatorLoc(), E->getKind(), E->getSourceRange()); } template ExprResult TreeTransform::TransformArraySubscriptExpr(ArraySubscriptExpr *E) { ExprResult LHS = getDerived().TransformExpr(E->getLHS()); if (LHS.isInvalid()) return ExprError(); ExprResult RHS = getDerived().TransformExpr(E->getRHS()); if (RHS.isInvalid()) return ExprError(); if (!getDerived().AlwaysRebuild() && LHS.get() == E->getLHS() && RHS.get() == E->getRHS()) return E; return getDerived().RebuildArraySubscriptExpr( LHS.get(), /*FIXME:*/ E->getLHS()->getBeginLoc(), RHS.get(), E->getRBracketLoc()); } template ExprResult TreeTransform::TransformOMPArraySectionExpr(OMPArraySectionExpr *E) { ExprResult Base = getDerived().TransformExpr(E->getBase()); if (Base.isInvalid()) return ExprError(); ExprResult LowerBound; if (E->getLowerBound()) { LowerBound = getDerived().TransformExpr(E->getLowerBound()); if (LowerBound.isInvalid()) return ExprError(); } ExprResult Length; if (E->getLength()) { Length = getDerived().TransformExpr(E->getLength()); if (Length.isInvalid()) return ExprError(); } if (!getDerived().AlwaysRebuild() && Base.get() == E->getBase() && LowerBound.get() == E->getLowerBound() && Length.get() == E->getLength()) return E; return getDerived().RebuildOMPArraySectionExpr( Base.get(), E->getBase()->getEndLoc(), LowerBound.get(), E->getColonLoc(), Length.get(), E->getRBracketLoc()); } template ExprResult TreeTransform::TransformCallExpr(CallExpr *E) { // Transform the callee. ExprResult Callee = getDerived().TransformExpr(E->getCallee()); if (Callee.isInvalid()) return ExprError(); // Transform arguments. bool ArgChanged = false; SmallVector Args; if (getDerived().TransformExprs(E->getArgs(), E->getNumArgs(), true, Args, &ArgChanged)) return ExprError(); if (!getDerived().AlwaysRebuild() && Callee.get() == E->getCallee() && !ArgChanged) return SemaRef.MaybeBindToTemporary(E); // FIXME: Wrong source location information for the '('. SourceLocation FakeLParenLoc = ((Expr *)Callee.get())->getSourceRange().getBegin(); return getDerived().RebuildCallExpr(Callee.get(), FakeLParenLoc, Args, E->getRParenLoc()); } template ExprResult TreeTransform::TransformMemberExpr(MemberExpr *E) { ExprResult Base = getDerived().TransformExpr(E->getBase()); if (Base.isInvalid()) return ExprError(); NestedNameSpecifierLoc QualifierLoc; if (E->hasQualifier()) { QualifierLoc = getDerived().TransformNestedNameSpecifierLoc(E->getQualifierLoc()); if (!QualifierLoc) return ExprError(); } SourceLocation TemplateKWLoc = E->getTemplateKeywordLoc(); ValueDecl *Member = cast_or_null(getDerived().TransformDecl(E->getMemberLoc(), E->getMemberDecl())); if (!Member) return ExprError(); NamedDecl *FoundDecl = E->getFoundDecl(); if (FoundDecl == E->getMemberDecl()) { FoundDecl = Member; } else { FoundDecl = cast_or_null( getDerived().TransformDecl(E->getMemberLoc(), FoundDecl)); if (!FoundDecl) return ExprError(); } if (!getDerived().AlwaysRebuild() && Base.get() == E->getBase() && QualifierLoc == E->getQualifierLoc() && Member == E->getMemberDecl() && FoundDecl == E->getFoundDecl() && !E->hasExplicitTemplateArgs()) { // Mark it referenced in the new context regardless. // FIXME: this is a bit instantiation-specific. SemaRef.MarkMemberReferenced(E); return E; } TemplateArgumentListInfo TransArgs; if (E->hasExplicitTemplateArgs()) { TransArgs.setLAngleLoc(E->getLAngleLoc()); TransArgs.setRAngleLoc(E->getRAngleLoc()); if (getDerived().TransformTemplateArguments(E->getTemplateArgs(), E->getNumTemplateArgs(), TransArgs)) return ExprError(); } // FIXME: Bogus source location for the operator SourceLocation FakeOperatorLoc = SemaRef.getLocForEndOfToken(E->getBase()->getSourceRange().getEnd()); // FIXME: to do this check properly, we will need to preserve the // first-qualifier-in-scope here, just in case we had a dependent // base (and therefore couldn't do the check) and a // nested-name-qualifier (and therefore could do the lookup). NamedDecl *FirstQualifierInScope = nullptr; DeclarationNameInfo MemberNameInfo = E->getMemberNameInfo(); if (MemberNameInfo.getName()) { MemberNameInfo = getDerived().TransformDeclarationNameInfo(MemberNameInfo); if (!MemberNameInfo.getName()) return ExprError(); } return getDerived().RebuildMemberExpr(Base.get(), FakeOperatorLoc, E->isArrow(), QualifierLoc, TemplateKWLoc, MemberNameInfo, Member, FoundDecl, (E->hasExplicitTemplateArgs() ? &TransArgs : nullptr), FirstQualifierInScope); } template ExprResult TreeTransform::TransformBinaryOperator(BinaryOperator *E) { ExprResult LHS = getDerived().TransformExpr(E->getLHS()); if (LHS.isInvalid()) return ExprError(); ExprResult RHS = getDerived().TransformExpr(E->getRHS()); if (RHS.isInvalid()) return ExprError(); if (!getDerived().AlwaysRebuild() && LHS.get() == E->getLHS() && RHS.get() == E->getRHS()) return E; Sema::FPContractStateRAII FPContractState(getSema()); getSema().FPFeatures = E->getFPFeatures(); return getDerived().RebuildBinaryOperator(E->getOperatorLoc(), E->getOpcode(), LHS.get(), RHS.get()); } template ExprResult TreeTransform::TransformCXXRewrittenBinaryOperator( CXXRewrittenBinaryOperator *E) { CXXRewrittenBinaryOperator::DecomposedForm Decomp = E->getDecomposedForm(); ExprResult LHS = getDerived().TransformExpr(const_cast(Decomp.LHS)); if (LHS.isInvalid()) return ExprError(); ExprResult RHS = getDerived().TransformExpr(const_cast(Decomp.RHS)); if (RHS.isInvalid()) return ExprError(); if (!getDerived().AlwaysRebuild() && LHS.get() == Decomp.LHS && RHS.get() == Decomp.RHS) return E; // Extract the already-resolved callee declarations so that we can restrict // ourselves to using them as the unqualified lookup results when rebuilding. UnresolvedSet<2> UnqualLookups; Expr *PossibleBinOps[] = {E->getSemanticForm(), const_cast(Decomp.InnerBinOp)}; for (Expr *PossibleBinOp : PossibleBinOps) { auto *Op = dyn_cast(PossibleBinOp->IgnoreImplicit()); if (!Op) continue; auto *Callee = dyn_cast(Op->getCallee()->IgnoreImplicit()); if (!Callee || isa(Callee->getDecl())) continue; // Transform the callee in case we built a call to a local extern // declaration. NamedDecl *Found = cast_or_null(getDerived().TransformDecl( E->getOperatorLoc(), Callee->getFoundDecl())); if (!Found) return ExprError(); UnqualLookups.addDecl(Found); } return getDerived().RebuildCXXRewrittenBinaryOperator( E->getOperatorLoc(), Decomp.Opcode, UnqualLookups, LHS.get(), RHS.get()); } template ExprResult TreeTransform::TransformCompoundAssignOperator( CompoundAssignOperator *E) { return getDerived().TransformBinaryOperator(E); } template ExprResult TreeTransform:: TransformBinaryConditionalOperator(BinaryConditionalOperator *e) { // Just rebuild the common and RHS expressions and see whether we // get any changes. ExprResult commonExpr = getDerived().TransformExpr(e->getCommon()); if (commonExpr.isInvalid()) return ExprError(); ExprResult rhs = getDerived().TransformExpr(e->getFalseExpr()); if (rhs.isInvalid()) return ExprError(); if (!getDerived().AlwaysRebuild() && commonExpr.get() == e->getCommon() && rhs.get() == e->getFalseExpr()) return e; return getDerived().RebuildConditionalOperator(commonExpr.get(), e->getQuestionLoc(), nullptr, e->getColonLoc(), rhs.get()); } template ExprResult TreeTransform::TransformConditionalOperator(ConditionalOperator *E) { ExprResult Cond = getDerived().TransformExpr(E->getCond()); if (Cond.isInvalid()) return ExprError(); ExprResult LHS = getDerived().TransformExpr(E->getLHS()); if (LHS.isInvalid()) return ExprError(); ExprResult RHS = getDerived().TransformExpr(E->getRHS()); if (RHS.isInvalid()) return ExprError(); if (!getDerived().AlwaysRebuild() && Cond.get() == E->getCond() && LHS.get() == E->getLHS() && RHS.get() == E->getRHS()) return E; return getDerived().RebuildConditionalOperator(Cond.get(), E->getQuestionLoc(), LHS.get(), E->getColonLoc(), RHS.get()); } template ExprResult TreeTransform::TransformImplicitCastExpr(ImplicitCastExpr *E) { // Implicit casts are eliminated during transformation, since they // will be recomputed by semantic analysis after transformation. return getDerived().TransformExpr(E->getSubExprAsWritten()); } template ExprResult TreeTransform::TransformCStyleCastExpr(CStyleCastExpr *E) { TypeSourceInfo *Type = getDerived().TransformType(E->getTypeInfoAsWritten()); if (!Type) return ExprError(); ExprResult SubExpr = getDerived().TransformExpr(E->getSubExprAsWritten()); if (SubExpr.isInvalid()) return ExprError(); if (!getDerived().AlwaysRebuild() && Type == E->getTypeInfoAsWritten() && SubExpr.get() == E->getSubExpr()) return E; return getDerived().RebuildCStyleCastExpr(E->getLParenLoc(), Type, E->getRParenLoc(), SubExpr.get()); } template ExprResult TreeTransform::TransformCompoundLiteralExpr(CompoundLiteralExpr *E) { TypeSourceInfo *OldT = E->getTypeSourceInfo(); TypeSourceInfo *NewT = getDerived().TransformType(OldT); if (!NewT) return ExprError(); ExprResult Init = getDerived().TransformExpr(E->getInitializer()); if (Init.isInvalid()) return ExprError(); if (!getDerived().AlwaysRebuild() && OldT == NewT && Init.get() == E->getInitializer()) return SemaRef.MaybeBindToTemporary(E); // Note: the expression type doesn't necessarily match the // type-as-written, but that's okay, because it should always be // derivable from the initializer. return getDerived().RebuildCompoundLiteralExpr( E->getLParenLoc(), NewT, /*FIXME:*/ E->getInitializer()->getEndLoc(), Init.get()); } template ExprResult TreeTransform::TransformExtVectorElementExpr(ExtVectorElementExpr *E) { ExprResult Base = getDerived().TransformExpr(E->getBase()); if (Base.isInvalid()) return ExprError(); if (!getDerived().AlwaysRebuild() && Base.get() == E->getBase()) return E; // FIXME: Bad source location SourceLocation FakeOperatorLoc = SemaRef.getLocForEndOfToken(E->getBase()->getEndLoc()); return getDerived().RebuildExtVectorElementExpr(Base.get(), FakeOperatorLoc, E->getAccessorLoc(), E->getAccessor()); } template ExprResult TreeTransform::TransformInitListExpr(InitListExpr *E) { if (InitListExpr *Syntactic = E->getSyntacticForm()) E = Syntactic; bool InitChanged = false; EnterExpressionEvaluationContext Context( getSema(), EnterExpressionEvaluationContext::InitList); SmallVector Inits; if (getDerived().TransformExprs(E->getInits(), E->getNumInits(), false, Inits, &InitChanged)) return ExprError(); if (!getDerived().AlwaysRebuild() && !InitChanged) { // FIXME: Attempt to reuse the existing syntactic form of the InitListExpr // in some cases. We can't reuse it in general, because the syntactic and // semantic forms are linked, and we can't know that semantic form will // match even if the syntactic form does. } return getDerived().RebuildInitList(E->getLBraceLoc(), Inits, E->getRBraceLoc()); } template ExprResult TreeTransform::TransformDesignatedInitExpr(DesignatedInitExpr *E) { Designation Desig; // transform the initializer value ExprResult Init = getDerived().TransformExpr(E->getInit()); if (Init.isInvalid()) return ExprError(); // transform the designators. SmallVector ArrayExprs; bool ExprChanged = false; for (const DesignatedInitExpr::Designator &D : E->designators()) { if (D.isFieldDesignator()) { Desig.AddDesignator(Designator::getField(D.getFieldName(), D.getDotLoc(), D.getFieldLoc())); if (D.getField()) { FieldDecl *Field = cast_or_null( getDerived().TransformDecl(D.getFieldLoc(), D.getField())); if (Field != D.getField()) // Rebuild the expression when the transformed FieldDecl is // different to the already assigned FieldDecl. ExprChanged = true; } else { // Ensure that the designator expression is rebuilt when there isn't // a resolved FieldDecl in the designator as we don't want to assign // a FieldDecl to a pattern designator that will be instantiated again. ExprChanged = true; } continue; } if (D.isArrayDesignator()) { ExprResult Index = getDerived().TransformExpr(E->getArrayIndex(D)); if (Index.isInvalid()) return ExprError(); Desig.AddDesignator( Designator::getArray(Index.get(), D.getLBracketLoc())); ExprChanged = ExprChanged || Init.get() != E->getArrayIndex(D); ArrayExprs.push_back(Index.get()); continue; } assert(D.isArrayRangeDesignator() && "New kind of designator?"); ExprResult Start = getDerived().TransformExpr(E->getArrayRangeStart(D)); if (Start.isInvalid()) return ExprError(); ExprResult End = getDerived().TransformExpr(E->getArrayRangeEnd(D)); if (End.isInvalid()) return ExprError(); Desig.AddDesignator(Designator::getArrayRange(Start.get(), End.get(), D.getLBracketLoc(), D.getEllipsisLoc())); ExprChanged = ExprChanged || Start.get() != E->getArrayRangeStart(D) || End.get() != E->getArrayRangeEnd(D); ArrayExprs.push_back(Start.get()); ArrayExprs.push_back(End.get()); } if (!getDerived().AlwaysRebuild() && Init.get() == E->getInit() && !ExprChanged) return E; return getDerived().RebuildDesignatedInitExpr(Desig, ArrayExprs, E->getEqualOrColonLoc(), E->usesGNUSyntax(), Init.get()); } // Seems that if TransformInitListExpr() only works on the syntactic form of an // InitListExpr, then a DesignatedInitUpdateExpr is not encountered. template ExprResult TreeTransform::TransformDesignatedInitUpdateExpr( DesignatedInitUpdateExpr *E) { llvm_unreachable("Unexpected DesignatedInitUpdateExpr in syntactic form of " "initializer"); return ExprError(); } template ExprResult TreeTransform::TransformNoInitExpr( NoInitExpr *E) { llvm_unreachable("Unexpected NoInitExpr in syntactic form of initializer"); return ExprError(); } template ExprResult TreeTransform::TransformArrayInitLoopExpr(ArrayInitLoopExpr *E) { llvm_unreachable("Unexpected ArrayInitLoopExpr outside of initializer"); return ExprError(); } template ExprResult TreeTransform::TransformArrayInitIndexExpr(ArrayInitIndexExpr *E) { llvm_unreachable("Unexpected ArrayInitIndexExpr outside of initializer"); return ExprError(); } template ExprResult TreeTransform::TransformImplicitValueInitExpr( ImplicitValueInitExpr *E) { TemporaryBase Rebase(*this, E->getBeginLoc(), DeclarationName()); // FIXME: Will we ever have proper type location here? Will we actually // need to transform the type? QualType T = getDerived().TransformType(E->getType()); if (T.isNull()) return ExprError(); if (!getDerived().AlwaysRebuild() && T == E->getType()) return E; return getDerived().RebuildImplicitValueInitExpr(T); } template ExprResult TreeTransform::TransformVAArgExpr(VAArgExpr *E) { TypeSourceInfo *TInfo = getDerived().TransformType(E->getWrittenTypeInfo()); if (!TInfo) return ExprError(); ExprResult SubExpr = getDerived().TransformExpr(E->getSubExpr()); if (SubExpr.isInvalid()) return ExprError(); if (!getDerived().AlwaysRebuild() && TInfo == E->getWrittenTypeInfo() && SubExpr.get() == E->getSubExpr()) return E; return getDerived().RebuildVAArgExpr(E->getBuiltinLoc(), SubExpr.get(), TInfo, E->getRParenLoc()); } template ExprResult TreeTransform::TransformParenListExpr(ParenListExpr *E) { bool ArgumentChanged = false; SmallVector Inits; if (TransformExprs(E->getExprs(), E->getNumExprs(), true, Inits, &ArgumentChanged)) return ExprError(); return getDerived().RebuildParenListExpr(E->getLParenLoc(), Inits, E->getRParenLoc()); } /// Transform an address-of-label expression. /// /// By default, the transformation of an address-of-label expression always /// rebuilds the expression, so that the label identifier can be resolved to /// the corresponding label statement by semantic analysis. template ExprResult TreeTransform::TransformAddrLabelExpr(AddrLabelExpr *E) { Decl *LD = getDerived().TransformDecl(E->getLabel()->getLocation(), E->getLabel()); if (!LD) return ExprError(); return getDerived().RebuildAddrLabelExpr(E->getAmpAmpLoc(), E->getLabelLoc(), cast(LD)); } template ExprResult TreeTransform::TransformStmtExpr(StmtExpr *E) { SemaRef.ActOnStartStmtExpr(); StmtResult SubStmt = getDerived().TransformCompoundStmt(E->getSubStmt(), true); if (SubStmt.isInvalid()) { SemaRef.ActOnStmtExprError(); return ExprError(); } if (!getDerived().AlwaysRebuild() && SubStmt.get() == E->getSubStmt()) { // Calling this an 'error' is unintuitive, but it does the right thing. SemaRef.ActOnStmtExprError(); return SemaRef.MaybeBindToTemporary(E); } return getDerived().RebuildStmtExpr(E->getLParenLoc(), SubStmt.get(), E->getRParenLoc()); } template ExprResult TreeTransform::TransformChooseExpr(ChooseExpr *E) { ExprResult Cond = getDerived().TransformExpr(E->getCond()); if (Cond.isInvalid()) return ExprError(); ExprResult LHS = getDerived().TransformExpr(E->getLHS()); if (LHS.isInvalid()) return ExprError(); ExprResult RHS = getDerived().TransformExpr(E->getRHS()); if (RHS.isInvalid()) return ExprError(); if (!getDerived().AlwaysRebuild() && Cond.get() == E->getCond() && LHS.get() == E->getLHS() && RHS.get() == E->getRHS()) return E; return getDerived().RebuildChooseExpr(E->getBuiltinLoc(), Cond.get(), LHS.get(), RHS.get(), E->getRParenLoc()); } template ExprResult TreeTransform::TransformGNUNullExpr(GNUNullExpr *E) { return E; } template ExprResult TreeTransform::TransformCXXOperatorCallExpr(CXXOperatorCallExpr *E) { switch (E->getOperator()) { case OO_New: case OO_Delete: case OO_Array_New: case OO_Array_Delete: llvm_unreachable("new and delete operators cannot use CXXOperatorCallExpr"); case OO_Call: { // This is a call to an object's operator(). assert(E->getNumArgs() >= 1 && "Object call is missing arguments"); // Transform the object itself. ExprResult Object = getDerived().TransformExpr(E->getArg(0)); if (Object.isInvalid()) return ExprError(); // FIXME: Poor location information SourceLocation FakeLParenLoc = SemaRef.getLocForEndOfToken( static_cast(Object.get())->getEndLoc()); // Transform the call arguments. SmallVector Args; if (getDerived().TransformExprs(E->getArgs() + 1, E->getNumArgs() - 1, true, Args)) return ExprError(); return getDerived().RebuildCallExpr(Object.get(), FakeLParenLoc, Args, E->getEndLoc()); } #define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly) \ case OO_##Name: #define OVERLOADED_OPERATOR_MULTI(Name,Spelling,Unary,Binary,MemberOnly) #include "clang/Basic/OperatorKinds.def" case OO_Subscript: // Handled below. break; case OO_Conditional: llvm_unreachable("conditional operator is not actually overloadable"); case OO_None: case NUM_OVERLOADED_OPERATORS: llvm_unreachable("not an overloaded operator?"); } ExprResult Callee = getDerived().TransformExpr(E->getCallee()); if (Callee.isInvalid()) return ExprError(); ExprResult First; if (E->getOperator() == OO_Amp) First = getDerived().TransformAddressOfOperand(E->getArg(0)); else First = getDerived().TransformExpr(E->getArg(0)); if (First.isInvalid()) return ExprError(); ExprResult Second; if (E->getNumArgs() == 2) { Second = getDerived().TransformExpr(E->getArg(1)); if (Second.isInvalid()) return ExprError(); } if (!getDerived().AlwaysRebuild() && Callee.get() == E->getCallee() && First.get() == E->getArg(0) && (E->getNumArgs() != 2 || Second.get() == E->getArg(1))) return SemaRef.MaybeBindToTemporary(E); Sema::FPContractStateRAII FPContractState(getSema()); getSema().FPFeatures = E->getFPFeatures(); return getDerived().RebuildCXXOperatorCallExpr(E->getOperator(), E->getOperatorLoc(), Callee.get(), First.get(), Second.get()); } template ExprResult TreeTransform::TransformCXXMemberCallExpr(CXXMemberCallExpr *E) { return getDerived().TransformCallExpr(E); } template ExprResult TreeTransform::TransformSourceLocExpr(SourceLocExpr *E) { bool NeedRebuildFunc = E->getIdentKind() == SourceLocExpr::Function && getSema().CurContext != E->getParentContext(); if (!getDerived().AlwaysRebuild() && !NeedRebuildFunc) return E; return getDerived().RebuildSourceLocExpr(E->getIdentKind(), E->getBeginLoc(), E->getEndLoc(), getSema().CurContext); } template ExprResult TreeTransform::TransformCUDAKernelCallExpr(CUDAKernelCallExpr *E) { // Transform the callee. ExprResult Callee = getDerived().TransformExpr(E->getCallee()); if (Callee.isInvalid()) return ExprError(); // Transform exec config. ExprResult EC = getDerived().TransformCallExpr(E->getConfig()); if (EC.isInvalid()) return ExprError(); // Transform arguments. bool ArgChanged = false; SmallVector Args; if (getDerived().TransformExprs(E->getArgs(), E->getNumArgs(), true, Args, &ArgChanged)) return ExprError(); if (!getDerived().AlwaysRebuild() && Callee.get() == E->getCallee() && !ArgChanged) return SemaRef.MaybeBindToTemporary(E); // FIXME: Wrong source location information for the '('. SourceLocation FakeLParenLoc = ((Expr *)Callee.get())->getSourceRange().getBegin(); return getDerived().RebuildCallExpr(Callee.get(), FakeLParenLoc, Args, E->getRParenLoc(), EC.get()); } template ExprResult TreeTransform::TransformCXXNamedCastExpr(CXXNamedCastExpr *E) { TypeSourceInfo *Type = getDerived().TransformType(E->getTypeInfoAsWritten()); if (!Type) return ExprError(); ExprResult SubExpr = getDerived().TransformExpr(E->getSubExprAsWritten()); if (SubExpr.isInvalid()) return ExprError(); if (!getDerived().AlwaysRebuild() && Type == E->getTypeInfoAsWritten() && SubExpr.get() == E->getSubExpr()) return E; return getDerived().RebuildCXXNamedCastExpr( E->getOperatorLoc(), E->getStmtClass(), E->getAngleBrackets().getBegin(), Type, E->getAngleBrackets().getEnd(), // FIXME. this should be '(' location E->getAngleBrackets().getEnd(), SubExpr.get(), E->getRParenLoc()); } template ExprResult TreeTransform::TransformBuiltinBitCastExpr(BuiltinBitCastExpr *BCE) { TypeSourceInfo *TSI = getDerived().TransformType(BCE->getTypeInfoAsWritten()); if (!TSI) return ExprError(); ExprResult Sub = getDerived().TransformExpr(BCE->getSubExpr()); if (Sub.isInvalid()) return ExprError(); return getDerived().RebuildBuiltinBitCastExpr(BCE->getBeginLoc(), TSI, Sub.get(), BCE->getEndLoc()); } template ExprResult TreeTransform::TransformCXXStaticCastExpr(CXXStaticCastExpr *E) { return getDerived().TransformCXXNamedCastExpr(E); } template ExprResult TreeTransform::TransformCXXDynamicCastExpr(CXXDynamicCastExpr *E) { return getDerived().TransformCXXNamedCastExpr(E); } template ExprResult TreeTransform::TransformCXXReinterpretCastExpr( CXXReinterpretCastExpr *E) { return getDerived().TransformCXXNamedCastExpr(E); } template ExprResult TreeTransform::TransformCXXConstCastExpr(CXXConstCastExpr *E) { return getDerived().TransformCXXNamedCastExpr(E); } template ExprResult TreeTransform::TransformCXXFunctionalCastExpr( CXXFunctionalCastExpr *E) { TypeSourceInfo *Type = getDerived().TransformTypeWithDeducedTST(E->getTypeInfoAsWritten()); if (!Type) return ExprError(); ExprResult SubExpr = getDerived().TransformExpr(E->getSubExprAsWritten()); if (SubExpr.isInvalid()) return ExprError(); if (!getDerived().AlwaysRebuild() && Type == E->getTypeInfoAsWritten() && SubExpr.get() == E->getSubExpr()) return E; return getDerived().RebuildCXXFunctionalCastExpr(Type, E->getLParenLoc(), SubExpr.get(), E->getRParenLoc(), E->isListInitialization()); } template ExprResult TreeTransform::TransformCXXTypeidExpr(CXXTypeidExpr *E) { if (E->isTypeOperand()) { TypeSourceInfo *TInfo = getDerived().TransformType(E->getTypeOperandSourceInfo()); if (!TInfo) return ExprError(); if (!getDerived().AlwaysRebuild() && TInfo == E->getTypeOperandSourceInfo()) return E; return getDerived().RebuildCXXTypeidExpr(E->getType(), E->getBeginLoc(), TInfo, E->getEndLoc()); } // We don't know whether the subexpression is potentially evaluated until // after we perform semantic analysis. We speculatively assume it is // unevaluated; it will get fixed later if the subexpression is in fact // potentially evaluated. EnterExpressionEvaluationContext Unevaluated( SemaRef, Sema::ExpressionEvaluationContext::Unevaluated, Sema::ReuseLambdaContextDecl); ExprResult SubExpr = getDerived().TransformExpr(E->getExprOperand()); if (SubExpr.isInvalid()) return ExprError(); if (!getDerived().AlwaysRebuild() && SubExpr.get() == E->getExprOperand()) return E; return getDerived().RebuildCXXTypeidExpr(E->getType(), E->getBeginLoc(), SubExpr.get(), E->getEndLoc()); } template ExprResult TreeTransform::TransformCXXUuidofExpr(CXXUuidofExpr *E) { if (E->isTypeOperand()) { TypeSourceInfo *TInfo = getDerived().TransformType(E->getTypeOperandSourceInfo()); if (!TInfo) return ExprError(); if (!getDerived().AlwaysRebuild() && TInfo == E->getTypeOperandSourceInfo()) return E; return getDerived().RebuildCXXUuidofExpr(E->getType(), E->getBeginLoc(), TInfo, E->getEndLoc()); } EnterExpressionEvaluationContext Unevaluated( SemaRef, Sema::ExpressionEvaluationContext::Unevaluated); ExprResult SubExpr = getDerived().TransformExpr(E->getExprOperand()); if (SubExpr.isInvalid()) return ExprError(); if (!getDerived().AlwaysRebuild() && SubExpr.get() == E->getExprOperand()) return E; return getDerived().RebuildCXXUuidofExpr(E->getType(), E->getBeginLoc(), SubExpr.get(), E->getEndLoc()); } template ExprResult TreeTransform::TransformCXXBoolLiteralExpr(CXXBoolLiteralExpr *E) { return E; } template ExprResult TreeTransform::TransformCXXNullPtrLiteralExpr( CXXNullPtrLiteralExpr *E) { return E; } template ExprResult TreeTransform::TransformCXXThisExpr(CXXThisExpr *E) { QualType T = getSema().getCurrentThisType(); if (!getDerived().AlwaysRebuild() && T == E->getType()) { // Mark it referenced in the new context regardless. // FIXME: this is a bit instantiation-specific. getSema().MarkThisReferenced(E); return E; } return getDerived().RebuildCXXThisExpr(E->getBeginLoc(), T, E->isImplicit()); } template ExprResult TreeTransform::TransformCXXThrowExpr(CXXThrowExpr *E) { ExprResult SubExpr = getDerived().TransformExpr(E->getSubExpr()); if (SubExpr.isInvalid()) return ExprError(); if (!getDerived().AlwaysRebuild() && SubExpr.get() == E->getSubExpr()) return E; return getDerived().RebuildCXXThrowExpr(E->getThrowLoc(), SubExpr.get(), E->isThrownVariableInScope()); } template ExprResult TreeTransform::TransformCXXDefaultArgExpr(CXXDefaultArgExpr *E) { ParmVarDecl *Param = cast_or_null( getDerived().TransformDecl(E->getBeginLoc(), E->getParam())); if (!Param) return ExprError(); if (!getDerived().AlwaysRebuild() && Param == E->getParam() && E->getUsedContext() == SemaRef.CurContext) return E; return getDerived().RebuildCXXDefaultArgExpr(E->getUsedLocation(), Param); } template ExprResult TreeTransform::TransformCXXDefaultInitExpr(CXXDefaultInitExpr *E) { FieldDecl *Field = cast_or_null( getDerived().TransformDecl(E->getBeginLoc(), E->getField())); if (!Field) return ExprError(); if (!getDerived().AlwaysRebuild() && Field == E->getField() && E->getUsedContext() == SemaRef.CurContext) return E; return getDerived().RebuildCXXDefaultInitExpr(E->getExprLoc(), Field); } template ExprResult TreeTransform::TransformCXXScalarValueInitExpr( CXXScalarValueInitExpr *E) { TypeSourceInfo *T = getDerived().TransformType(E->getTypeSourceInfo()); if (!T) return ExprError(); if (!getDerived().AlwaysRebuild() && T == E->getTypeSourceInfo()) return E; return getDerived().RebuildCXXScalarValueInitExpr(T, /*FIXME:*/T->getTypeLoc().getEndLoc(), E->getRParenLoc()); } template ExprResult TreeTransform::TransformCXXNewExpr(CXXNewExpr *E) { // Transform the type that we're allocating TypeSourceInfo *AllocTypeInfo = getDerived().TransformTypeWithDeducedTST(E->getAllocatedTypeSourceInfo()); if (!AllocTypeInfo) return ExprError(); // Transform the size of the array we're allocating (if any). Optional ArraySize; if (Optional OldArraySize = E->getArraySize()) { ExprResult NewArraySize; if (*OldArraySize) { NewArraySize = getDerived().TransformExpr(*OldArraySize); if (NewArraySize.isInvalid()) return ExprError(); } ArraySize = NewArraySize.get(); } // Transform the placement arguments (if any). bool ArgumentChanged = false; SmallVector PlacementArgs; if (getDerived().TransformExprs(E->getPlacementArgs(), E->getNumPlacementArgs(), true, PlacementArgs, &ArgumentChanged)) return ExprError(); // Transform the initializer (if any). Expr *OldInit = E->getInitializer(); ExprResult NewInit; if (OldInit) NewInit = getDerived().TransformInitializer(OldInit, true); if (NewInit.isInvalid()) return ExprError(); // Transform new operator and delete operator. FunctionDecl *OperatorNew = nullptr; if (E->getOperatorNew()) { OperatorNew = cast_or_null( getDerived().TransformDecl(E->getBeginLoc(), E->getOperatorNew())); if (!OperatorNew) return ExprError(); } FunctionDecl *OperatorDelete = nullptr; if (E->getOperatorDelete()) { OperatorDelete = cast_or_null( getDerived().TransformDecl(E->getBeginLoc(), E->getOperatorDelete())); if (!OperatorDelete) return ExprError(); } if (!getDerived().AlwaysRebuild() && AllocTypeInfo == E->getAllocatedTypeSourceInfo() && ArraySize == E->getArraySize() && NewInit.get() == OldInit && OperatorNew == E->getOperatorNew() && OperatorDelete == E->getOperatorDelete() && !ArgumentChanged) { // Mark any declarations we need as referenced. // FIXME: instantiation-specific. if (OperatorNew) SemaRef.MarkFunctionReferenced(E->getBeginLoc(), OperatorNew); if (OperatorDelete) SemaRef.MarkFunctionReferenced(E->getBeginLoc(), OperatorDelete); if (E->isArray() && !E->getAllocatedType()->isDependentType()) { QualType ElementType = SemaRef.Context.getBaseElementType(E->getAllocatedType()); if (const RecordType *RecordT = ElementType->getAs()) { CXXRecordDecl *Record = cast(RecordT->getDecl()); if (CXXDestructorDecl *Destructor = SemaRef.LookupDestructor(Record)) { SemaRef.MarkFunctionReferenced(E->getBeginLoc(), Destructor); } } } return E; } QualType AllocType = AllocTypeInfo->getType(); if (!ArraySize) { // If no array size was specified, but the new expression was // instantiated with an array type (e.g., "new T" where T is // instantiated with "int[4]"), extract the outer bound from the // array type as our array size. We do this with constant and // dependently-sized array types. const ArrayType *ArrayT = SemaRef.Context.getAsArrayType(AllocType); if (!ArrayT) { // Do nothing } else if (const ConstantArrayType *ConsArrayT = dyn_cast(ArrayT)) { ArraySize = IntegerLiteral::Create(SemaRef.Context, ConsArrayT->getSize(), SemaRef.Context.getSizeType(), /*FIXME:*/ E->getBeginLoc()); AllocType = ConsArrayT->getElementType(); } else if (const DependentSizedArrayType *DepArrayT = dyn_cast(ArrayT)) { if (DepArrayT->getSizeExpr()) { ArraySize = DepArrayT->getSizeExpr(); AllocType = DepArrayT->getElementType(); } } } return getDerived().RebuildCXXNewExpr( E->getBeginLoc(), E->isGlobalNew(), /*FIXME:*/ E->getBeginLoc(), PlacementArgs, /*FIXME:*/ E->getBeginLoc(), E->getTypeIdParens(), AllocType, AllocTypeInfo, ArraySize, E->getDirectInitRange(), NewInit.get()); } template ExprResult TreeTransform::TransformCXXDeleteExpr(CXXDeleteExpr *E) { ExprResult Operand = getDerived().TransformExpr(E->getArgument()); if (Operand.isInvalid()) return ExprError(); // Transform the delete operator, if known. FunctionDecl *OperatorDelete = nullptr; if (E->getOperatorDelete()) { OperatorDelete = cast_or_null( getDerived().TransformDecl(E->getBeginLoc(), E->getOperatorDelete())); if (!OperatorDelete) return ExprError(); } if (!getDerived().AlwaysRebuild() && Operand.get() == E->getArgument() && OperatorDelete == E->getOperatorDelete()) { // Mark any declarations we need as referenced. // FIXME: instantiation-specific. if (OperatorDelete) SemaRef.MarkFunctionReferenced(E->getBeginLoc(), OperatorDelete); if (!E->getArgument()->isTypeDependent()) { QualType Destroyed = SemaRef.Context.getBaseElementType( E->getDestroyedType()); if (const RecordType *DestroyedRec = Destroyed->getAs()) { CXXRecordDecl *Record = cast(DestroyedRec->getDecl()); SemaRef.MarkFunctionReferenced(E->getBeginLoc(), SemaRef.LookupDestructor(Record)); } } return E; } return getDerived().RebuildCXXDeleteExpr( E->getBeginLoc(), E->isGlobalDelete(), E->isArrayForm(), Operand.get()); } template ExprResult TreeTransform::TransformCXXPseudoDestructorExpr( CXXPseudoDestructorExpr *E) { ExprResult Base = getDerived().TransformExpr(E->getBase()); if (Base.isInvalid()) return ExprError(); ParsedType ObjectTypePtr; bool MayBePseudoDestructor = false; Base = SemaRef.ActOnStartCXXMemberReference(nullptr, Base.get(), E->getOperatorLoc(), E->isArrow()? tok::arrow : tok::period, ObjectTypePtr, MayBePseudoDestructor); if (Base.isInvalid()) return ExprError(); QualType ObjectType = ObjectTypePtr.get(); NestedNameSpecifierLoc QualifierLoc = E->getQualifierLoc(); if (QualifierLoc) { QualifierLoc = getDerived().TransformNestedNameSpecifierLoc(QualifierLoc, ObjectType); if (!QualifierLoc) return ExprError(); } CXXScopeSpec SS; SS.Adopt(QualifierLoc); PseudoDestructorTypeStorage Destroyed; if (E->getDestroyedTypeInfo()) { TypeSourceInfo *DestroyedTypeInfo = getDerived().TransformTypeInObjectScope(E->getDestroyedTypeInfo(), ObjectType, nullptr, SS); if (!DestroyedTypeInfo) return ExprError(); Destroyed = DestroyedTypeInfo; } else if (!ObjectType.isNull() && ObjectType->isDependentType()) { // We aren't likely to be able to resolve the identifier down to a type // now anyway, so just retain the identifier. Destroyed = PseudoDestructorTypeStorage(E->getDestroyedTypeIdentifier(), E->getDestroyedTypeLoc()); } else { // Look for a destructor known with the given name. ParsedType T = SemaRef.getDestructorName(E->getTildeLoc(), *E->getDestroyedTypeIdentifier(), E->getDestroyedTypeLoc(), /*Scope=*/nullptr, SS, ObjectTypePtr, false); if (!T) return ExprError(); Destroyed = SemaRef.Context.getTrivialTypeSourceInfo(SemaRef.GetTypeFromParser(T), E->getDestroyedTypeLoc()); } TypeSourceInfo *ScopeTypeInfo = nullptr; if (E->getScopeTypeInfo()) { CXXScopeSpec EmptySS; ScopeTypeInfo = getDerived().TransformTypeInObjectScope( E->getScopeTypeInfo(), ObjectType, nullptr, EmptySS); if (!ScopeTypeInfo) return ExprError(); } return getDerived().RebuildCXXPseudoDestructorExpr(Base.get(), E->getOperatorLoc(), E->isArrow(), SS, ScopeTypeInfo, E->getColonColonLoc(), E->getTildeLoc(), Destroyed); } template bool TreeTransform::TransformOverloadExprDecls(OverloadExpr *Old, bool RequiresADL, LookupResult &R) { // Transform all the decls. bool AllEmptyPacks = true; for (auto *OldD : Old->decls()) { Decl *InstD = getDerived().TransformDecl(Old->getNameLoc(), OldD); if (!InstD) { // Silently ignore these if a UsingShadowDecl instantiated to nothing. // This can happen because of dependent hiding. if (isa(OldD)) continue; else { R.clear(); return true; } } // Expand using pack declarations. NamedDecl *SingleDecl = cast(InstD); ArrayRef Decls = SingleDecl; if (auto *UPD = dyn_cast(InstD)) Decls = UPD->expansions(); // Expand using declarations. for (auto *D : Decls) { if (auto *UD = dyn_cast(D)) { for (auto *SD : UD->shadows()) R.addDecl(SD); } else { R.addDecl(D); } } AllEmptyPacks &= Decls.empty(); }; // C++ [temp.res]/8.4.2: // The program is ill-formed, no diagnostic required, if [...] lookup for // a name in the template definition found a using-declaration, but the // lookup in the corresponding scope in the instantiation odoes not find // any declarations because the using-declaration was a pack expansion and // the corresponding pack is empty if (AllEmptyPacks && !RequiresADL) { getSema().Diag(Old->getNameLoc(), diag::err_using_pack_expansion_empty) << isa(Old) << Old->getName(); return true; } // Resolve a kind, but don't do any further analysis. If it's // ambiguous, the callee needs to deal with it. R.resolveKind(); return false; } template ExprResult TreeTransform::TransformUnresolvedLookupExpr( UnresolvedLookupExpr *Old) { LookupResult R(SemaRef, Old->getName(), Old->getNameLoc(), Sema::LookupOrdinaryName); // Transform the declaration set. if (TransformOverloadExprDecls(Old, Old->requiresADL(), R)) return ExprError(); // Rebuild the nested-name qualifier, if present. CXXScopeSpec SS; if (Old->getQualifierLoc()) { NestedNameSpecifierLoc QualifierLoc = getDerived().TransformNestedNameSpecifierLoc(Old->getQualifierLoc()); if (!QualifierLoc) return ExprError(); SS.Adopt(QualifierLoc); } if (Old->getNamingClass()) { CXXRecordDecl *NamingClass = cast_or_null(getDerived().TransformDecl( Old->getNameLoc(), Old->getNamingClass())); if (!NamingClass) { R.clear(); return ExprError(); } R.setNamingClass(NamingClass); } SourceLocation TemplateKWLoc = Old->getTemplateKeywordLoc(); // If we have neither explicit template arguments, nor the template keyword, // it's a normal declaration name or member reference. if (!Old->hasExplicitTemplateArgs() && !TemplateKWLoc.isValid()) { NamedDecl *D = R.getAsSingle(); // In a C++11 unevaluated context, an UnresolvedLookupExpr might refer to an // instance member. In other contexts, BuildPossibleImplicitMemberExpr will // give a good diagnostic. if (D && D->isCXXInstanceMember()) { return SemaRef.BuildPossibleImplicitMemberExpr(SS, TemplateKWLoc, R, /*TemplateArgs=*/nullptr, /*Scope=*/nullptr); } return getDerived().RebuildDeclarationNameExpr(SS, R, Old->requiresADL()); } // If we have template arguments, rebuild them, then rebuild the // templateid expression. TemplateArgumentListInfo TransArgs(Old->getLAngleLoc(), Old->getRAngleLoc()); if (Old->hasExplicitTemplateArgs() && getDerived().TransformTemplateArguments(Old->getTemplateArgs(), Old->getNumTemplateArgs(), TransArgs)) { R.clear(); return ExprError(); } return getDerived().RebuildTemplateIdExpr(SS, TemplateKWLoc, R, Old->requiresADL(), &TransArgs); } template ExprResult TreeTransform::TransformTypeTraitExpr(TypeTraitExpr *E) { bool ArgChanged = false; SmallVector Args; for (unsigned I = 0, N = E->getNumArgs(); I != N; ++I) { TypeSourceInfo *From = E->getArg(I); TypeLoc FromTL = From->getTypeLoc(); if (!FromTL.getAs()) { TypeLocBuilder TLB; TLB.reserve(FromTL.getFullDataSize()); QualType To = getDerived().TransformType(TLB, FromTL); if (To.isNull()) return ExprError(); if (To == From->getType()) Args.push_back(From); else { Args.push_back(TLB.getTypeSourceInfo(SemaRef.Context, To)); ArgChanged = true; } continue; } ArgChanged = true; // We have a pack expansion. Instantiate it. PackExpansionTypeLoc ExpansionTL = FromTL.castAs(); TypeLoc PatternTL = ExpansionTL.getPatternLoc(); SmallVector Unexpanded; SemaRef.collectUnexpandedParameterPacks(PatternTL, Unexpanded); // Determine whether the set of unexpanded parameter packs can and should // be expanded. bool Expand = true; bool RetainExpansion = false; Optional OrigNumExpansions = ExpansionTL.getTypePtr()->getNumExpansions(); Optional NumExpansions = OrigNumExpansions; if (getDerived().TryExpandParameterPacks(ExpansionTL.getEllipsisLoc(), PatternTL.getSourceRange(), Unexpanded, Expand, RetainExpansion, NumExpansions)) return ExprError(); if (!Expand) { // The transform has determined that we should perform a simple // transformation on the pack expansion, producing another pack // expansion. Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), -1); TypeLocBuilder TLB; TLB.reserve(From->getTypeLoc().getFullDataSize()); QualType To = getDerived().TransformType(TLB, PatternTL); if (To.isNull()) return ExprError(); To = getDerived().RebuildPackExpansionType(To, PatternTL.getSourceRange(), ExpansionTL.getEllipsisLoc(), NumExpansions); if (To.isNull()) return ExprError(); PackExpansionTypeLoc ToExpansionTL = TLB.push(To); ToExpansionTL.setEllipsisLoc(ExpansionTL.getEllipsisLoc()); Args.push_back(TLB.getTypeSourceInfo(SemaRef.Context, To)); continue; } // Expand the pack expansion by substituting for each argument in the // pack(s). for (unsigned I = 0; I != *NumExpansions; ++I) { Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(SemaRef, I); TypeLocBuilder TLB; TLB.reserve(PatternTL.getFullDataSize()); QualType To = getDerived().TransformType(TLB, PatternTL); if (To.isNull()) return ExprError(); if (To->containsUnexpandedParameterPack()) { To = getDerived().RebuildPackExpansionType(To, PatternTL.getSourceRange(), ExpansionTL.getEllipsisLoc(), NumExpansions); if (To.isNull()) return ExprError(); PackExpansionTypeLoc ToExpansionTL = TLB.push(To); ToExpansionTL.setEllipsisLoc(ExpansionTL.getEllipsisLoc()); } Args.push_back(TLB.getTypeSourceInfo(SemaRef.Context, To)); } if (!RetainExpansion) continue; // If we're supposed to retain a pack expansion, do so by temporarily // forgetting the partially-substituted parameter pack. ForgetPartiallySubstitutedPackRAII Forget(getDerived()); TypeLocBuilder TLB; TLB.reserve(From->getTypeLoc().getFullDataSize()); QualType To = getDerived().TransformType(TLB, PatternTL); if (To.isNull()) return ExprError(); To = getDerived().RebuildPackExpansionType(To, PatternTL.getSourceRange(), ExpansionTL.getEllipsisLoc(), NumExpansions); if (To.isNull()) return ExprError(); PackExpansionTypeLoc ToExpansionTL = TLB.push(To); ToExpansionTL.setEllipsisLoc(ExpansionTL.getEllipsisLoc()); Args.push_back(TLB.getTypeSourceInfo(SemaRef.Context, To)); } if (!getDerived().AlwaysRebuild() && !ArgChanged) return E; return getDerived().RebuildTypeTrait(E->getTrait(), E->getBeginLoc(), Args, E->getEndLoc()); } template ExprResult TreeTransform::TransformConceptSpecializationExpr( ConceptSpecializationExpr *E) { const ASTTemplateArgumentListInfo *Old = E->getTemplateArgsAsWritten(); TemplateArgumentListInfo TransArgs(Old->LAngleLoc, Old->RAngleLoc); if (getDerived().TransformTemplateArguments(Old->getTemplateArgs(), Old->NumTemplateArgs, TransArgs)) return ExprError(); return getDerived().RebuildConceptSpecializationExpr( E->getNestedNameSpecifierLoc(), E->getTemplateKWLoc(), E->getConceptNameInfo(), E->getFoundDecl(), E->getNamedConcept(), &TransArgs); } template ExprResult TreeTransform::TransformRequiresExpr(RequiresExpr *E) { SmallVector TransParams; SmallVector TransParamTypes; Sema::ExtParameterInfoBuilder ExtParamInfos; // C++2a [expr.prim.req]p2 // Expressions appearing within a requirement-body are unevaluated operands. EnterExpressionEvaluationContext Ctx( SemaRef, Sema::ExpressionEvaluationContext::Unevaluated); RequiresExprBodyDecl *Body = RequiresExprBodyDecl::Create( getSema().Context, E->getBody()->getDeclContext(), E->getBody()->getBeginLoc()); Sema::ContextRAII SavedContext(getSema(), Body, /*NewThisContext*/false); if (getDerived().TransformFunctionTypeParams(E->getRequiresKWLoc(), E->getLocalParameters(), /*ParamTypes=*/nullptr, /*ParamInfos=*/nullptr, TransParamTypes, &TransParams, ExtParamInfos)) return ExprError(); for (ParmVarDecl *Param : TransParams) Param->setDeclContext(Body); SmallVector TransReqs; if (getDerived().TransformRequiresExprRequirements(E->getRequirements(), TransReqs)) return ExprError(); for (concepts::Requirement *Req : TransReqs) { if (auto *ER = dyn_cast(Req)) { if (ER->getReturnTypeRequirement().isTypeConstraint()) { ER->getReturnTypeRequirement() .getTypeConstraintTemplateParameterList()->getParam(0) ->setDeclContext(Body); } } } return getDerived().RebuildRequiresExpr(E->getRequiresKWLoc(), Body, TransParams, TransReqs, E->getRBraceLoc()); } template bool TreeTransform::TransformRequiresExprRequirements( ArrayRef Reqs, SmallVectorImpl &Transformed) { for (concepts::Requirement *Req : Reqs) { concepts::Requirement *TransReq = nullptr; if (auto *TypeReq = dyn_cast(Req)) TransReq = getDerived().TransformTypeRequirement(TypeReq); else if (auto *ExprReq = dyn_cast(Req)) TransReq = getDerived().TransformExprRequirement(ExprReq); else TransReq = getDerived().TransformNestedRequirement( cast(Req)); if (!TransReq) return true; Transformed.push_back(TransReq); } return false; } template concepts::TypeRequirement * TreeTransform::TransformTypeRequirement( concepts::TypeRequirement *Req) { if (Req->isSubstitutionFailure()) { if (getDerived().AlwaysRebuild()) return getDerived().RebuildTypeRequirement( Req->getSubstitutionDiagnostic()); return Req; } TypeSourceInfo *TransType = getDerived().TransformType(Req->getType()); if (!TransType) return nullptr; return getDerived().RebuildTypeRequirement(TransType); } template concepts::ExprRequirement * TreeTransform::TransformExprRequirement(concepts::ExprRequirement *Req) { llvm::PointerUnion TransExpr; if (Req->isExprSubstitutionFailure()) TransExpr = Req->getExprSubstitutionDiagnostic(); else { ExprResult TransExprRes = getDerived().TransformExpr(Req->getExpr()); if (TransExprRes.isInvalid()) return nullptr; TransExpr = TransExprRes.get(); } llvm::Optional TransRetReq; const auto &RetReq = Req->getReturnTypeRequirement(); if (RetReq.isEmpty()) TransRetReq.emplace(); else if (RetReq.isSubstitutionFailure()) TransRetReq.emplace(RetReq.getSubstitutionDiagnostic()); else if (RetReq.isTypeConstraint()) { TemplateParameterList *OrigTPL = RetReq.getTypeConstraintTemplateParameterList(); TemplateParameterList *TPL = getDerived().TransformTemplateParameterList(OrigTPL); if (!TPL) return nullptr; TransRetReq.emplace(TPL); } assert(TransRetReq.hasValue() && "All code paths leading here must set TransRetReq"); if (Expr *E = TransExpr.dyn_cast()) return getDerived().RebuildExprRequirement(E, Req->isSimple(), Req->getNoexceptLoc(), std::move(*TransRetReq)); return getDerived().RebuildExprRequirement( TransExpr.get(), Req->isSimple(), Req->getNoexceptLoc(), std::move(*TransRetReq)); } template concepts::NestedRequirement * TreeTransform::TransformNestedRequirement( concepts::NestedRequirement *Req) { if (Req->isSubstitutionFailure()) { if (getDerived().AlwaysRebuild()) return getDerived().RebuildNestedRequirement( Req->getSubstitutionDiagnostic()); return Req; } ExprResult TransConstraint = getDerived().TransformExpr(Req->getConstraintExpr()); if (TransConstraint.isInvalid()) return nullptr; return getDerived().RebuildNestedRequirement(TransConstraint.get()); } template ExprResult TreeTransform::TransformArrayTypeTraitExpr(ArrayTypeTraitExpr *E) { TypeSourceInfo *T = getDerived().TransformType(E->getQueriedTypeSourceInfo()); if (!T) return ExprError(); if (!getDerived().AlwaysRebuild() && T == E->getQueriedTypeSourceInfo()) return E; ExprResult SubExpr; { EnterExpressionEvaluationContext Unevaluated( SemaRef, Sema::ExpressionEvaluationContext::Unevaluated); SubExpr = getDerived().TransformExpr(E->getDimensionExpression()); if (SubExpr.isInvalid()) return ExprError(); if (!getDerived().AlwaysRebuild() && SubExpr.get() == E->getDimensionExpression()) return E; } return getDerived().RebuildArrayTypeTrait(E->getTrait(), E->getBeginLoc(), T, SubExpr.get(), E->getEndLoc()); } template ExprResult TreeTransform::TransformExpressionTraitExpr(ExpressionTraitExpr *E) { ExprResult SubExpr; { EnterExpressionEvaluationContext Unevaluated( SemaRef, Sema::ExpressionEvaluationContext::Unevaluated); SubExpr = getDerived().TransformExpr(E->getQueriedExpression()); if (SubExpr.isInvalid()) return ExprError(); if (!getDerived().AlwaysRebuild() && SubExpr.get() == E->getQueriedExpression()) return E; } return getDerived().RebuildExpressionTrait(E->getTrait(), E->getBeginLoc(), SubExpr.get(), E->getEndLoc()); } template ExprResult TreeTransform::TransformParenDependentScopeDeclRefExpr( ParenExpr *PE, DependentScopeDeclRefExpr *DRE, bool AddrTaken, TypeSourceInfo **RecoveryTSI) { ExprResult NewDRE = getDerived().TransformDependentScopeDeclRefExpr( DRE, AddrTaken, RecoveryTSI); // Propagate both errors and recovered types, which return ExprEmpty. if (!NewDRE.isUsable()) return NewDRE; // We got an expr, wrap it up in parens. if (!getDerived().AlwaysRebuild() && NewDRE.get() == DRE) return PE; return getDerived().RebuildParenExpr(NewDRE.get(), PE->getLParen(), PE->getRParen()); } template ExprResult TreeTransform::TransformDependentScopeDeclRefExpr( DependentScopeDeclRefExpr *E) { return TransformDependentScopeDeclRefExpr(E, /*IsAddressOfOperand=*/false, nullptr); } template ExprResult TreeTransform::TransformDependentScopeDeclRefExpr( DependentScopeDeclRefExpr *E, bool IsAddressOfOperand, TypeSourceInfo **RecoveryTSI) { assert(E->getQualifierLoc()); NestedNameSpecifierLoc QualifierLoc = getDerived().TransformNestedNameSpecifierLoc(E->getQualifierLoc()); if (!QualifierLoc) return ExprError(); SourceLocation TemplateKWLoc = E->getTemplateKeywordLoc(); // TODO: If this is a conversion-function-id, verify that the // destination type name (if present) resolves the same way after // instantiation as it did in the local scope. DeclarationNameInfo NameInfo = getDerived().TransformDeclarationNameInfo(E->getNameInfo()); if (!NameInfo.getName()) return ExprError(); if (!E->hasExplicitTemplateArgs()) { if (!getDerived().AlwaysRebuild() && QualifierLoc == E->getQualifierLoc() && // Note: it is sufficient to compare the Name component of NameInfo: // if name has not changed, DNLoc has not changed either. NameInfo.getName() == E->getDeclName()) return E; return getDerived().RebuildDependentScopeDeclRefExpr( QualifierLoc, TemplateKWLoc, NameInfo, /*TemplateArgs=*/nullptr, IsAddressOfOperand, RecoveryTSI); } TemplateArgumentListInfo TransArgs(E->getLAngleLoc(), E->getRAngleLoc()); if (getDerived().TransformTemplateArguments(E->getTemplateArgs(), E->getNumTemplateArgs(), TransArgs)) return ExprError(); return getDerived().RebuildDependentScopeDeclRefExpr( QualifierLoc, TemplateKWLoc, NameInfo, &TransArgs, IsAddressOfOperand, RecoveryTSI); } template ExprResult TreeTransform::TransformCXXConstructExpr(CXXConstructExpr *E) { // CXXConstructExprs other than for list-initialization and // CXXTemporaryObjectExpr are always implicit, so when we have // a 1-argument construction we just transform that argument. if ((E->getNumArgs() == 1 || (E->getNumArgs() > 1 && getDerived().DropCallArgument(E->getArg(1)))) && (!getDerived().DropCallArgument(E->getArg(0))) && !E->isListInitialization()) return getDerived().TransformExpr(E->getArg(0)); TemporaryBase Rebase(*this, /*FIXME*/ E->getBeginLoc(), DeclarationName()); QualType T = getDerived().TransformType(E->getType()); if (T.isNull()) return ExprError(); CXXConstructorDecl *Constructor = cast_or_null( getDerived().TransformDecl(E->getBeginLoc(), E->getConstructor())); if (!Constructor) return ExprError(); bool ArgumentChanged = false; SmallVector Args; { EnterExpressionEvaluationContext Context( getSema(), EnterExpressionEvaluationContext::InitList, E->isListInitialization()); if (getDerived().TransformExprs(E->getArgs(), E->getNumArgs(), true, Args, &ArgumentChanged)) return ExprError(); } if (!getDerived().AlwaysRebuild() && T == E->getType() && Constructor == E->getConstructor() && !ArgumentChanged) { // Mark the constructor as referenced. // FIXME: Instantiation-specific SemaRef.MarkFunctionReferenced(E->getBeginLoc(), Constructor); return E; } return getDerived().RebuildCXXConstructExpr( T, /*FIXME:*/ E->getBeginLoc(), Constructor, E->isElidable(), Args, E->hadMultipleCandidates(), E->isListInitialization(), E->isStdInitListInitialization(), E->requiresZeroInitialization(), E->getConstructionKind(), E->getParenOrBraceRange()); } template ExprResult TreeTransform::TransformCXXInheritedCtorInitExpr( CXXInheritedCtorInitExpr *E) { QualType T = getDerived().TransformType(E->getType()); if (T.isNull()) return ExprError(); CXXConstructorDecl *Constructor = cast_or_null( getDerived().TransformDecl(E->getBeginLoc(), E->getConstructor())); if (!Constructor) return ExprError(); if (!getDerived().AlwaysRebuild() && T == E->getType() && Constructor == E->getConstructor()) { // Mark the constructor as referenced. // FIXME: Instantiation-specific SemaRef.MarkFunctionReferenced(E->getBeginLoc(), Constructor); return E; } return getDerived().RebuildCXXInheritedCtorInitExpr( T, E->getLocation(), Constructor, E->constructsVBase(), E->inheritedFromVBase()); } /// Transform a C++ temporary-binding expression. /// /// Since CXXBindTemporaryExpr nodes are implicitly generated, we just /// transform the subexpression and return that. template ExprResult TreeTransform::TransformCXXBindTemporaryExpr(CXXBindTemporaryExpr *E) { return getDerived().TransformExpr(E->getSubExpr()); } /// Transform a C++ expression that contains cleanups that should /// be run after the expression is evaluated. /// /// Since ExprWithCleanups nodes are implicitly generated, we /// just transform the subexpression and return that. template ExprResult TreeTransform::TransformExprWithCleanups(ExprWithCleanups *E) { return getDerived().TransformExpr(E->getSubExpr()); } template ExprResult TreeTransform::TransformCXXTemporaryObjectExpr( CXXTemporaryObjectExpr *E) { TypeSourceInfo *T = getDerived().TransformTypeWithDeducedTST(E->getTypeSourceInfo()); if (!T) return ExprError(); CXXConstructorDecl *Constructor = cast_or_null( getDerived().TransformDecl(E->getBeginLoc(), E->getConstructor())); if (!Constructor) return ExprError(); bool ArgumentChanged = false; SmallVector Args; Args.reserve(E->getNumArgs()); { EnterExpressionEvaluationContext Context( getSema(), EnterExpressionEvaluationContext::InitList, E->isListInitialization()); if (TransformExprs(E->getArgs(), E->getNumArgs(), true, Args, &ArgumentChanged)) return ExprError(); } if (!getDerived().AlwaysRebuild() && T == E->getTypeSourceInfo() && Constructor == E->getConstructor() && !ArgumentChanged) { // FIXME: Instantiation-specific SemaRef.MarkFunctionReferenced(E->getBeginLoc(), Constructor); return SemaRef.MaybeBindToTemporary(E); } // FIXME: We should just pass E->isListInitialization(), but we're not // prepared to handle list-initialization without a child InitListExpr. SourceLocation LParenLoc = T->getTypeLoc().getEndLoc(); return getDerived().RebuildCXXTemporaryObjectExpr( T, LParenLoc, Args, E->getEndLoc(), /*ListInitialization=*/LParenLoc.isInvalid()); } template ExprResult TreeTransform::TransformLambdaExpr(LambdaExpr *E) { // Transform any init-capture expressions before entering the scope of the // lambda body, because they are not semantically within that scope. typedef std::pair InitCaptureInfoTy; struct TransformedInitCapture { // The location of the ... if the result is retaining a pack expansion. SourceLocation EllipsisLoc; // Zero or more expansions of the init-capture. SmallVector Expansions; }; SmallVector InitCaptures; InitCaptures.resize(E->explicit_capture_end() - E->explicit_capture_begin()); for (LambdaExpr::capture_iterator C = E->capture_begin(), CEnd = E->capture_end(); C != CEnd; ++C) { if (!E->isInitCapture(C)) continue; TransformedInitCapture &Result = InitCaptures[C - E->capture_begin()]; VarDecl *OldVD = C->getCapturedVar(); auto SubstInitCapture = [&](SourceLocation EllipsisLoc, Optional NumExpansions) { ExprResult NewExprInitResult = getDerived().TransformInitializer( OldVD->getInit(), OldVD->getInitStyle() == VarDecl::CallInit); if (NewExprInitResult.isInvalid()) { Result.Expansions.push_back(InitCaptureInfoTy(ExprError(), QualType())); return; } Expr *NewExprInit = NewExprInitResult.get(); QualType NewInitCaptureType = getSema().buildLambdaInitCaptureInitialization( C->getLocation(), OldVD->getType()->isReferenceType(), EllipsisLoc, NumExpansions, OldVD->getIdentifier(), C->getCapturedVar()->getInitStyle() != VarDecl::CInit, NewExprInit); Result.Expansions.push_back( InitCaptureInfoTy(NewExprInit, NewInitCaptureType)); }; // If this is an init-capture pack, consider expanding the pack now. if (OldVD->isParameterPack()) { PackExpansionTypeLoc ExpansionTL = OldVD->getTypeSourceInfo() ->getTypeLoc() .castAs(); SmallVector Unexpanded; SemaRef.collectUnexpandedParameterPacks(OldVD->getInit(), Unexpanded); // Determine whether the set of unexpanded parameter packs can and should // be expanded. bool Expand = true; bool RetainExpansion = false; Optional OrigNumExpansions = ExpansionTL.getTypePtr()->getNumExpansions(); Optional NumExpansions = OrigNumExpansions; if (getDerived().TryExpandParameterPacks( ExpansionTL.getEllipsisLoc(), OldVD->getInit()->getSourceRange(), Unexpanded, Expand, RetainExpansion, NumExpansions)) return ExprError(); if (Expand) { for (unsigned I = 0; I != *NumExpansions; ++I) { Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), I); SubstInitCapture(SourceLocation(), None); } } if (!Expand || RetainExpansion) { ForgetPartiallySubstitutedPackRAII Forget(getDerived()); SubstInitCapture(ExpansionTL.getEllipsisLoc(), NumExpansions); Result.EllipsisLoc = ExpansionTL.getEllipsisLoc(); } } else { SubstInitCapture(SourceLocation(), None); } } LambdaScopeInfo *LSI = getSema().PushLambdaScope(); Sema::FunctionScopeRAII FuncScopeCleanup(getSema()); // Transform the template parameters, and add them to the current // instantiation scope. The null case is handled correctly. auto TPL = getDerived().TransformTemplateParameterList( E->getTemplateParameterList()); LSI->GLTemplateParameterList = TPL; // Transform the type of the original lambda's call operator. // The transformation MUST be done in the CurrentInstantiationScope since // it introduces a mapping of the original to the newly created // transformed parameters. TypeSourceInfo *NewCallOpTSI = nullptr; { TypeSourceInfo *OldCallOpTSI = E->getCallOperator()->getTypeSourceInfo(); FunctionProtoTypeLoc OldCallOpFPTL = OldCallOpTSI->getTypeLoc().getAs(); TypeLocBuilder NewCallOpTLBuilder; SmallVector ExceptionStorage; TreeTransform *This = this; // Work around gcc.gnu.org/PR56135. QualType NewCallOpType = TransformFunctionProtoType( NewCallOpTLBuilder, OldCallOpFPTL, nullptr, Qualifiers(), [&](FunctionProtoType::ExceptionSpecInfo &ESI, bool &Changed) { return This->TransformExceptionSpec(OldCallOpFPTL.getBeginLoc(), ESI, ExceptionStorage, Changed); }); if (NewCallOpType.isNull()) return ExprError(); NewCallOpTSI = NewCallOpTLBuilder.getTypeSourceInfo(getSema().Context, NewCallOpType); } // Transform the trailing requires clause ExprResult NewTrailingRequiresClause; if (Expr *TRC = E->getCallOperator()->getTrailingRequiresClause()) // FIXME: Concepts: Substitution into requires clause should only happen // when checking satisfaction. NewTrailingRequiresClause = getDerived().TransformExpr(TRC); // Create the local class that will describe the lambda. + // FIXME: KnownDependent below is wrong when substituting inside a templated + // context that isn't a DeclContext (such as a variable template). CXXRecordDecl *OldClass = E->getLambdaClass(); CXXRecordDecl *Class = getSema().createLambdaClosureType(E->getIntroducerRange(), NewCallOpTSI, /*KnownDependent=*/false, E->getCaptureDefault()); getDerived().transformedLocalDecl(OldClass, {Class}); Optional> Mangling; if (getDerived().ReplacingOriginal()) Mangling = std::make_tuple(OldClass->getLambdaManglingNumber(), OldClass->hasKnownLambdaInternalLinkage(), OldClass->getLambdaContextDecl()); // Build the call operator. CXXMethodDecl *NewCallOperator = getSema().startLambdaDefinition( Class, E->getIntroducerRange(), NewCallOpTSI, E->getCallOperator()->getEndLoc(), NewCallOpTSI->getTypeLoc().castAs().getParams(), E->getCallOperator()->getConstexprKind(), NewTrailingRequiresClause.get()); LSI->CallOperator = NewCallOperator; for (unsigned I = 0, NumParams = NewCallOperator->getNumParams(); I != NumParams; ++I) { auto *P = NewCallOperator->getParamDecl(I); if (P->hasUninstantiatedDefaultArg()) { EnterExpressionEvaluationContext Eval( getSema(), Sema::ExpressionEvaluationContext::PotentiallyEvaluatedIfUsed, P); ExprResult R = getDerived().TransformExpr( E->getCallOperator()->getParamDecl(I)->getDefaultArg()); P->setDefaultArg(R.get()); } } getDerived().transformAttrs(E->getCallOperator(), NewCallOperator); getDerived().transformedLocalDecl(E->getCallOperator(), {NewCallOperator}); // Number the lambda for linkage purposes if necessary. getSema().handleLambdaNumbering(Class, NewCallOperator, Mangling); // Introduce the context of the call operator. Sema::ContextRAII SavedContext(getSema(), NewCallOperator, /*NewThisContext*/false); // Enter the scope of the lambda. getSema().buildLambdaScope(LSI, NewCallOperator, E->getIntroducerRange(), E->getCaptureDefault(), E->getCaptureDefaultLoc(), E->hasExplicitParameters(), E->hasExplicitResultType(), E->isMutable()); bool Invalid = false; // Transform captures. for (LambdaExpr::capture_iterator C = E->capture_begin(), CEnd = E->capture_end(); C != CEnd; ++C) { // When we hit the first implicit capture, tell Sema that we've finished // the list of explicit captures. if (C->isImplicit()) break; // Capturing 'this' is trivial. if (C->capturesThis()) { getSema().CheckCXXThisCapture(C->getLocation(), C->isExplicit(), /*BuildAndDiagnose*/ true, nullptr, C->getCaptureKind() == LCK_StarThis); continue; } // Captured expression will be recaptured during captured variables // rebuilding. if (C->capturesVLAType()) continue; // Rebuild init-captures, including the implied field declaration. if (E->isInitCapture(C)) { TransformedInitCapture &NewC = InitCaptures[C - E->capture_begin()]; VarDecl *OldVD = C->getCapturedVar(); llvm::SmallVector NewVDs; for (InitCaptureInfoTy &Info : NewC.Expansions) { ExprResult Init = Info.first; QualType InitQualType = Info.second; if (Init.isInvalid() || InitQualType.isNull()) { Invalid = true; break; } VarDecl *NewVD = getSema().createLambdaInitCaptureVarDecl( OldVD->getLocation(), InitQualType, NewC.EllipsisLoc, OldVD->getIdentifier(), OldVD->getInitStyle(), Init.get()); if (!NewVD) { Invalid = true; break; } NewVDs.push_back(NewVD); getSema().addInitCapture(LSI, NewVD); } if (Invalid) break; getDerived().transformedLocalDecl(OldVD, NewVDs); continue; } assert(C->capturesVariable() && "unexpected kind of lambda capture"); // Determine the capture kind for Sema. Sema::TryCaptureKind Kind = C->isImplicit()? Sema::TryCapture_Implicit : C->getCaptureKind() == LCK_ByCopy ? Sema::TryCapture_ExplicitByVal : Sema::TryCapture_ExplicitByRef; SourceLocation EllipsisLoc; if (C->isPackExpansion()) { UnexpandedParameterPack Unexpanded(C->getCapturedVar(), C->getLocation()); bool ShouldExpand = false; bool RetainExpansion = false; Optional NumExpansions; if (getDerived().TryExpandParameterPacks(C->getEllipsisLoc(), C->getLocation(), Unexpanded, ShouldExpand, RetainExpansion, NumExpansions)) { Invalid = true; continue; } if (ShouldExpand) { // The transform has determined that we should perform an expansion; // transform and capture each of the arguments. // expansion of the pattern. Do so. VarDecl *Pack = C->getCapturedVar(); for (unsigned I = 0; I != *NumExpansions; ++I) { Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), I); VarDecl *CapturedVar = cast_or_null(getDerived().TransformDecl(C->getLocation(), Pack)); if (!CapturedVar) { Invalid = true; continue; } // Capture the transformed variable. getSema().tryCaptureVariable(CapturedVar, C->getLocation(), Kind); } // FIXME: Retain a pack expansion if RetainExpansion is true. continue; } EllipsisLoc = C->getEllipsisLoc(); } // Transform the captured variable. VarDecl *CapturedVar = cast_or_null(getDerived().TransformDecl(C->getLocation(), C->getCapturedVar())); if (!CapturedVar || CapturedVar->isInvalidDecl()) { Invalid = true; continue; } // Capture the transformed variable. getSema().tryCaptureVariable(CapturedVar, C->getLocation(), Kind, EllipsisLoc); } getSema().finishLambdaExplicitCaptures(LSI); // FIXME: Sema's lambda-building mechanism expects us to push an expression // evaluation context even if we're not transforming the function body. getSema().PushExpressionEvaluationContext( Sema::ExpressionEvaluationContext::PotentiallyEvaluated); // Instantiate the body of the lambda expression. StmtResult Body = Invalid ? StmtError() : getDerived().TransformLambdaBody(E, E->getBody()); // ActOnLambda* will pop the function scope for us. FuncScopeCleanup.disable(); if (Body.isInvalid()) { SavedContext.pop(); getSema().ActOnLambdaError(E->getBeginLoc(), /*CurScope=*/nullptr, /*IsInstantiation=*/true); return ExprError(); } // Copy the LSI before ActOnFinishFunctionBody removes it. // FIXME: This is dumb. Store the lambda information somewhere that outlives // the call operator. auto LSICopy = *LSI; getSema().ActOnFinishFunctionBody(NewCallOperator, Body.get(), /*IsInstantiation*/ true); SavedContext.pop(); return getSema().BuildLambdaExpr(E->getBeginLoc(), Body.get()->getEndLoc(), &LSICopy); } template StmtResult TreeTransform::TransformLambdaBody(LambdaExpr *E, Stmt *S) { return TransformStmt(S); } template StmtResult TreeTransform::SkipLambdaBody(LambdaExpr *E, Stmt *S) { // Transform captures. for (LambdaExpr::capture_iterator C = E->capture_begin(), CEnd = E->capture_end(); C != CEnd; ++C) { // When we hit the first implicit capture, tell Sema that we've finished // the list of explicit captures. if (!C->isImplicit()) continue; // Capturing 'this' is trivial. if (C->capturesThis()) { getSema().CheckCXXThisCapture(C->getLocation(), C->isExplicit(), /*BuildAndDiagnose*/ true, nullptr, C->getCaptureKind() == LCK_StarThis); continue; } // Captured expression will be recaptured during captured variables // rebuilding. if (C->capturesVLAType()) continue; assert(C->capturesVariable() && "unexpected kind of lambda capture"); assert(!E->isInitCapture(C) && "implicit init-capture?"); // Transform the captured variable. VarDecl *CapturedVar = cast_or_null( getDerived().TransformDecl(C->getLocation(), C->getCapturedVar())); if (!CapturedVar || CapturedVar->isInvalidDecl()) return StmtError(); // Capture the transformed variable. getSema().tryCaptureVariable(CapturedVar, C->getLocation()); } return S; } template ExprResult TreeTransform::TransformCXXUnresolvedConstructExpr( CXXUnresolvedConstructExpr *E) { TypeSourceInfo *T = getDerived().TransformTypeWithDeducedTST(E->getTypeSourceInfo()); if (!T) return ExprError(); bool ArgumentChanged = false; SmallVector Args; Args.reserve(E->arg_size()); { EnterExpressionEvaluationContext Context( getSema(), EnterExpressionEvaluationContext::InitList, E->isListInitialization()); if (getDerived().TransformExprs(E->arg_begin(), E->arg_size(), true, Args, &ArgumentChanged)) return ExprError(); } if (!getDerived().AlwaysRebuild() && T == E->getTypeSourceInfo() && !ArgumentChanged) return E; // FIXME: we're faking the locations of the commas return getDerived().RebuildCXXUnresolvedConstructExpr( T, E->getLParenLoc(), Args, E->getRParenLoc(), E->isListInitialization()); } template ExprResult TreeTransform::TransformCXXDependentScopeMemberExpr( CXXDependentScopeMemberExpr *E) { // Transform the base of the expression. ExprResult Base((Expr*) nullptr); Expr *OldBase; QualType BaseType; QualType ObjectType; if (!E->isImplicitAccess()) { OldBase = E->getBase(); Base = getDerived().TransformExpr(OldBase); if (Base.isInvalid()) return ExprError(); // Start the member reference and compute the object's type. ParsedType ObjectTy; bool MayBePseudoDestructor = false; Base = SemaRef.ActOnStartCXXMemberReference(nullptr, Base.get(), E->getOperatorLoc(), E->isArrow()? tok::arrow : tok::period, ObjectTy, MayBePseudoDestructor); if (Base.isInvalid()) return ExprError(); ObjectType = ObjectTy.get(); BaseType = ((Expr*) Base.get())->getType(); } else { OldBase = nullptr; BaseType = getDerived().TransformType(E->getBaseType()); ObjectType = BaseType->castAs()->getPointeeType(); } // Transform the first part of the nested-name-specifier that qualifies // the member name. NamedDecl *FirstQualifierInScope = getDerived().TransformFirstQualifierInScope( E->getFirstQualifierFoundInScope(), E->getQualifierLoc().getBeginLoc()); NestedNameSpecifierLoc QualifierLoc; if (E->getQualifier()) { QualifierLoc = getDerived().TransformNestedNameSpecifierLoc(E->getQualifierLoc(), ObjectType, FirstQualifierInScope); if (!QualifierLoc) return ExprError(); } SourceLocation TemplateKWLoc = E->getTemplateKeywordLoc(); // TODO: If this is a conversion-function-id, verify that the // destination type name (if present) resolves the same way after // instantiation as it did in the local scope. DeclarationNameInfo NameInfo = getDerived().TransformDeclarationNameInfo(E->getMemberNameInfo()); if (!NameInfo.getName()) return ExprError(); if (!E->hasExplicitTemplateArgs()) { // This is a reference to a member without an explicitly-specified // template argument list. Optimize for this common case. if (!getDerived().AlwaysRebuild() && Base.get() == OldBase && BaseType == E->getBaseType() && QualifierLoc == E->getQualifierLoc() && NameInfo.getName() == E->getMember() && FirstQualifierInScope == E->getFirstQualifierFoundInScope()) return E; return getDerived().RebuildCXXDependentScopeMemberExpr(Base.get(), BaseType, E->isArrow(), E->getOperatorLoc(), QualifierLoc, TemplateKWLoc, FirstQualifierInScope, NameInfo, /*TemplateArgs*/nullptr); } TemplateArgumentListInfo TransArgs(E->getLAngleLoc(), E->getRAngleLoc()); if (getDerived().TransformTemplateArguments(E->getTemplateArgs(), E->getNumTemplateArgs(), TransArgs)) return ExprError(); return getDerived().RebuildCXXDependentScopeMemberExpr(Base.get(), BaseType, E->isArrow(), E->getOperatorLoc(), QualifierLoc, TemplateKWLoc, FirstQualifierInScope, NameInfo, &TransArgs); } template ExprResult TreeTransform::TransformUnresolvedMemberExpr(UnresolvedMemberExpr *Old) { // Transform the base of the expression. ExprResult Base((Expr*) nullptr); QualType BaseType; if (!Old->isImplicitAccess()) { Base = getDerived().TransformExpr(Old->getBase()); if (Base.isInvalid()) return ExprError(); Base = getSema().PerformMemberExprBaseConversion(Base.get(), Old->isArrow()); if (Base.isInvalid()) return ExprError(); BaseType = Base.get()->getType(); } else { BaseType = getDerived().TransformType(Old->getBaseType()); } NestedNameSpecifierLoc QualifierLoc; if (Old->getQualifierLoc()) { QualifierLoc = getDerived().TransformNestedNameSpecifierLoc(Old->getQualifierLoc()); if (!QualifierLoc) return ExprError(); } SourceLocation TemplateKWLoc = Old->getTemplateKeywordLoc(); LookupResult R(SemaRef, Old->getMemberNameInfo(), Sema::LookupOrdinaryName); // Transform the declaration set. if (TransformOverloadExprDecls(Old, /*RequiresADL*/false, R)) return ExprError(); // Determine the naming class. if (Old->getNamingClass()) { CXXRecordDecl *NamingClass = cast_or_null(getDerived().TransformDecl( Old->getMemberLoc(), Old->getNamingClass())); if (!NamingClass) return ExprError(); R.setNamingClass(NamingClass); } TemplateArgumentListInfo TransArgs; if (Old->hasExplicitTemplateArgs()) { TransArgs.setLAngleLoc(Old->getLAngleLoc()); TransArgs.setRAngleLoc(Old->getRAngleLoc()); if (getDerived().TransformTemplateArguments(Old->getTemplateArgs(), Old->getNumTemplateArgs(), TransArgs)) return ExprError(); } // FIXME: to do this check properly, we will need to preserve the // first-qualifier-in-scope here, just in case we had a dependent // base (and therefore couldn't do the check) and a // nested-name-qualifier (and therefore could do the lookup). NamedDecl *FirstQualifierInScope = nullptr; return getDerived().RebuildUnresolvedMemberExpr(Base.get(), BaseType, Old->getOperatorLoc(), Old->isArrow(), QualifierLoc, TemplateKWLoc, FirstQualifierInScope, R, (Old->hasExplicitTemplateArgs() ? &TransArgs : nullptr)); } template ExprResult TreeTransform::TransformCXXNoexceptExpr(CXXNoexceptExpr *E) { EnterExpressionEvaluationContext Unevaluated( SemaRef, Sema::ExpressionEvaluationContext::Unevaluated); ExprResult SubExpr = getDerived().TransformExpr(E->getOperand()); if (SubExpr.isInvalid()) return ExprError(); if (!getDerived().AlwaysRebuild() && SubExpr.get() == E->getOperand()) return E; return getDerived().RebuildCXXNoexceptExpr(E->getSourceRange(),SubExpr.get()); } template ExprResult TreeTransform::TransformPackExpansionExpr(PackExpansionExpr *E) { ExprResult Pattern = getDerived().TransformExpr(E->getPattern()); if (Pattern.isInvalid()) return ExprError(); if (!getDerived().AlwaysRebuild() && Pattern.get() == E->getPattern()) return E; return getDerived().RebuildPackExpansion(Pattern.get(), E->getEllipsisLoc(), E->getNumExpansions()); } template ExprResult TreeTransform::TransformSizeOfPackExpr(SizeOfPackExpr *E) { // If E is not value-dependent, then nothing will change when we transform it. // Note: This is an instantiation-centric view. if (!E->isValueDependent()) return E; EnterExpressionEvaluationContext Unevaluated( getSema(), Sema::ExpressionEvaluationContext::Unevaluated); ArrayRef PackArgs; TemplateArgument ArgStorage; // Find the argument list to transform. if (E->isPartiallySubstituted()) { PackArgs = E->getPartialArguments(); } else if (E->isValueDependent()) { UnexpandedParameterPack Unexpanded(E->getPack(), E->getPackLoc()); bool ShouldExpand = false; bool RetainExpansion = false; Optional NumExpansions; if (getDerived().TryExpandParameterPacks(E->getOperatorLoc(), E->getPackLoc(), Unexpanded, ShouldExpand, RetainExpansion, NumExpansions)) return ExprError(); // If we need to expand the pack, build a template argument from it and // expand that. if (ShouldExpand) { auto *Pack = E->getPack(); if (auto *TTPD = dyn_cast(Pack)) { ArgStorage = getSema().Context.getPackExpansionType( getSema().Context.getTypeDeclType(TTPD), None); } else if (auto *TTPD = dyn_cast(Pack)) { ArgStorage = TemplateArgument(TemplateName(TTPD), None); } else { auto *VD = cast(Pack); ExprResult DRE = getSema().BuildDeclRefExpr( VD, VD->getType().getNonLValueExprType(getSema().Context), VD->getType()->isReferenceType() ? VK_LValue : VK_RValue, E->getPackLoc()); if (DRE.isInvalid()) return ExprError(); ArgStorage = new (getSema().Context) PackExpansionExpr( getSema().Context.DependentTy, DRE.get(), E->getPackLoc(), None); } PackArgs = ArgStorage; } } // If we're not expanding the pack, just transform the decl. if (!PackArgs.size()) { auto *Pack = cast_or_null( getDerived().TransformDecl(E->getPackLoc(), E->getPack())); if (!Pack) return ExprError(); return getDerived().RebuildSizeOfPackExpr(E->getOperatorLoc(), Pack, E->getPackLoc(), E->getRParenLoc(), None, None); } // Try to compute the result without performing a partial substitution. Optional Result = 0; for (const TemplateArgument &Arg : PackArgs) { if (!Arg.isPackExpansion()) { Result = *Result + 1; continue; } TemplateArgumentLoc ArgLoc; InventTemplateArgumentLoc(Arg, ArgLoc); // Find the pattern of the pack expansion. SourceLocation Ellipsis; Optional OrigNumExpansions; TemplateArgumentLoc Pattern = getSema().getTemplateArgumentPackExpansionPattern(ArgLoc, Ellipsis, OrigNumExpansions); // Substitute under the pack expansion. Do not expand the pack (yet). TemplateArgumentLoc OutPattern; Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), -1); if (getDerived().TransformTemplateArgument(Pattern, OutPattern, /*Uneval*/ true)) return true; // See if we can determine the number of arguments from the result. Optional NumExpansions = getSema().getFullyPackExpandedSize(OutPattern.getArgument()); if (!NumExpansions) { // No: we must be in an alias template expansion, and we're going to need // to actually expand the packs. Result = None; break; } Result = *Result + *NumExpansions; } // Common case: we could determine the number of expansions without // substituting. if (Result) return getDerived().RebuildSizeOfPackExpr(E->getOperatorLoc(), E->getPack(), E->getPackLoc(), E->getRParenLoc(), *Result, None); TemplateArgumentListInfo TransformedPackArgs(E->getPackLoc(), E->getPackLoc()); { TemporaryBase Rebase(*this, E->getPackLoc(), getBaseEntity()); typedef TemplateArgumentLocInventIterator< Derived, const TemplateArgument*> PackLocIterator; if (TransformTemplateArguments(PackLocIterator(*this, PackArgs.begin()), PackLocIterator(*this, PackArgs.end()), TransformedPackArgs, /*Uneval*/true)) return ExprError(); } // Check whether we managed to fully-expand the pack. // FIXME: Is it possible for us to do so and not hit the early exit path? SmallVector Args; bool PartialSubstitution = false; for (auto &Loc : TransformedPackArgs.arguments()) { Args.push_back(Loc.getArgument()); if (Loc.getArgument().isPackExpansion()) PartialSubstitution = true; } if (PartialSubstitution) return getDerived().RebuildSizeOfPackExpr(E->getOperatorLoc(), E->getPack(), E->getPackLoc(), E->getRParenLoc(), None, Args); return getDerived().RebuildSizeOfPackExpr(E->getOperatorLoc(), E->getPack(), E->getPackLoc(), E->getRParenLoc(), Args.size(), None); } template ExprResult TreeTransform::TransformSubstNonTypeTemplateParmPackExpr( SubstNonTypeTemplateParmPackExpr *E) { // Default behavior is to do nothing with this transformation. return E; } template ExprResult TreeTransform::TransformSubstNonTypeTemplateParmExpr( SubstNonTypeTemplateParmExpr *E) { // Default behavior is to do nothing with this transformation. return E; } template ExprResult TreeTransform::TransformFunctionParmPackExpr(FunctionParmPackExpr *E) { // Default behavior is to do nothing with this transformation. return E; } template ExprResult TreeTransform::TransformMaterializeTemporaryExpr( MaterializeTemporaryExpr *E) { return getDerived().TransformExpr(E->getSubExpr()); } template ExprResult TreeTransform::TransformCXXFoldExpr(CXXFoldExpr *E) { Expr *Pattern = E->getPattern(); SmallVector Unexpanded; getSema().collectUnexpandedParameterPacks(Pattern, Unexpanded); assert(!Unexpanded.empty() && "Pack expansion without parameter packs?"); // Determine whether the set of unexpanded parameter packs can and should // be expanded. bool Expand = true; bool RetainExpansion = false; Optional OrigNumExpansions = E->getNumExpansions(), NumExpansions = OrigNumExpansions; if (getDerived().TryExpandParameterPacks(E->getEllipsisLoc(), Pattern->getSourceRange(), Unexpanded, Expand, RetainExpansion, NumExpansions)) return true; if (!Expand) { // Do not expand any packs here, just transform and rebuild a fold // expression. Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), -1); ExprResult LHS = E->getLHS() ? getDerived().TransformExpr(E->getLHS()) : ExprResult(); if (LHS.isInvalid()) return true; ExprResult RHS = E->getRHS() ? getDerived().TransformExpr(E->getRHS()) : ExprResult(); if (RHS.isInvalid()) return true; if (!getDerived().AlwaysRebuild() && LHS.get() == E->getLHS() && RHS.get() == E->getRHS()) return E; return getDerived().RebuildCXXFoldExpr( E->getBeginLoc(), LHS.get(), E->getOperator(), E->getEllipsisLoc(), RHS.get(), E->getEndLoc(), NumExpansions); } // The transform has determined that we should perform an elementwise // expansion of the pattern. Do so. ExprResult Result = getDerived().TransformExpr(E->getInit()); if (Result.isInvalid()) return true; bool LeftFold = E->isLeftFold(); // If we're retaining an expansion for a right fold, it is the innermost // component and takes the init (if any). if (!LeftFold && RetainExpansion) { ForgetPartiallySubstitutedPackRAII Forget(getDerived()); ExprResult Out = getDerived().TransformExpr(Pattern); if (Out.isInvalid()) return true; Result = getDerived().RebuildCXXFoldExpr( E->getBeginLoc(), Out.get(), E->getOperator(), E->getEllipsisLoc(), Result.get(), E->getEndLoc(), OrigNumExpansions); if (Result.isInvalid()) return true; } for (unsigned I = 0; I != *NumExpansions; ++I) { Sema::ArgumentPackSubstitutionIndexRAII SubstIndex( getSema(), LeftFold ? I : *NumExpansions - I - 1); ExprResult Out = getDerived().TransformExpr(Pattern); if (Out.isInvalid()) return true; if (Out.get()->containsUnexpandedParameterPack()) { // We still have a pack; retain a pack expansion for this slice. Result = getDerived().RebuildCXXFoldExpr( E->getBeginLoc(), LeftFold ? Result.get() : Out.get(), E->getOperator(), E->getEllipsisLoc(), LeftFold ? Out.get() : Result.get(), E->getEndLoc(), OrigNumExpansions); } else if (Result.isUsable()) { // We've got down to a single element; build a binary operator. Result = getDerived().RebuildBinaryOperator( E->getEllipsisLoc(), E->getOperator(), LeftFold ? Result.get() : Out.get(), LeftFold ? Out.get() : Result.get()); } else Result = Out; if (Result.isInvalid()) return true; } // If we're retaining an expansion for a left fold, it is the outermost // component and takes the complete expansion so far as its init (if any). if (LeftFold && RetainExpansion) { ForgetPartiallySubstitutedPackRAII Forget(getDerived()); ExprResult Out = getDerived().TransformExpr(Pattern); if (Out.isInvalid()) return true; Result = getDerived().RebuildCXXFoldExpr( E->getBeginLoc(), Result.get(), E->getOperator(), E->getEllipsisLoc(), Out.get(), E->getEndLoc(), OrigNumExpansions); if (Result.isInvalid()) return true; } // If we had no init and an empty pack, and we're not retaining an expansion, // then produce a fallback value or error. if (Result.isUnset()) return getDerived().RebuildEmptyCXXFoldExpr(E->getEllipsisLoc(), E->getOperator()); return Result; } template ExprResult TreeTransform::TransformCXXStdInitializerListExpr( CXXStdInitializerListExpr *E) { return getDerived().TransformExpr(E->getSubExpr()); } template ExprResult TreeTransform::TransformObjCStringLiteral(ObjCStringLiteral *E) { return SemaRef.MaybeBindToTemporary(E); } template ExprResult TreeTransform::TransformObjCBoolLiteralExpr(ObjCBoolLiteralExpr *E) { return E; } template ExprResult TreeTransform::TransformObjCBoxedExpr(ObjCBoxedExpr *E) { ExprResult SubExpr = getDerived().TransformExpr(E->getSubExpr()); if (SubExpr.isInvalid()) return ExprError(); if (!getDerived().AlwaysRebuild() && SubExpr.get() == E->getSubExpr()) return E; return getDerived().RebuildObjCBoxedExpr(E->getSourceRange(), SubExpr.get()); } template ExprResult TreeTransform::TransformObjCArrayLiteral(ObjCArrayLiteral *E) { // Transform each of the elements. SmallVector Elements; bool ArgChanged = false; if (getDerived().TransformExprs(E->getElements(), E->getNumElements(), /*IsCall=*/false, Elements, &ArgChanged)) return ExprError(); if (!getDerived().AlwaysRebuild() && !ArgChanged) return SemaRef.MaybeBindToTemporary(E); return getDerived().RebuildObjCArrayLiteral(E->getSourceRange(), Elements.data(), Elements.size()); } template ExprResult TreeTransform::TransformObjCDictionaryLiteral( ObjCDictionaryLiteral *E) { // Transform each of the elements. SmallVector Elements; bool ArgChanged = false; for (unsigned I = 0, N = E->getNumElements(); I != N; ++I) { ObjCDictionaryElement OrigElement = E->getKeyValueElement(I); if (OrigElement.isPackExpansion()) { // This key/value element is a pack expansion. SmallVector Unexpanded; getSema().collectUnexpandedParameterPacks(OrigElement.Key, Unexpanded); getSema().collectUnexpandedParameterPacks(OrigElement.Value, Unexpanded); assert(!Unexpanded.empty() && "Pack expansion without parameter packs?"); // Determine whether the set of unexpanded parameter packs can // and should be expanded. bool Expand = true; bool RetainExpansion = false; Optional OrigNumExpansions = OrigElement.NumExpansions; Optional NumExpansions = OrigNumExpansions; SourceRange PatternRange(OrigElement.Key->getBeginLoc(), OrigElement.Value->getEndLoc()); if (getDerived().TryExpandParameterPacks(OrigElement.EllipsisLoc, PatternRange, Unexpanded, Expand, RetainExpansion, NumExpansions)) return ExprError(); if (!Expand) { // The transform has determined that we should perform a simple // transformation on the pack expansion, producing another pack // expansion. Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), -1); ExprResult Key = getDerived().TransformExpr(OrigElement.Key); if (Key.isInvalid()) return ExprError(); if (Key.get() != OrigElement.Key) ArgChanged = true; ExprResult Value = getDerived().TransformExpr(OrigElement.Value); if (Value.isInvalid()) return ExprError(); if (Value.get() != OrigElement.Value) ArgChanged = true; ObjCDictionaryElement Expansion = { Key.get(), Value.get(), OrigElement.EllipsisLoc, NumExpansions }; Elements.push_back(Expansion); continue; } // Record right away that the argument was changed. This needs // to happen even if the array expands to nothing. ArgChanged = true; // The transform has determined that we should perform an elementwise // expansion of the pattern. Do so. for (unsigned I = 0; I != *NumExpansions; ++I) { Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), I); ExprResult Key = getDerived().TransformExpr(OrigElement.Key); if (Key.isInvalid()) return ExprError(); ExprResult Value = getDerived().TransformExpr(OrigElement.Value); if (Value.isInvalid()) return ExprError(); ObjCDictionaryElement Element = { Key.get(), Value.get(), SourceLocation(), NumExpansions }; // If any unexpanded parameter packs remain, we still have a // pack expansion. // FIXME: Can this really happen? if (Key.get()->containsUnexpandedParameterPack() || Value.get()->containsUnexpandedParameterPack()) Element.EllipsisLoc = OrigElement.EllipsisLoc; Elements.push_back(Element); } // FIXME: Retain a pack expansion if RetainExpansion is true. // We've finished with this pack expansion. continue; } // Transform and check key. ExprResult Key = getDerived().TransformExpr(OrigElement.Key); if (Key.isInvalid()) return ExprError(); if (Key.get() != OrigElement.Key) ArgChanged = true; // Transform and check value. ExprResult Value = getDerived().TransformExpr(OrigElement.Value); if (Value.isInvalid()) return ExprError(); if (Value.get() != OrigElement.Value) ArgChanged = true; ObjCDictionaryElement Element = { Key.get(), Value.get(), SourceLocation(), None }; Elements.push_back(Element); } if (!getDerived().AlwaysRebuild() && !ArgChanged) return SemaRef.MaybeBindToTemporary(E); return getDerived().RebuildObjCDictionaryLiteral(E->getSourceRange(), Elements); } template ExprResult TreeTransform::TransformObjCEncodeExpr(ObjCEncodeExpr *E) { TypeSourceInfo *EncodedTypeInfo = getDerived().TransformType(E->getEncodedTypeSourceInfo()); if (!EncodedTypeInfo) return ExprError(); if (!getDerived().AlwaysRebuild() && EncodedTypeInfo == E->getEncodedTypeSourceInfo()) return E; return getDerived().RebuildObjCEncodeExpr(E->getAtLoc(), EncodedTypeInfo, E->getRParenLoc()); } template ExprResult TreeTransform:: TransformObjCIndirectCopyRestoreExpr(ObjCIndirectCopyRestoreExpr *E) { // This is a kind of implicit conversion, and it needs to get dropped // and recomputed for the same general reasons that ImplicitCastExprs // do, as well a more specific one: this expression is only valid when // it appears *immediately* as an argument expression. return getDerived().TransformExpr(E->getSubExpr()); } template ExprResult TreeTransform:: TransformObjCBridgedCastExpr(ObjCBridgedCastExpr *E) { TypeSourceInfo *TSInfo = getDerived().TransformType(E->getTypeInfoAsWritten()); if (!TSInfo) return ExprError(); ExprResult Result = getDerived().TransformExpr(E->getSubExpr()); if (Result.isInvalid()) return ExprError(); if (!getDerived().AlwaysRebuild() && TSInfo == E->getTypeInfoAsWritten() && Result.get() == E->getSubExpr()) return E; return SemaRef.BuildObjCBridgedCast(E->getLParenLoc(), E->getBridgeKind(), E->getBridgeKeywordLoc(), TSInfo, Result.get()); } template ExprResult TreeTransform::TransformObjCAvailabilityCheckExpr( ObjCAvailabilityCheckExpr *E) { return E; } template ExprResult TreeTransform::TransformObjCMessageExpr(ObjCMessageExpr *E) { // Transform arguments. bool ArgChanged = false; SmallVector Args; Args.reserve(E->getNumArgs()); if (getDerived().TransformExprs(E->getArgs(), E->getNumArgs(), false, Args, &ArgChanged)) return ExprError(); if (E->getReceiverKind() == ObjCMessageExpr::Class) { // Class message: transform the receiver type. TypeSourceInfo *ReceiverTypeInfo = getDerived().TransformType(E->getClassReceiverTypeInfo()); if (!ReceiverTypeInfo) return ExprError(); // If nothing changed, just retain the existing message send. if (!getDerived().AlwaysRebuild() && ReceiverTypeInfo == E->getClassReceiverTypeInfo() && !ArgChanged) return SemaRef.MaybeBindToTemporary(E); // Build a new class message send. SmallVector SelLocs; E->getSelectorLocs(SelLocs); return getDerived().RebuildObjCMessageExpr(ReceiverTypeInfo, E->getSelector(), SelLocs, E->getMethodDecl(), E->getLeftLoc(), Args, E->getRightLoc()); } else if (E->getReceiverKind() == ObjCMessageExpr::SuperClass || E->getReceiverKind() == ObjCMessageExpr::SuperInstance) { if (!E->getMethodDecl()) return ExprError(); // Build a new class message send to 'super'. SmallVector SelLocs; E->getSelectorLocs(SelLocs); return getDerived().RebuildObjCMessageExpr(E->getSuperLoc(), E->getSelector(), SelLocs, E->getReceiverType(), E->getMethodDecl(), E->getLeftLoc(), Args, E->getRightLoc()); } // Instance message: transform the receiver assert(E->getReceiverKind() == ObjCMessageExpr::Instance && "Only class and instance messages may be instantiated"); ExprResult Receiver = getDerived().TransformExpr(E->getInstanceReceiver()); if (Receiver.isInvalid()) return ExprError(); // If nothing changed, just retain the existing message send. if (!getDerived().AlwaysRebuild() && Receiver.get() == E->getInstanceReceiver() && !ArgChanged) return SemaRef.MaybeBindToTemporary(E); // Build a new instance message send. SmallVector SelLocs; E->getSelectorLocs(SelLocs); return getDerived().RebuildObjCMessageExpr(Receiver.get(), E->getSelector(), SelLocs, E->getMethodDecl(), E->getLeftLoc(), Args, E->getRightLoc()); } template ExprResult TreeTransform::TransformObjCSelectorExpr(ObjCSelectorExpr *E) { return E; } template ExprResult TreeTransform::TransformObjCProtocolExpr(ObjCProtocolExpr *E) { return E; } template ExprResult TreeTransform::TransformObjCIvarRefExpr(ObjCIvarRefExpr *E) { // Transform the base expression. ExprResult Base = getDerived().TransformExpr(E->getBase()); if (Base.isInvalid()) return ExprError(); // We don't need to transform the ivar; it will never change. // If nothing changed, just retain the existing expression. if (!getDerived().AlwaysRebuild() && Base.get() == E->getBase()) return E; return getDerived().RebuildObjCIvarRefExpr(Base.get(), E->getDecl(), E->getLocation(), E->isArrow(), E->isFreeIvar()); } template ExprResult TreeTransform::TransformObjCPropertyRefExpr(ObjCPropertyRefExpr *E) { // 'super' and types never change. Property never changes. Just // retain the existing expression. if (!E->isObjectReceiver()) return E; // Transform the base expression. ExprResult Base = getDerived().TransformExpr(E->getBase()); if (Base.isInvalid()) return ExprError(); // We don't need to transform the property; it will never change. // If nothing changed, just retain the existing expression. if (!getDerived().AlwaysRebuild() && Base.get() == E->getBase()) return E; if (E->isExplicitProperty()) return getDerived().RebuildObjCPropertyRefExpr(Base.get(), E->getExplicitProperty(), E->getLocation()); return getDerived().RebuildObjCPropertyRefExpr(Base.get(), SemaRef.Context.PseudoObjectTy, E->getImplicitPropertyGetter(), E->getImplicitPropertySetter(), E->getLocation()); } template ExprResult TreeTransform::TransformObjCSubscriptRefExpr(ObjCSubscriptRefExpr *E) { // Transform the base expression. ExprResult Base = getDerived().TransformExpr(E->getBaseExpr()); if (Base.isInvalid()) return ExprError(); // Transform the key expression. ExprResult Key = getDerived().TransformExpr(E->getKeyExpr()); if (Key.isInvalid()) return ExprError(); // If nothing changed, just retain the existing expression. if (!getDerived().AlwaysRebuild() && Key.get() == E->getKeyExpr() && Base.get() == E->getBaseExpr()) return E; return getDerived().RebuildObjCSubscriptRefExpr(E->getRBracket(), Base.get(), Key.get(), E->getAtIndexMethodDecl(), E->setAtIndexMethodDecl()); } template ExprResult TreeTransform::TransformObjCIsaExpr(ObjCIsaExpr *E) { // Transform the base expression. ExprResult Base = getDerived().TransformExpr(E->getBase()); if (Base.isInvalid()) return ExprError(); // If nothing changed, just retain the existing expression. if (!getDerived().AlwaysRebuild() && Base.get() == E->getBase()) return E; return getDerived().RebuildObjCIsaExpr(Base.get(), E->getIsaMemberLoc(), E->getOpLoc(), E->isArrow()); } template ExprResult TreeTransform::TransformShuffleVectorExpr(ShuffleVectorExpr *E) { bool ArgumentChanged = false; SmallVector SubExprs; SubExprs.reserve(E->getNumSubExprs()); if (getDerived().TransformExprs(E->getSubExprs(), E->getNumSubExprs(), false, SubExprs, &ArgumentChanged)) return ExprError(); if (!getDerived().AlwaysRebuild() && !ArgumentChanged) return E; return getDerived().RebuildShuffleVectorExpr(E->getBuiltinLoc(), SubExprs, E->getRParenLoc()); } template ExprResult TreeTransform::TransformConvertVectorExpr(ConvertVectorExpr *E) { ExprResult SrcExpr = getDerived().TransformExpr(E->getSrcExpr()); if (SrcExpr.isInvalid()) return ExprError(); TypeSourceInfo *Type = getDerived().TransformType(E->getTypeSourceInfo()); if (!Type) return ExprError(); if (!getDerived().AlwaysRebuild() && Type == E->getTypeSourceInfo() && SrcExpr.get() == E->getSrcExpr()) return E; return getDerived().RebuildConvertVectorExpr(E->getBuiltinLoc(), SrcExpr.get(), Type, E->getRParenLoc()); } template ExprResult TreeTransform::TransformBlockExpr(BlockExpr *E) { BlockDecl *oldBlock = E->getBlockDecl(); SemaRef.ActOnBlockStart(E->getCaretLocation(), /*Scope=*/nullptr); BlockScopeInfo *blockScope = SemaRef.getCurBlock(); blockScope->TheDecl->setIsVariadic(oldBlock->isVariadic()); blockScope->TheDecl->setBlockMissingReturnType( oldBlock->blockMissingReturnType()); SmallVector params; SmallVector paramTypes; const FunctionProtoType *exprFunctionType = E->getFunctionType(); // Parameter substitution. Sema::ExtParameterInfoBuilder extParamInfos; if (getDerived().TransformFunctionTypeParams( E->getCaretLocation(), oldBlock->parameters(), nullptr, exprFunctionType->getExtParameterInfosOrNull(), paramTypes, ¶ms, extParamInfos)) { getSema().ActOnBlockError(E->getCaretLocation(), /*Scope=*/nullptr); return ExprError(); } QualType exprResultType = getDerived().TransformType(exprFunctionType->getReturnType()); auto epi = exprFunctionType->getExtProtoInfo(); epi.ExtParameterInfos = extParamInfos.getPointerOrNull(paramTypes.size()); QualType functionType = getDerived().RebuildFunctionProtoType(exprResultType, paramTypes, epi); blockScope->FunctionType = functionType; // Set the parameters on the block decl. if (!params.empty()) blockScope->TheDecl->setParams(params); if (!oldBlock->blockMissingReturnType()) { blockScope->HasImplicitReturnType = false; blockScope->ReturnType = exprResultType; } // Transform the body StmtResult body = getDerived().TransformStmt(E->getBody()); if (body.isInvalid()) { getSema().ActOnBlockError(E->getCaretLocation(), /*Scope=*/nullptr); return ExprError(); } #ifndef NDEBUG // In builds with assertions, make sure that we captured everything we // captured before. if (!SemaRef.getDiagnostics().hasErrorOccurred()) { for (const auto &I : oldBlock->captures()) { VarDecl *oldCapture = I.getVariable(); // Ignore parameter packs. if (oldCapture->isParameterPack()) continue; VarDecl *newCapture = cast(getDerived().TransformDecl(E->getCaretLocation(), oldCapture)); assert(blockScope->CaptureMap.count(newCapture)); } assert(oldBlock->capturesCXXThis() == blockScope->isCXXThisCaptured()); } #endif return SemaRef.ActOnBlockStmtExpr(E->getCaretLocation(), body.get(), /*Scope=*/nullptr); } template ExprResult TreeTransform::TransformAsTypeExpr(AsTypeExpr *E) { llvm_unreachable("Cannot transform asType expressions yet"); } template ExprResult TreeTransform::TransformAtomicExpr(AtomicExpr *E) { bool ArgumentChanged = false; SmallVector SubExprs; SubExprs.reserve(E->getNumSubExprs()); if (getDerived().TransformExprs(E->getSubExprs(), E->getNumSubExprs(), false, SubExprs, &ArgumentChanged)) return ExprError(); if (!getDerived().AlwaysRebuild() && !ArgumentChanged) return E; return getDerived().RebuildAtomicExpr(E->getBuiltinLoc(), SubExprs, E->getOp(), E->getRParenLoc()); } //===----------------------------------------------------------------------===// // Type reconstruction //===----------------------------------------------------------------------===// template QualType TreeTransform::RebuildPointerType(QualType PointeeType, SourceLocation Star) { return SemaRef.BuildPointerType(PointeeType, Star, getDerived().getBaseEntity()); } template QualType TreeTransform::RebuildBlockPointerType(QualType PointeeType, SourceLocation Star) { return SemaRef.BuildBlockPointerType(PointeeType, Star, getDerived().getBaseEntity()); } template QualType TreeTransform::RebuildReferenceType(QualType ReferentType, bool WrittenAsLValue, SourceLocation Sigil) { return SemaRef.BuildReferenceType(ReferentType, WrittenAsLValue, Sigil, getDerived().getBaseEntity()); } template QualType TreeTransform::RebuildMemberPointerType(QualType PointeeType, QualType ClassType, SourceLocation Sigil) { return SemaRef.BuildMemberPointerType(PointeeType, ClassType, Sigil, getDerived().getBaseEntity()); } template QualType TreeTransform::RebuildObjCTypeParamType( const ObjCTypeParamDecl *Decl, SourceLocation ProtocolLAngleLoc, ArrayRef Protocols, ArrayRef ProtocolLocs, SourceLocation ProtocolRAngleLoc) { return SemaRef.BuildObjCTypeParamType(Decl, ProtocolLAngleLoc, Protocols, ProtocolLocs, ProtocolRAngleLoc, /*FailOnError=*/true); } template QualType TreeTransform::RebuildObjCObjectType( QualType BaseType, SourceLocation Loc, SourceLocation TypeArgsLAngleLoc, ArrayRef TypeArgs, SourceLocation TypeArgsRAngleLoc, SourceLocation ProtocolLAngleLoc, ArrayRef Protocols, ArrayRef ProtocolLocs, SourceLocation ProtocolRAngleLoc) { return SemaRef.BuildObjCObjectType(BaseType, Loc, TypeArgsLAngleLoc, TypeArgs, TypeArgsRAngleLoc, ProtocolLAngleLoc, Protocols, ProtocolLocs, ProtocolRAngleLoc, /*FailOnError=*/true); } template QualType TreeTransform::RebuildObjCObjectPointerType( QualType PointeeType, SourceLocation Star) { return SemaRef.Context.getObjCObjectPointerType(PointeeType); } template QualType TreeTransform::RebuildArrayType(QualType ElementType, ArrayType::ArraySizeModifier SizeMod, const llvm::APInt *Size, Expr *SizeExpr, unsigned IndexTypeQuals, SourceRange BracketsRange) { if (SizeExpr || !Size) return SemaRef.BuildArrayType(ElementType, SizeMod, SizeExpr, IndexTypeQuals, BracketsRange, getDerived().getBaseEntity()); QualType Types[] = { SemaRef.Context.UnsignedCharTy, SemaRef.Context.UnsignedShortTy, SemaRef.Context.UnsignedIntTy, SemaRef.Context.UnsignedLongTy, SemaRef.Context.UnsignedLongLongTy, SemaRef.Context.UnsignedInt128Ty }; const unsigned NumTypes = llvm::array_lengthof(Types); QualType SizeType; for (unsigned I = 0; I != NumTypes; ++I) if (Size->getBitWidth() == SemaRef.Context.getIntWidth(Types[I])) { SizeType = Types[I]; break; } // Note that we can return a VariableArrayType here in the case where // the element type was a dependent VariableArrayType. IntegerLiteral *ArraySize = IntegerLiteral::Create(SemaRef.Context, *Size, SizeType, /*FIXME*/BracketsRange.getBegin()); return SemaRef.BuildArrayType(ElementType, SizeMod, ArraySize, IndexTypeQuals, BracketsRange, getDerived().getBaseEntity()); } template QualType TreeTransform::RebuildConstantArrayType(QualType ElementType, ArrayType::ArraySizeModifier SizeMod, const llvm::APInt &Size, Expr *SizeExpr, unsigned IndexTypeQuals, SourceRange BracketsRange) { return getDerived().RebuildArrayType(ElementType, SizeMod, &Size, SizeExpr, IndexTypeQuals, BracketsRange); } template QualType TreeTransform::RebuildIncompleteArrayType(QualType ElementType, ArrayType::ArraySizeModifier SizeMod, unsigned IndexTypeQuals, SourceRange BracketsRange) { return getDerived().RebuildArrayType(ElementType, SizeMod, nullptr, nullptr, IndexTypeQuals, BracketsRange); } template QualType TreeTransform::RebuildVariableArrayType(QualType ElementType, ArrayType::ArraySizeModifier SizeMod, Expr *SizeExpr, unsigned IndexTypeQuals, SourceRange BracketsRange) { return getDerived().RebuildArrayType(ElementType, SizeMod, nullptr, SizeExpr, IndexTypeQuals, BracketsRange); } template QualType TreeTransform::RebuildDependentSizedArrayType(QualType ElementType, ArrayType::ArraySizeModifier SizeMod, Expr *SizeExpr, unsigned IndexTypeQuals, SourceRange BracketsRange) { return getDerived().RebuildArrayType(ElementType, SizeMod, nullptr, SizeExpr, IndexTypeQuals, BracketsRange); } template QualType TreeTransform::RebuildDependentAddressSpaceType( QualType PointeeType, Expr *AddrSpaceExpr, SourceLocation AttributeLoc) { return SemaRef.BuildAddressSpaceAttr(PointeeType, AddrSpaceExpr, AttributeLoc); } template QualType TreeTransform::RebuildVectorType(QualType ElementType, unsigned NumElements, VectorType::VectorKind VecKind) { // FIXME: semantic checking! return SemaRef.Context.getVectorType(ElementType, NumElements, VecKind); } template QualType TreeTransform::RebuildDependentVectorType( QualType ElementType, Expr *SizeExpr, SourceLocation AttributeLoc, VectorType::VectorKind VecKind) { return SemaRef.BuildVectorType(ElementType, SizeExpr, AttributeLoc); } template QualType TreeTransform::RebuildExtVectorType(QualType ElementType, unsigned NumElements, SourceLocation AttributeLoc) { llvm::APInt numElements(SemaRef.Context.getIntWidth(SemaRef.Context.IntTy), NumElements, true); IntegerLiteral *VectorSize = IntegerLiteral::Create(SemaRef.Context, numElements, SemaRef.Context.IntTy, AttributeLoc); return SemaRef.BuildExtVectorType(ElementType, VectorSize, AttributeLoc); } template QualType TreeTransform::RebuildDependentSizedExtVectorType(QualType ElementType, Expr *SizeExpr, SourceLocation AttributeLoc) { return SemaRef.BuildExtVectorType(ElementType, SizeExpr, AttributeLoc); } template QualType TreeTransform::RebuildFunctionProtoType( QualType T, MutableArrayRef ParamTypes, const FunctionProtoType::ExtProtoInfo &EPI) { return SemaRef.BuildFunctionType(T, ParamTypes, getDerived().getBaseLocation(), getDerived().getBaseEntity(), EPI); } template QualType TreeTransform::RebuildFunctionNoProtoType(QualType T) { return SemaRef.Context.getFunctionNoProtoType(T); } template QualType TreeTransform::RebuildUnresolvedUsingType(SourceLocation Loc, Decl *D) { assert(D && "no decl found"); if (D->isInvalidDecl()) return QualType(); // FIXME: Doesn't account for ObjCInterfaceDecl! TypeDecl *Ty; if (auto *UPD = dyn_cast(D)) { // A valid resolved using typename pack expansion decl can have multiple // UsingDecls, but they must each have exactly one type, and it must be // the same type in every case. But we must have at least one expansion! if (UPD->expansions().empty()) { getSema().Diag(Loc, diag::err_using_pack_expansion_empty) << UPD->isCXXClassMember() << UPD; return QualType(); } // We might still have some unresolved types. Try to pick a resolved type // if we can. The final instantiation will check that the remaining // unresolved types instantiate to the type we pick. QualType FallbackT; QualType T; for (auto *E : UPD->expansions()) { QualType ThisT = RebuildUnresolvedUsingType(Loc, E); if (ThisT.isNull()) continue; else if (ThisT->getAs()) FallbackT = ThisT; else if (T.isNull()) T = ThisT; else assert(getSema().Context.hasSameType(ThisT, T) && "mismatched resolved types in using pack expansion"); } return T.isNull() ? FallbackT : T; } else if (auto *Using = dyn_cast(D)) { assert(Using->hasTypename() && "UnresolvedUsingTypenameDecl transformed to non-typename using"); // A valid resolved using typename decl points to exactly one type decl. assert(++Using->shadow_begin() == Using->shadow_end()); Ty = cast((*Using->shadow_begin())->getTargetDecl()); } else { assert(isa(D) && "UnresolvedUsingTypenameDecl transformed to non-using decl"); Ty = cast(D); } return SemaRef.Context.getTypeDeclType(Ty); } template QualType TreeTransform::RebuildTypeOfExprType(Expr *E, SourceLocation Loc) { return SemaRef.BuildTypeofExprType(E, Loc); } template QualType TreeTransform::RebuildTypeOfType(QualType Underlying) { return SemaRef.Context.getTypeOfType(Underlying); } template QualType TreeTransform::RebuildDecltypeType(Expr *E, SourceLocation Loc) { return SemaRef.BuildDecltypeType(E, Loc); } template QualType TreeTransform::RebuildUnaryTransformType(QualType BaseType, UnaryTransformType::UTTKind UKind, SourceLocation Loc) { return SemaRef.BuildUnaryTransformType(BaseType, UKind, Loc); } template QualType TreeTransform::RebuildTemplateSpecializationType( TemplateName Template, SourceLocation TemplateNameLoc, TemplateArgumentListInfo &TemplateArgs) { return SemaRef.CheckTemplateIdType(Template, TemplateNameLoc, TemplateArgs); } template QualType TreeTransform::RebuildAtomicType(QualType ValueType, SourceLocation KWLoc) { return SemaRef.BuildAtomicType(ValueType, KWLoc); } template QualType TreeTransform::RebuildPipeType(QualType ValueType, SourceLocation KWLoc, bool isReadPipe) { return isReadPipe ? SemaRef.BuildReadPipeType(ValueType, KWLoc) : SemaRef.BuildWritePipeType(ValueType, KWLoc); } template TemplateName TreeTransform::RebuildTemplateName(CXXScopeSpec &SS, bool TemplateKW, TemplateDecl *Template) { return SemaRef.Context.getQualifiedTemplateName(SS.getScopeRep(), TemplateKW, Template); } template TemplateName TreeTransform::RebuildTemplateName(CXXScopeSpec &SS, SourceLocation TemplateKWLoc, const IdentifierInfo &Name, SourceLocation NameLoc, QualType ObjectType, NamedDecl *FirstQualifierInScope, bool AllowInjectedClassName) { UnqualifiedId TemplateName; TemplateName.setIdentifier(&Name, NameLoc); Sema::TemplateTy Template; getSema().ActOnDependentTemplateName(/*Scope=*/nullptr, SS, TemplateKWLoc, TemplateName, ParsedType::make(ObjectType), /*EnteringContext=*/false, Template, AllowInjectedClassName); return Template.get(); } template TemplateName TreeTransform::RebuildTemplateName(CXXScopeSpec &SS, SourceLocation TemplateKWLoc, OverloadedOperatorKind Operator, SourceLocation NameLoc, QualType ObjectType, bool AllowInjectedClassName) { UnqualifiedId Name; // FIXME: Bogus location information. SourceLocation SymbolLocations[3] = { NameLoc, NameLoc, NameLoc }; Name.setOperatorFunctionId(NameLoc, Operator, SymbolLocations); Sema::TemplateTy Template; getSema().ActOnDependentTemplateName(/*Scope=*/nullptr, SS, TemplateKWLoc, Name, ParsedType::make(ObjectType), /*EnteringContext=*/false, Template, AllowInjectedClassName); return Template.get(); } template ExprResult TreeTransform::RebuildCXXOperatorCallExpr(OverloadedOperatorKind Op, SourceLocation OpLoc, Expr *OrigCallee, Expr *First, Expr *Second) { Expr *Callee = OrigCallee->IgnoreParenCasts(); bool isPostIncDec = Second && (Op == OO_PlusPlus || Op == OO_MinusMinus); if (First->getObjectKind() == OK_ObjCProperty) { BinaryOperatorKind Opc = BinaryOperator::getOverloadedOpcode(Op); if (BinaryOperator::isAssignmentOp(Opc)) return SemaRef.checkPseudoObjectAssignment(/*Scope=*/nullptr, OpLoc, Opc, First, Second); ExprResult Result = SemaRef.CheckPlaceholderExpr(First); if (Result.isInvalid()) return ExprError(); First = Result.get(); } if (Second && Second->getObjectKind() == OK_ObjCProperty) { ExprResult Result = SemaRef.CheckPlaceholderExpr(Second); if (Result.isInvalid()) return ExprError(); Second = Result.get(); } // Determine whether this should be a builtin operation. if (Op == OO_Subscript) { if (!First->getType()->isOverloadableType() && !Second->getType()->isOverloadableType()) return getSema().CreateBuiltinArraySubscriptExpr( First, Callee->getBeginLoc(), Second, OpLoc); } else if (Op == OO_Arrow) { // -> is never a builtin operation. return SemaRef.BuildOverloadedArrowExpr(nullptr, First, OpLoc); } else if (Second == nullptr || isPostIncDec) { if (!First->getType()->isOverloadableType() || (Op == OO_Amp && getSema().isQualifiedMemberAccess(First))) { // The argument is not of overloadable type, or this is an expression // of the form &Class::member, so try to create a built-in unary // operation. UnaryOperatorKind Opc = UnaryOperator::getOverloadedOpcode(Op, isPostIncDec); return getSema().CreateBuiltinUnaryOp(OpLoc, Opc, First); } } else { if (!First->getType()->isOverloadableType() && !Second->getType()->isOverloadableType()) { // Neither of the arguments is an overloadable type, so try to // create a built-in binary operation. BinaryOperatorKind Opc = BinaryOperator::getOverloadedOpcode(Op); ExprResult Result = SemaRef.CreateBuiltinBinOp(OpLoc, Opc, First, Second); if (Result.isInvalid()) return ExprError(); return Result; } } // Compute the transformed set of functions (and function templates) to be // used during overload resolution. UnresolvedSet<16> Functions; bool RequiresADL; if (UnresolvedLookupExpr *ULE = dyn_cast(Callee)) { Functions.append(ULE->decls_begin(), ULE->decls_end()); // If the overload could not be resolved in the template definition // (because we had a dependent argument), ADL is performed as part of // template instantiation. RequiresADL = ULE->requiresADL(); } else { // If we've resolved this to a particular non-member function, just call // that function. If we resolved it to a member function, // CreateOverloaded* will find that function for us. NamedDecl *ND = cast(Callee)->getDecl(); if (!isa(ND)) Functions.addDecl(ND); RequiresADL = false; } // Add any functions found via argument-dependent lookup. Expr *Args[2] = { First, Second }; unsigned NumArgs = 1 + (Second != nullptr); // Create the overloaded operator invocation for unary operators. if (NumArgs == 1 || isPostIncDec) { UnaryOperatorKind Opc = UnaryOperator::getOverloadedOpcode(Op, isPostIncDec); return SemaRef.CreateOverloadedUnaryOp(OpLoc, Opc, Functions, First, RequiresADL); } if (Op == OO_Subscript) { SourceLocation LBrace; SourceLocation RBrace; if (DeclRefExpr *DRE = dyn_cast(Callee)) { DeclarationNameLoc NameLoc = DRE->getNameInfo().getInfo(); LBrace = SourceLocation::getFromRawEncoding( NameLoc.CXXOperatorName.BeginOpNameLoc); RBrace = SourceLocation::getFromRawEncoding( NameLoc.CXXOperatorName.EndOpNameLoc); } else { LBrace = Callee->getBeginLoc(); RBrace = OpLoc; } return SemaRef.CreateOverloadedArraySubscriptExpr(LBrace, RBrace, First, Second); } // Create the overloaded operator invocation for binary operators. BinaryOperatorKind Opc = BinaryOperator::getOverloadedOpcode(Op); ExprResult Result = SemaRef.CreateOverloadedBinOp( OpLoc, Opc, Functions, Args[0], Args[1], RequiresADL); if (Result.isInvalid()) return ExprError(); return Result; } template ExprResult TreeTransform::RebuildCXXPseudoDestructorExpr(Expr *Base, SourceLocation OperatorLoc, bool isArrow, CXXScopeSpec &SS, TypeSourceInfo *ScopeType, SourceLocation CCLoc, SourceLocation TildeLoc, PseudoDestructorTypeStorage Destroyed) { QualType BaseType = Base->getType(); if (Base->isTypeDependent() || Destroyed.getIdentifier() || (!isArrow && !BaseType->getAs()) || (isArrow && BaseType->getAs() && !BaseType->castAs()->getPointeeType() ->template getAs())){ // This pseudo-destructor expression is still a pseudo-destructor. return SemaRef.BuildPseudoDestructorExpr( Base, OperatorLoc, isArrow ? tok::arrow : tok::period, SS, ScopeType, CCLoc, TildeLoc, Destroyed); } TypeSourceInfo *DestroyedType = Destroyed.getTypeSourceInfo(); DeclarationName Name(SemaRef.Context.DeclarationNames.getCXXDestructorName( SemaRef.Context.getCanonicalType(DestroyedType->getType()))); DeclarationNameInfo NameInfo(Name, Destroyed.getLocation()); NameInfo.setNamedTypeInfo(DestroyedType); // The scope type is now known to be a valid nested name specifier // component. Tack it on to the end of the nested name specifier. if (ScopeType) { if (!ScopeType->getType()->getAs()) { getSema().Diag(ScopeType->getTypeLoc().getBeginLoc(), diag::err_expected_class_or_namespace) << ScopeType->getType() << getSema().getLangOpts().CPlusPlus; return ExprError(); } SS.Extend(SemaRef.Context, SourceLocation(), ScopeType->getTypeLoc(), CCLoc); } SourceLocation TemplateKWLoc; // FIXME: retrieve it from caller. return getSema().BuildMemberReferenceExpr(Base, BaseType, OperatorLoc, isArrow, SS, TemplateKWLoc, /*FIXME: FirstQualifier*/ nullptr, NameInfo, /*TemplateArgs*/ nullptr, /*S*/nullptr); } template StmtResult TreeTransform::TransformCapturedStmt(CapturedStmt *S) { SourceLocation Loc = S->getBeginLoc(); CapturedDecl *CD = S->getCapturedDecl(); unsigned NumParams = CD->getNumParams(); unsigned ContextParamPos = CD->getContextParamPosition(); SmallVector Params; for (unsigned I = 0; I < NumParams; ++I) { if (I != ContextParamPos) { Params.push_back( std::make_pair( CD->getParam(I)->getName(), getDerived().TransformType(CD->getParam(I)->getType()))); } else { Params.push_back(std::make_pair(StringRef(), QualType())); } } getSema().ActOnCapturedRegionStart(Loc, /*CurScope*/nullptr, S->getCapturedRegionKind(), Params); StmtResult Body; { Sema::CompoundScopeRAII CompoundScope(getSema()); Body = getDerived().TransformStmt(S->getCapturedStmt()); } if (Body.isInvalid()) { getSema().ActOnCapturedRegionError(); return StmtError(); } return getSema().ActOnCapturedRegionEnd(Body.get()); } } // end namespace clang #endif // LLVM_CLANG_LIB_SEMA_TREETRANSFORM_H diff --git a/contrib/llvm-project/lld/docs/ReleaseNotes.rst b/contrib/llvm-project/lld/docs/ReleaseNotes.rst index 5be348bb1894..724c0097a949 100644 --- a/contrib/llvm-project/lld/docs/ReleaseNotes.rst +++ b/contrib/llvm-project/lld/docs/ReleaseNotes.rst @@ -1,89 +1,129 @@ ======================== lld 10.0.0 Release Notes ======================== .. contents:: :local: -.. warning:: - These are in-progress notes for the upcoming LLVM 10.0.0 release. - Release notes for previous releases can be found on - `the Download Page `_. Introduction ============ This document contains the release notes for the lld linker, release 10.0.0. Here we describe the status of lld, including major improvements from the previous release. All lld releases may be downloaded from the `LLVM releases web site `_. Non-comprehensive list of changes in this release ================================================= ELF Improvements ---------------- * Glob pattern, which you can use in linker scripts or version scripts, now supports `\` and `[!...]`. Except character classes (e.g. `[[:digit:]]`), lld's glob pattern should be fully compatible with GNU now. (`r375051 `_) * New ``elf32btsmipn32_fbsd`` and ``elf32ltsmipn32_fbsd`` emulations are supported. -* Relax MIPS ``jalr``and ``jr`` instructions marked by the ``R_MIPS_JALR`` +* Relax MIPS ``jalr`` and ``jr`` instructions marked by the ``R_MIPS_JALR`` relocation. +* For certain "undefined symbol" errors, a definition with a close spelling will be suggested. + (`D67039 `_) +* ``extern "C"`` is suggested if an undefined reference is mangled(unmangled) while there + is a likely unmangled(mangled) definition. + (`D69592 `_ `D69650 `_) +* New ``-z noseparate-code``, ``-z separate-code`` and ``-z separate-loadable-segments``. + ``-z noseparate-code`` is the default, which can reduce sizes of linked binaries by up to + 3 times maxpagesize. + (`D64903 `_ `D67481 `_) +* ``-z force-bti`` and ``-z pac-plt`` are added for AArch64 Branch Target Identification and Pointer Authentication. + (`D62609 `_) +* ``--fix-cortex-a8`` is added to fix erratum 657417. + (`D67284 `_) +* ``-z force-ibt`` and ``-z shstk`` are added for Intel Control-flow Enforcement Technology. + (`D59780 `_) +* ``PT_GNU_PROPERTY`` is added to help loaders locate the ``.note.gnu.property`` section. + It may be used by a future Linux kernel. + (`D70961 `_) +* For ``--compress-debug-sections=zlib``, ``-O0`` and ``-O1`` enable compression level 1 + while ``-O2`` enables compression level 6. ``-O1`` (default) is faster than before. + (`D70658 `_) +* Range extension thunks with addends are implemented for AArch64, PowerPC32 and PowerPC64. + (`D70637 `_ `D70937 `_ + `D73424 `_) +* ``R_RISCV_ALIGN`` will be errored because linker relaxation for RISC-V is not supported. + Pass ``-mno-relax`` to disable ``R_RISCV_ALIGN``. + (`D71820 `_) +* The ARM port will no longer insert interworking thunks for non STT_FUNC symbols. + (`D73474 `_) +* The quality of PowerPC32 port has been greatly improved (canonical PLT, copy + relocations, non-preemptible IFUNC, range extension thunks with addends). + It can link FreeBSD 13.0 userland. +* The PowerPC64 port supports non-preemptible IFUNC. + (`D71509 `_) +* lld creates a RO PT_LOAD and a RX PT_LOAD without a linker script. + lld creates a unified RX PT_LOAD with a linker script. + A future release will eliminate this difference and use a RO PT_LOAD and a RX PT_LOAD by default. + The linker script case will require ``--no-rosegment`` to restore the current behavior. +* GNU style compressed debug sections ``.zdebug`` (obsoleted by ``SHF_COMPRESSED``) + are supported for input files, but not for the output. + A future release may drop ``.zdebug`` support. + +Breaking changes +---------------- -* Reduced size of linked MIPS binaries. - -COFF Improvements ------------------ +* ``-Ttext=$base`` (base is usually 0) is no longer supported. + If PT_PHDR is needed, use ``--image-base=$base`` instead. + If PT_PHDR is not needed, use a linker script with `.text 0 : { *(.text*) }` as the first + output section description. + See https://bugs.llvm.org/show_bug.cgi?id=44715 for more information. + (`D67325 `_) +* ``-Ttext-segment`` is no longer supported. Its meaning was different from GNU ld's and + could cause subtle bugs. + (`D70468 `_) -* ... MinGW Improvements ------------------ * Allow using custom .edata sections from input object files (for use by Wine) - (`dadc6f248868 `) + (`dadc6f248868 `_) * Don't implicitly create import libraries unless requested - (`6540e55067e3 `) + (`6540e55067e3 `_) * Support merging multiple resource object files - (`3d3a9b3b413d `) + (`3d3a9b3b413d `_) and properly handle the default manifest object files that GCC can pass - (`d581dd501381 `) + (`d581dd501381 `_) * Demangle itanium symbol names in warnings/error messages - (`a66fc1c99f3e `) + (`a66fc1c99f3e `_) * Print source locations for undefined references and duplicate symbols, if possible - (`1d06d48bb346 `) + (`1d06d48bb346 `_) and - (`b38f577c015c `) + (`b38f577c015c `_) * Look for more filename patterns when resolving ``-l`` options - (`0226c35262df `) + (`0226c35262df `_) * Don't error out on duplicate absolute symbols with the same value (which can happen for the default-null symbol for weak symbols) - (`1737cc750c46 `) - -MachO Improvements ------------------- + (`1737cc750c46 `_) -* Item 1. WebAssembly Improvements ------------------------ * `__data_end` and `__heap_base` are no longer exported by default, as it's best to keep them internal when possible. They can be explicitly exported with `--export=__data_end` and `--export=__heap_base`, respectively. * wasm-ld now elides .bss sections when the memory is not imported diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp index 7cea013eea7f..0a98f6a15d75 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp @@ -1,1384 +1,1384 @@ //===-- GDBRemoteCommunication.cpp ------------------------------*- 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 // //===----------------------------------------------------------------------===// #include "GDBRemoteCommunication.h" #include #include #include #include #include "lldb/Core/StreamFile.h" #include "lldb/Host/Config.h" #include "lldb/Host/ConnectionFileDescriptor.h" #include "lldb/Host/FileSystem.h" #include "lldb/Host/Host.h" #include "lldb/Host/HostInfo.h" #include "lldb/Host/Pipe.h" #include "lldb/Host/ProcessLaunchInfo.h" #include "lldb/Host/Socket.h" #include "lldb/Host/StringConvert.h" #include "lldb/Host/ThreadLauncher.h" #include "lldb/Host/common/TCPSocket.h" #include "lldb/Host/posix/ConnectionFileDescriptorPosix.h" #include "lldb/Target/Platform.h" #include "lldb/Utility/Event.h" #include "lldb/Utility/FileSpec.h" #include "lldb/Utility/Log.h" #include "lldb/Utility/RegularExpression.h" #include "lldb/Utility/Reproducer.h" #include "lldb/Utility/StreamString.h" #include "llvm/ADT/SmallString.h" #include "llvm/Support/ScopedPrinter.h" #include "ProcessGDBRemoteLog.h" #if defined(__APPLE__) #define DEBUGSERVER_BASENAME "debugserver" #elif defined(_WIN32) #define DEBUGSERVER_BASENAME "lldb-server.exe" #else #define DEBUGSERVER_BASENAME "lldb-server" #endif #if defined(HAVE_LIBCOMPRESSION) #include #endif -#if LLVM_ENABLE_ZLIB +#if defined(HAVE_LIBZ) #include #endif using namespace lldb; using namespace lldb_private; using namespace lldb_private::process_gdb_remote; // GDBRemoteCommunication constructor GDBRemoteCommunication::GDBRemoteCommunication(const char *comm_name, const char *listener_name) : Communication(comm_name), #ifdef LLDB_CONFIGURATION_DEBUG m_packet_timeout(1000), #else m_packet_timeout(1), #endif m_echo_number(0), m_supports_qEcho(eLazyBoolCalculate), m_history(512), m_send_acks(true), m_compression_type(CompressionType::None), m_listen_url() { } // Destructor GDBRemoteCommunication::~GDBRemoteCommunication() { if (IsConnected()) { Disconnect(); } #if defined(HAVE_LIBCOMPRESSION) if (m_decompression_scratch) free (m_decompression_scratch); #endif // Stop the communications read thread which is used to parse all incoming // packets. This function will block until the read thread returns. if (m_read_thread_enabled) StopReadThread(); } char GDBRemoteCommunication::CalculcateChecksum(llvm::StringRef payload) { int checksum = 0; for (char c : payload) checksum += c; return checksum & 255; } size_t GDBRemoteCommunication::SendAck() { Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PACKETS)); ConnectionStatus status = eConnectionStatusSuccess; char ch = '+'; const size_t bytes_written = Write(&ch, 1, status, nullptr); LLDB_LOGF(log, "<%4" PRIu64 "> send packet: %c", (uint64_t)bytes_written, ch); m_history.AddPacket(ch, GDBRemotePacket::ePacketTypeSend, bytes_written); return bytes_written; } size_t GDBRemoteCommunication::SendNack() { Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PACKETS)); ConnectionStatus status = eConnectionStatusSuccess; char ch = '-'; const size_t bytes_written = Write(&ch, 1, status, nullptr); LLDB_LOGF(log, "<%4" PRIu64 "> send packet: %c", (uint64_t)bytes_written, ch); m_history.AddPacket(ch, GDBRemotePacket::ePacketTypeSend, bytes_written); return bytes_written; } GDBRemoteCommunication::PacketResult GDBRemoteCommunication::SendPacketNoLock(llvm::StringRef payload) { StreamString packet(0, 4, eByteOrderBig); packet.PutChar('$'); packet.Write(payload.data(), payload.size()); packet.PutChar('#'); packet.PutHex8(CalculcateChecksum(payload)); std::string packet_str = packet.GetString(); return SendRawPacketNoLock(packet_str); } GDBRemoteCommunication::PacketResult GDBRemoteCommunication::SendRawPacketNoLock(llvm::StringRef packet, bool skip_ack) { if (IsConnected()) { Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PACKETS)); ConnectionStatus status = eConnectionStatusSuccess; const char *packet_data = packet.data(); const size_t packet_length = packet.size(); size_t bytes_written = Write(packet_data, packet_length, status, nullptr); if (log) { size_t binary_start_offset = 0; if (strncmp(packet_data, "$vFile:pwrite:", strlen("$vFile:pwrite:")) == 0) { const char *first_comma = strchr(packet_data, ','); if (first_comma) { const char *second_comma = strchr(first_comma + 1, ','); if (second_comma) binary_start_offset = second_comma - packet_data + 1; } } // If logging was just enabled and we have history, then dump out what we // have to the log so we get the historical context. The Dump() call that // logs all of the packet will set a boolean so that we don't dump this // more than once if (!m_history.DidDumpToLog()) m_history.Dump(log); if (binary_start_offset) { StreamString strm; // Print non binary data header strm.Printf("<%4" PRIu64 "> send packet: %.*s", (uint64_t)bytes_written, (int)binary_start_offset, packet_data); const uint8_t *p; // Print binary data exactly as sent for (p = (const uint8_t *)packet_data + binary_start_offset; *p != '#'; ++p) strm.Printf("\\x%2.2x", *p); // Print the checksum strm.Printf("%*s", (int)3, p); log->PutString(strm.GetString()); } else LLDB_LOGF(log, "<%4" PRIu64 "> send packet: %.*s", (uint64_t)bytes_written, (int)packet_length, packet_data); } m_history.AddPacket(packet.str(), packet_length, GDBRemotePacket::ePacketTypeSend, bytes_written); if (bytes_written == packet_length) { if (!skip_ack && GetSendAcks()) return GetAck(); else return PacketResult::Success; } else { LLDB_LOGF(log, "error: failed to send packet: %.*s", (int)packet_length, packet_data); } } return PacketResult::ErrorSendFailed; } GDBRemoteCommunication::PacketResult GDBRemoteCommunication::GetAck() { StringExtractorGDBRemote packet; PacketResult result = ReadPacket(packet, GetPacketTimeout(), false); if (result == PacketResult::Success) { if (packet.GetResponseType() == StringExtractorGDBRemote::ResponseType::eAck) return PacketResult::Success; else return PacketResult::ErrorSendAck; } return result; } GDBRemoteCommunication::PacketResult GDBRemoteCommunication::ReadPacketWithOutputSupport( StringExtractorGDBRemote &response, Timeout timeout, bool sync_on_timeout, llvm::function_ref output_callback) { auto result = ReadPacket(response, timeout, sync_on_timeout); while (result == PacketResult::Success && response.IsNormalResponse() && response.PeekChar() == 'O') { response.GetChar(); std::string output; if (response.GetHexByteString(output)) output_callback(output); result = ReadPacket(response, timeout, sync_on_timeout); } return result; } GDBRemoteCommunication::PacketResult GDBRemoteCommunication::ReadPacket(StringExtractorGDBRemote &response, Timeout timeout, bool sync_on_timeout) { if (m_read_thread_enabled) return PopPacketFromQueue(response, timeout); else return WaitForPacketNoLock(response, timeout, sync_on_timeout); } // This function is called when a packet is requested. // A whole packet is popped from the packet queue and returned to the caller. // Packets are placed into this queue from the communication read thread. See // GDBRemoteCommunication::AppendBytesToCache. GDBRemoteCommunication::PacketResult GDBRemoteCommunication::PopPacketFromQueue(StringExtractorGDBRemote &response, Timeout timeout) { auto pred = [&] { return !m_packet_queue.empty() && IsConnected(); }; // lock down the packet queue std::unique_lock lock(m_packet_queue_mutex); if (!timeout) m_condition_queue_not_empty.wait(lock, pred); else { if (!m_condition_queue_not_empty.wait_for(lock, *timeout, pred)) return PacketResult::ErrorReplyTimeout; if (!IsConnected()) return PacketResult::ErrorDisconnected; } // get the front element of the queue response = m_packet_queue.front(); // remove the front element m_packet_queue.pop(); // we got a packet return PacketResult::Success; } GDBRemoteCommunication::PacketResult GDBRemoteCommunication::WaitForPacketNoLock(StringExtractorGDBRemote &packet, Timeout timeout, bool sync_on_timeout) { uint8_t buffer[8192]; Status error; Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PACKETS)); // Check for a packet from our cache first without trying any reading... if (CheckForPacket(nullptr, 0, packet) != PacketType::Invalid) return PacketResult::Success; bool timed_out = false; bool disconnected = false; while (IsConnected() && !timed_out) { lldb::ConnectionStatus status = eConnectionStatusNoConnection; size_t bytes_read = Read(buffer, sizeof(buffer), timeout, status, &error); LLDB_LOGV(log, "Read(buffer, sizeof(buffer), timeout = {0}, " "status = {1}, error = {2}) => bytes_read = {3}", timeout, Communication::ConnectionStatusAsCString(status), error, bytes_read); if (bytes_read > 0) { if (CheckForPacket(buffer, bytes_read, packet) != PacketType::Invalid) return PacketResult::Success; } else { switch (status) { case eConnectionStatusTimedOut: case eConnectionStatusInterrupted: if (sync_on_timeout) { /// Sync the remote GDB server and make sure we get a response that /// corresponds to what we send. /// /// Sends a "qEcho" packet and makes sure it gets the exact packet /// echoed back. If the qEcho packet isn't supported, we send a qC /// packet and make sure we get a valid thread ID back. We use the /// "qC" packet since its response if very unique: is responds with /// "QC%x" where %x is the thread ID of the current thread. This /// makes the response unique enough from other packet responses to /// ensure we are back on track. /// /// This packet is needed after we time out sending a packet so we /// can ensure that we are getting the response for the packet we /// are sending. There are no sequence IDs in the GDB remote /// protocol (there used to be, but they are not supported anymore) /// so if you timeout sending packet "abc", you might then send /// packet "cde" and get the response for the previous "abc" packet. /// Many responses are "OK" or "" (unsupported) or "EXX" (error) so /// many responses for packets can look like responses for other /// packets. So if we timeout, we need to ensure that we can get /// back on track. If we can't get back on track, we must /// disconnect. bool sync_success = false; bool got_actual_response = false; // We timed out, we need to sync back up with the char echo_packet[32]; int echo_packet_len = 0; RegularExpression response_regex; if (m_supports_qEcho == eLazyBoolYes) { echo_packet_len = ::snprintf(echo_packet, sizeof(echo_packet), "qEcho:%u", ++m_echo_number); std::string regex_str = "^"; regex_str += echo_packet; regex_str += "$"; response_regex = RegularExpression(regex_str); } else { echo_packet_len = ::snprintf(echo_packet, sizeof(echo_packet), "qC"); response_regex = RegularExpression(llvm::StringRef("^QC[0-9A-Fa-f]+$")); } PacketResult echo_packet_result = SendPacketNoLock(llvm::StringRef(echo_packet, echo_packet_len)); if (echo_packet_result == PacketResult::Success) { const uint32_t max_retries = 3; uint32_t successful_responses = 0; for (uint32_t i = 0; i < max_retries; ++i) { StringExtractorGDBRemote echo_response; echo_packet_result = WaitForPacketNoLock(echo_response, timeout, false); if (echo_packet_result == PacketResult::Success) { ++successful_responses; if (response_regex.Execute(echo_response.GetStringRef())) { sync_success = true; break; } else if (successful_responses == 1) { // We got something else back as the first successful // response, it probably is the response to the packet we // actually wanted, so copy it over if this is the first // success and continue to try to get the qEcho response packet = echo_response; got_actual_response = true; } } else if (echo_packet_result == PacketResult::ErrorReplyTimeout) continue; // Packet timed out, continue waiting for a response else break; // Something else went wrong getting the packet back, we // failed and are done trying } } // We weren't able to sync back up with the server, we must abort // otherwise all responses might not be from the right packets... if (sync_success) { // We timed out, but were able to recover if (got_actual_response) { // We initially timed out, but we did get a response that came in // before the successful reply to our qEcho packet, so lets say // everything is fine... return PacketResult::Success; } } else { disconnected = true; Disconnect(); } } timed_out = true; break; case eConnectionStatusSuccess: // printf ("status = success but error = %s\n", // error.AsCString("")); break; case eConnectionStatusEndOfFile: case eConnectionStatusNoConnection: case eConnectionStatusLostConnection: case eConnectionStatusError: disconnected = true; Disconnect(); break; } } } packet.Clear(); if (disconnected) return PacketResult::ErrorDisconnected; if (timed_out) return PacketResult::ErrorReplyTimeout; else return PacketResult::ErrorReplyFailed; } bool GDBRemoteCommunication::DecompressPacket() { Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PACKETS)); if (!CompressionIsEnabled()) return true; size_t pkt_size = m_bytes.size(); // Smallest possible compressed packet is $N#00 - an uncompressed empty // reply, most commonly indicating an unsupported packet. Anything less than // 5 characters, it's definitely not a compressed packet. if (pkt_size < 5) return true; if (m_bytes[0] != '$' && m_bytes[0] != '%') return true; if (m_bytes[1] != 'C' && m_bytes[1] != 'N') return true; size_t hash_mark_idx = m_bytes.find('#'); if (hash_mark_idx == std::string::npos) return true; if (hash_mark_idx + 2 >= m_bytes.size()) return true; if (!::isxdigit(m_bytes[hash_mark_idx + 1]) || !::isxdigit(m_bytes[hash_mark_idx + 2])) return true; size_t content_length = pkt_size - 5; // not counting '$', 'C' | 'N', '#', & the two hex checksum chars size_t content_start = 2; // The first character of the // compressed/not-compressed text of the packet size_t checksum_idx = hash_mark_idx + 1; // The first character of the two hex checksum characters // Normally size_of_first_packet == m_bytes.size() but m_bytes may contain // multiple packets. size_of_first_packet is the size of the initial packet // which we'll replace with the decompressed version of, leaving the rest of // m_bytes unmodified. size_t size_of_first_packet = hash_mark_idx + 3; // Compressed packets ("$C") start with a base10 number which is the size of // the uncompressed payload, then a : and then the compressed data. e.g. // $C1024:#00 Update content_start and content_length to only include // the part of the packet. uint64_t decompressed_bufsize = ULONG_MAX; if (m_bytes[1] == 'C') { size_t i = content_start; while (i < hash_mark_idx && isdigit(m_bytes[i])) i++; if (i < hash_mark_idx && m_bytes[i] == ':') { i++; content_start = i; content_length = hash_mark_idx - content_start; std::string bufsize_str(m_bytes.data() + 2, i - 2 - 1); errno = 0; decompressed_bufsize = ::strtoul(bufsize_str.c_str(), nullptr, 10); if (errno != 0 || decompressed_bufsize == ULONG_MAX) { m_bytes.erase(0, size_of_first_packet); return false; } } } if (GetSendAcks()) { char packet_checksum_cstr[3]; packet_checksum_cstr[0] = m_bytes[checksum_idx]; packet_checksum_cstr[1] = m_bytes[checksum_idx + 1]; packet_checksum_cstr[2] = '\0'; long packet_checksum = strtol(packet_checksum_cstr, nullptr, 16); long actual_checksum = CalculcateChecksum( llvm::StringRef(m_bytes).substr(1, hash_mark_idx - 1)); bool success = packet_checksum == actual_checksum; if (!success) { LLDB_LOGF(log, "error: checksum mismatch: %.*s expected 0x%2.2x, got 0x%2.2x", (int)(pkt_size), m_bytes.c_str(), (uint8_t)packet_checksum, (uint8_t)actual_checksum); } // Send the ack or nack if needed if (!success) { SendNack(); m_bytes.erase(0, size_of_first_packet); return false; } else { SendAck(); } } if (m_bytes[1] == 'N') { // This packet was not compressed -- delete the 'N' character at the start // and the packet may be processed as-is. m_bytes.erase(1, 1); return true; } // Reverse the gdb-remote binary escaping that was done to the compressed // text to guard characters like '$', '#', '}', etc. std::vector unescaped_content; unescaped_content.reserve(content_length); size_t i = content_start; while (i < hash_mark_idx) { if (m_bytes[i] == '}') { i++; unescaped_content.push_back(m_bytes[i] ^ 0x20); } else { unescaped_content.push_back(m_bytes[i]); } i++; } uint8_t *decompressed_buffer = nullptr; size_t decompressed_bytes = 0; if (decompressed_bufsize != ULONG_MAX) { decompressed_buffer = (uint8_t *)malloc(decompressed_bufsize); if (decompressed_buffer == nullptr) { m_bytes.erase(0, size_of_first_packet); return false; } } #if defined(HAVE_LIBCOMPRESSION) if (m_compression_type == CompressionType::ZlibDeflate || m_compression_type == CompressionType::LZFSE || m_compression_type == CompressionType::LZ4 || m_compression_type == CompressionType::LZMA) { compression_algorithm compression_type; if (m_compression_type == CompressionType::LZFSE) compression_type = COMPRESSION_LZFSE; else if (m_compression_type == CompressionType::ZlibDeflate) compression_type = COMPRESSION_ZLIB; else if (m_compression_type == CompressionType::LZ4) compression_type = COMPRESSION_LZ4_RAW; else if (m_compression_type == CompressionType::LZMA) compression_type = COMPRESSION_LZMA; if (m_decompression_scratch_type != m_compression_type) { if (m_decompression_scratch) { free (m_decompression_scratch); m_decompression_scratch = nullptr; } size_t scratchbuf_size = 0; if (m_compression_type == CompressionType::LZFSE) scratchbuf_size = compression_decode_scratch_buffer_size (COMPRESSION_LZFSE); else if (m_compression_type == CompressionType::LZ4) scratchbuf_size = compression_decode_scratch_buffer_size (COMPRESSION_LZ4_RAW); else if (m_compression_type == CompressionType::ZlibDeflate) scratchbuf_size = compression_decode_scratch_buffer_size (COMPRESSION_ZLIB); else if (m_compression_type == CompressionType::LZMA) scratchbuf_size = compression_decode_scratch_buffer_size (COMPRESSION_LZMA); else if (m_compression_type == CompressionType::LZFSE) scratchbuf_size = compression_decode_scratch_buffer_size (COMPRESSION_LZFSE); if (scratchbuf_size > 0) { m_decompression_scratch = (void*) malloc (scratchbuf_size); m_decompression_scratch_type = m_compression_type; } } if (decompressed_bufsize != ULONG_MAX && decompressed_buffer != nullptr) { decompressed_bytes = compression_decode_buffer( decompressed_buffer, decompressed_bufsize, (uint8_t *)unescaped_content.data(), unescaped_content.size(), m_decompression_scratch, compression_type); } } #endif -#if LLVM_ENABLE_ZLIB +#if defined(HAVE_LIBZ) if (decompressed_bytes == 0 && decompressed_bufsize != ULONG_MAX && decompressed_buffer != nullptr && m_compression_type == CompressionType::ZlibDeflate) { z_stream stream; memset(&stream, 0, sizeof(z_stream)); stream.next_in = (Bytef *)unescaped_content.data(); stream.avail_in = (uInt)unescaped_content.size(); stream.total_in = 0; stream.next_out = (Bytef *)decompressed_buffer; stream.avail_out = decompressed_bufsize; stream.total_out = 0; stream.zalloc = Z_NULL; stream.zfree = Z_NULL; stream.opaque = Z_NULL; if (inflateInit2(&stream, -15) == Z_OK) { int status = inflate(&stream, Z_NO_FLUSH); inflateEnd(&stream); if (status == Z_STREAM_END) { decompressed_bytes = stream.total_out; } } } #endif if (decompressed_bytes == 0 || decompressed_buffer == nullptr) { if (decompressed_buffer) free(decompressed_buffer); m_bytes.erase(0, size_of_first_packet); return false; } std::string new_packet; new_packet.reserve(decompressed_bytes + 6); new_packet.push_back(m_bytes[0]); new_packet.append((const char *)decompressed_buffer, decompressed_bytes); new_packet.push_back('#'); if (GetSendAcks()) { uint8_t decompressed_checksum = CalculcateChecksum( llvm::StringRef((const char *)decompressed_buffer, decompressed_bytes)); char decompressed_checksum_str[3]; snprintf(decompressed_checksum_str, 3, "%02x", decompressed_checksum); new_packet.append(decompressed_checksum_str); } else { new_packet.push_back('0'); new_packet.push_back('0'); } m_bytes.replace(0, size_of_first_packet, new_packet.data(), new_packet.size()); free(decompressed_buffer); return true; } GDBRemoteCommunication::PacketType GDBRemoteCommunication::CheckForPacket(const uint8_t *src, size_t src_len, StringExtractorGDBRemote &packet) { // Put the packet data into the buffer in a thread safe fashion std::lock_guard guard(m_bytes_mutex); Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PACKETS)); if (src && src_len > 0) { if (log && log->GetVerbose()) { StreamString s; LLDB_LOGF(log, "GDBRemoteCommunication::%s adding %u bytes: %.*s", __FUNCTION__, (uint32_t)src_len, (uint32_t)src_len, src); } m_bytes.append((const char *)src, src_len); } bool isNotifyPacket = false; // Parse up the packets into gdb remote packets if (!m_bytes.empty()) { // end_idx must be one past the last valid packet byte. Start it off with // an invalid value that is the same as the current index. size_t content_start = 0; size_t content_length = 0; size_t total_length = 0; size_t checksum_idx = std::string::npos; // Size of packet before it is decompressed, for logging purposes size_t original_packet_size = m_bytes.size(); if (CompressionIsEnabled()) { if (!DecompressPacket()) { packet.Clear(); return GDBRemoteCommunication::PacketType::Standard; } } switch (m_bytes[0]) { case '+': // Look for ack case '-': // Look for cancel case '\x03': // ^C to halt target content_length = total_length = 1; // The command is one byte long... break; case '%': // Async notify packet isNotifyPacket = true; LLVM_FALLTHROUGH; case '$': // Look for a standard gdb packet? { size_t hash_pos = m_bytes.find('#'); if (hash_pos != std::string::npos) { if (hash_pos + 2 < m_bytes.size()) { checksum_idx = hash_pos + 1; // Skip the dollar sign content_start = 1; // Don't include the # in the content or the $ in the content // length content_length = hash_pos - 1; total_length = hash_pos + 3; // Skip the # and the two hex checksum bytes } else { // Checksum bytes aren't all here yet content_length = std::string::npos; } } } break; default: { // We have an unexpected byte and we need to flush all bad data that is // in m_bytes, so we need to find the first byte that is a '+' (ACK), '-' // (NACK), \x03 (CTRL+C interrupt), or '$' character (start of packet // header) or of course, the end of the data in m_bytes... const size_t bytes_len = m_bytes.size(); bool done = false; uint32_t idx; for (idx = 1; !done && idx < bytes_len; ++idx) { switch (m_bytes[idx]) { case '+': case '-': case '\x03': case '%': case '$': done = true; break; default: break; } } LLDB_LOGF(log, "GDBRemoteCommunication::%s tossing %u junk bytes: '%.*s'", __FUNCTION__, idx - 1, idx - 1, m_bytes.c_str()); m_bytes.erase(0, idx - 1); } break; } if (content_length == std::string::npos) { packet.Clear(); return GDBRemoteCommunication::PacketType::Invalid; } else if (total_length > 0) { // We have a valid packet... assert(content_length <= m_bytes.size()); assert(total_length <= m_bytes.size()); assert(content_length <= total_length); size_t content_end = content_start + content_length; bool success = true; if (log) { // If logging was just enabled and we have history, then dump out what // we have to the log so we get the historical context. The Dump() call // that logs all of the packet will set a boolean so that we don't dump // this more than once if (!m_history.DidDumpToLog()) m_history.Dump(log); bool binary = false; // Only detect binary for packets that start with a '$' and have a // '#CC' checksum if (m_bytes[0] == '$' && total_length > 4) { for (size_t i = 0; !binary && i < total_length; ++i) { unsigned char c = m_bytes[i]; if (isprint(c) == 0 && isspace(c) == 0) { binary = true; } } } if (binary) { StreamString strm; // Packet header... if (CompressionIsEnabled()) strm.Printf("<%4" PRIu64 ":%" PRIu64 "> read packet: %c", (uint64_t)original_packet_size, (uint64_t)total_length, m_bytes[0]); else strm.Printf("<%4" PRIu64 "> read packet: %c", (uint64_t)total_length, m_bytes[0]); for (size_t i = content_start; i < content_end; ++i) { // Remove binary escaped bytes when displaying the packet... const char ch = m_bytes[i]; if (ch == 0x7d) { // 0x7d is the escape character. The next character is to be // XOR'd with 0x20. const char escapee = m_bytes[++i] ^ 0x20; strm.Printf("%2.2x", escapee); } else { strm.Printf("%2.2x", (uint8_t)ch); } } // Packet footer... strm.Printf("%c%c%c", m_bytes[total_length - 3], m_bytes[total_length - 2], m_bytes[total_length - 1]); log->PutString(strm.GetString()); } else { if (CompressionIsEnabled()) LLDB_LOGF(log, "<%4" PRIu64 ":%" PRIu64 "> read packet: %.*s", (uint64_t)original_packet_size, (uint64_t)total_length, (int)(total_length), m_bytes.c_str()); else LLDB_LOGF(log, "<%4" PRIu64 "> read packet: %.*s", (uint64_t)total_length, (int)(total_length), m_bytes.c_str()); } } m_history.AddPacket(m_bytes, total_length, GDBRemotePacket::ePacketTypeRecv, total_length); // Copy the packet from m_bytes to packet_str expanding the run-length // encoding in the process. Reserve enough byte for the most common case // (no RLE used) std ::string packet_str; packet_str.reserve(m_bytes.length()); for (std::string::const_iterator c = m_bytes.begin() + content_start; c != m_bytes.begin() + content_end; ++c) { if (*c == '*') { // '*' indicates RLE. Next character will give us the repeat count // and previous character is what is to be repeated. char char_to_repeat = packet_str.back(); // Number of time the previous character is repeated int repeat_count = *++c + 3 - ' '; // We have the char_to_repeat and repeat_count. Now push it in the // packet. for (int i = 0; i < repeat_count; ++i) packet_str.push_back(char_to_repeat); } else if (*c == 0x7d) { // 0x7d is the escape character. The next character is to be XOR'd // with 0x20. char escapee = *++c ^ 0x20; packet_str.push_back(escapee); } else { packet_str.push_back(*c); } } packet = StringExtractorGDBRemote(packet_str); if (m_bytes[0] == '$' || m_bytes[0] == '%') { assert(checksum_idx < m_bytes.size()); if (::isxdigit(m_bytes[checksum_idx + 0]) || ::isxdigit(m_bytes[checksum_idx + 1])) { if (GetSendAcks()) { const char *packet_checksum_cstr = &m_bytes[checksum_idx]; char packet_checksum = strtol(packet_checksum_cstr, nullptr, 16); char actual_checksum = CalculcateChecksum( llvm::StringRef(m_bytes).slice(content_start, content_end)); success = packet_checksum == actual_checksum; if (!success) { LLDB_LOGF(log, "error: checksum mismatch: %.*s expected 0x%2.2x, " "got 0x%2.2x", (int)(total_length), m_bytes.c_str(), (uint8_t)packet_checksum, (uint8_t)actual_checksum); } // Send the ack or nack if needed if (!success) SendNack(); else SendAck(); } } else { success = false; LLDB_LOGF(log, "error: invalid checksum in packet: '%s'\n", m_bytes.c_str()); } } m_bytes.erase(0, total_length); packet.SetFilePos(0); if (isNotifyPacket) return GDBRemoteCommunication::PacketType::Notify; else return GDBRemoteCommunication::PacketType::Standard; } } packet.Clear(); return GDBRemoteCommunication::PacketType::Invalid; } Status GDBRemoteCommunication::StartListenThread(const char *hostname, uint16_t port) { if (m_listen_thread.IsJoinable()) return Status("listen thread already running"); char listen_url[512]; if (hostname && hostname[0]) snprintf(listen_url, sizeof(listen_url), "listen://%s:%i", hostname, port); else snprintf(listen_url, sizeof(listen_url), "listen://%i", port); m_listen_url = listen_url; SetConnection(new ConnectionFileDescriptor()); llvm::Expected listen_thread = ThreadLauncher::LaunchThread( listen_url, GDBRemoteCommunication::ListenThread, this); if (!listen_thread) return Status(listen_thread.takeError()); m_listen_thread = *listen_thread; return Status(); } bool GDBRemoteCommunication::JoinListenThread() { if (m_listen_thread.IsJoinable()) m_listen_thread.Join(nullptr); return true; } lldb::thread_result_t GDBRemoteCommunication::ListenThread(lldb::thread_arg_t arg) { GDBRemoteCommunication *comm = (GDBRemoteCommunication *)arg; Status error; ConnectionFileDescriptor *connection = (ConnectionFileDescriptor *)comm->GetConnection(); if (connection) { // Do the listen on another thread so we can continue on... if (connection->Connect(comm->m_listen_url.c_str(), &error) != eConnectionStatusSuccess) comm->SetConnection(nullptr); } return {}; } Status GDBRemoteCommunication::StartDebugserverProcess( const char *url, Platform *platform, ProcessLaunchInfo &launch_info, uint16_t *port, const Args *inferior_args, int pass_comm_fd) { Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); LLDB_LOGF(log, "GDBRemoteCommunication::%s(url=%s, port=%" PRIu16 ")", __FUNCTION__, url ? url : "", port ? *port : uint16_t(0)); Status error; // If we locate debugserver, keep that located version around static FileSpec g_debugserver_file_spec; char debugserver_path[PATH_MAX]; FileSpec &debugserver_file_spec = launch_info.GetExecutableFile(); Environment host_env = Host::GetEnvironment(); // Always check to see if we have an environment override for the path to the // debugserver to use and use it if we do. std::string env_debugserver_path = host_env.lookup("LLDB_DEBUGSERVER_PATH"); if (!env_debugserver_path.empty()) { debugserver_file_spec.SetFile(env_debugserver_path, FileSpec::Style::native); LLDB_LOGF(log, "GDBRemoteCommunication::%s() gdb-remote stub exe path set " "from environment variable: %s", __FUNCTION__, env_debugserver_path.c_str()); } else debugserver_file_spec = g_debugserver_file_spec; bool debugserver_exists = FileSystem::Instance().Exists(debugserver_file_spec); if (!debugserver_exists) { // The debugserver binary is in the LLDB.framework/Resources directory. debugserver_file_spec = HostInfo::GetSupportExeDir(); if (debugserver_file_spec) { debugserver_file_spec.AppendPathComponent(DEBUGSERVER_BASENAME); debugserver_exists = FileSystem::Instance().Exists(debugserver_file_spec); if (debugserver_exists) { LLDB_LOGF(log, "GDBRemoteCommunication::%s() found gdb-remote stub exe '%s'", __FUNCTION__, debugserver_file_spec.GetPath().c_str()); g_debugserver_file_spec = debugserver_file_spec; } else { if (platform) debugserver_file_spec = platform->LocateExecutable(DEBUGSERVER_BASENAME); else debugserver_file_spec.Clear(); if (debugserver_file_spec) { // Platform::LocateExecutable() wouldn't return a path if it doesn't // exist debugserver_exists = true; } else { LLDB_LOGF(log, "GDBRemoteCommunication::%s() could not find " "gdb-remote stub exe '%s'", __FUNCTION__, debugserver_file_spec.GetPath().c_str()); } // Don't cache the platform specific GDB server binary as it could // change from platform to platform g_debugserver_file_spec.Clear(); } } } if (debugserver_exists) { debugserver_file_spec.GetPath(debugserver_path, sizeof(debugserver_path)); Args &debugserver_args = launch_info.GetArguments(); debugserver_args.Clear(); // Start args with "debugserver /file/path -r --" debugserver_args.AppendArgument(llvm::StringRef(debugserver_path)); #if !defined(__APPLE__) // First argument to lldb-server must be mode in which to run. debugserver_args.AppendArgument(llvm::StringRef("gdbserver")); #endif // If a url is supplied then use it if (url) debugserver_args.AppendArgument(llvm::StringRef(url)); if (pass_comm_fd >= 0) { StreamString fd_arg; fd_arg.Printf("--fd=%i", pass_comm_fd); debugserver_args.AppendArgument(fd_arg.GetString()); // Send "pass_comm_fd" down to the inferior so it can use it to // communicate back with this process launch_info.AppendDuplicateFileAction(pass_comm_fd, pass_comm_fd); } // use native registers, not the GDB registers debugserver_args.AppendArgument(llvm::StringRef("--native-regs")); if (launch_info.GetLaunchInSeparateProcessGroup()) { debugserver_args.AppendArgument(llvm::StringRef("--setsid")); } llvm::SmallString<128> named_pipe_path; // socket_pipe is used by debug server to communicate back either // TCP port or domain socket name which it listens on. // The second purpose of the pipe to serve as a synchronization point - // once data is written to the pipe, debug server is up and running. Pipe socket_pipe; // port is null when debug server should listen on domain socket - we're // not interested in port value but rather waiting for debug server to // become available. if (pass_comm_fd == -1) { if (url) { // Create a temporary file to get the stdout/stderr and redirect the output of // the command into this file. We will later read this file if all goes well // and fill the data into "command_output_ptr" #if defined(__APPLE__) // Binding to port zero, we need to figure out what port it ends up // using using a named pipe... error = socket_pipe.CreateWithUniqueName("debugserver-named-pipe", false, named_pipe_path); if (error.Fail()) { LLDB_LOGF(log, "GDBRemoteCommunication::%s() " "named pipe creation failed: %s", __FUNCTION__, error.AsCString()); return error; } debugserver_args.AppendArgument(llvm::StringRef("--named-pipe")); debugserver_args.AppendArgument(named_pipe_path); #else // Binding to port zero, we need to figure out what port it ends up // using using an unnamed pipe... error = socket_pipe.CreateNew(true); if (error.Fail()) { LLDB_LOGF(log, "GDBRemoteCommunication::%s() " "unnamed pipe creation failed: %s", __FUNCTION__, error.AsCString()); return error; } pipe_t write = socket_pipe.GetWritePipe(); debugserver_args.AppendArgument(llvm::StringRef("--pipe")); debugserver_args.AppendArgument(llvm::to_string(write)); launch_info.AppendCloseFileAction(socket_pipe.GetReadFileDescriptor()); #endif } else { // No host and port given, so lets listen on our end and make the // debugserver connect to us.. error = StartListenThread("127.0.0.1", 0); if (error.Fail()) { LLDB_LOGF(log, "GDBRemoteCommunication::%s() unable to start listen " "thread: %s", __FUNCTION__, error.AsCString()); return error; } ConnectionFileDescriptor *connection = (ConnectionFileDescriptor *)GetConnection(); // Wait for 10 seconds to resolve the bound port uint16_t port_ = connection->GetListeningPort(std::chrono::seconds(10)); if (port_ > 0) { char port_cstr[32]; snprintf(port_cstr, sizeof(port_cstr), "127.0.0.1:%i", port_); // Send the host and port down that debugserver and specify an option // so that it connects back to the port we are listening to in this // process debugserver_args.AppendArgument(llvm::StringRef("--reverse-connect")); debugserver_args.AppendArgument(llvm::StringRef(port_cstr)); if (port) *port = port_; } else { error.SetErrorString("failed to bind to port 0 on 127.0.0.1"); LLDB_LOGF(log, "GDBRemoteCommunication::%s() failed: %s", __FUNCTION__, error.AsCString()); return error; } } } std::string env_debugserver_log_file = host_env.lookup("LLDB_DEBUGSERVER_LOG_FILE"); if (!env_debugserver_log_file.empty()) { debugserver_args.AppendArgument( llvm::formatv("--log-file={0}", env_debugserver_log_file).str()); } #if defined(__APPLE__) const char *env_debugserver_log_flags = getenv("LLDB_DEBUGSERVER_LOG_FLAGS"); if (env_debugserver_log_flags) { debugserver_args.AppendArgument( llvm::formatv("--log-flags={0}", env_debugserver_log_flags).str()); } #else std::string env_debugserver_log_channels = host_env.lookup("LLDB_SERVER_LOG_CHANNELS"); if (!env_debugserver_log_channels.empty()) { debugserver_args.AppendArgument( llvm::formatv("--log-channels={0}", env_debugserver_log_channels) .str()); } #endif // Add additional args, starting with LLDB_DEBUGSERVER_EXTRA_ARG_1 until an // env var doesn't come back. uint32_t env_var_index = 1; bool has_env_var; do { char env_var_name[64]; snprintf(env_var_name, sizeof(env_var_name), "LLDB_DEBUGSERVER_EXTRA_ARG_%" PRIu32, env_var_index++); std::string extra_arg = host_env.lookup(env_var_name); has_env_var = !extra_arg.empty(); if (has_env_var) { debugserver_args.AppendArgument(llvm::StringRef(extra_arg)); LLDB_LOGF(log, "GDBRemoteCommunication::%s adding env var %s contents " "to stub command line (%s)", __FUNCTION__, env_var_name, extra_arg.c_str()); } } while (has_env_var); if (inferior_args && inferior_args->GetArgumentCount() > 0) { debugserver_args.AppendArgument(llvm::StringRef("--")); debugserver_args.AppendArguments(*inferior_args); } // Copy the current environment to the gdbserver/debugserver instance launch_info.GetEnvironment() = host_env; // Close STDIN, STDOUT and STDERR. launch_info.AppendCloseFileAction(STDIN_FILENO); launch_info.AppendCloseFileAction(STDOUT_FILENO); launch_info.AppendCloseFileAction(STDERR_FILENO); // Redirect STDIN, STDOUT and STDERR to "/dev/null". launch_info.AppendSuppressFileAction(STDIN_FILENO, true, false); launch_info.AppendSuppressFileAction(STDOUT_FILENO, false, true); launch_info.AppendSuppressFileAction(STDERR_FILENO, false, true); if (log) { StreamString string_stream; Platform *const platform = nullptr; launch_info.Dump(string_stream, platform); LLDB_LOGF(log, "launch info for gdb-remote stub:\n%s", string_stream.GetData()); } error = Host::LaunchProcess(launch_info); if (error.Success() && (launch_info.GetProcessID() != LLDB_INVALID_PROCESS_ID) && pass_comm_fd == -1) { if (named_pipe_path.size() > 0) { error = socket_pipe.OpenAsReader(named_pipe_path, false); if (error.Fail()) LLDB_LOGF(log, "GDBRemoteCommunication::%s() " "failed to open named pipe %s for reading: %s", __FUNCTION__, named_pipe_path.c_str(), error.AsCString()); } if (socket_pipe.CanWrite()) socket_pipe.CloseWriteFileDescriptor(); if (socket_pipe.CanRead()) { char port_cstr[PATH_MAX] = {0}; port_cstr[0] = '\0'; size_t num_bytes = sizeof(port_cstr); // Read port from pipe with 10 second timeout. error = socket_pipe.ReadWithTimeout( port_cstr, num_bytes, std::chrono::seconds{10}, num_bytes); if (error.Success() && (port != nullptr)) { assert(num_bytes > 0 && port_cstr[num_bytes - 1] == '\0'); uint16_t child_port = StringConvert::ToUInt32(port_cstr, 0); if (*port == 0 || *port == child_port) { *port = child_port; LLDB_LOGF(log, "GDBRemoteCommunication::%s() " "debugserver listens %u port", __FUNCTION__, *port); } else { LLDB_LOGF(log, "GDBRemoteCommunication::%s() " "debugserver listening on port " "%d but requested port was %d", __FUNCTION__, (uint32_t)child_port, (uint32_t)(*port)); } } else { LLDB_LOGF(log, "GDBRemoteCommunication::%s() " "failed to read a port value from pipe %s: %s", __FUNCTION__, named_pipe_path.c_str(), error.AsCString()); } socket_pipe.Close(); } if (named_pipe_path.size() > 0) { const auto err = socket_pipe.Delete(named_pipe_path); if (err.Fail()) { LLDB_LOGF(log, "GDBRemoteCommunication::%s failed to delete pipe %s: %s", __FUNCTION__, named_pipe_path.c_str(), err.AsCString()); } } // Make sure we actually connect with the debugserver... JoinListenThread(); } } else { error.SetErrorStringWithFormat("unable to locate " DEBUGSERVER_BASENAME); } if (error.Fail()) { LLDB_LOGF(log, "GDBRemoteCommunication::%s() failed: %s", __FUNCTION__, error.AsCString()); } return error; } void GDBRemoteCommunication::DumpHistory(Stream &strm) { m_history.Dump(strm); } void GDBRemoteCommunication::SetPacketRecorder( repro::PacketRecorder *recorder) { m_history.SetRecorder(recorder); } llvm::Error GDBRemoteCommunication::ConnectLocally(GDBRemoteCommunication &client, GDBRemoteCommunication &server) { const bool child_processes_inherit = false; const int backlog = 5; TCPSocket listen_socket(true, child_processes_inherit); if (llvm::Error error = listen_socket.Listen("127.0.0.1:0", backlog).ToError()) return error; Socket *accept_socket; std::future accept_status = std::async( std::launch::async, [&] { return listen_socket.Accept(accept_socket); }); llvm::SmallString<32> remote_addr; llvm::raw_svector_ostream(remote_addr) << "connect://127.0.0.1:" << listen_socket.GetLocalPortNumber(); std::unique_ptr conn_up( new ConnectionFileDescriptor()); Status status; if (conn_up->Connect(remote_addr, &status) != lldb::eConnectionStatusSuccess) return llvm::createStringError(llvm::inconvertibleErrorCode(), "Unable to connect: %s", status.AsCString()); client.SetConnection(conn_up.release()); if (llvm::Error error = accept_status.get().ToError()) return error; server.SetConnection(new ConnectionFileDescriptor(accept_socket)); return llvm::Error::success(); } GDBRemoteCommunication::ScopedTimeout::ScopedTimeout( GDBRemoteCommunication &gdb_comm, std::chrono::seconds timeout) : m_gdb_comm(gdb_comm), m_timeout_modified(false) { auto curr_timeout = gdb_comm.GetPacketTimeout(); // Only update the timeout if the timeout is greater than the current // timeout. If the current timeout is larger, then just use that. if (curr_timeout < timeout) { m_timeout_modified = true; m_saved_timeout = m_gdb_comm.SetPacketTimeout(timeout); } } GDBRemoteCommunication::ScopedTimeout::~ScopedTimeout() { // Only restore the timeout if we set it in the constructor. if (m_timeout_modified) m_gdb_comm.SetPacketTimeout(m_saved_timeout); } // This function is called via the Communications class read thread when bytes // become available for this connection. This function will consume all // incoming bytes and try to parse whole packets as they become available. Full // packets are placed in a queue, so that all packet requests can simply pop // from this queue. Async notification packets will be dispatched immediately // to the ProcessGDBRemote Async thread via an event. void GDBRemoteCommunication::AppendBytesToCache(const uint8_t *bytes, size_t len, bool broadcast, lldb::ConnectionStatus status) { StringExtractorGDBRemote packet; while (true) { PacketType type = CheckForPacket(bytes, len, packet); // scrub the data so we do not pass it back to CheckForPacket on future // passes of the loop bytes = nullptr; len = 0; // we may have received no packet so lets bail out if (type == PacketType::Invalid) break; if (type == PacketType::Standard) { // scope for the mutex { // lock down the packet queue std::lock_guard guard(m_packet_queue_mutex); // push a new packet into the queue m_packet_queue.push(packet); // Signal condition variable that we have a packet m_condition_queue_not_empty.notify_one(); } } if (type == PacketType::Notify) { // put this packet into an event const char *pdata = packet.GetStringRef().data(); // as the communication class, we are a broadcaster and the async thread // is tuned to listen to us BroadcastEvent(eBroadcastBitGdbReadThreadGotNotify, new EventDataBytes(pdata)); } } } void llvm::format_provider::format( const GDBRemoteCommunication::PacketResult &result, raw_ostream &Stream, StringRef Style) { using PacketResult = GDBRemoteCommunication::PacketResult; switch (result) { case PacketResult::Success: Stream << "Success"; break; case PacketResult::ErrorSendFailed: Stream << "ErrorSendFailed"; break; case PacketResult::ErrorSendAck: Stream << "ErrorSendAck"; break; case PacketResult::ErrorReplyFailed: Stream << "ErrorReplyFailed"; break; case PacketResult::ErrorReplyTimeout: Stream << "ErrorReplyTimeout"; break; case PacketResult::ErrorReplyInvalid: Stream << "ErrorReplyInvalid"; break; case PacketResult::ErrorReplyAck: Stream << "ErrorReplyAck"; break; case PacketResult::ErrorDisconnected: Stream << "ErrorDisconnected"; break; case PacketResult::ErrorNoSequenceLock: Stream << "ErrorNoSequenceLock"; break; } } diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp index b2f1ee527e8b..4dafa1d494d8 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp @@ -1,4048 +1,4048 @@ //===-- GDBRemoteCommunicationClient.cpp ------------------------*- 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 // //===----------------------------------------------------------------------===// #include "GDBRemoteCommunicationClient.h" #include #include #include #include #include "lldb/Core/ModuleSpec.h" #include "lldb/Host/HostInfo.h" #include "lldb/Host/XML.h" #include "lldb/Symbol/Symbol.h" #include "lldb/Target/MemoryRegionInfo.h" #include "lldb/Target/Target.h" #include "lldb/Target/UnixSignals.h" #include "lldb/Utility/Args.h" #include "lldb/Utility/DataBufferHeap.h" #include "lldb/Utility/LLDBAssert.h" #include "lldb/Utility/Log.h" #include "lldb/Utility/State.h" #include "lldb/Utility/StreamString.h" #include "ProcessGDBRemote.h" #include "ProcessGDBRemoteLog.h" #include "lldb/Host/Config.h" #include "lldb/Utility/StringExtractorGDBRemote.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Support/JSON.h" #if defined(HAVE_LIBCOMPRESSION) #include #endif using namespace lldb; using namespace lldb_private::process_gdb_remote; using namespace lldb_private; using namespace std::chrono; // GDBRemoteCommunicationClient constructor GDBRemoteCommunicationClient::GDBRemoteCommunicationClient() : GDBRemoteClientBase("gdb-remote.client", "gdb-remote.client.rx_packet"), m_supports_not_sending_acks(eLazyBoolCalculate), m_supports_thread_suffix(eLazyBoolCalculate), m_supports_threads_in_stop_reply(eLazyBoolCalculate), m_supports_vCont_all(eLazyBoolCalculate), m_supports_vCont_any(eLazyBoolCalculate), m_supports_vCont_c(eLazyBoolCalculate), m_supports_vCont_C(eLazyBoolCalculate), m_supports_vCont_s(eLazyBoolCalculate), m_supports_vCont_S(eLazyBoolCalculate), m_qHostInfo_is_valid(eLazyBoolCalculate), m_curr_pid_is_valid(eLazyBoolCalculate), m_qProcessInfo_is_valid(eLazyBoolCalculate), m_qGDBServerVersion_is_valid(eLazyBoolCalculate), m_supports_alloc_dealloc_memory(eLazyBoolCalculate), m_supports_memory_region_info(eLazyBoolCalculate), m_supports_watchpoint_support_info(eLazyBoolCalculate), m_supports_detach_stay_stopped(eLazyBoolCalculate), m_watchpoints_trigger_after_instruction(eLazyBoolCalculate), m_attach_or_wait_reply(eLazyBoolCalculate), m_prepare_for_reg_writing_reply(eLazyBoolCalculate), m_supports_p(eLazyBoolCalculate), m_supports_x(eLazyBoolCalculate), m_avoid_g_packets(eLazyBoolCalculate), m_supports_QSaveRegisterState(eLazyBoolCalculate), m_supports_qXfer_auxv_read(eLazyBoolCalculate), m_supports_qXfer_libraries_read(eLazyBoolCalculate), m_supports_qXfer_libraries_svr4_read(eLazyBoolCalculate), m_supports_qXfer_features_read(eLazyBoolCalculate), m_supports_qXfer_memory_map_read(eLazyBoolCalculate), m_supports_augmented_libraries_svr4_read(eLazyBoolCalculate), m_supports_jThreadExtendedInfo(eLazyBoolCalculate), m_supports_jLoadedDynamicLibrariesInfos(eLazyBoolCalculate), m_supports_jGetSharedCacheInfo(eLazyBoolCalculate), m_supports_QPassSignals(eLazyBoolCalculate), m_supports_error_string_reply(eLazyBoolCalculate), m_supports_qProcessInfoPID(true), m_supports_qfProcessInfo(true), m_supports_qUserName(true), m_supports_qGroupName(true), m_supports_qThreadStopInfo(true), m_supports_z0(true), m_supports_z1(true), m_supports_z2(true), m_supports_z3(true), m_supports_z4(true), m_supports_QEnvironment(true), m_supports_QEnvironmentHexEncoded(true), m_supports_qSymbol(true), m_qSymbol_requests_done(false), m_supports_qModuleInfo(true), m_supports_jThreadsInfo(true), m_supports_jModulesInfo(true), m_curr_pid(LLDB_INVALID_PROCESS_ID), m_curr_tid(LLDB_INVALID_THREAD_ID), m_curr_tid_run(LLDB_INVALID_THREAD_ID), m_num_supported_hardware_watchpoints(0), m_host_arch(), m_process_arch(), m_os_build(), m_os_kernel(), m_hostname(), m_gdb_server_name(), m_gdb_server_version(UINT32_MAX), m_default_packet_timeout(0), m_max_packet_size(0), m_qSupported_response(), m_supported_async_json_packets_is_valid(false), m_supported_async_json_packets_sp(), m_qXfer_memory_map(), m_qXfer_memory_map_loaded(false) {} // Destructor GDBRemoteCommunicationClient::~GDBRemoteCommunicationClient() { if (IsConnected()) Disconnect(); } bool GDBRemoteCommunicationClient::HandshakeWithServer(Status *error_ptr) { ResetDiscoverableSettings(false); // Start the read thread after we send the handshake ack since if we fail to // send the handshake ack, there is no reason to continue... if (SendAck()) { // Wait for any responses that might have been queued up in the remote // GDB server and flush them all StringExtractorGDBRemote response; PacketResult packet_result = PacketResult::Success; while (packet_result == PacketResult::Success) packet_result = ReadPacket(response, milliseconds(10), false); // The return value from QueryNoAckModeSupported() is true if the packet // was sent and _any_ response (including UNIMPLEMENTED) was received), or // false if no response was received. This quickly tells us if we have a // live connection to a remote GDB server... if (QueryNoAckModeSupported()) { return true; } else { if (error_ptr) error_ptr->SetErrorString("failed to get reply to handshake packet"); } } else { if (error_ptr) error_ptr->SetErrorString("failed to send the handshake ack"); } return false; } bool GDBRemoteCommunicationClient::GetEchoSupported() { if (m_supports_qEcho == eLazyBoolCalculate) { GetRemoteQSupported(); } return m_supports_qEcho == eLazyBoolYes; } bool GDBRemoteCommunicationClient::GetQPassSignalsSupported() { if (m_supports_QPassSignals == eLazyBoolCalculate) { GetRemoteQSupported(); } return m_supports_QPassSignals == eLazyBoolYes; } bool GDBRemoteCommunicationClient::GetAugmentedLibrariesSVR4ReadSupported() { if (m_supports_augmented_libraries_svr4_read == eLazyBoolCalculate) { GetRemoteQSupported(); } return m_supports_augmented_libraries_svr4_read == eLazyBoolYes; } bool GDBRemoteCommunicationClient::GetQXferLibrariesSVR4ReadSupported() { if (m_supports_qXfer_libraries_svr4_read == eLazyBoolCalculate) { GetRemoteQSupported(); } return m_supports_qXfer_libraries_svr4_read == eLazyBoolYes; } bool GDBRemoteCommunicationClient::GetQXferLibrariesReadSupported() { if (m_supports_qXfer_libraries_read == eLazyBoolCalculate) { GetRemoteQSupported(); } return m_supports_qXfer_libraries_read == eLazyBoolYes; } bool GDBRemoteCommunicationClient::GetQXferAuxvReadSupported() { if (m_supports_qXfer_auxv_read == eLazyBoolCalculate) { GetRemoteQSupported(); } return m_supports_qXfer_auxv_read == eLazyBoolYes; } bool GDBRemoteCommunicationClient::GetQXferFeaturesReadSupported() { if (m_supports_qXfer_features_read == eLazyBoolCalculate) { GetRemoteQSupported(); } return m_supports_qXfer_features_read == eLazyBoolYes; } bool GDBRemoteCommunicationClient::GetQXferMemoryMapReadSupported() { if (m_supports_qXfer_memory_map_read == eLazyBoolCalculate) { GetRemoteQSupported(); } return m_supports_qXfer_memory_map_read == eLazyBoolYes; } uint64_t GDBRemoteCommunicationClient::GetRemoteMaxPacketSize() { if (m_max_packet_size == 0) { GetRemoteQSupported(); } return m_max_packet_size; } bool GDBRemoteCommunicationClient::QueryNoAckModeSupported() { if (m_supports_not_sending_acks == eLazyBoolCalculate) { m_send_acks = true; m_supports_not_sending_acks = eLazyBoolNo; // This is the first real packet that we'll send in a debug session and it // may take a little longer than normal to receive a reply. Wait at least // 6 seconds for a reply to this packet. ScopedTimeout timeout(*this, std::max(GetPacketTimeout(), seconds(6))); StringExtractorGDBRemote response; if (SendPacketAndWaitForResponse("QStartNoAckMode", response, false) == PacketResult::Success) { if (response.IsOKResponse()) { m_send_acks = false; m_supports_not_sending_acks = eLazyBoolYes; } return true; } } return false; } void GDBRemoteCommunicationClient::GetListThreadsInStopReplySupported() { if (m_supports_threads_in_stop_reply == eLazyBoolCalculate) { m_supports_threads_in_stop_reply = eLazyBoolNo; StringExtractorGDBRemote response; if (SendPacketAndWaitForResponse("QListThreadsInStopReply", response, false) == PacketResult::Success) { if (response.IsOKResponse()) m_supports_threads_in_stop_reply = eLazyBoolYes; } } } bool GDBRemoteCommunicationClient::GetVAttachOrWaitSupported() { if (m_attach_or_wait_reply == eLazyBoolCalculate) { m_attach_or_wait_reply = eLazyBoolNo; StringExtractorGDBRemote response; if (SendPacketAndWaitForResponse("qVAttachOrWaitSupported", response, false) == PacketResult::Success) { if (response.IsOKResponse()) m_attach_or_wait_reply = eLazyBoolYes; } } return m_attach_or_wait_reply == eLazyBoolYes; } bool GDBRemoteCommunicationClient::GetSyncThreadStateSupported() { if (m_prepare_for_reg_writing_reply == eLazyBoolCalculate) { m_prepare_for_reg_writing_reply = eLazyBoolNo; StringExtractorGDBRemote response; if (SendPacketAndWaitForResponse("qSyncThreadStateSupported", response, false) == PacketResult::Success) { if (response.IsOKResponse()) m_prepare_for_reg_writing_reply = eLazyBoolYes; } } return m_prepare_for_reg_writing_reply == eLazyBoolYes; } void GDBRemoteCommunicationClient::ResetDiscoverableSettings(bool did_exec) { if (!did_exec) { // Hard reset everything, this is when we first connect to a GDB server m_supports_not_sending_acks = eLazyBoolCalculate; m_supports_thread_suffix = eLazyBoolCalculate; m_supports_threads_in_stop_reply = eLazyBoolCalculate; m_supports_vCont_c = eLazyBoolCalculate; m_supports_vCont_C = eLazyBoolCalculate; m_supports_vCont_s = eLazyBoolCalculate; m_supports_vCont_S = eLazyBoolCalculate; m_supports_p = eLazyBoolCalculate; m_supports_x = eLazyBoolCalculate; m_supports_QSaveRegisterState = eLazyBoolCalculate; m_qHostInfo_is_valid = eLazyBoolCalculate; m_curr_pid_is_valid = eLazyBoolCalculate; m_qGDBServerVersion_is_valid = eLazyBoolCalculate; m_supports_alloc_dealloc_memory = eLazyBoolCalculate; m_supports_memory_region_info = eLazyBoolCalculate; m_prepare_for_reg_writing_reply = eLazyBoolCalculate; m_attach_or_wait_reply = eLazyBoolCalculate; m_avoid_g_packets = eLazyBoolCalculate; m_supports_qXfer_auxv_read = eLazyBoolCalculate; m_supports_qXfer_libraries_read = eLazyBoolCalculate; m_supports_qXfer_libraries_svr4_read = eLazyBoolCalculate; m_supports_qXfer_features_read = eLazyBoolCalculate; m_supports_qXfer_memory_map_read = eLazyBoolCalculate; m_supports_augmented_libraries_svr4_read = eLazyBoolCalculate; m_supports_qProcessInfoPID = true; m_supports_qfProcessInfo = true; m_supports_qUserName = true; m_supports_qGroupName = true; m_supports_qThreadStopInfo = true; m_supports_z0 = true; m_supports_z1 = true; m_supports_z2 = true; m_supports_z3 = true; m_supports_z4 = true; m_supports_QEnvironment = true; m_supports_QEnvironmentHexEncoded = true; m_supports_qSymbol = true; m_qSymbol_requests_done = false; m_supports_qModuleInfo = true; m_host_arch.Clear(); m_os_version = llvm::VersionTuple(); m_os_build.clear(); m_os_kernel.clear(); m_hostname.clear(); m_gdb_server_name.clear(); m_gdb_server_version = UINT32_MAX; m_default_packet_timeout = seconds(0); m_max_packet_size = 0; m_qSupported_response.clear(); m_supported_async_json_packets_is_valid = false; m_supported_async_json_packets_sp.reset(); m_supports_jModulesInfo = true; } // These flags should be reset when we first connect to a GDB server and when // our inferior process execs m_qProcessInfo_is_valid = eLazyBoolCalculate; m_process_arch.Clear(); } void GDBRemoteCommunicationClient::GetRemoteQSupported() { // Clear out any capabilities we expect to see in the qSupported response m_supports_qXfer_auxv_read = eLazyBoolNo; m_supports_qXfer_libraries_read = eLazyBoolNo; m_supports_qXfer_libraries_svr4_read = eLazyBoolNo; m_supports_augmented_libraries_svr4_read = eLazyBoolNo; m_supports_qXfer_features_read = eLazyBoolNo; m_supports_qXfer_memory_map_read = eLazyBoolNo; m_max_packet_size = UINT64_MAX; // It's supposed to always be there, but if // not, we assume no limit // build the qSupported packet std::vector features = {"xmlRegisters=i386,arm,mips,arc"}; StreamString packet; packet.PutCString("qSupported"); for (uint32_t i = 0; i < features.size(); ++i) { packet.PutCString(i == 0 ? ":" : ";"); packet.PutCString(features[i]); } StringExtractorGDBRemote response; if (SendPacketAndWaitForResponse(packet.GetString(), response, /*send_async=*/false) == PacketResult::Success) { const char *response_cstr = response.GetStringRef().data(); // Hang on to the qSupported packet, so that platforms can do custom // configuration of the transport before attaching/launching the process. m_qSupported_response = response_cstr; if (::strstr(response_cstr, "qXfer:auxv:read+")) m_supports_qXfer_auxv_read = eLazyBoolYes; if (::strstr(response_cstr, "qXfer:libraries-svr4:read+")) m_supports_qXfer_libraries_svr4_read = eLazyBoolYes; if (::strstr(response_cstr, "augmented-libraries-svr4-read")) { m_supports_qXfer_libraries_svr4_read = eLazyBoolYes; // implied m_supports_augmented_libraries_svr4_read = eLazyBoolYes; } if (::strstr(response_cstr, "qXfer:libraries:read+")) m_supports_qXfer_libraries_read = eLazyBoolYes; if (::strstr(response_cstr, "qXfer:features:read+")) m_supports_qXfer_features_read = eLazyBoolYes; if (::strstr(response_cstr, "qXfer:memory-map:read+")) m_supports_qXfer_memory_map_read = eLazyBoolYes; // Look for a list of compressions in the features list e.g. // qXfer:features:read+;PacketSize=20000;qEcho+;SupportedCompressions=zlib- // deflate,lzma const char *features_list = ::strstr(response_cstr, "qXfer:features:"); if (features_list) { const char *compressions = ::strstr(features_list, "SupportedCompressions="); if (compressions) { std::vector supported_compressions; compressions += sizeof("SupportedCompressions=") - 1; const char *end_of_compressions = strchr(compressions, ';'); if (end_of_compressions == nullptr) { end_of_compressions = strchr(compressions, '\0'); } const char *current_compression = compressions; while (current_compression < end_of_compressions) { const char *next_compression_name = strchr(current_compression, ','); const char *end_of_this_word = next_compression_name; if (next_compression_name == nullptr || end_of_compressions < next_compression_name) { end_of_this_word = end_of_compressions; } if (end_of_this_word) { if (end_of_this_word == current_compression) { current_compression++; } else { std::string this_compression( current_compression, end_of_this_word - current_compression); supported_compressions.push_back(this_compression); current_compression = end_of_this_word + 1; } } else { supported_compressions.push_back(current_compression); current_compression = end_of_compressions; } } if (supported_compressions.size() > 0) { MaybeEnableCompression(supported_compressions); } } } if (::strstr(response_cstr, "qEcho")) m_supports_qEcho = eLazyBoolYes; else m_supports_qEcho = eLazyBoolNo; if (::strstr(response_cstr, "QPassSignals+")) m_supports_QPassSignals = eLazyBoolYes; else m_supports_QPassSignals = eLazyBoolNo; const char *packet_size_str = ::strstr(response_cstr, "PacketSize="); if (packet_size_str) { StringExtractorGDBRemote packet_response(packet_size_str + strlen("PacketSize=")); m_max_packet_size = packet_response.GetHexMaxU64(/*little_endian=*/false, UINT64_MAX); if (m_max_packet_size == 0) { m_max_packet_size = UINT64_MAX; // Must have been a garbled response Log *log( ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); LLDB_LOGF(log, "Garbled PacketSize spec in qSupported response"); } } } } bool GDBRemoteCommunicationClient::GetThreadSuffixSupported() { if (m_supports_thread_suffix == eLazyBoolCalculate) { StringExtractorGDBRemote response; m_supports_thread_suffix = eLazyBoolNo; if (SendPacketAndWaitForResponse("QThreadSuffixSupported", response, false) == PacketResult::Success) { if (response.IsOKResponse()) m_supports_thread_suffix = eLazyBoolYes; } } return m_supports_thread_suffix; } bool GDBRemoteCommunicationClient::GetVContSupported(char flavor) { if (m_supports_vCont_c == eLazyBoolCalculate) { StringExtractorGDBRemote response; m_supports_vCont_any = eLazyBoolNo; m_supports_vCont_all = eLazyBoolNo; m_supports_vCont_c = eLazyBoolNo; m_supports_vCont_C = eLazyBoolNo; m_supports_vCont_s = eLazyBoolNo; m_supports_vCont_S = eLazyBoolNo; if (SendPacketAndWaitForResponse("vCont?", response, false) == PacketResult::Success) { const char *response_cstr = response.GetStringRef().data(); if (::strstr(response_cstr, ";c")) m_supports_vCont_c = eLazyBoolYes; if (::strstr(response_cstr, ";C")) m_supports_vCont_C = eLazyBoolYes; if (::strstr(response_cstr, ";s")) m_supports_vCont_s = eLazyBoolYes; if (::strstr(response_cstr, ";S")) m_supports_vCont_S = eLazyBoolYes; if (m_supports_vCont_c == eLazyBoolYes && m_supports_vCont_C == eLazyBoolYes && m_supports_vCont_s == eLazyBoolYes && m_supports_vCont_S == eLazyBoolYes) { m_supports_vCont_all = eLazyBoolYes; } if (m_supports_vCont_c == eLazyBoolYes || m_supports_vCont_C == eLazyBoolYes || m_supports_vCont_s == eLazyBoolYes || m_supports_vCont_S == eLazyBoolYes) { m_supports_vCont_any = eLazyBoolYes; } } } switch (flavor) { case 'a': return m_supports_vCont_any; case 'A': return m_supports_vCont_all; case 'c': return m_supports_vCont_c; case 'C': return m_supports_vCont_C; case 's': return m_supports_vCont_s; case 'S': return m_supports_vCont_S; default: break; } return false; } GDBRemoteCommunication::PacketResult GDBRemoteCommunicationClient::SendThreadSpecificPacketAndWaitForResponse( lldb::tid_t tid, StreamString &&payload, StringExtractorGDBRemote &response, bool send_async) { Lock lock(*this, send_async); if (!lock) { if (Log *log = ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet( GDBR_LOG_PROCESS | GDBR_LOG_PACKETS)) LLDB_LOGF(log, "GDBRemoteCommunicationClient::%s: Didn't get sequence mutex " "for %s packet.", __FUNCTION__, payload.GetData()); return PacketResult::ErrorNoSequenceLock; } if (GetThreadSuffixSupported()) payload.Printf(";thread:%4.4" PRIx64 ";", tid); else { if (!SetCurrentThread(tid)) return PacketResult::ErrorSendFailed; } return SendPacketAndWaitForResponseNoLock(payload.GetString(), response); } // Check if the target supports 'p' packet. It sends out a 'p' packet and // checks the response. A normal packet will tell us that support is available. // // Takes a valid thread ID because p needs to apply to a thread. bool GDBRemoteCommunicationClient::GetpPacketSupported(lldb::tid_t tid) { if (m_supports_p == eLazyBoolCalculate) m_supports_p = GetThreadPacketSupported(tid, "p0"); return m_supports_p; } LazyBool GDBRemoteCommunicationClient::GetThreadPacketSupported( lldb::tid_t tid, llvm::StringRef packetStr) { StreamString payload; payload.PutCString(packetStr); StringExtractorGDBRemote response; if (SendThreadSpecificPacketAndWaitForResponse( tid, std::move(payload), response, false) == PacketResult::Success && response.IsNormalResponse()) { return eLazyBoolYes; } return eLazyBoolNo; } StructuredData::ObjectSP GDBRemoteCommunicationClient::GetThreadsInfo() { // Get information on all threads at one using the "jThreadsInfo" packet StructuredData::ObjectSP object_sp; if (m_supports_jThreadsInfo) { StringExtractorGDBRemote response; response.SetResponseValidatorToJSON(); if (SendPacketAndWaitForResponse("jThreadsInfo", response, false) == PacketResult::Success) { if (response.IsUnsupportedResponse()) { m_supports_jThreadsInfo = false; } else if (!response.Empty()) { object_sp = StructuredData::ParseJSON(response.GetStringRef()); } } } return object_sp; } bool GDBRemoteCommunicationClient::GetThreadExtendedInfoSupported() { if (m_supports_jThreadExtendedInfo == eLazyBoolCalculate) { StringExtractorGDBRemote response; m_supports_jThreadExtendedInfo = eLazyBoolNo; if (SendPacketAndWaitForResponse("jThreadExtendedInfo:", response, false) == PacketResult::Success) { if (response.IsOKResponse()) { m_supports_jThreadExtendedInfo = eLazyBoolYes; } } } return m_supports_jThreadExtendedInfo; } void GDBRemoteCommunicationClient::EnableErrorStringInPacket() { if (m_supports_error_string_reply == eLazyBoolCalculate) { StringExtractorGDBRemote response; // We try to enable error strings in remote packets but if we fail, we just // work in the older way. m_supports_error_string_reply = eLazyBoolNo; if (SendPacketAndWaitForResponse("QEnableErrorStrings", response, false) == PacketResult::Success) { if (response.IsOKResponse()) { m_supports_error_string_reply = eLazyBoolYes; } } } } bool GDBRemoteCommunicationClient::GetLoadedDynamicLibrariesInfosSupported() { if (m_supports_jLoadedDynamicLibrariesInfos == eLazyBoolCalculate) { StringExtractorGDBRemote response; m_supports_jLoadedDynamicLibrariesInfos = eLazyBoolNo; if (SendPacketAndWaitForResponse("jGetLoadedDynamicLibrariesInfos:", response, false) == PacketResult::Success) { if (response.IsOKResponse()) { m_supports_jLoadedDynamicLibrariesInfos = eLazyBoolYes; } } } return m_supports_jLoadedDynamicLibrariesInfos; } bool GDBRemoteCommunicationClient::GetSharedCacheInfoSupported() { if (m_supports_jGetSharedCacheInfo == eLazyBoolCalculate) { StringExtractorGDBRemote response; m_supports_jGetSharedCacheInfo = eLazyBoolNo; if (SendPacketAndWaitForResponse("jGetSharedCacheInfo:", response, false) == PacketResult::Success) { if (response.IsOKResponse()) { m_supports_jGetSharedCacheInfo = eLazyBoolYes; } } } return m_supports_jGetSharedCacheInfo; } bool GDBRemoteCommunicationClient::GetxPacketSupported() { if (m_supports_x == eLazyBoolCalculate) { StringExtractorGDBRemote response; m_supports_x = eLazyBoolNo; char packet[256]; snprintf(packet, sizeof(packet), "x0,0"); if (SendPacketAndWaitForResponse(packet, response, false) == PacketResult::Success) { if (response.IsOKResponse()) m_supports_x = eLazyBoolYes; } } return m_supports_x; } GDBRemoteCommunicationClient::PacketResult GDBRemoteCommunicationClient::SendPacketsAndConcatenateResponses( const char *payload_prefix, std::string &response_string) { Lock lock(*this, false); if (!lock) { Log *log(ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet(GDBR_LOG_PROCESS | GDBR_LOG_PACKETS)); LLDB_LOGF(log, "error: failed to get packet sequence mutex, not sending " "packets with prefix '%s'", payload_prefix); return PacketResult::ErrorNoSequenceLock; } response_string = ""; std::string payload_prefix_str(payload_prefix); unsigned int response_size = 0x1000; if (response_size > GetRemoteMaxPacketSize()) { // May send qSupported packet response_size = GetRemoteMaxPacketSize(); } for (unsigned int offset = 0; true; offset += response_size) { StringExtractorGDBRemote this_response; // Construct payload char sizeDescriptor[128]; snprintf(sizeDescriptor, sizeof(sizeDescriptor), "%x,%x", offset, response_size); PacketResult result = SendPacketAndWaitForResponseNoLock( payload_prefix_str + sizeDescriptor, this_response); if (result != PacketResult::Success) return result; const std::string &this_string = this_response.GetStringRef(); // Check for m or l as first character; l seems to mean this is the last // chunk char first_char = *this_string.c_str(); if (first_char != 'm' && first_char != 'l') { return PacketResult::ErrorReplyInvalid; } // Concatenate the result so far (skipping 'm' or 'l') response_string.append(this_string, 1, std::string::npos); if (first_char == 'l') // We're done return PacketResult::Success; } } lldb::pid_t GDBRemoteCommunicationClient::GetCurrentProcessID(bool allow_lazy) { if (allow_lazy && m_curr_pid_is_valid == eLazyBoolYes) return m_curr_pid; // First try to retrieve the pid via the qProcessInfo request. GetCurrentProcessInfo(allow_lazy); if (m_curr_pid_is_valid == eLazyBoolYes) { // We really got it. return m_curr_pid; } else { // If we don't get a response for qProcessInfo, check if $qC gives us a // result. $qC only returns a real process id on older debugserver and // lldb-platform stubs. The gdb remote protocol documents $qC as returning // the thread id, which newer debugserver and lldb-gdbserver stubs return // correctly. StringExtractorGDBRemote response; if (SendPacketAndWaitForResponse("qC", response, false) == PacketResult::Success) { if (response.GetChar() == 'Q') { if (response.GetChar() == 'C') { m_curr_pid = response.GetHexMaxU32(false, LLDB_INVALID_PROCESS_ID); if (m_curr_pid != LLDB_INVALID_PROCESS_ID) { m_curr_pid_is_valid = eLazyBoolYes; return m_curr_pid; } } } } // If we don't get a response for $qC, check if $qfThreadID gives us a // result. if (m_curr_pid == LLDB_INVALID_PROCESS_ID) { std::vector thread_ids; bool sequence_mutex_unavailable; size_t size; size = GetCurrentThreadIDs(thread_ids, sequence_mutex_unavailable); if (size && !sequence_mutex_unavailable) { m_curr_pid = thread_ids.front(); m_curr_pid_is_valid = eLazyBoolYes; return m_curr_pid; } } } return LLDB_INVALID_PROCESS_ID; } bool GDBRemoteCommunicationClient::GetLaunchSuccess(std::string &error_str) { error_str.clear(); StringExtractorGDBRemote response; if (SendPacketAndWaitForResponse("qLaunchSuccess", response, false) == PacketResult::Success) { if (response.IsOKResponse()) return true; if (response.GetChar() == 'E') { // A string the describes what failed when launching... error_str = response.GetStringRef().substr(1); } else { error_str.assign("unknown error occurred launching process"); } } else { error_str.assign("timed out waiting for app to launch"); } return false; } int GDBRemoteCommunicationClient::SendArgumentsPacket( const ProcessLaunchInfo &launch_info) { // Since we don't get the send argv0 separate from the executable path, we // need to make sure to use the actual executable path found in the // launch_info... std::vector argv; FileSpec exe_file = launch_info.GetExecutableFile(); std::string exe_path; const char *arg = nullptr; const Args &launch_args = launch_info.GetArguments(); if (exe_file) exe_path = exe_file.GetPath(false); else { arg = launch_args.GetArgumentAtIndex(0); if (arg) exe_path = arg; } if (!exe_path.empty()) { argv.push_back(exe_path.c_str()); for (uint32_t i = 1; (arg = launch_args.GetArgumentAtIndex(i)) != nullptr; ++i) { if (arg) argv.push_back(arg); } } if (!argv.empty()) { StreamString packet; packet.PutChar('A'); for (size_t i = 0, n = argv.size(); i < n; ++i) { arg = argv[i]; const int arg_len = strlen(arg); if (i > 0) packet.PutChar(','); packet.Printf("%i,%i,", arg_len * 2, (int)i); packet.PutBytesAsRawHex8(arg, arg_len); } StringExtractorGDBRemote response; if (SendPacketAndWaitForResponse(packet.GetString(), response, false) == PacketResult::Success) { if (response.IsOKResponse()) return 0; uint8_t error = response.GetError(); if (error) return error; } } return -1; } int GDBRemoteCommunicationClient::SendEnvironment(const Environment &env) { for (const auto &KV : env) { int r = SendEnvironmentPacket(Environment::compose(KV).c_str()); if (r != 0) return r; } return 0; } int GDBRemoteCommunicationClient::SendEnvironmentPacket( char const *name_equal_value) { if (name_equal_value && name_equal_value[0]) { StreamString packet; bool send_hex_encoding = false; for (const char *p = name_equal_value; *p != '\0' && !send_hex_encoding; ++p) { if (isprint(*p)) { switch (*p) { case '$': case '#': case '*': case '}': send_hex_encoding = true; break; default: break; } } else { // We have non printable characters, lets hex encode this... send_hex_encoding = true; } } StringExtractorGDBRemote response; if (send_hex_encoding) { if (m_supports_QEnvironmentHexEncoded) { packet.PutCString("QEnvironmentHexEncoded:"); packet.PutBytesAsRawHex8(name_equal_value, strlen(name_equal_value)); if (SendPacketAndWaitForResponse(packet.GetString(), response, false) == PacketResult::Success) { if (response.IsOKResponse()) return 0; uint8_t error = response.GetError(); if (error) return error; if (response.IsUnsupportedResponse()) m_supports_QEnvironmentHexEncoded = false; } } } else if (m_supports_QEnvironment) { packet.Printf("QEnvironment:%s", name_equal_value); if (SendPacketAndWaitForResponse(packet.GetString(), response, false) == PacketResult::Success) { if (response.IsOKResponse()) return 0; uint8_t error = response.GetError(); if (error) return error; if (response.IsUnsupportedResponse()) m_supports_QEnvironment = false; } } } return -1; } int GDBRemoteCommunicationClient::SendLaunchArchPacket(char const *arch) { if (arch && arch[0]) { StreamString packet; packet.Printf("QLaunchArch:%s", arch); StringExtractorGDBRemote response; if (SendPacketAndWaitForResponse(packet.GetString(), response, false) == PacketResult::Success) { if (response.IsOKResponse()) return 0; uint8_t error = response.GetError(); if (error) return error; } } return -1; } int GDBRemoteCommunicationClient::SendLaunchEventDataPacket( char const *data, bool *was_supported) { if (data && *data != '\0') { StreamString packet; packet.Printf("QSetProcessEvent:%s", data); StringExtractorGDBRemote response; if (SendPacketAndWaitForResponse(packet.GetString(), response, false) == PacketResult::Success) { if (response.IsOKResponse()) { if (was_supported) *was_supported = true; return 0; } else if (response.IsUnsupportedResponse()) { if (was_supported) *was_supported = false; return -1; } else { uint8_t error = response.GetError(); if (was_supported) *was_supported = true; if (error) return error; } } } return -1; } llvm::VersionTuple GDBRemoteCommunicationClient::GetOSVersion() { GetHostInfo(); return m_os_version; } llvm::VersionTuple GDBRemoteCommunicationClient::GetMacCatalystVersion() { GetHostInfo(); return m_maccatalyst_version; } bool GDBRemoteCommunicationClient::GetOSBuildString(std::string &s) { if (GetHostInfo()) { if (!m_os_build.empty()) { s = m_os_build; return true; } } s.clear(); return false; } bool GDBRemoteCommunicationClient::GetOSKernelDescription(std::string &s) { if (GetHostInfo()) { if (!m_os_kernel.empty()) { s = m_os_kernel; return true; } } s.clear(); return false; } bool GDBRemoteCommunicationClient::GetHostname(std::string &s) { if (GetHostInfo()) { if (!m_hostname.empty()) { s = m_hostname; return true; } } s.clear(); return false; } ArchSpec GDBRemoteCommunicationClient::GetSystemArchitecture() { if (GetHostInfo()) return m_host_arch; return ArchSpec(); } const lldb_private::ArchSpec & GDBRemoteCommunicationClient::GetProcessArchitecture() { if (m_qProcessInfo_is_valid == eLazyBoolCalculate) GetCurrentProcessInfo(); return m_process_arch; } bool GDBRemoteCommunicationClient::GetGDBServerVersion() { if (m_qGDBServerVersion_is_valid == eLazyBoolCalculate) { m_gdb_server_name.clear(); m_gdb_server_version = 0; m_qGDBServerVersion_is_valid = eLazyBoolNo; StringExtractorGDBRemote response; if (SendPacketAndWaitForResponse("qGDBServerVersion", response, false) == PacketResult::Success) { if (response.IsNormalResponse()) { llvm::StringRef name, value; bool success = false; while (response.GetNameColonValue(name, value)) { if (name.equals("name")) { success = true; m_gdb_server_name = value; } else if (name.equals("version")) { llvm::StringRef major, minor; std::tie(major, minor) = value.split('.'); if (!major.getAsInteger(0, m_gdb_server_version)) success = true; } } if (success) m_qGDBServerVersion_is_valid = eLazyBoolYes; } } } return m_qGDBServerVersion_is_valid == eLazyBoolYes; } void GDBRemoteCommunicationClient::MaybeEnableCompression( std::vector supported_compressions) { CompressionType avail_type = CompressionType::None; std::string avail_name; #if defined(HAVE_LIBCOMPRESSION) if (avail_type == CompressionType::None) { for (auto compression : supported_compressions) { if (compression == "lzfse") { avail_type = CompressionType::LZFSE; avail_name = compression; break; } } } #endif #if defined(HAVE_LIBCOMPRESSION) if (avail_type == CompressionType::None) { for (auto compression : supported_compressions) { if (compression == "zlib-deflate") { avail_type = CompressionType::ZlibDeflate; avail_name = compression; break; } } } #endif -#if LLVM_ENABLE_ZLIB +#if defined(HAVE_LIBZ) if (avail_type == CompressionType::None) { for (auto compression : supported_compressions) { if (compression == "zlib-deflate") { avail_type = CompressionType::ZlibDeflate; avail_name = compression; break; } } } #endif #if defined(HAVE_LIBCOMPRESSION) if (avail_type == CompressionType::None) { for (auto compression : supported_compressions) { if (compression == "lz4") { avail_type = CompressionType::LZ4; avail_name = compression; break; } } } #endif #if defined(HAVE_LIBCOMPRESSION) if (avail_type == CompressionType::None) { for (auto compression : supported_compressions) { if (compression == "lzma") { avail_type = CompressionType::LZMA; avail_name = compression; break; } } } #endif if (avail_type != CompressionType::None) { StringExtractorGDBRemote response; std::string packet = "QEnableCompression:type:" + avail_name + ";"; if (SendPacketAndWaitForResponse(packet, response, false) != PacketResult::Success) return; if (response.IsOKResponse()) { m_compression_type = avail_type; } } } const char *GDBRemoteCommunicationClient::GetGDBServerProgramName() { if (GetGDBServerVersion()) { if (!m_gdb_server_name.empty()) return m_gdb_server_name.c_str(); } return nullptr; } uint32_t GDBRemoteCommunicationClient::GetGDBServerProgramVersion() { if (GetGDBServerVersion()) return m_gdb_server_version; return 0; } bool GDBRemoteCommunicationClient::GetDefaultThreadId(lldb::tid_t &tid) { StringExtractorGDBRemote response; if (SendPacketAndWaitForResponse("qC", response, false) != PacketResult::Success) return false; if (!response.IsNormalResponse()) return false; if (response.GetChar() == 'Q' && response.GetChar() == 'C') tid = response.GetHexMaxU32(true, -1); return true; } bool GDBRemoteCommunicationClient::GetHostInfo(bool force) { Log *log(ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet(GDBR_LOG_PROCESS)); if (force || m_qHostInfo_is_valid == eLazyBoolCalculate) { // host info computation can require DNS traffic and shelling out to external processes. // Increase the timeout to account for that. ScopedTimeout timeout(*this, seconds(10)); m_qHostInfo_is_valid = eLazyBoolNo; StringExtractorGDBRemote response; if (SendPacketAndWaitForResponse("qHostInfo", response, false) == PacketResult::Success) { if (response.IsNormalResponse()) { llvm::StringRef name; llvm::StringRef value; uint32_t cpu = LLDB_INVALID_CPUTYPE; uint32_t sub = 0; std::string arch_name; std::string os_name; std::string environment; std::string vendor_name; std::string triple; std::string distribution_id; uint32_t pointer_byte_size = 0; ByteOrder byte_order = eByteOrderInvalid; uint32_t num_keys_decoded = 0; while (response.GetNameColonValue(name, value)) { if (name.equals("cputype")) { // exception type in big endian hex if (!value.getAsInteger(0, cpu)) ++num_keys_decoded; } else if (name.equals("cpusubtype")) { // exception count in big endian hex if (!value.getAsInteger(0, sub)) ++num_keys_decoded; } else if (name.equals("arch")) { arch_name = value; ++num_keys_decoded; } else if (name.equals("triple")) { StringExtractor extractor(value); extractor.GetHexByteString(triple); ++num_keys_decoded; } else if (name.equals("distribution_id")) { StringExtractor extractor(value); extractor.GetHexByteString(distribution_id); ++num_keys_decoded; } else if (name.equals("os_build")) { StringExtractor extractor(value); extractor.GetHexByteString(m_os_build); ++num_keys_decoded; } else if (name.equals("hostname")) { StringExtractor extractor(value); extractor.GetHexByteString(m_hostname); ++num_keys_decoded; } else if (name.equals("os_kernel")) { StringExtractor extractor(value); extractor.GetHexByteString(m_os_kernel); ++num_keys_decoded; } else if (name.equals("ostype")) { if (value.equals("maccatalyst")) { os_name = "ios"; environment = "macabi"; } else os_name = value; ++num_keys_decoded; } else if (name.equals("vendor")) { vendor_name = value; ++num_keys_decoded; } else if (name.equals("endian")) { byte_order = llvm::StringSwitch(value) .Case("little", eByteOrderLittle) .Case("big", eByteOrderBig) .Case("pdp", eByteOrderPDP) .Default(eByteOrderInvalid); if (byte_order != eByteOrderInvalid) ++num_keys_decoded; } else if (name.equals("ptrsize")) { if (!value.getAsInteger(0, pointer_byte_size)) ++num_keys_decoded; } else if (name.equals("os_version") || name.equals( "version")) // Older debugserver binaries used the // "version" key instead of // "os_version"... { if (!m_os_version.tryParse(value)) ++num_keys_decoded; } else if (name.equals("maccatalyst_version")) { if (!m_maccatalyst_version.tryParse(value)) ++num_keys_decoded; } else if (name.equals("watchpoint_exceptions_received")) { m_watchpoints_trigger_after_instruction = llvm::StringSwitch(value) .Case("before", eLazyBoolNo) .Case("after", eLazyBoolYes) .Default(eLazyBoolCalculate); if (m_watchpoints_trigger_after_instruction != eLazyBoolCalculate) ++num_keys_decoded; } else if (name.equals("default_packet_timeout")) { uint32_t timeout_seconds; if (!value.getAsInteger(0, timeout_seconds)) { m_default_packet_timeout = seconds(timeout_seconds); SetPacketTimeout(m_default_packet_timeout); ++num_keys_decoded; } } } if (num_keys_decoded > 0) m_qHostInfo_is_valid = eLazyBoolYes; if (triple.empty()) { if (arch_name.empty()) { if (cpu != LLDB_INVALID_CPUTYPE) { m_host_arch.SetArchitecture(eArchTypeMachO, cpu, sub); if (pointer_byte_size) { assert(pointer_byte_size == m_host_arch.GetAddressByteSize()); } if (byte_order != eByteOrderInvalid) { assert(byte_order == m_host_arch.GetByteOrder()); } if (!vendor_name.empty()) m_host_arch.GetTriple().setVendorName( llvm::StringRef(vendor_name)); if (!os_name.empty()) m_host_arch.GetTriple().setOSName(llvm::StringRef(os_name)); if (!environment.empty()) m_host_arch.GetTriple().setEnvironmentName(environment); } } else { std::string triple; triple += arch_name; if (!vendor_name.empty() || !os_name.empty()) { triple += '-'; if (vendor_name.empty()) triple += "unknown"; else triple += vendor_name; triple += '-'; if (os_name.empty()) triple += "unknown"; else triple += os_name; } m_host_arch.SetTriple(triple.c_str()); llvm::Triple &host_triple = m_host_arch.GetTriple(); if (host_triple.getVendor() == llvm::Triple::Apple && host_triple.getOS() == llvm::Triple::Darwin) { switch (m_host_arch.GetMachine()) { case llvm::Triple::aarch64: case llvm::Triple::aarch64_32: case llvm::Triple::arm: case llvm::Triple::thumb: host_triple.setOS(llvm::Triple::IOS); break; default: host_triple.setOS(llvm::Triple::MacOSX); break; } } if (pointer_byte_size) { assert(pointer_byte_size == m_host_arch.GetAddressByteSize()); } if (byte_order != eByteOrderInvalid) { assert(byte_order == m_host_arch.GetByteOrder()); } } } else { m_host_arch.SetTriple(triple.c_str()); if (pointer_byte_size) { assert(pointer_byte_size == m_host_arch.GetAddressByteSize()); } if (byte_order != eByteOrderInvalid) { assert(byte_order == m_host_arch.GetByteOrder()); } LLDB_LOGF(log, "GDBRemoteCommunicationClient::%s parsed host " "architecture as %s, triple as %s from triple text %s", __FUNCTION__, m_host_arch.GetArchitectureName() ? m_host_arch.GetArchitectureName() : "", m_host_arch.GetTriple().getTriple().c_str(), triple.c_str()); } if (!distribution_id.empty()) m_host_arch.SetDistributionId(distribution_id.c_str()); } } } return m_qHostInfo_is_valid == eLazyBoolYes; } int GDBRemoteCommunicationClient::SendAttach( lldb::pid_t pid, StringExtractorGDBRemote &response) { if (pid != LLDB_INVALID_PROCESS_ID) { char packet[64]; const int packet_len = ::snprintf(packet, sizeof(packet), "vAttach;%" PRIx64, pid); UNUSED_IF_ASSERT_DISABLED(packet_len); assert(packet_len < (int)sizeof(packet)); if (SendPacketAndWaitForResponse(packet, response, false) == PacketResult::Success) { if (response.IsErrorResponse()) return response.GetError(); return 0; } } return -1; } int GDBRemoteCommunicationClient::SendStdinNotification(const char *data, size_t data_len) { StreamString packet; packet.PutCString("I"); packet.PutBytesAsRawHex8(data, data_len); StringExtractorGDBRemote response; if (SendPacketAndWaitForResponse(packet.GetString(), response, false) == PacketResult::Success) { return 0; } return response.GetError(); } const lldb_private::ArchSpec & GDBRemoteCommunicationClient::GetHostArchitecture() { if (m_qHostInfo_is_valid == eLazyBoolCalculate) GetHostInfo(); return m_host_arch; } seconds GDBRemoteCommunicationClient::GetHostDefaultPacketTimeout() { if (m_qHostInfo_is_valid == eLazyBoolCalculate) GetHostInfo(); return m_default_packet_timeout; } addr_t GDBRemoteCommunicationClient::AllocateMemory(size_t size, uint32_t permissions) { if (m_supports_alloc_dealloc_memory != eLazyBoolNo) { m_supports_alloc_dealloc_memory = eLazyBoolYes; char packet[64]; const int packet_len = ::snprintf( packet, sizeof(packet), "_M%" PRIx64 ",%s%s%s", (uint64_t)size, permissions & lldb::ePermissionsReadable ? "r" : "", permissions & lldb::ePermissionsWritable ? "w" : "", permissions & lldb::ePermissionsExecutable ? "x" : ""); assert(packet_len < (int)sizeof(packet)); UNUSED_IF_ASSERT_DISABLED(packet_len); StringExtractorGDBRemote response; if (SendPacketAndWaitForResponse(packet, response, false) == PacketResult::Success) { if (response.IsUnsupportedResponse()) m_supports_alloc_dealloc_memory = eLazyBoolNo; else if (!response.IsErrorResponse()) return response.GetHexMaxU64(false, LLDB_INVALID_ADDRESS); } else { m_supports_alloc_dealloc_memory = eLazyBoolNo; } } return LLDB_INVALID_ADDRESS; } bool GDBRemoteCommunicationClient::DeallocateMemory(addr_t addr) { if (m_supports_alloc_dealloc_memory != eLazyBoolNo) { m_supports_alloc_dealloc_memory = eLazyBoolYes; char packet[64]; const int packet_len = ::snprintf(packet, sizeof(packet), "_m%" PRIx64, (uint64_t)addr); assert(packet_len < (int)sizeof(packet)); UNUSED_IF_ASSERT_DISABLED(packet_len); StringExtractorGDBRemote response; if (SendPacketAndWaitForResponse(packet, response, false) == PacketResult::Success) { if (response.IsUnsupportedResponse()) m_supports_alloc_dealloc_memory = eLazyBoolNo; else if (response.IsOKResponse()) return true; } else { m_supports_alloc_dealloc_memory = eLazyBoolNo; } } return false; } Status GDBRemoteCommunicationClient::Detach(bool keep_stopped) { Status error; if (keep_stopped) { if (m_supports_detach_stay_stopped == eLazyBoolCalculate) { char packet[64]; const int packet_len = ::snprintf(packet, sizeof(packet), "qSupportsDetachAndStayStopped:"); assert(packet_len < (int)sizeof(packet)); UNUSED_IF_ASSERT_DISABLED(packet_len); StringExtractorGDBRemote response; if (SendPacketAndWaitForResponse(packet, response, false) == PacketResult::Success && response.IsOKResponse()) { m_supports_detach_stay_stopped = eLazyBoolYes; } else { m_supports_detach_stay_stopped = eLazyBoolNo; } } if (m_supports_detach_stay_stopped == eLazyBoolNo) { error.SetErrorString("Stays stopped not supported by this target."); return error; } else { StringExtractorGDBRemote response; PacketResult packet_result = SendPacketAndWaitForResponse("D1", response, false); if (packet_result != PacketResult::Success) error.SetErrorString("Sending extended disconnect packet failed."); } } else { StringExtractorGDBRemote response; PacketResult packet_result = SendPacketAndWaitForResponse("D", response, false); if (packet_result != PacketResult::Success) error.SetErrorString("Sending disconnect packet failed."); } return error; } Status GDBRemoteCommunicationClient::GetMemoryRegionInfo( lldb::addr_t addr, lldb_private::MemoryRegionInfo ®ion_info) { Status error; region_info.Clear(); if (m_supports_memory_region_info != eLazyBoolNo) { m_supports_memory_region_info = eLazyBoolYes; char packet[64]; const int packet_len = ::snprintf( packet, sizeof(packet), "qMemoryRegionInfo:%" PRIx64, (uint64_t)addr); assert(packet_len < (int)sizeof(packet)); UNUSED_IF_ASSERT_DISABLED(packet_len); StringExtractorGDBRemote response; if (SendPacketAndWaitForResponse(packet, response, false) == PacketResult::Success && response.GetResponseType() == StringExtractorGDBRemote::eResponse) { llvm::StringRef name; llvm::StringRef value; addr_t addr_value = LLDB_INVALID_ADDRESS; bool success = true; bool saw_permissions = false; while (success && response.GetNameColonValue(name, value)) { if (name.equals("start")) { if (!value.getAsInteger(16, addr_value)) region_info.GetRange().SetRangeBase(addr_value); } else if (name.equals("size")) { if (!value.getAsInteger(16, addr_value)) region_info.GetRange().SetByteSize(addr_value); } else if (name.equals("permissions") && region_info.GetRange().IsValid()) { saw_permissions = true; if (region_info.GetRange().Contains(addr)) { if (value.find('r') != llvm::StringRef::npos) region_info.SetReadable(MemoryRegionInfo::eYes); else region_info.SetReadable(MemoryRegionInfo::eNo); if (value.find('w') != llvm::StringRef::npos) region_info.SetWritable(MemoryRegionInfo::eYes); else region_info.SetWritable(MemoryRegionInfo::eNo); if (value.find('x') != llvm::StringRef::npos) region_info.SetExecutable(MemoryRegionInfo::eYes); else region_info.SetExecutable(MemoryRegionInfo::eNo); region_info.SetMapped(MemoryRegionInfo::eYes); } else { // The reported region does not contain this address -- we're // looking at an unmapped page region_info.SetReadable(MemoryRegionInfo::eNo); region_info.SetWritable(MemoryRegionInfo::eNo); region_info.SetExecutable(MemoryRegionInfo::eNo); region_info.SetMapped(MemoryRegionInfo::eNo); } } else if (name.equals("name")) { StringExtractorGDBRemote name_extractor(value); std::string name; name_extractor.GetHexByteString(name); region_info.SetName(name.c_str()); } else if (name.equals("error")) { StringExtractorGDBRemote error_extractor(value); std::string error_string; // Now convert the HEX bytes into a string value error_extractor.GetHexByteString(error_string); error.SetErrorString(error_string.c_str()); } } if (region_info.GetRange().IsValid()) { // We got a valid address range back but no permissions -- which means // this is an unmapped page if (!saw_permissions) { region_info.SetReadable(MemoryRegionInfo::eNo); region_info.SetWritable(MemoryRegionInfo::eNo); region_info.SetExecutable(MemoryRegionInfo::eNo); region_info.SetMapped(MemoryRegionInfo::eNo); } } else { // We got an invalid address range back error.SetErrorString("Server returned invalid range"); } } else { m_supports_memory_region_info = eLazyBoolNo; } } if (m_supports_memory_region_info == eLazyBoolNo) { error.SetErrorString("qMemoryRegionInfo is not supported"); } // Try qXfer:memory-map:read to get region information not included in // qMemoryRegionInfo MemoryRegionInfo qXfer_region_info; Status qXfer_error = GetQXferMemoryMapRegionInfo(addr, qXfer_region_info); if (error.Fail()) { // If qMemoryRegionInfo failed, but qXfer:memory-map:read succeeded, use // the qXfer result as a fallback if (qXfer_error.Success()) { region_info = qXfer_region_info; error.Clear(); } else { region_info.Clear(); } } else if (qXfer_error.Success()) { // If both qMemoryRegionInfo and qXfer:memory-map:read succeeded, and if // both regions are the same range, update the result to include the flash- // memory information that is specific to the qXfer result. if (region_info.GetRange() == qXfer_region_info.GetRange()) { region_info.SetFlash(qXfer_region_info.GetFlash()); region_info.SetBlocksize(qXfer_region_info.GetBlocksize()); } } return error; } Status GDBRemoteCommunicationClient::GetQXferMemoryMapRegionInfo( lldb::addr_t addr, MemoryRegionInfo ®ion) { Status error = LoadQXferMemoryMap(); if (!error.Success()) return error; for (const auto &map_region : m_qXfer_memory_map) { if (map_region.GetRange().Contains(addr)) { region = map_region; return error; } } error.SetErrorString("Region not found"); return error; } Status GDBRemoteCommunicationClient::LoadQXferMemoryMap() { Status error; if (m_qXfer_memory_map_loaded) // Already loaded, return success return error; if (!XMLDocument::XMLEnabled()) { error.SetErrorString("XML is not supported"); return error; } if (!GetQXferMemoryMapReadSupported()) { error.SetErrorString("Memory map is not supported"); return error; } std::string xml; lldb_private::Status lldberr; if (!ReadExtFeature(ConstString("memory-map"), ConstString(""), xml, lldberr)) { error.SetErrorString("Failed to read memory map"); return error; } XMLDocument xml_document; if (!xml_document.ParseMemory(xml.c_str(), xml.size())) { error.SetErrorString("Failed to parse memory map xml"); return error; } XMLNode map_node = xml_document.GetRootElement("memory-map"); if (!map_node) { error.SetErrorString("Invalid root node in memory map xml"); return error; } m_qXfer_memory_map.clear(); map_node.ForEachChildElement([this](const XMLNode &memory_node) -> bool { if (!memory_node.IsElement()) return true; if (memory_node.GetName() != "memory") return true; auto type = memory_node.GetAttributeValue("type", ""); uint64_t start; uint64_t length; if (!memory_node.GetAttributeValueAsUnsigned("start", start)) return true; if (!memory_node.GetAttributeValueAsUnsigned("length", length)) return true; MemoryRegionInfo region; region.GetRange().SetRangeBase(start); region.GetRange().SetByteSize(length); if (type == "rom") { region.SetReadable(MemoryRegionInfo::eYes); this->m_qXfer_memory_map.push_back(region); } else if (type == "ram") { region.SetReadable(MemoryRegionInfo::eYes); region.SetWritable(MemoryRegionInfo::eYes); this->m_qXfer_memory_map.push_back(region); } else if (type == "flash") { region.SetFlash(MemoryRegionInfo::eYes); memory_node.ForEachChildElement( [®ion](const XMLNode &prop_node) -> bool { if (!prop_node.IsElement()) return true; if (prop_node.GetName() != "property") return true; auto propname = prop_node.GetAttributeValue("name", ""); if (propname == "blocksize") { uint64_t blocksize; if (prop_node.GetElementTextAsUnsigned(blocksize)) region.SetBlocksize(blocksize); } return true; }); this->m_qXfer_memory_map.push_back(region); } return true; }); m_qXfer_memory_map_loaded = true; return error; } Status GDBRemoteCommunicationClient::GetWatchpointSupportInfo(uint32_t &num) { Status error; if (m_supports_watchpoint_support_info == eLazyBoolYes) { num = m_num_supported_hardware_watchpoints; return error; } // Set num to 0 first. num = 0; if (m_supports_watchpoint_support_info != eLazyBoolNo) { char packet[64]; const int packet_len = ::snprintf(packet, sizeof(packet), "qWatchpointSupportInfo:"); assert(packet_len < (int)sizeof(packet)); UNUSED_IF_ASSERT_DISABLED(packet_len); StringExtractorGDBRemote response; if (SendPacketAndWaitForResponse(packet, response, false) == PacketResult::Success) { m_supports_watchpoint_support_info = eLazyBoolYes; llvm::StringRef name; llvm::StringRef value; bool found_num_field = false; while (response.GetNameColonValue(name, value)) { if (name.equals("num")) { value.getAsInteger(0, m_num_supported_hardware_watchpoints); num = m_num_supported_hardware_watchpoints; found_num_field = true; } } if (!found_num_field) { m_supports_watchpoint_support_info = eLazyBoolNo; } } else { m_supports_watchpoint_support_info = eLazyBoolNo; } } if (m_supports_watchpoint_support_info == eLazyBoolNo) { error.SetErrorString("qWatchpointSupportInfo is not supported"); } return error; } lldb_private::Status GDBRemoteCommunicationClient::GetWatchpointSupportInfo( uint32_t &num, bool &after, const ArchSpec &arch) { Status error(GetWatchpointSupportInfo(num)); if (error.Success()) error = GetWatchpointsTriggerAfterInstruction(after, arch); return error; } lldb_private::Status GDBRemoteCommunicationClient::GetWatchpointsTriggerAfterInstruction( bool &after, const ArchSpec &arch) { Status error; llvm::Triple triple = arch.GetTriple(); // we assume watchpoints will happen after running the relevant opcode and we // only want to override this behavior if we have explicitly received a // qHostInfo telling us otherwise if (m_qHostInfo_is_valid != eLazyBoolYes) { // On targets like MIPS and ppc64, watchpoint exceptions are always // generated before the instruction is executed. The connected target may // not support qHostInfo or qWatchpointSupportInfo packets. after = !(triple.isMIPS() || triple.isPPC64()); } else { // For MIPS and ppc64, set m_watchpoints_trigger_after_instruction to // eLazyBoolNo if it is not calculated before. if (m_watchpoints_trigger_after_instruction == eLazyBoolCalculate && (triple.isMIPS() || triple.isPPC64())) m_watchpoints_trigger_after_instruction = eLazyBoolNo; after = (m_watchpoints_trigger_after_instruction != eLazyBoolNo); } return error; } int GDBRemoteCommunicationClient::SetSTDIN(const FileSpec &file_spec) { if (file_spec) { std::string path{file_spec.GetPath(false)}; StreamString packet; packet.PutCString("QSetSTDIN:"); packet.PutStringAsRawHex8(path); StringExtractorGDBRemote response; if (SendPacketAndWaitForResponse(packet.GetString(), response, false) == PacketResult::Success) { if (response.IsOKResponse()) return 0; uint8_t error = response.GetError(); if (error) return error; } } return -1; } int GDBRemoteCommunicationClient::SetSTDOUT(const FileSpec &file_spec) { if (file_spec) { std::string path{file_spec.GetPath(false)}; StreamString packet; packet.PutCString("QSetSTDOUT:"); packet.PutStringAsRawHex8(path); StringExtractorGDBRemote response; if (SendPacketAndWaitForResponse(packet.GetString(), response, false) == PacketResult::Success) { if (response.IsOKResponse()) return 0; uint8_t error = response.GetError(); if (error) return error; } } return -1; } int GDBRemoteCommunicationClient::SetSTDERR(const FileSpec &file_spec) { if (file_spec) { std::string path{file_spec.GetPath(false)}; StreamString packet; packet.PutCString("QSetSTDERR:"); packet.PutStringAsRawHex8(path); StringExtractorGDBRemote response; if (SendPacketAndWaitForResponse(packet.GetString(), response, false) == PacketResult::Success) { if (response.IsOKResponse()) return 0; uint8_t error = response.GetError(); if (error) return error; } } return -1; } bool GDBRemoteCommunicationClient::GetWorkingDir(FileSpec &working_dir) { StringExtractorGDBRemote response; if (SendPacketAndWaitForResponse("qGetWorkingDir", response, false) == PacketResult::Success) { if (response.IsUnsupportedResponse()) return false; if (response.IsErrorResponse()) return false; std::string cwd; response.GetHexByteString(cwd); working_dir.SetFile(cwd, GetHostArchitecture().GetTriple()); return !cwd.empty(); } return false; } int GDBRemoteCommunicationClient::SetWorkingDir(const FileSpec &working_dir) { if (working_dir) { std::string path{working_dir.GetPath(false)}; StreamString packet; packet.PutCString("QSetWorkingDir:"); packet.PutStringAsRawHex8(path); StringExtractorGDBRemote response; if (SendPacketAndWaitForResponse(packet.GetString(), response, false) == PacketResult::Success) { if (response.IsOKResponse()) return 0; uint8_t error = response.GetError(); if (error) return error; } } return -1; } int GDBRemoteCommunicationClient::SetDisableASLR(bool enable) { char packet[32]; const int packet_len = ::snprintf(packet, sizeof(packet), "QSetDisableASLR:%i", enable ? 1 : 0); assert(packet_len < (int)sizeof(packet)); UNUSED_IF_ASSERT_DISABLED(packet_len); StringExtractorGDBRemote response; if (SendPacketAndWaitForResponse(packet, response, false) == PacketResult::Success) { if (response.IsOKResponse()) return 0; uint8_t error = response.GetError(); if (error) return error; } return -1; } int GDBRemoteCommunicationClient::SetDetachOnError(bool enable) { char packet[32]; const int packet_len = ::snprintf(packet, sizeof(packet), "QSetDetachOnError:%i", enable ? 1 : 0); assert(packet_len < (int)sizeof(packet)); UNUSED_IF_ASSERT_DISABLED(packet_len); StringExtractorGDBRemote response; if (SendPacketAndWaitForResponse(packet, response, false) == PacketResult::Success) { if (response.IsOKResponse()) return 0; uint8_t error = response.GetError(); if (error) return error; } return -1; } bool GDBRemoteCommunicationClient::DecodeProcessInfoResponse( StringExtractorGDBRemote &response, ProcessInstanceInfo &process_info) { if (response.IsNormalResponse()) { llvm::StringRef name; llvm::StringRef value; StringExtractor extractor; uint32_t cpu = LLDB_INVALID_CPUTYPE; uint32_t sub = 0; std::string vendor; std::string os_type; while (response.GetNameColonValue(name, value)) { if (name.equals("pid")) { lldb::pid_t pid = LLDB_INVALID_PROCESS_ID; value.getAsInteger(0, pid); process_info.SetProcessID(pid); } else if (name.equals("ppid")) { lldb::pid_t pid = LLDB_INVALID_PROCESS_ID; value.getAsInteger(0, pid); process_info.SetParentProcessID(pid); } else if (name.equals("uid")) { uint32_t uid = UINT32_MAX; value.getAsInteger(0, uid); process_info.SetUserID(uid); } else if (name.equals("euid")) { uint32_t uid = UINT32_MAX; value.getAsInteger(0, uid); process_info.SetEffectiveUserID(uid); } else if (name.equals("gid")) { uint32_t gid = UINT32_MAX; value.getAsInteger(0, gid); process_info.SetGroupID(gid); } else if (name.equals("egid")) { uint32_t gid = UINT32_MAX; value.getAsInteger(0, gid); process_info.SetEffectiveGroupID(gid); } else if (name.equals("triple")) { StringExtractor extractor(value); std::string triple; extractor.GetHexByteString(triple); process_info.GetArchitecture().SetTriple(triple.c_str()); } else if (name.equals("name")) { StringExtractor extractor(value); // The process name from ASCII hex bytes since we can't control the // characters in a process name std::string name; extractor.GetHexByteString(name); process_info.GetExecutableFile().SetFile(name, FileSpec::Style::native); } else if (name.equals("args")) { llvm::StringRef encoded_args(value), hex_arg; bool is_arg0 = true; while (!encoded_args.empty()) { std::tie(hex_arg, encoded_args) = encoded_args.split('-'); std::string arg; StringExtractor extractor(hex_arg); if (extractor.GetHexByteString(arg) * 2 != hex_arg.size()) { // In case of wrong encoding, we discard all the arguments process_info.GetArguments().Clear(); process_info.SetArg0(""); break; } if (is_arg0) process_info.SetArg0(arg); else process_info.GetArguments().AppendArgument(arg); is_arg0 = false; } } else if (name.equals("cputype")) { value.getAsInteger(0, cpu); } else if (name.equals("cpusubtype")) { value.getAsInteger(0, sub); } else if (name.equals("vendor")) { vendor = value; } else if (name.equals("ostype")) { os_type = value; } } if (cpu != LLDB_INVALID_CPUTYPE && !vendor.empty() && !os_type.empty()) { if (vendor == "apple") { process_info.GetArchitecture().SetArchitecture(eArchTypeMachO, cpu, sub); process_info.GetArchitecture().GetTriple().setVendorName( llvm::StringRef(vendor)); process_info.GetArchitecture().GetTriple().setOSName( llvm::StringRef(os_type)); } } if (process_info.GetProcessID() != LLDB_INVALID_PROCESS_ID) return true; } return false; } bool GDBRemoteCommunicationClient::GetProcessInfo( lldb::pid_t pid, ProcessInstanceInfo &process_info) { process_info.Clear(); if (m_supports_qProcessInfoPID) { char packet[32]; const int packet_len = ::snprintf(packet, sizeof(packet), "qProcessInfoPID:%" PRIu64, pid); assert(packet_len < (int)sizeof(packet)); UNUSED_IF_ASSERT_DISABLED(packet_len); StringExtractorGDBRemote response; if (SendPacketAndWaitForResponse(packet, response, false) == PacketResult::Success) { return DecodeProcessInfoResponse(response, process_info); } else { m_supports_qProcessInfoPID = false; return false; } } return false; } bool GDBRemoteCommunicationClient::GetCurrentProcessInfo(bool allow_lazy) { Log *log(ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet(GDBR_LOG_PROCESS | GDBR_LOG_PACKETS)); if (allow_lazy) { if (m_qProcessInfo_is_valid == eLazyBoolYes) return true; if (m_qProcessInfo_is_valid == eLazyBoolNo) return false; } GetHostInfo(); StringExtractorGDBRemote response; if (SendPacketAndWaitForResponse("qProcessInfo", response, false) == PacketResult::Success) { if (response.IsNormalResponse()) { llvm::StringRef name; llvm::StringRef value; uint32_t cpu = LLDB_INVALID_CPUTYPE; uint32_t sub = 0; std::string arch_name; std::string os_name; std::string environment; std::string vendor_name; std::string triple; std::string elf_abi; uint32_t pointer_byte_size = 0; StringExtractor extractor; ByteOrder byte_order = eByteOrderInvalid; uint32_t num_keys_decoded = 0; lldb::pid_t pid = LLDB_INVALID_PROCESS_ID; while (response.GetNameColonValue(name, value)) { if (name.equals("cputype")) { if (!value.getAsInteger(16, cpu)) ++num_keys_decoded; } else if (name.equals("cpusubtype")) { if (!value.getAsInteger(16, sub)) ++num_keys_decoded; } else if (name.equals("triple")) { StringExtractor extractor(value); extractor.GetHexByteString(triple); ++num_keys_decoded; } else if (name.equals("ostype")) { if (value.equals("maccatalyst")) { os_name = "ios"; environment = "macabi"; } else os_name = value; ++num_keys_decoded; } else if (name.equals("vendor")) { vendor_name = value; ++num_keys_decoded; } else if (name.equals("endian")) { byte_order = llvm::StringSwitch(value) .Case("little", eByteOrderLittle) .Case("big", eByteOrderBig) .Case("pdp", eByteOrderPDP) .Default(eByteOrderInvalid); if (byte_order != eByteOrderInvalid) ++num_keys_decoded; } else if (name.equals("ptrsize")) { if (!value.getAsInteger(16, pointer_byte_size)) ++num_keys_decoded; } else if (name.equals("pid")) { if (!value.getAsInteger(16, pid)) ++num_keys_decoded; } else if (name.equals("elf_abi")) { elf_abi = value; ++num_keys_decoded; } } if (num_keys_decoded > 0) m_qProcessInfo_is_valid = eLazyBoolYes; if (pid != LLDB_INVALID_PROCESS_ID) { m_curr_pid_is_valid = eLazyBoolYes; m_curr_pid = pid; } // Set the ArchSpec from the triple if we have it. if (!triple.empty()) { m_process_arch.SetTriple(triple.c_str()); m_process_arch.SetFlags(elf_abi); if (pointer_byte_size) { assert(pointer_byte_size == m_process_arch.GetAddressByteSize()); } } else if (cpu != LLDB_INVALID_CPUTYPE && !os_name.empty() && !vendor_name.empty()) { llvm::Triple triple(llvm::Twine("-") + vendor_name + "-" + os_name); if (!environment.empty()) triple.setEnvironmentName(environment); assert(triple.getObjectFormat() != llvm::Triple::UnknownObjectFormat); assert(triple.getObjectFormat() != llvm::Triple::Wasm); assert(triple.getObjectFormat() != llvm::Triple::XCOFF); switch (triple.getObjectFormat()) { case llvm::Triple::MachO: m_process_arch.SetArchitecture(eArchTypeMachO, cpu, sub); break; case llvm::Triple::ELF: m_process_arch.SetArchitecture(eArchTypeELF, cpu, sub); break; case llvm::Triple::COFF: m_process_arch.SetArchitecture(eArchTypeCOFF, cpu, sub); break; case llvm::Triple::Wasm: case llvm::Triple::XCOFF: LLDB_LOGF(log, "error: not supported target architecture"); return false; case llvm::Triple::UnknownObjectFormat: LLDB_LOGF(log, "error: failed to determine target architecture"); return false; } if (pointer_byte_size) { assert(pointer_byte_size == m_process_arch.GetAddressByteSize()); } if (byte_order != eByteOrderInvalid) { assert(byte_order == m_process_arch.GetByteOrder()); } m_process_arch.GetTriple().setVendorName(llvm::StringRef(vendor_name)); m_process_arch.GetTriple().setOSName(llvm::StringRef(os_name)); m_process_arch.GetTriple().setEnvironmentName(llvm::StringRef(environment)); m_host_arch.GetTriple().setVendorName(llvm::StringRef(vendor_name)); m_host_arch.GetTriple().setOSName(llvm::StringRef(os_name)); m_host_arch.GetTriple().setEnvironmentName(llvm::StringRef(environment)); } return true; } } else { m_qProcessInfo_is_valid = eLazyBoolNo; } return false; } uint32_t GDBRemoteCommunicationClient::FindProcesses( const ProcessInstanceInfoMatch &match_info, ProcessInstanceInfoList &process_infos) { process_infos.Clear(); if (m_supports_qfProcessInfo) { StreamString packet; packet.PutCString("qfProcessInfo"); if (!match_info.MatchAllProcesses()) { packet.PutChar(':'); const char *name = match_info.GetProcessInfo().GetName(); bool has_name_match = false; if (name && name[0]) { has_name_match = true; NameMatch name_match_type = match_info.GetNameMatchType(); switch (name_match_type) { case NameMatch::Ignore: has_name_match = false; break; case NameMatch::Equals: packet.PutCString("name_match:equals;"); break; case NameMatch::Contains: packet.PutCString("name_match:contains;"); break; case NameMatch::StartsWith: packet.PutCString("name_match:starts_with;"); break; case NameMatch::EndsWith: packet.PutCString("name_match:ends_with;"); break; case NameMatch::RegularExpression: packet.PutCString("name_match:regex;"); break; } if (has_name_match) { packet.PutCString("name:"); packet.PutBytesAsRawHex8(name, ::strlen(name)); packet.PutChar(';'); } } if (match_info.GetProcessInfo().ProcessIDIsValid()) packet.Printf("pid:%" PRIu64 ";", match_info.GetProcessInfo().GetProcessID()); if (match_info.GetProcessInfo().ParentProcessIDIsValid()) packet.Printf("parent_pid:%" PRIu64 ";", match_info.GetProcessInfo().GetParentProcessID()); if (match_info.GetProcessInfo().UserIDIsValid()) packet.Printf("uid:%u;", match_info.GetProcessInfo().GetUserID()); if (match_info.GetProcessInfo().GroupIDIsValid()) packet.Printf("gid:%u;", match_info.GetProcessInfo().GetGroupID()); if (match_info.GetProcessInfo().EffectiveUserIDIsValid()) packet.Printf("euid:%u;", match_info.GetProcessInfo().GetEffectiveUserID()); if (match_info.GetProcessInfo().EffectiveGroupIDIsValid()) packet.Printf("egid:%u;", match_info.GetProcessInfo().GetEffectiveGroupID()); packet.Printf("all_users:%u;", match_info.GetMatchAllUsers() ? 1 : 0); if (match_info.GetProcessInfo().GetArchitecture().IsValid()) { const ArchSpec &match_arch = match_info.GetProcessInfo().GetArchitecture(); const llvm::Triple &triple = match_arch.GetTriple(); packet.PutCString("triple:"); packet.PutCString(triple.getTriple()); packet.PutChar(';'); } } StringExtractorGDBRemote response; // Increase timeout as the first qfProcessInfo packet takes a long time on // Android. The value of 1min was arrived at empirically. ScopedTimeout timeout(*this, minutes(1)); if (SendPacketAndWaitForResponse(packet.GetString(), response, false) == PacketResult::Success) { do { ProcessInstanceInfo process_info; if (!DecodeProcessInfoResponse(response, process_info)) break; process_infos.Append(process_info); response = StringExtractorGDBRemote(); } while (SendPacketAndWaitForResponse("qsProcessInfo", response, false) == PacketResult::Success); } else { m_supports_qfProcessInfo = false; return 0; } } return process_infos.GetSize(); } bool GDBRemoteCommunicationClient::GetUserName(uint32_t uid, std::string &name) { if (m_supports_qUserName) { char packet[32]; const int packet_len = ::snprintf(packet, sizeof(packet), "qUserName:%i", uid); assert(packet_len < (int)sizeof(packet)); UNUSED_IF_ASSERT_DISABLED(packet_len); StringExtractorGDBRemote response; if (SendPacketAndWaitForResponse(packet, response, false) == PacketResult::Success) { if (response.IsNormalResponse()) { // Make sure we parsed the right number of characters. The response is // the hex encoded user name and should make up the entire packet. If // there are any non-hex ASCII bytes, the length won't match below.. if (response.GetHexByteString(name) * 2 == response.GetStringRef().size()) return true; } } else { m_supports_qUserName = false; return false; } } return false; } bool GDBRemoteCommunicationClient::GetGroupName(uint32_t gid, std::string &name) { if (m_supports_qGroupName) { char packet[32]; const int packet_len = ::snprintf(packet, sizeof(packet), "qGroupName:%i", gid); assert(packet_len < (int)sizeof(packet)); UNUSED_IF_ASSERT_DISABLED(packet_len); StringExtractorGDBRemote response; if (SendPacketAndWaitForResponse(packet, response, false) == PacketResult::Success) { if (response.IsNormalResponse()) { // Make sure we parsed the right number of characters. The response is // the hex encoded group name and should make up the entire packet. If // there are any non-hex ASCII bytes, the length won't match below.. if (response.GetHexByteString(name) * 2 == response.GetStringRef().size()) return true; } } else { m_supports_qGroupName = false; return false; } } return false; } bool GDBRemoteCommunicationClient::SetNonStopMode(const bool enable) { // Form non-stop packet request char packet[32]; const int packet_len = ::snprintf(packet, sizeof(packet), "QNonStop:%1d", (int)enable); assert(packet_len < (int)sizeof(packet)); UNUSED_IF_ASSERT_DISABLED(packet_len); StringExtractorGDBRemote response; // Send to target if (SendPacketAndWaitForResponse(packet, response, false) == PacketResult::Success) if (response.IsOKResponse()) return true; // Failed or not supported return false; } static void MakeSpeedTestPacket(StreamString &packet, uint32_t send_size, uint32_t recv_size) { packet.Clear(); packet.Printf("qSpeedTest:response_size:%i;data:", recv_size); uint32_t bytes_left = send_size; while (bytes_left > 0) { if (bytes_left >= 26) { packet.PutCString("abcdefghijklmnopqrstuvwxyz"); bytes_left -= 26; } else { packet.Printf("%*.*s;", bytes_left, bytes_left, "abcdefghijklmnopqrstuvwxyz"); bytes_left = 0; } } } duration calculate_standard_deviation(const std::vector> &v) { using Dur = duration; Dur sum = std::accumulate(std::begin(v), std::end(v), Dur()); Dur mean = sum / v.size(); float accum = 0; for (auto d : v) { float delta = (d - mean).count(); accum += delta * delta; }; return Dur(sqrtf(accum / (v.size() - 1))); } void GDBRemoteCommunicationClient::TestPacketSpeed(const uint32_t num_packets, uint32_t max_send, uint32_t max_recv, uint64_t recv_amount, bool json, Stream &strm) { uint32_t i; if (SendSpeedTestPacket(0, 0)) { StreamString packet; if (json) strm.Printf("{ \"packet_speeds\" : {\n \"num_packets\" : %u,\n " "\"results\" : [", num_packets); else strm.Printf("Testing sending %u packets of various sizes:\n", num_packets); strm.Flush(); uint32_t result_idx = 0; uint32_t send_size; std::vector> packet_times; for (send_size = 0; send_size <= max_send; send_size ? send_size *= 2 : send_size = 4) { for (uint32_t recv_size = 0; recv_size <= max_recv; recv_size ? recv_size *= 2 : recv_size = 4) { MakeSpeedTestPacket(packet, send_size, recv_size); packet_times.clear(); // Test how long it takes to send 'num_packets' packets const auto start_time = steady_clock::now(); for (i = 0; i < num_packets; ++i) { const auto packet_start_time = steady_clock::now(); StringExtractorGDBRemote response; SendPacketAndWaitForResponse(packet.GetString(), response, false); const auto packet_end_time = steady_clock::now(); packet_times.push_back(packet_end_time - packet_start_time); } const auto end_time = steady_clock::now(); const auto total_time = end_time - start_time; float packets_per_second = ((float)num_packets) / duration(total_time).count(); auto average_per_packet = total_time / num_packets; const duration standard_deviation = calculate_standard_deviation(packet_times); if (json) { strm.Format("{0}\n {{\"send_size\" : {1,6}, \"recv_size\" : " "{2,6}, \"total_time_nsec\" : {3,12:ns-}, " "\"standard_deviation_nsec\" : {4,9:ns-f0}}", result_idx > 0 ? "," : "", send_size, recv_size, total_time, standard_deviation); ++result_idx; } else { strm.Format("qSpeedTest(send={0,7}, recv={1,7}) in {2:s+f9} for " "{3,9:f2} packets/s ({4,10:ms+f6} per packet) with " "standard deviation of {5,10:ms+f6}\n", send_size, recv_size, duration(total_time), packets_per_second, duration(average_per_packet), standard_deviation); } strm.Flush(); } } const float k_recv_amount_mb = (float)recv_amount / (1024.0f * 1024.0f); if (json) strm.Printf("\n ]\n },\n \"download_speed\" : {\n \"byte_size\" " ": %" PRIu64 ",\n \"results\" : [", recv_amount); else strm.Printf("Testing receiving %2.1fMB of data using varying receive " "packet sizes:\n", k_recv_amount_mb); strm.Flush(); send_size = 0; result_idx = 0; for (uint32_t recv_size = 32; recv_size <= max_recv; recv_size *= 2) { MakeSpeedTestPacket(packet, send_size, recv_size); // If we have a receive size, test how long it takes to receive 4MB of // data if (recv_size > 0) { const auto start_time = steady_clock::now(); uint32_t bytes_read = 0; uint32_t packet_count = 0; while (bytes_read < recv_amount) { StringExtractorGDBRemote response; SendPacketAndWaitForResponse(packet.GetString(), response, false); bytes_read += recv_size; ++packet_count; } const auto end_time = steady_clock::now(); const auto total_time = end_time - start_time; float mb_second = ((float)recv_amount) / duration(total_time).count() / (1024.0 * 1024.0); float packets_per_second = ((float)packet_count) / duration(total_time).count(); const auto average_per_packet = total_time / packet_count; if (json) { strm.Format("{0}\n {{\"send_size\" : {1,6}, \"recv_size\" : " "{2,6}, \"total_time_nsec\" : {3,12:ns-}}", result_idx > 0 ? "," : "", send_size, recv_size, total_time); ++result_idx; } else { strm.Format("qSpeedTest(send={0,7}, recv={1,7}) {2,6} packets needed " "to receive {3:f1}MB in {4:s+f9} for {5} MB/sec for " "{6,9:f2} packets/sec ({7,10:ms+f6} per packet)\n", send_size, recv_size, packet_count, k_recv_amount_mb, duration(total_time), mb_second, packets_per_second, duration(average_per_packet)); } strm.Flush(); } } if (json) strm.Printf("\n ]\n }\n}\n"); else strm.EOL(); } } bool GDBRemoteCommunicationClient::SendSpeedTestPacket(uint32_t send_size, uint32_t recv_size) { StreamString packet; packet.Printf("qSpeedTest:response_size:%i;data:", recv_size); uint32_t bytes_left = send_size; while (bytes_left > 0) { if (bytes_left >= 26) { packet.PutCString("abcdefghijklmnopqrstuvwxyz"); bytes_left -= 26; } else { packet.Printf("%*.*s;", bytes_left, bytes_left, "abcdefghijklmnopqrstuvwxyz"); bytes_left = 0; } } StringExtractorGDBRemote response; return SendPacketAndWaitForResponse(packet.GetString(), response, false) == PacketResult::Success; } bool GDBRemoteCommunicationClient::LaunchGDBServer( const char *remote_accept_hostname, lldb::pid_t &pid, uint16_t &port, std::string &socket_name) { pid = LLDB_INVALID_PROCESS_ID; port = 0; socket_name.clear(); StringExtractorGDBRemote response; StreamString stream; stream.PutCString("qLaunchGDBServer;"); std::string hostname; if (remote_accept_hostname && remote_accept_hostname[0]) hostname = remote_accept_hostname; else { if (HostInfo::GetHostname(hostname)) { // Make the GDB server we launch only accept connections from this host stream.Printf("host:%s;", hostname.c_str()); } else { // Make the GDB server we launch accept connections from any host since // we can't figure out the hostname stream.Printf("host:*;"); } } // give the process a few seconds to startup ScopedTimeout timeout(*this, seconds(10)); if (SendPacketAndWaitForResponse(stream.GetString(), response, false) == PacketResult::Success) { llvm::StringRef name; llvm::StringRef value; while (response.GetNameColonValue(name, value)) { if (name.equals("port")) value.getAsInteger(0, port); else if (name.equals("pid")) value.getAsInteger(0, pid); else if (name.compare("socket_name") == 0) { StringExtractor extractor(value); extractor.GetHexByteString(socket_name); } } return true; } return false; } size_t GDBRemoteCommunicationClient::QueryGDBServer( std::vector> &connection_urls) { connection_urls.clear(); StringExtractorGDBRemote response; if (SendPacketAndWaitForResponse("qQueryGDBServer", response, false) != PacketResult::Success) return 0; StructuredData::ObjectSP data = StructuredData::ParseJSON(response.GetStringRef()); if (!data) return 0; StructuredData::Array *array = data->GetAsArray(); if (!array) return 0; for (size_t i = 0, count = array->GetSize(); i < count; ++i) { StructuredData::Dictionary *element = nullptr; if (!array->GetItemAtIndexAsDictionary(i, element)) continue; uint16_t port = 0; if (StructuredData::ObjectSP port_osp = element->GetValueForKey(llvm::StringRef("port"))) port = port_osp->GetIntegerValue(0); std::string socket_name; if (StructuredData::ObjectSP socket_name_osp = element->GetValueForKey(llvm::StringRef("socket_name"))) socket_name = socket_name_osp->GetStringValue(); if (port != 0 || !socket_name.empty()) connection_urls.emplace_back(port, socket_name); } return connection_urls.size(); } bool GDBRemoteCommunicationClient::KillSpawnedProcess(lldb::pid_t pid) { StreamString stream; stream.Printf("qKillSpawnedProcess:%" PRId64, pid); StringExtractorGDBRemote response; if (SendPacketAndWaitForResponse(stream.GetString(), response, false) == PacketResult::Success) { if (response.IsOKResponse()) return true; } return false; } bool GDBRemoteCommunicationClient::SetCurrentThread(uint64_t tid) { if (m_curr_tid == tid) return true; char packet[32]; int packet_len; if (tid == UINT64_MAX) packet_len = ::snprintf(packet, sizeof(packet), "Hg-1"); else packet_len = ::snprintf(packet, sizeof(packet), "Hg%" PRIx64, tid); assert(packet_len + 1 < (int)sizeof(packet)); UNUSED_IF_ASSERT_DISABLED(packet_len); StringExtractorGDBRemote response; if (SendPacketAndWaitForResponse(packet, response, false) == PacketResult::Success) { if (response.IsOKResponse()) { m_curr_tid = tid; return true; } /* * Connected bare-iron target (like YAMON gdb-stub) may not have support for * Hg packet. * The reply from '?' packet could be as simple as 'S05'. There is no packet * which can * give us pid and/or tid. Assume pid=tid=1 in such cases. */ if (response.IsUnsupportedResponse() && IsConnected()) { m_curr_tid = 1; return true; } } return false; } bool GDBRemoteCommunicationClient::SetCurrentThreadForRun(uint64_t tid) { if (m_curr_tid_run == tid) return true; char packet[32]; int packet_len; if (tid == UINT64_MAX) packet_len = ::snprintf(packet, sizeof(packet), "Hc-1"); else packet_len = ::snprintf(packet, sizeof(packet), "Hc%" PRIx64, tid); assert(packet_len + 1 < (int)sizeof(packet)); UNUSED_IF_ASSERT_DISABLED(packet_len); StringExtractorGDBRemote response; if (SendPacketAndWaitForResponse(packet, response, false) == PacketResult::Success) { if (response.IsOKResponse()) { m_curr_tid_run = tid; return true; } /* * Connected bare-iron target (like YAMON gdb-stub) may not have support for * Hc packet. * The reply from '?' packet could be as simple as 'S05'. There is no packet * which can * give us pid and/or tid. Assume pid=tid=1 in such cases. */ if (response.IsUnsupportedResponse() && IsConnected()) { m_curr_tid_run = 1; return true; } } return false; } bool GDBRemoteCommunicationClient::GetStopReply( StringExtractorGDBRemote &response) { if (SendPacketAndWaitForResponse("?", response, false) == PacketResult::Success) return response.IsNormalResponse(); return false; } bool GDBRemoteCommunicationClient::GetThreadStopInfo( lldb::tid_t tid, StringExtractorGDBRemote &response) { if (m_supports_qThreadStopInfo) { char packet[256]; int packet_len = ::snprintf(packet, sizeof(packet), "qThreadStopInfo%" PRIx64, tid); assert(packet_len < (int)sizeof(packet)); UNUSED_IF_ASSERT_DISABLED(packet_len); if (SendPacketAndWaitForResponse(packet, response, false) == PacketResult::Success) { if (response.IsUnsupportedResponse()) m_supports_qThreadStopInfo = false; else if (response.IsNormalResponse()) return true; else return false; } else { m_supports_qThreadStopInfo = false; } } return false; } uint8_t GDBRemoteCommunicationClient::SendGDBStoppointTypePacket( GDBStoppointType type, bool insert, addr_t addr, uint32_t length) { Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_BREAKPOINTS)); LLDB_LOGF(log, "GDBRemoteCommunicationClient::%s() %s at addr = 0x%" PRIx64, __FUNCTION__, insert ? "add" : "remove", addr); // Check if the stub is known not to support this breakpoint type if (!SupportsGDBStoppointPacket(type)) return UINT8_MAX; // Construct the breakpoint packet char packet[64]; const int packet_len = ::snprintf(packet, sizeof(packet), "%c%i,%" PRIx64 ",%x", insert ? 'Z' : 'z', type, addr, length); // Check we haven't overwritten the end of the packet buffer assert(packet_len + 1 < (int)sizeof(packet)); UNUSED_IF_ASSERT_DISABLED(packet_len); StringExtractorGDBRemote response; // Make sure the response is either "OK", "EXX" where XX are two hex digits, // or "" (unsupported) response.SetResponseValidatorToOKErrorNotSupported(); // Try to send the breakpoint packet, and check that it was correctly sent if (SendPacketAndWaitForResponse(packet, response, true) == PacketResult::Success) { // Receive and OK packet when the breakpoint successfully placed if (response.IsOKResponse()) return 0; // Status while setting breakpoint, send back specific error if (response.IsErrorResponse()) return response.GetError(); // Empty packet informs us that breakpoint is not supported if (response.IsUnsupportedResponse()) { // Disable this breakpoint type since it is unsupported switch (type) { case eBreakpointSoftware: m_supports_z0 = false; break; case eBreakpointHardware: m_supports_z1 = false; break; case eWatchpointWrite: m_supports_z2 = false; break; case eWatchpointRead: m_supports_z3 = false; break; case eWatchpointReadWrite: m_supports_z4 = false; break; case eStoppointInvalid: return UINT8_MAX; } } } // Signal generic failure return UINT8_MAX; } size_t GDBRemoteCommunicationClient::GetCurrentThreadIDs( std::vector &thread_ids, bool &sequence_mutex_unavailable) { thread_ids.clear(); Lock lock(*this, false); if (lock) { sequence_mutex_unavailable = false; StringExtractorGDBRemote response; PacketResult packet_result; for (packet_result = SendPacketAndWaitForResponseNoLock("qfThreadInfo", response); packet_result == PacketResult::Success && response.IsNormalResponse(); packet_result = SendPacketAndWaitForResponseNoLock("qsThreadInfo", response)) { char ch = response.GetChar(); if (ch == 'l') break; if (ch == 'm') { do { tid_t tid = response.GetHexMaxU64(false, LLDB_INVALID_THREAD_ID); if (tid != LLDB_INVALID_THREAD_ID) { thread_ids.push_back(tid); } ch = response.GetChar(); // Skip the command separator } while (ch == ','); // Make sure we got a comma separator } } /* * Connected bare-iron target (like YAMON gdb-stub) may not have support for * qProcessInfo, qC and qfThreadInfo packets. The reply from '?' packet * could * be as simple as 'S05'. There is no packet which can give us pid and/or * tid. * Assume pid=tid=1 in such cases. */ if ((response.IsUnsupportedResponse() || response.IsNormalResponse()) && thread_ids.size() == 0 && IsConnected()) { thread_ids.push_back(1); } } else { #if !defined(LLDB_CONFIGURATION_DEBUG) Log *log(ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet(GDBR_LOG_PROCESS | GDBR_LOG_PACKETS)); LLDB_LOGF(log, "error: failed to get packet sequence mutex, not sending " "packet 'qfThreadInfo'"); #endif sequence_mutex_unavailable = true; } return thread_ids.size(); } lldb::addr_t GDBRemoteCommunicationClient::GetShlibInfoAddr() { StringExtractorGDBRemote response; if (SendPacketAndWaitForResponse("qShlibInfoAddr", response, false) != PacketResult::Success || !response.IsNormalResponse()) return LLDB_INVALID_ADDRESS; return response.GetHexMaxU64(false, LLDB_INVALID_ADDRESS); } lldb_private::Status GDBRemoteCommunicationClient::RunShellCommand( const char *command, // Shouldn't be NULL const FileSpec & working_dir, // Pass empty FileSpec to use the current working directory int *status_ptr, // Pass NULL if you don't want the process exit status int *signo_ptr, // Pass NULL if you don't want the signal that caused the // process to exit std::string *command_output, // Pass NULL if you don't want the command output const Timeout &timeout) { lldb_private::StreamString stream; stream.PutCString("qPlatform_shell:"); stream.PutBytesAsRawHex8(command, strlen(command)); stream.PutChar(','); uint32_t timeout_sec = UINT32_MAX; if (timeout) { // TODO: Use chrono version of std::ceil once c++17 is available. timeout_sec = std::ceil(std::chrono::duration(*timeout).count()); } stream.PutHex32(timeout_sec); if (working_dir) { std::string path{working_dir.GetPath(false)}; stream.PutChar(','); stream.PutStringAsRawHex8(path); } StringExtractorGDBRemote response; if (SendPacketAndWaitForResponse(stream.GetString(), response, false) == PacketResult::Success) { if (response.GetChar() != 'F') return Status("malformed reply"); if (response.GetChar() != ',') return Status("malformed reply"); uint32_t exitcode = response.GetHexMaxU32(false, UINT32_MAX); if (exitcode == UINT32_MAX) return Status("unable to run remote process"); else if (status_ptr) *status_ptr = exitcode; if (response.GetChar() != ',') return Status("malformed reply"); uint32_t signo = response.GetHexMaxU32(false, UINT32_MAX); if (signo_ptr) *signo_ptr = signo; if (response.GetChar() != ',') return Status("malformed reply"); std::string output; response.GetEscapedBinaryData(output); if (command_output) command_output->assign(output); return Status(); } return Status("unable to send packet"); } Status GDBRemoteCommunicationClient::MakeDirectory(const FileSpec &file_spec, uint32_t file_permissions) { std::string path{file_spec.GetPath(false)}; lldb_private::StreamString stream; stream.PutCString("qPlatform_mkdir:"); stream.PutHex32(file_permissions); stream.PutChar(','); stream.PutStringAsRawHex8(path); llvm::StringRef packet = stream.GetString(); StringExtractorGDBRemote response; if (SendPacketAndWaitForResponse(packet, response, false) != PacketResult::Success) return Status("failed to send '%s' packet", packet.str().c_str()); if (response.GetChar() != 'F') return Status("invalid response to '%s' packet", packet.str().c_str()); return Status(response.GetU32(UINT32_MAX), eErrorTypePOSIX); } Status GDBRemoteCommunicationClient::SetFilePermissions(const FileSpec &file_spec, uint32_t file_permissions) { std::string path{file_spec.GetPath(false)}; lldb_private::StreamString stream; stream.PutCString("qPlatform_chmod:"); stream.PutHex32(file_permissions); stream.PutChar(','); stream.PutStringAsRawHex8(path); llvm::StringRef packet = stream.GetString(); StringExtractorGDBRemote response; if (SendPacketAndWaitForResponse(packet, response, false) != PacketResult::Success) return Status("failed to send '%s' packet", stream.GetData()); if (response.GetChar() != 'F') return Status("invalid response to '%s' packet", stream.GetData()); return Status(response.GetU32(UINT32_MAX), eErrorTypePOSIX); } static uint64_t ParseHostIOPacketResponse(StringExtractorGDBRemote &response, uint64_t fail_result, Status &error) { response.SetFilePos(0); if (response.GetChar() != 'F') return fail_result; int32_t result = response.GetS32(-2); if (result == -2) return fail_result; if (response.GetChar() == ',') { int result_errno = response.GetS32(-2); if (result_errno != -2) error.SetError(result_errno, eErrorTypePOSIX); else error.SetError(-1, eErrorTypeGeneric); } else error.Clear(); return result; } lldb::user_id_t GDBRemoteCommunicationClient::OpenFile(const lldb_private::FileSpec &file_spec, File::OpenOptions flags, mode_t mode, Status &error) { std::string path(file_spec.GetPath(false)); lldb_private::StreamString stream; stream.PutCString("vFile:open:"); if (path.empty()) return UINT64_MAX; stream.PutStringAsRawHex8(path); stream.PutChar(','); stream.PutHex32(flags); stream.PutChar(','); stream.PutHex32(mode); StringExtractorGDBRemote response; if (SendPacketAndWaitForResponse(stream.GetString(), response, false) == PacketResult::Success) { return ParseHostIOPacketResponse(response, UINT64_MAX, error); } return UINT64_MAX; } bool GDBRemoteCommunicationClient::CloseFile(lldb::user_id_t fd, Status &error) { lldb_private::StreamString stream; stream.Printf("vFile:close:%i", (int)fd); StringExtractorGDBRemote response; if (SendPacketAndWaitForResponse(stream.GetString(), response, false) == PacketResult::Success) { return ParseHostIOPacketResponse(response, -1, error) == 0; } return false; } // Extension of host I/O packets to get the file size. lldb::user_id_t GDBRemoteCommunicationClient::GetFileSize( const lldb_private::FileSpec &file_spec) { std::string path(file_spec.GetPath(false)); lldb_private::StreamString stream; stream.PutCString("vFile:size:"); stream.PutStringAsRawHex8(path); StringExtractorGDBRemote response; if (SendPacketAndWaitForResponse(stream.GetString(), response, false) == PacketResult::Success) { if (response.GetChar() != 'F') return UINT64_MAX; uint32_t retcode = response.GetHexMaxU64(false, UINT64_MAX); return retcode; } return UINT64_MAX; } Status GDBRemoteCommunicationClient::GetFilePermissions(const FileSpec &file_spec, uint32_t &file_permissions) { std::string path{file_spec.GetPath(false)}; Status error; lldb_private::StreamString stream; stream.PutCString("vFile:mode:"); stream.PutStringAsRawHex8(path); StringExtractorGDBRemote response; if (SendPacketAndWaitForResponse(stream.GetString(), response, false) == PacketResult::Success) { if (response.GetChar() != 'F') { error.SetErrorStringWithFormat("invalid response to '%s' packet", stream.GetData()); } else { const uint32_t mode = response.GetS32(-1); if (static_cast(mode) == -1) { if (response.GetChar() == ',') { int response_errno = response.GetS32(-1); if (response_errno > 0) error.SetError(response_errno, lldb::eErrorTypePOSIX); else error.SetErrorToGenericError(); } else error.SetErrorToGenericError(); } else { file_permissions = mode & (S_IRWXU | S_IRWXG | S_IRWXO); } } } else { error.SetErrorStringWithFormat("failed to send '%s' packet", stream.GetData()); } return error; } uint64_t GDBRemoteCommunicationClient::ReadFile(lldb::user_id_t fd, uint64_t offset, void *dst, uint64_t dst_len, Status &error) { lldb_private::StreamString stream; stream.Printf("vFile:pread:%i,%" PRId64 ",%" PRId64, (int)fd, dst_len, offset); StringExtractorGDBRemote response; if (SendPacketAndWaitForResponse(stream.GetString(), response, false) == PacketResult::Success) { if (response.GetChar() != 'F') return 0; uint32_t retcode = response.GetHexMaxU32(false, UINT32_MAX); if (retcode == UINT32_MAX) return retcode; const char next = (response.Peek() ? *response.Peek() : 0); if (next == ',') return 0; if (next == ';') { response.GetChar(); // skip the semicolon std::string buffer; if (response.GetEscapedBinaryData(buffer)) { const uint64_t data_to_write = std::min(dst_len, buffer.size()); if (data_to_write > 0) memcpy(dst, &buffer[0], data_to_write); return data_to_write; } } } return 0; } uint64_t GDBRemoteCommunicationClient::WriteFile(lldb::user_id_t fd, uint64_t offset, const void *src, uint64_t src_len, Status &error) { lldb_private::StreamGDBRemote stream; stream.Printf("vFile:pwrite:%i,%" PRId64 ",", (int)fd, offset); stream.PutEscapedBytes(src, src_len); StringExtractorGDBRemote response; if (SendPacketAndWaitForResponse(stream.GetString(), response, false) == PacketResult::Success) { if (response.GetChar() != 'F') { error.SetErrorStringWithFormat("write file failed"); return 0; } uint64_t bytes_written = response.GetU64(UINT64_MAX); if (bytes_written == UINT64_MAX) { error.SetErrorToGenericError(); if (response.GetChar() == ',') { int response_errno = response.GetS32(-1); if (response_errno > 0) error.SetError(response_errno, lldb::eErrorTypePOSIX); } return 0; } return bytes_written; } else { error.SetErrorString("failed to send vFile:pwrite packet"); } return 0; } Status GDBRemoteCommunicationClient::CreateSymlink(const FileSpec &src, const FileSpec &dst) { std::string src_path{src.GetPath(false)}, dst_path{dst.GetPath(false)}; Status error; lldb_private::StreamGDBRemote stream; stream.PutCString("vFile:symlink:"); // the unix symlink() command reverses its parameters where the dst if first, // so we follow suit here stream.PutStringAsRawHex8(dst_path); stream.PutChar(','); stream.PutStringAsRawHex8(src_path); StringExtractorGDBRemote response; if (SendPacketAndWaitForResponse(stream.GetString(), response, false) == PacketResult::Success) { if (response.GetChar() == 'F') { uint32_t result = response.GetU32(UINT32_MAX); if (result != 0) { error.SetErrorToGenericError(); if (response.GetChar() == ',') { int response_errno = response.GetS32(-1); if (response_errno > 0) error.SetError(response_errno, lldb::eErrorTypePOSIX); } } } else { // Should have returned with 'F[,]' error.SetErrorStringWithFormat("symlink failed"); } } else { error.SetErrorString("failed to send vFile:symlink packet"); } return error; } Status GDBRemoteCommunicationClient::Unlink(const FileSpec &file_spec) { std::string path{file_spec.GetPath(false)}; Status error; lldb_private::StreamGDBRemote stream; stream.PutCString("vFile:unlink:"); // the unix symlink() command reverses its parameters where the dst if first, // so we follow suit here stream.PutStringAsRawHex8(path); StringExtractorGDBRemote response; if (SendPacketAndWaitForResponse(stream.GetString(), response, false) == PacketResult::Success) { if (response.GetChar() == 'F') { uint32_t result = response.GetU32(UINT32_MAX); if (result != 0) { error.SetErrorToGenericError(); if (response.GetChar() == ',') { int response_errno = response.GetS32(-1); if (response_errno > 0) error.SetError(response_errno, lldb::eErrorTypePOSIX); } } } else { // Should have returned with 'F[,]' error.SetErrorStringWithFormat("unlink failed"); } } else { error.SetErrorString("failed to send vFile:unlink packet"); } return error; } // Extension of host I/O packets to get whether a file exists. bool GDBRemoteCommunicationClient::GetFileExists( const lldb_private::FileSpec &file_spec) { std::string path(file_spec.GetPath(false)); lldb_private::StreamString stream; stream.PutCString("vFile:exists:"); stream.PutStringAsRawHex8(path); StringExtractorGDBRemote response; if (SendPacketAndWaitForResponse(stream.GetString(), response, false) == PacketResult::Success) { if (response.GetChar() != 'F') return false; if (response.GetChar() != ',') return false; bool retcode = (response.GetChar() != '0'); return retcode; } return false; } bool GDBRemoteCommunicationClient::CalculateMD5( const lldb_private::FileSpec &file_spec, uint64_t &high, uint64_t &low) { std::string path(file_spec.GetPath(false)); lldb_private::StreamString stream; stream.PutCString("vFile:MD5:"); stream.PutStringAsRawHex8(path); StringExtractorGDBRemote response; if (SendPacketAndWaitForResponse(stream.GetString(), response, false) == PacketResult::Success) { if (response.GetChar() != 'F') return false; if (response.GetChar() != ',') return false; if (response.Peek() && *response.Peek() == 'x') return false; low = response.GetHexMaxU64(false, UINT64_MAX); high = response.GetHexMaxU64(false, UINT64_MAX); return true; } return false; } bool GDBRemoteCommunicationClient::AvoidGPackets(ProcessGDBRemote *process) { // Some targets have issues with g/G packets and we need to avoid using them if (m_avoid_g_packets == eLazyBoolCalculate) { if (process) { m_avoid_g_packets = eLazyBoolNo; const ArchSpec &arch = process->GetTarget().GetArchitecture(); if (arch.IsValid() && arch.GetTriple().getVendor() == llvm::Triple::Apple && arch.GetTriple().getOS() == llvm::Triple::IOS && (arch.GetTriple().getArch() == llvm::Triple::aarch64 || arch.GetTriple().getArch() == llvm::Triple::aarch64_32)) { m_avoid_g_packets = eLazyBoolYes; uint32_t gdb_server_version = GetGDBServerProgramVersion(); if (gdb_server_version != 0) { const char *gdb_server_name = GetGDBServerProgramName(); if (gdb_server_name && strcmp(gdb_server_name, "debugserver") == 0) { if (gdb_server_version >= 310) m_avoid_g_packets = eLazyBoolNo; } } } } } return m_avoid_g_packets == eLazyBoolYes; } DataBufferSP GDBRemoteCommunicationClient::ReadRegister(lldb::tid_t tid, uint32_t reg) { StreamString payload; payload.Printf("p%x", reg); StringExtractorGDBRemote response; if (SendThreadSpecificPacketAndWaitForResponse( tid, std::move(payload), response, false) != PacketResult::Success || !response.IsNormalResponse()) return nullptr; DataBufferSP buffer_sp( new DataBufferHeap(response.GetStringRef().size() / 2, 0)); response.GetHexBytes(buffer_sp->GetData(), '\xcc'); return buffer_sp; } DataBufferSP GDBRemoteCommunicationClient::ReadAllRegisters(lldb::tid_t tid) { StreamString payload; payload.PutChar('g'); StringExtractorGDBRemote response; if (SendThreadSpecificPacketAndWaitForResponse( tid, std::move(payload), response, false) != PacketResult::Success || !response.IsNormalResponse()) return nullptr; DataBufferSP buffer_sp( new DataBufferHeap(response.GetStringRef().size() / 2, 0)); response.GetHexBytes(buffer_sp->GetData(), '\xcc'); return buffer_sp; } bool GDBRemoteCommunicationClient::WriteRegister(lldb::tid_t tid, uint32_t reg_num, llvm::ArrayRef data) { StreamString payload; payload.Printf("P%x=", reg_num); payload.PutBytesAsRawHex8(data.data(), data.size(), endian::InlHostByteOrder(), endian::InlHostByteOrder()); StringExtractorGDBRemote response; return SendThreadSpecificPacketAndWaitForResponse(tid, std::move(payload), response, false) == PacketResult::Success && response.IsOKResponse(); } bool GDBRemoteCommunicationClient::WriteAllRegisters( lldb::tid_t tid, llvm::ArrayRef data) { StreamString payload; payload.PutChar('G'); payload.PutBytesAsRawHex8(data.data(), data.size(), endian::InlHostByteOrder(), endian::InlHostByteOrder()); StringExtractorGDBRemote response; return SendThreadSpecificPacketAndWaitForResponse(tid, std::move(payload), response, false) == PacketResult::Success && response.IsOKResponse(); } bool GDBRemoteCommunicationClient::SaveRegisterState(lldb::tid_t tid, uint32_t &save_id) { save_id = 0; // Set to invalid save ID if (m_supports_QSaveRegisterState == eLazyBoolNo) return false; m_supports_QSaveRegisterState = eLazyBoolYes; StreamString payload; payload.PutCString("QSaveRegisterState"); StringExtractorGDBRemote response; if (SendThreadSpecificPacketAndWaitForResponse( tid, std::move(payload), response, false) != PacketResult::Success) return false; if (response.IsUnsupportedResponse()) m_supports_QSaveRegisterState = eLazyBoolNo; const uint32_t response_save_id = response.GetU32(0); if (response_save_id == 0) return false; save_id = response_save_id; return true; } bool GDBRemoteCommunicationClient::RestoreRegisterState(lldb::tid_t tid, uint32_t save_id) { // We use the "m_supports_QSaveRegisterState" variable here because the // QSaveRegisterState and QRestoreRegisterState packets must both be // supported in order to be useful if (m_supports_QSaveRegisterState == eLazyBoolNo) return false; StreamString payload; payload.Printf("QRestoreRegisterState:%u", save_id); StringExtractorGDBRemote response; if (SendThreadSpecificPacketAndWaitForResponse( tid, std::move(payload), response, false) != PacketResult::Success) return false; if (response.IsOKResponse()) return true; if (response.IsUnsupportedResponse()) m_supports_QSaveRegisterState = eLazyBoolNo; return false; } bool GDBRemoteCommunicationClient::SyncThreadState(lldb::tid_t tid) { if (!GetSyncThreadStateSupported()) return false; StreamString packet; StringExtractorGDBRemote response; packet.Printf("QSyncThreadState:%4.4" PRIx64 ";", tid); return SendPacketAndWaitForResponse(packet.GetString(), response, false) == GDBRemoteCommunication::PacketResult::Success && response.IsOKResponse(); } lldb::user_id_t GDBRemoteCommunicationClient::SendStartTracePacket(const TraceOptions &options, Status &error) { Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); lldb::user_id_t ret_uid = LLDB_INVALID_UID; StreamGDBRemote escaped_packet; escaped_packet.PutCString("jTraceStart:"); StructuredData::Dictionary json_packet; json_packet.AddIntegerItem("type", options.getType()); json_packet.AddIntegerItem("buffersize", options.getTraceBufferSize()); json_packet.AddIntegerItem("metabuffersize", options.getMetaDataBufferSize()); if (options.getThreadID() != LLDB_INVALID_THREAD_ID) json_packet.AddIntegerItem("threadid", options.getThreadID()); StructuredData::DictionarySP custom_params = options.getTraceParams(); if (custom_params) json_packet.AddItem("params", custom_params); StreamString json_string; json_packet.Dump(json_string, false); escaped_packet.PutEscapedBytes(json_string.GetData(), json_string.GetSize()); StringExtractorGDBRemote response; if (SendPacketAndWaitForResponse(escaped_packet.GetString(), response, true) == GDBRemoteCommunication::PacketResult::Success) { if (!response.IsNormalResponse()) { error = response.GetStatus(); LLDB_LOG(log, "Target does not support Tracing , error {0}", error); } else { ret_uid = response.GetHexMaxU64(false, LLDB_INVALID_UID); } } else { LLDB_LOG(log, "failed to send packet"); error.SetErrorStringWithFormat("failed to send packet: '%s'", escaped_packet.GetData()); } return ret_uid; } Status GDBRemoteCommunicationClient::SendStopTracePacket(lldb::user_id_t uid, lldb::tid_t thread_id) { Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); StringExtractorGDBRemote response; Status error; StructuredData::Dictionary json_packet; StreamGDBRemote escaped_packet; StreamString json_string; escaped_packet.PutCString("jTraceStop:"); json_packet.AddIntegerItem("traceid", uid); if (thread_id != LLDB_INVALID_THREAD_ID) json_packet.AddIntegerItem("threadid", thread_id); json_packet.Dump(json_string, false); escaped_packet.PutEscapedBytes(json_string.GetData(), json_string.GetSize()); if (SendPacketAndWaitForResponse(escaped_packet.GetString(), response, true) == GDBRemoteCommunication::PacketResult::Success) { if (!response.IsOKResponse()) { error = response.GetStatus(); LLDB_LOG(log, "stop tracing failed"); } } else { LLDB_LOG(log, "failed to send packet"); error.SetErrorStringWithFormat( "failed to send packet: '%s' with error '%d'", escaped_packet.GetData(), response.GetError()); } return error; } Status GDBRemoteCommunicationClient::SendGetDataPacket( lldb::user_id_t uid, lldb::tid_t thread_id, llvm::MutableArrayRef &buffer, size_t offset) { StreamGDBRemote escaped_packet; escaped_packet.PutCString("jTraceBufferRead:"); return SendGetTraceDataPacket(escaped_packet, uid, thread_id, buffer, offset); } Status GDBRemoteCommunicationClient::SendGetMetaDataPacket( lldb::user_id_t uid, lldb::tid_t thread_id, llvm::MutableArrayRef &buffer, size_t offset) { StreamGDBRemote escaped_packet; escaped_packet.PutCString("jTraceMetaRead:"); return SendGetTraceDataPacket(escaped_packet, uid, thread_id, buffer, offset); } Status GDBRemoteCommunicationClient::SendGetTraceConfigPacket(lldb::user_id_t uid, TraceOptions &options) { Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); StringExtractorGDBRemote response; Status error; StreamString json_string; StreamGDBRemote escaped_packet; escaped_packet.PutCString("jTraceConfigRead:"); StructuredData::Dictionary json_packet; json_packet.AddIntegerItem("traceid", uid); if (options.getThreadID() != LLDB_INVALID_THREAD_ID) json_packet.AddIntegerItem("threadid", options.getThreadID()); json_packet.Dump(json_string, false); escaped_packet.PutEscapedBytes(json_string.GetData(), json_string.GetSize()); if (SendPacketAndWaitForResponse(escaped_packet.GetString(), response, true) == GDBRemoteCommunication::PacketResult::Success) { if (response.IsNormalResponse()) { uint64_t type = std::numeric_limits::max(); uint64_t buffersize = std::numeric_limits::max(); uint64_t metabuffersize = std::numeric_limits::max(); auto json_object = StructuredData::ParseJSON(response.Peek()); if (!json_object || json_object->GetType() != lldb::eStructuredDataTypeDictionary) { error.SetErrorString("Invalid Configuration obtained"); return error; } auto json_dict = json_object->GetAsDictionary(); json_dict->GetValueForKeyAsInteger("metabuffersize", metabuffersize); options.setMetaDataBufferSize(metabuffersize); json_dict->GetValueForKeyAsInteger("buffersize", buffersize); options.setTraceBufferSize(buffersize); json_dict->GetValueForKeyAsInteger("type", type); options.setType(static_cast(type)); StructuredData::ObjectSP custom_params_sp = json_dict->GetValueForKey("params"); if (custom_params_sp) { if (custom_params_sp->GetType() != lldb::eStructuredDataTypeDictionary) { error.SetErrorString("Invalid Configuration obtained"); return error; } else options.setTraceParams( static_pointer_cast( custom_params_sp)); } } else { error = response.GetStatus(); } } else { LLDB_LOG(log, "failed to send packet"); error.SetErrorStringWithFormat("failed to send packet: '%s'", escaped_packet.GetData()); } return error; } Status GDBRemoteCommunicationClient::SendGetTraceDataPacket( StreamGDBRemote &packet, lldb::user_id_t uid, lldb::tid_t thread_id, llvm::MutableArrayRef &buffer, size_t offset) { Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); Status error; StructuredData::Dictionary json_packet; json_packet.AddIntegerItem("traceid", uid); json_packet.AddIntegerItem("offset", offset); json_packet.AddIntegerItem("buffersize", buffer.size()); if (thread_id != LLDB_INVALID_THREAD_ID) json_packet.AddIntegerItem("threadid", thread_id); StreamString json_string; json_packet.Dump(json_string, false); packet.PutEscapedBytes(json_string.GetData(), json_string.GetSize()); StringExtractorGDBRemote response; if (SendPacketAndWaitForResponse(packet.GetString(), response, true) == GDBRemoteCommunication::PacketResult::Success) { if (response.IsNormalResponse()) { size_t filled_size = response.GetHexBytesAvail(buffer); buffer = llvm::MutableArrayRef(buffer.data(), filled_size); } else { error = response.GetStatus(); buffer = buffer.slice(buffer.size()); } } else { LLDB_LOG(log, "failed to send packet"); error.SetErrorStringWithFormat("failed to send packet: '%s'", packet.GetData()); buffer = buffer.slice(buffer.size()); } return error; } bool GDBRemoteCommunicationClient::GetModuleInfo( const FileSpec &module_file_spec, const lldb_private::ArchSpec &arch_spec, ModuleSpec &module_spec) { if (!m_supports_qModuleInfo) return false; std::string module_path = module_file_spec.GetPath(false); if (module_path.empty()) return false; StreamString packet; packet.PutCString("qModuleInfo:"); packet.PutStringAsRawHex8(module_path); packet.PutCString(";"); const auto &triple = arch_spec.GetTriple().getTriple(); packet.PutStringAsRawHex8(triple); StringExtractorGDBRemote response; if (SendPacketAndWaitForResponse(packet.GetString(), response, false) != PacketResult::Success) return false; if (response.IsErrorResponse()) return false; if (response.IsUnsupportedResponse()) { m_supports_qModuleInfo = false; return false; } llvm::StringRef name; llvm::StringRef value; module_spec.Clear(); module_spec.GetFileSpec() = module_file_spec; while (response.GetNameColonValue(name, value)) { if (name == "uuid" || name == "md5") { StringExtractor extractor(value); std::string uuid; extractor.GetHexByteString(uuid); module_spec.GetUUID().SetFromStringRef(uuid, uuid.size() / 2); } else if (name == "triple") { StringExtractor extractor(value); std::string triple; extractor.GetHexByteString(triple); module_spec.GetArchitecture().SetTriple(triple.c_str()); } else if (name == "file_offset") { uint64_t ival = 0; if (!value.getAsInteger(16, ival)) module_spec.SetObjectOffset(ival); } else if (name == "file_size") { uint64_t ival = 0; if (!value.getAsInteger(16, ival)) module_spec.SetObjectSize(ival); } else if (name == "file_path") { StringExtractor extractor(value); std::string path; extractor.GetHexByteString(path); module_spec.GetFileSpec() = FileSpec(path, arch_spec.GetTriple()); } } return true; } static llvm::Optional ParseModuleSpec(StructuredData::Dictionary *dict) { ModuleSpec result; if (!dict) return llvm::None; llvm::StringRef string; uint64_t integer; if (!dict->GetValueForKeyAsString("uuid", string)) return llvm::None; if (result.GetUUID().SetFromStringRef(string, string.size() / 2) != string.size()) return llvm::None; if (!dict->GetValueForKeyAsInteger("file_offset", integer)) return llvm::None; result.SetObjectOffset(integer); if (!dict->GetValueForKeyAsInteger("file_size", integer)) return llvm::None; result.SetObjectSize(integer); if (!dict->GetValueForKeyAsString("triple", string)) return llvm::None; result.GetArchitecture().SetTriple(string); if (!dict->GetValueForKeyAsString("file_path", string)) return llvm::None; result.GetFileSpec() = FileSpec(string, result.GetArchitecture().GetTriple()); return result; } llvm::Optional> GDBRemoteCommunicationClient::GetModulesInfo( llvm::ArrayRef module_file_specs, const llvm::Triple &triple) { namespace json = llvm::json; if (!m_supports_jModulesInfo) return llvm::None; json::Array module_array; for (const FileSpec &module_file_spec : module_file_specs) { module_array.push_back( json::Object{{"file", module_file_spec.GetPath(false)}, {"triple", triple.getTriple()}}); } StreamString unescaped_payload; unescaped_payload.PutCString("jModulesInfo:"); unescaped_payload.AsRawOstream() << std::move(module_array); StreamGDBRemote payload; payload.PutEscapedBytes(unescaped_payload.GetString().data(), unescaped_payload.GetSize()); // Increase the timeout for jModulesInfo since this packet can take longer. ScopedTimeout timeout(*this, std::chrono::seconds(10)); StringExtractorGDBRemote response; if (SendPacketAndWaitForResponse(payload.GetString(), response, false) != PacketResult::Success || response.IsErrorResponse()) return llvm::None; if (response.IsUnsupportedResponse()) { m_supports_jModulesInfo = false; return llvm::None; } StructuredData::ObjectSP response_object_sp = StructuredData::ParseJSON(response.GetStringRef()); if (!response_object_sp) return llvm::None; StructuredData::Array *response_array = response_object_sp->GetAsArray(); if (!response_array) return llvm::None; std::vector result; for (size_t i = 0; i < response_array->GetSize(); ++i) { if (llvm::Optional module_spec = ParseModuleSpec( response_array->GetItemAtIndex(i)->GetAsDictionary())) result.push_back(*module_spec); } return result; } // query the target remote for extended information using the qXfer packet // // example: object='features', annex='target.xml', out= return: // 'true' on success // 'false' on failure (err set) bool GDBRemoteCommunicationClient::ReadExtFeature( const lldb_private::ConstString object, const lldb_private::ConstString annex, std::string &out, lldb_private::Status &err) { std::stringstream output; StringExtractorGDBRemote chunk; uint64_t size = GetRemoteMaxPacketSize(); if (size == 0) size = 0x1000; size = size - 1; // Leave space for the 'm' or 'l' character in the response int offset = 0; bool active = true; // loop until all data has been read while (active) { // send query extended feature packet std::stringstream packet; packet << "qXfer:" << object.AsCString("") << ":read:" << annex.AsCString("") << ":" << std::hex << offset << "," << std::hex << size; GDBRemoteCommunication::PacketResult res = SendPacketAndWaitForResponse(packet.str(), chunk, false); if (res != GDBRemoteCommunication::PacketResult::Success) { err.SetErrorString("Error sending $qXfer packet"); return false; } const std::string &str = chunk.GetStringRef(); if (str.length() == 0) { // should have some data in chunk err.SetErrorString("Empty response from $qXfer packet"); return false; } // check packet code switch (str[0]) { // last chunk case ('l'): active = false; LLVM_FALLTHROUGH; // more chunks case ('m'): if (str.length() > 1) output << &str[1]; offset += str.length() - 1; break; // unknown chunk default: err.SetErrorString("Invalid continuation code from $qXfer packet"); return false; } } out = output.str(); err.Success(); return true; } // Notify the target that gdb is prepared to serve symbol lookup requests. // packet: "qSymbol::" // reply: // OK The target does not need to look up any (more) symbols. // qSymbol: The target requests the value of symbol sym_name (hex // encoded). // LLDB may provide the value by sending another qSymbol // packet // in the form of"qSymbol::". // // Three examples: // // lldb sends: qSymbol:: // lldb receives: OK // Remote gdb stub does not need to know the addresses of any symbols, lldb // does not // need to ask again in this session. // // lldb sends: qSymbol:: // lldb receives: qSymbol:64697370617463685f71756575655f6f666673657473 // lldb sends: qSymbol::64697370617463685f71756575655f6f666673657473 // lldb receives: OK // Remote gdb stub asks for address of 'dispatch_queue_offsets'. lldb does // not know // the address at this time. lldb needs to send qSymbol:: again when it has // more // solibs loaded. // // lldb sends: qSymbol:: // lldb receives: qSymbol:64697370617463685f71756575655f6f666673657473 // lldb sends: qSymbol:2bc97554:64697370617463685f71756575655f6f666673657473 // lldb receives: OK // Remote gdb stub asks for address of 'dispatch_queue_offsets'. lldb says // that it // is at address 0x2bc97554. Remote gdb stub sends 'OK' indicating that it // does not // need any more symbols. lldb does not need to ask again in this session. void GDBRemoteCommunicationClient::ServeSymbolLookups( lldb_private::Process *process) { // Set to true once we've resolved a symbol to an address for the remote // stub. If we get an 'OK' response after this, the remote stub doesn't need // any more symbols and we can stop asking. bool symbol_response_provided = false; // Is this the initial qSymbol:: packet? bool first_qsymbol_query = true; if (m_supports_qSymbol && !m_qSymbol_requests_done) { Lock lock(*this, false); if (lock) { StreamString packet; packet.PutCString("qSymbol::"); StringExtractorGDBRemote response; while (SendPacketAndWaitForResponseNoLock(packet.GetString(), response) == PacketResult::Success) { if (response.IsOKResponse()) { if (symbol_response_provided || first_qsymbol_query) { m_qSymbol_requests_done = true; } // We are done serving symbols requests return; } first_qsymbol_query = false; if (response.IsUnsupportedResponse()) { // qSymbol is not supported by the current GDB server we are // connected to m_supports_qSymbol = false; return; } else { llvm::StringRef response_str(response.GetStringRef()); if (response_str.startswith("qSymbol:")) { response.SetFilePos(strlen("qSymbol:")); std::string symbol_name; if (response.GetHexByteString(symbol_name)) { if (symbol_name.empty()) return; addr_t symbol_load_addr = LLDB_INVALID_ADDRESS; lldb_private::SymbolContextList sc_list; process->GetTarget().GetImages().FindSymbolsWithNameAndType( ConstString(symbol_name), eSymbolTypeAny, sc_list); if (!sc_list.IsEmpty()) { const size_t num_scs = sc_list.GetSize(); for (size_t sc_idx = 0; sc_idx < num_scs && symbol_load_addr == LLDB_INVALID_ADDRESS; ++sc_idx) { SymbolContext sc; if (sc_list.GetContextAtIndex(sc_idx, sc)) { if (sc.symbol) { switch (sc.symbol->GetType()) { case eSymbolTypeInvalid: case eSymbolTypeAbsolute: case eSymbolTypeUndefined: case eSymbolTypeSourceFile: case eSymbolTypeHeaderFile: case eSymbolTypeObjectFile: case eSymbolTypeCommonBlock: case eSymbolTypeBlock: case eSymbolTypeLocal: case eSymbolTypeParam: case eSymbolTypeVariable: case eSymbolTypeVariableType: case eSymbolTypeLineEntry: case eSymbolTypeLineHeader: case eSymbolTypeScopeBegin: case eSymbolTypeScopeEnd: case eSymbolTypeAdditional: case eSymbolTypeCompiler: case eSymbolTypeInstrumentation: case eSymbolTypeTrampoline: break; case eSymbolTypeCode: case eSymbolTypeResolver: case eSymbolTypeData: case eSymbolTypeRuntime: case eSymbolTypeException: case eSymbolTypeObjCClass: case eSymbolTypeObjCMetaClass: case eSymbolTypeObjCIVar: case eSymbolTypeReExported: symbol_load_addr = sc.symbol->GetLoadAddress(&process->GetTarget()); break; } } } } } // This is the normal path where our symbol lookup was successful // and we want to send a packet with the new symbol value and see // if another lookup needs to be done. // Change "packet" to contain the requested symbol value and name packet.Clear(); packet.PutCString("qSymbol:"); if (symbol_load_addr != LLDB_INVALID_ADDRESS) { packet.Printf("%" PRIx64, symbol_load_addr); symbol_response_provided = true; } else { symbol_response_provided = false; } packet.PutCString(":"); packet.PutBytesAsRawHex8(symbol_name.data(), symbol_name.size()); continue; // go back to the while loop and send "packet" and wait // for another response } } } } // If we make it here, the symbol request packet response wasn't valid or // our symbol lookup failed so we must abort return; } else if (Log *log = ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet( GDBR_LOG_PROCESS | GDBR_LOG_PACKETS)) { LLDB_LOGF(log, "GDBRemoteCommunicationClient::%s: Didn't get sequence mutex.", __FUNCTION__); } } } StructuredData::Array * GDBRemoteCommunicationClient::GetSupportedStructuredDataPlugins() { if (!m_supported_async_json_packets_is_valid) { // Query the server for the array of supported asynchronous JSON packets. m_supported_async_json_packets_is_valid = true; Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); // Poll it now. StringExtractorGDBRemote response; const bool send_async = false; if (SendPacketAndWaitForResponse("qStructuredDataPlugins", response, send_async) == PacketResult::Success) { m_supported_async_json_packets_sp = StructuredData::ParseJSON(response.GetStringRef()); if (m_supported_async_json_packets_sp && !m_supported_async_json_packets_sp->GetAsArray()) { // We were returned something other than a JSON array. This is // invalid. Clear it out. LLDB_LOGF(log, "GDBRemoteCommunicationClient::%s(): " "QSupportedAsyncJSONPackets returned invalid " "result: %s", __FUNCTION__, response.GetStringRef().data()); m_supported_async_json_packets_sp.reset(); } } else { LLDB_LOGF(log, "GDBRemoteCommunicationClient::%s(): " "QSupportedAsyncJSONPackets unsupported", __FUNCTION__); } if (log && m_supported_async_json_packets_sp) { StreamString stream; m_supported_async_json_packets_sp->Dump(stream); LLDB_LOGF(log, "GDBRemoteCommunicationClient::%s(): supported async " "JSON packets: %s", __FUNCTION__, stream.GetData()); } } return m_supported_async_json_packets_sp ? m_supported_async_json_packets_sp->GetAsArray() : nullptr; } Status GDBRemoteCommunicationClient::SendSignalsToIgnore( llvm::ArrayRef signals) { // Format packet: // QPassSignals:;...; auto range = llvm::make_range(signals.begin(), signals.end()); std::string packet = formatv("QPassSignals:{0:$[;]@(x-2)}", range).str(); StringExtractorGDBRemote response; auto send_status = SendPacketAndWaitForResponse(packet, response, false); if (send_status != GDBRemoteCommunication::PacketResult::Success) return Status("Sending QPassSignals packet failed"); if (response.IsOKResponse()) { return Status(); } else { return Status("Unknown error happened during sending QPassSignals packet."); } } Status GDBRemoteCommunicationClient::ConfigureRemoteStructuredData( ConstString type_name, const StructuredData::ObjectSP &config_sp) { Status error; if (type_name.GetLength() == 0) { error.SetErrorString("invalid type_name argument"); return error; } // Build command: Configure{type_name}: serialized config data. StreamGDBRemote stream; stream.PutCString("QConfigure"); stream.PutCString(type_name.AsCString()); stream.PutChar(':'); if (config_sp) { // Gather the plain-text version of the configuration data. StreamString unescaped_stream; config_sp->Dump(unescaped_stream); unescaped_stream.Flush(); // Add it to the stream in escaped fashion. stream.PutEscapedBytes(unescaped_stream.GetString().data(), unescaped_stream.GetSize()); } stream.Flush(); // Send the packet. const bool send_async = false; StringExtractorGDBRemote response; auto result = SendPacketAndWaitForResponse(stream.GetString(), response, send_async); if (result == PacketResult::Success) { // We failed if the config result comes back other than OK. if (strcmp(response.GetStringRef().data(), "OK") == 0) { // Okay! error.Clear(); } else { error.SetErrorStringWithFormat("configuring StructuredData feature " "%s failed with error %s", type_name.AsCString(), response.GetStringRef().data()); } } else { // Can we get more data here on the failure? error.SetErrorStringWithFormat("configuring StructuredData feature %s " "failed when sending packet: " "PacketResult=%d", type_name.AsCString(), (int)result); } return error; } void GDBRemoteCommunicationClient::OnRunPacketSent(bool first) { GDBRemoteClientBase::OnRunPacketSent(first); m_curr_tid = LLDB_INVALID_THREAD_ID; } diff --git a/contrib/llvm-project/llvm/lib/Support/Windows/WindowsSupport.h b/contrib/llvm-project/llvm/include/llvm/Support/Windows/WindowsSupport.h similarity index 100% rename from contrib/llvm-project/llvm/lib/Support/Windows/WindowsSupport.h rename to contrib/llvm-project/llvm/include/llvm/Support/Windows/WindowsSupport.h diff --git a/contrib/llvm-project/llvm/include/llvm/module.modulemap b/contrib/llvm-project/llvm/include/llvm/module.modulemap index 05de40698e35..d281682ae003 100644 --- a/contrib/llvm-project/llvm/include/llvm/module.modulemap +++ b/contrib/llvm-project/llvm/include/llvm/module.modulemap @@ -1,414 +1,417 @@ module LLVM_Analysis { requires cplusplus umbrella "Analysis" module * { export * } // This is intended for (repeated) textual inclusion. textual header "Analysis/TargetLibraryInfo.def" textual header "Analysis/VecFuncs.def" } module LLVM_AsmParser { requires cplusplus umbrella "AsmParser" module * { export * } } // A module covering CodeGen/ and Target/. These are intertwined // and codependent, and thus notionally form a single module. module LLVM_Backend { requires cplusplus module CodeGen { umbrella "CodeGen" module * { export * } // Exclude these; they're intended to be included into only a single // translation unit (or none) and aren't part of this module. exclude header "CodeGen/LinkAllAsmWriterComponents.h" exclude header "CodeGen/LinkAllCodegenComponents.h" // These are intended for (repeated) textual inclusion. textual header "CodeGen/CommandFlags.inc" textual header "CodeGen/DIEValue.def" } } // FIXME: Make this as a submodule of LLVM_Backend again. // Doing so causes a linker error in clang-format. module LLVM_Backend_Target { umbrella "Target" module * { export * } } module LLVM_Bitcode { requires cplusplus umbrella "Bitcode" module * { export * } } module LLVM_BinaryFormat { requires cplusplus umbrella "BinaryFormat" module * { export * } textual header "BinaryFormat/Dwarf.def" textual header "BinaryFormat/DynamicTags.def" textual header "BinaryFormat/MachO.def" textual header "BinaryFormat/MinidumpConstants.def" textual header "BinaryFormat/ELFRelocs/AArch64.def" textual header "BinaryFormat/ELFRelocs/AMDGPU.def" textual header "BinaryFormat/ELFRelocs/ARM.def" textual header "BinaryFormat/ELFRelocs/ARC.def" textual header "BinaryFormat/ELFRelocs/AVR.def" textual header "BinaryFormat/ELFRelocs/BPF.def" textual header "BinaryFormat/ELFRelocs/Hexagon.def" textual header "BinaryFormat/ELFRelocs/i386.def" textual header "BinaryFormat/ELFRelocs/Lanai.def" textual header "BinaryFormat/ELFRelocs/Mips.def" textual header "BinaryFormat/ELFRelocs/MSP430.def" textual header "BinaryFormat/ELFRelocs/PowerPC64.def" textual header "BinaryFormat/ELFRelocs/PowerPC.def" textual header "BinaryFormat/ELFRelocs/RISCV.def" textual header "BinaryFormat/ELFRelocs/Sparc.def" textual header "BinaryFormat/ELFRelocs/SystemZ.def" textual header "BinaryFormat/ELFRelocs/x86_64.def" textual header "BinaryFormat/WasmRelocs.def" textual header "BinaryFormat/MsgPack.def" } module LLVM_Config { requires cplusplus umbrella "Config" extern module LLVM_Extern_Config_Def "module.extern.modulemap" module * { export * } } module LLVM_DebugInfo { requires cplusplus module DIContext { header "DebugInfo/DIContext.h" export * } } module LLVM_DebugInfo_DWARF { requires cplusplus umbrella "DebugInfo/DWARF" module * { export * } } module LLVM_DebugInfo_PDB { requires cplusplus umbrella "DebugInfo/PDB" module * { export * } // Separate out this subdirectory; it's an optional component that depends on // a separate library which might not be available. // // FIXME: There should be a better way to specify this. exclude header "DebugInfo/PDB/DIA/DIADataStream.h" exclude header "DebugInfo/PDB/DIA/DIAEnumDebugStreams.h" exclude header "DebugInfo/PDB/DIA/DIAEnumFrameData.h" exclude header "DebugInfo/PDB/DIA/DIAEnumInjectedSources.h" exclude header "DebugInfo/PDB/DIA/DIAEnumLineNumbers.h" exclude header "DebugInfo/PDB/DIA/DIAEnumSectionContribs.h" exclude header "DebugInfo/PDB/DIA/DIAEnumSourceFiles.h" exclude header "DebugInfo/PDB/DIA/DIAEnumSymbols.h" exclude header "DebugInfo/PDB/DIA/DIAEnumTables.h" exclude header "DebugInfo/PDB/DIA/DIAFrameData.h" exclude header "DebugInfo/PDB/DIA/DIAInjectedSource.h" exclude header "DebugInfo/PDB/DIA/DIALineNumber.h" exclude header "DebugInfo/PDB/DIA/DIARawSymbol.h" exclude header "DebugInfo/PDB/DIA/DIASectionContrib.h" exclude header "DebugInfo/PDB/DIA/DIASession.h" exclude header "DebugInfo/PDB/DIA/DIASourceFile.h" exclude header "DebugInfo/PDB/DIA/DIASupport.h" exclude header "DebugInfo/PDB/DIA/DIATable.h" exclude header "DebugInfo/PDB/DIA/DIAUtils.h" } module LLVM_DebugInfo_PDB_DIA { requires cplusplus umbrella "DebugInfo/PDB/DIA" module * { export * } } module LLVM_DebugInfo_MSF { requires cplusplus umbrella "DebugInfo/MSF" module * { export * } } module LLVM_DebugInfo_CodeView { requires cplusplus umbrella "DebugInfo/CodeView" module * { export * } // These are intended for (repeated) textual inclusion. textual header "DebugInfo/CodeView/CodeViewRegisters.def" textual header "DebugInfo/CodeView/CodeViewTypes.def" textual header "DebugInfo/CodeView/CodeViewSymbols.def" } module LLVM_DWARFLinker { requires cplusplus umbrella "DWARFLinker" module * { export * } } module LLVM_ExecutionEngine { requires cplusplus umbrella "ExecutionEngine" module * { export * } // Exclude this; it's an optional component of the ExecutionEngine. exclude header "ExecutionEngine/OProfileWrapper.h" // Exclude these; they're intended to be included into only a single // translation unit (or none) and aren't part of this module. exclude header "ExecutionEngine/MCJIT.h" exclude header "ExecutionEngine/Interpreter.h" exclude header "ExecutionEngine/OrcMCJITReplacement.h" // FIXME: These exclude directives were added as a workaround for // and should be removed once it is fixed. exclude header "ExecutionEngine/Orc/OrcRemoteTargetRPCAPI.h" exclude header "ExecutionEngine/Orc/OrcRemoteTargetClient.h" exclude header "ExecutionEngine/Orc/OrcRemoteTargetServer.h" exclude header "ExecutionEngine/Orc/RemoteObjectLayer.h" // Exclude headers from LLVM_OrcSupport. exclude header "ExecutionEngine/Orc/OrcError.h" exclude header "ExecutionEngine/Orc/RPC/RPCUtils.h" exclude header "ExecutionEngine/Orc/RPC/RPCSerialization.h" exclude header "ExecutionEngine/Orc/RPC/RawByteChannel.h" } // Orc utilities that don't depend only on Support (not ExecutionEngine or // IR). This is a workaround for ExecutionEngine's broken layering, and will // be removed in the future. module LLVM_OrcSupport { requires cplusplus header "ExecutionEngine/Orc/OrcError.h" header "ExecutionEngine/Orc/RPC/RPCUtils.h" header "ExecutionEngine/Orc/RPC/RPCSerialization.h" header "ExecutionEngine/Orc/RPC/RawByteChannel.h" export * } module LLVM_Pass { module Pass { // PassSupport.h and PassAnalysisSupport.h are made available only through // Pass.h. header "Pass.h" header "PassSupport.h" header "PassAnalysisSupport.h" export * } module PassRegistry { header "PassRegistry.h" export * } module InitializePasses { header "InitializePasses.h" export * } } module LLVM_intrinsic_gen { requires cplusplus // Delay building the modules containing dependencies to Attributes.h and // Intrinsics.h because they need to be generated by tablegen first. // Attributes.h module IR_Argument { header "IR/Argument.h" export * } module IR_Attributes { header "IR/Attributes.h" extern module LLVM_Extern_IR_Attributes_Gen "module.extern.modulemap" export * } module IR_CallSite { header "IR/CallSite.h" export * } module IR_ConstantFolder { header "IR/ConstantFolder.h" export * } module IR_GlobalVariable { header "IR/GlobalVariable.h" export * } module IR_NoFolder { header "IR/NoFolder.h" export * } module IR_Module { header "IR/Module.h" export * } module IR_ModuleSummaryIndex { header "IR/ModuleSummaryIndex.h" export * } module IR_ModuleSummaryIndexYAML { header "IR/ModuleSummaryIndexYAML.h" export * } module IR_Function { header "IR/Function.h" export * } module IR_InstrTypes { header "IR/InstrTypes.h" export * } module IR_Instructions { header "IR/Instructions.h" export * } // Intrinsics.h module IR_CFG { header "IR/CFG.h" export * } module IR_CFGDiff { header "IR/CFGDiff.h" export * } module IR_ConstantRange { header "IR/ConstantRange.h" export * } module IR_Dominators { header "IR/Dominators.h" export * } module Analysis_PostDominators { header "Analysis/PostDominators.h" export * } module Analysis_DomTreeUpdater { header "Analysis/DomTreeUpdater.h" export * } module IR_IRBuilder { header "IR/IRBuilder.h" export * } module IR_PassManager { header "IR/PassManager.h" export * } module IR_PredIteratorCache { header "IR/PredIteratorCache.h" export * } module IR_Verifier { header "IR/Verifier.h" export * } module IR_InstIterator { header "IR/InstIterator.h" export * } module IR_InstVisitor { header "IR/InstVisitor.h" export * } module IR_Intrinsics { header "IR/Intrinsics.h" extern module LLVM_Extern_IR_Intricsics_Gen "module.extern.modulemap" extern module LLVM_Extern_IR_Intrinsics_Enum "module.extern.modulemap" export * } module IR_IntrinsicInst { header "IR/IntrinsicInst.h" export * } module IR_PatternMatch { header "IR/PatternMatch.h" export * } module IR_SafepointIRVerifier { header "IR/SafepointIRVerifier.h" export * } module IR_Statepoint { header "IR/Statepoint.h" export * } export * } module LLVM_IR { requires cplusplus umbrella "IR" module * { export * } // These are intended for (repeated) textual inclusion. textual header "IR/ConstrainedOps.def" textual header "IR/DebugInfoFlags.def" textual header "IR/Instruction.def" textual header "IR/Metadata.def" textual header "IR/FixedMetadataKinds.def" textual header "IR/Value.def" textual header "IR/RuntimeLibcalls.def" } module LLVM_IRReader { requires cplusplus umbrella "IRReader" module * { export * } } module LLVM_LineEditor { requires cplusplus umbrella "LineEditor" module * { export * } } module LLVM_LTO { requires cplusplus umbrella "LTO" module * { export * } } module LLVM_MC { requires cplusplus umbrella "MC" module * { export * } textual header "MC/MCTargetOptionsCommandFlags.inc" } // Used by llvm-tblgen module LLVM_MC_TableGen { requires cplusplus module MC_LaneBitmask { header "MC/LaneBitmask.h" export * } module MC_FixedLenDisassembler { header "MC/MCFixedLenDisassembler.h" export * } module MC_InstrItineraries { header "MC/MCInstrItineraries.h" export * } module MC_Schedule { header "MC/MCSchedule.h" export * } module MC_SubtargetFeature { header "MC/SubtargetFeature.h" export * } } module LLVM_Object { requires cplusplus umbrella "Object" module * { export * } } module LLVM_Option { requires cplusplus umbrella "Option" module * { export * } } module LLVM_ProfileData { requires cplusplus umbrella "ProfileData" module * { export * } textual header "ProfileData/InstrProfData.inc" } // FIXME: Mislayered? module LLVM_Support_TargetRegistry { requires cplusplus header "Support/TargetRegistry.h" export * } module LLVM_TableGen { requires cplusplus umbrella "TableGen" module * { export * } } module LLVM_Transforms { requires cplusplus umbrella "Transforms" module * { export * } } extern module LLVM_Extern_Utils_DataTypes "module.extern.modulemap" // A module covering ADT/ and Support/. These are intertwined and // codependent, and notionally form a single module. module LLVM_Utils { module ADT { requires cplusplus umbrella "ADT" module * { export * } } module Support { requires cplusplus umbrella "Support" module * { export * } + + // Exclude this; it should only be used on Windows. + exclude header "Support/Windows/WindowsSupport.h" // Exclude these; they are fundamentally non-modular. exclude header "Support/PluginLoader.h" exclude header "Support/Solaris/sys/regset.h" // These are intended for textual inclusion. textual header "Support/ARMTargetParser.def" textual header "Support/AArch64TargetParser.def" textual header "Support/TargetOpcodes.def" textual header "Support/X86TargetParser.def" } // This part of the module is usable from both C and C++ code. module ConvertUTF { header "Support/ConvertUTF.h" export * } } // This is used for a $src == $build compilation. Otherwise we use // LLVM_Support_DataTypes_Build, defined in a module map that is // copied into the build area. module LLVM_Support_DataTypes_Src { header "llvm/Support/DataTypes.h" export * } module LLVM_WindowsManifest { requires cplusplus umbrella "WindowsManifest" module * { export * } } diff --git a/contrib/llvm-project/llvm/lib/Analysis/TargetLibraryInfo.cpp b/contrib/llvm-project/llvm/lib/Analysis/TargetLibraryInfo.cpp index c7238db43aab..1a32adf4723a 100644 --- a/contrib/llvm-project/llvm/lib/Analysis/TargetLibraryInfo.cpp +++ b/contrib/llvm-project/llvm/lib/Analysis/TargetLibraryInfo.cpp @@ -1,1643 +1,1646 @@ //===-- TargetLibraryInfo.cpp - Runtime library information ----------------==// // // 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 TargetLibraryInfo class. // //===----------------------------------------------------------------------===// #include "llvm/Analysis/TargetLibraryInfo.h" #include "llvm/ADT/Triple.h" #include "llvm/IR/Constants.h" #include "llvm/InitializePasses.h" #include "llvm/Support/CommandLine.h" using namespace llvm; static cl::opt ClVectorLibrary( "vector-library", cl::Hidden, cl::desc("Vector functions library"), cl::init(TargetLibraryInfoImpl::NoLibrary), cl::values(clEnumValN(TargetLibraryInfoImpl::NoLibrary, "none", "No vector functions library"), clEnumValN(TargetLibraryInfoImpl::Accelerate, "Accelerate", "Accelerate framework"), clEnumValN(TargetLibraryInfoImpl::MASSV, "MASSV", "IBM MASS vector library"), clEnumValN(TargetLibraryInfoImpl::SVML, "SVML", "Intel SVML library"))); StringLiteral const TargetLibraryInfoImpl::StandardNames[LibFunc::NumLibFuncs] = { #define TLI_DEFINE_STRING #include "llvm/Analysis/TargetLibraryInfo.def" }; static bool hasSinCosPiStret(const Triple &T) { // Only Darwin variants have _stret versions of combined trig functions. if (!T.isOSDarwin()) return false; // The ABI is rather complicated on x86, so don't do anything special there. if (T.getArch() == Triple::x86) return false; if (T.isMacOSX() && T.isMacOSXVersionLT(10, 9)) return false; if (T.isiOS() && T.isOSVersionLT(7, 0)) return false; return true; } static bool hasBcmp(const Triple &TT) { // Posix removed support from bcmp() in 2001, but the glibc and several // implementations of the libc still have it. if (TT.isOSLinux()) return TT.isGNUEnvironment() || TT.isMusl(); // Both NetBSD and OpenBSD are planning to remove the function. Windows does // not have it. return TT.isOSFreeBSD() || TT.isOSSolaris(); } /// Initialize the set of available library functions based on the specified /// target triple. This should be carefully written so that a missing target /// triple gets a sane set of defaults. static void initialize(TargetLibraryInfoImpl &TLI, const Triple &T, ArrayRef StandardNames) { // Verify that the StandardNames array is in alphabetical order. assert(std::is_sorted(StandardNames.begin(), StandardNames.end(), [](StringRef LHS, StringRef RHS) { return LHS < RHS; }) && "TargetLibraryInfoImpl function names must be sorted"); // Set IO unlocked variants as unavailable // Set them as available per system below TLI.setUnavailable(LibFunc_getchar_unlocked); TLI.setUnavailable(LibFunc_putc_unlocked); TLI.setUnavailable(LibFunc_putchar_unlocked); TLI.setUnavailable(LibFunc_fputc_unlocked); TLI.setUnavailable(LibFunc_fgetc_unlocked); TLI.setUnavailable(LibFunc_fread_unlocked); TLI.setUnavailable(LibFunc_fwrite_unlocked); TLI.setUnavailable(LibFunc_fputs_unlocked); TLI.setUnavailable(LibFunc_fgets_unlocked); bool ShouldExtI32Param = false, ShouldExtI32Return = false, ShouldSignExtI32Param = false; // PowerPC64, Sparc64, SystemZ need signext/zeroext on i32 parameters and // returns corresponding to C-level ints and unsigned ints. if (T.isPPC64() || T.getArch() == Triple::sparcv9 || T.getArch() == Triple::systemz) { ShouldExtI32Param = true; ShouldExtI32Return = true; } // Mips, on the other hand, needs signext on i32 parameters corresponding // to both signed and unsigned ints. if (T.isMIPS()) { ShouldSignExtI32Param = true; } TLI.setShouldExtI32Param(ShouldExtI32Param); TLI.setShouldExtI32Return(ShouldExtI32Return); TLI.setShouldSignExtI32Param(ShouldSignExtI32Param); if (T.getArch() == Triple::r600 || T.getArch() == Triple::amdgcn) TLI.disableAllFunctions(); // There are no library implementations of memcpy and memset for AMD gpus and // these can be difficult to lower in the backend. if (T.getArch() == Triple::r600 || T.getArch() == Triple::amdgcn) { TLI.setUnavailable(LibFunc_memcpy); TLI.setUnavailable(LibFunc_memset); TLI.setUnavailable(LibFunc_memset_pattern16); return; } // memset_pattern16 is only available on iOS 3.0 and Mac OS X 10.5 and later. // All versions of watchOS support it. if (T.isMacOSX()) { // available IO unlocked variants on Mac OS X TLI.setAvailable(LibFunc_getc_unlocked); TLI.setAvailable(LibFunc_getchar_unlocked); TLI.setAvailable(LibFunc_putc_unlocked); TLI.setAvailable(LibFunc_putchar_unlocked); if (T.isMacOSXVersionLT(10, 5)) TLI.setUnavailable(LibFunc_memset_pattern16); } else if (T.isiOS()) { if (T.isOSVersionLT(3, 0)) TLI.setUnavailable(LibFunc_memset_pattern16); } else if (!T.isWatchOS()) { TLI.setUnavailable(LibFunc_memset_pattern16); } if (!hasSinCosPiStret(T)) { TLI.setUnavailable(LibFunc_sinpi); TLI.setUnavailable(LibFunc_sinpif); TLI.setUnavailable(LibFunc_cospi); TLI.setUnavailable(LibFunc_cospif); TLI.setUnavailable(LibFunc_sincospi_stret); TLI.setUnavailable(LibFunc_sincospif_stret); } if (!hasBcmp(T)) TLI.setUnavailable(LibFunc_bcmp); if (T.isMacOSX() && T.getArch() == Triple::x86 && !T.isMacOSXVersionLT(10, 7)) { // x86-32 OSX has a scheme where fwrite and fputs (and some other functions // we don't care about) have two versions; on recent OSX, the one we want // has a $UNIX2003 suffix. The two implementations are identical except // for the return value in some edge cases. However, we don't want to // generate code that depends on the old symbols. TLI.setAvailableWithName(LibFunc_fwrite, "fwrite$UNIX2003"); TLI.setAvailableWithName(LibFunc_fputs, "fputs$UNIX2003"); } // iprintf and friends are only available on XCore, TCE, and Emscripten. if (T.getArch() != Triple::xcore && T.getArch() != Triple::tce && T.getOS() != Triple::Emscripten) { TLI.setUnavailable(LibFunc_iprintf); TLI.setUnavailable(LibFunc_siprintf); TLI.setUnavailable(LibFunc_fiprintf); } // __small_printf and friends are only available on Emscripten. if (T.getOS() != Triple::Emscripten) { TLI.setUnavailable(LibFunc_small_printf); TLI.setUnavailable(LibFunc_small_sprintf); TLI.setUnavailable(LibFunc_small_fprintf); } if (T.isOSWindows() && !T.isOSCygMing()) { // XXX: The earliest documentation available at the moment is for VS2015/VC19: // https://docs.microsoft.com/en-us/cpp/c-runtime-library/floating-point-support?view=vs-2015 // XXX: In order to use an MSVCRT older than VC19, // the specific library version must be explicit in the target triple, // e.g., x86_64-pc-windows-msvc18. bool hasPartialC99 = true; if (T.isKnownWindowsMSVCEnvironment()) { unsigned Major, Minor, Micro; T.getEnvironmentVersion(Major, Minor, Micro); hasPartialC99 = (Major == 0 || Major >= 19); } // Latest targets support C89 math functions, in part. bool isARM = (T.getArch() == Triple::aarch64 || T.getArch() == Triple::arm); bool hasPartialFloat = (isARM || T.getArch() == Triple::x86_64); // Win32 does not support float C89 math functions, in general. if (!hasPartialFloat) { TLI.setUnavailable(LibFunc_acosf); TLI.setUnavailable(LibFunc_asinf); TLI.setUnavailable(LibFunc_atan2f); TLI.setUnavailable(LibFunc_atanf); TLI.setUnavailable(LibFunc_ceilf); TLI.setUnavailable(LibFunc_cosf); TLI.setUnavailable(LibFunc_coshf); TLI.setUnavailable(LibFunc_expf); TLI.setUnavailable(LibFunc_floorf); TLI.setUnavailable(LibFunc_fmodf); TLI.setUnavailable(LibFunc_log10f); TLI.setUnavailable(LibFunc_logf); TLI.setUnavailable(LibFunc_modff); TLI.setUnavailable(LibFunc_powf); TLI.setUnavailable(LibFunc_sinf); TLI.setUnavailable(LibFunc_sinhf); TLI.setUnavailable(LibFunc_sqrtf); TLI.setUnavailable(LibFunc_tanf); TLI.setUnavailable(LibFunc_tanhf); } if (!isARM) TLI.setUnavailable(LibFunc_fabsf); TLI.setUnavailable(LibFunc_frexpf); TLI.setUnavailable(LibFunc_ldexpf); // Win32 does not support long double C89 math functions. TLI.setUnavailable(LibFunc_acosl); TLI.setUnavailable(LibFunc_asinl); TLI.setUnavailable(LibFunc_atan2l); TLI.setUnavailable(LibFunc_atanl); TLI.setUnavailable(LibFunc_ceill); TLI.setUnavailable(LibFunc_cosl); TLI.setUnavailable(LibFunc_coshl); TLI.setUnavailable(LibFunc_expl); TLI.setUnavailable(LibFunc_fabsl); TLI.setUnavailable(LibFunc_floorl); TLI.setUnavailable(LibFunc_fmodl); TLI.setUnavailable(LibFunc_frexpl); TLI.setUnavailable(LibFunc_ldexpl); TLI.setUnavailable(LibFunc_log10l); TLI.setUnavailable(LibFunc_logl); TLI.setUnavailable(LibFunc_modfl); TLI.setUnavailable(LibFunc_powl); TLI.setUnavailable(LibFunc_sinl); TLI.setUnavailable(LibFunc_sinhl); TLI.setUnavailable(LibFunc_sqrtl); TLI.setUnavailable(LibFunc_tanl); TLI.setUnavailable(LibFunc_tanhl); // Win32 does not fully support C99 math functions. if (!hasPartialC99) { TLI.setUnavailable(LibFunc_acosh); TLI.setUnavailable(LibFunc_acoshf); TLI.setUnavailable(LibFunc_asinh); TLI.setUnavailable(LibFunc_asinhf); TLI.setUnavailable(LibFunc_atanh); TLI.setUnavailable(LibFunc_atanhf); TLI.setAvailableWithName(LibFunc_cabs, "_cabs"); TLI.setUnavailable(LibFunc_cabsf); TLI.setUnavailable(LibFunc_cbrt); TLI.setUnavailable(LibFunc_cbrtf); TLI.setAvailableWithName(LibFunc_copysign, "_copysign"); TLI.setAvailableWithName(LibFunc_copysignf, "_copysignf"); TLI.setUnavailable(LibFunc_exp2); TLI.setUnavailable(LibFunc_exp2f); TLI.setUnavailable(LibFunc_expm1); TLI.setUnavailable(LibFunc_expm1f); TLI.setUnavailable(LibFunc_fmax); TLI.setUnavailable(LibFunc_fmaxf); TLI.setUnavailable(LibFunc_fmin); TLI.setUnavailable(LibFunc_fminf); TLI.setUnavailable(LibFunc_log1p); TLI.setUnavailable(LibFunc_log1pf); TLI.setUnavailable(LibFunc_log2); TLI.setUnavailable(LibFunc_log2f); TLI.setAvailableWithName(LibFunc_logb, "_logb"); if (hasPartialFloat) TLI.setAvailableWithName(LibFunc_logbf, "_logbf"); else TLI.setUnavailable(LibFunc_logbf); TLI.setUnavailable(LibFunc_rint); TLI.setUnavailable(LibFunc_rintf); TLI.setUnavailable(LibFunc_round); TLI.setUnavailable(LibFunc_roundf); TLI.setUnavailable(LibFunc_trunc); TLI.setUnavailable(LibFunc_truncf); } // Win32 does not support long double C99 math functions. TLI.setUnavailable(LibFunc_acoshl); TLI.setUnavailable(LibFunc_asinhl); TLI.setUnavailable(LibFunc_atanhl); TLI.setUnavailable(LibFunc_cabsl); TLI.setUnavailable(LibFunc_cbrtl); TLI.setUnavailable(LibFunc_copysignl); TLI.setUnavailable(LibFunc_exp2l); TLI.setUnavailable(LibFunc_expm1l); TLI.setUnavailable(LibFunc_fmaxl); TLI.setUnavailable(LibFunc_fminl); TLI.setUnavailable(LibFunc_log1pl); TLI.setUnavailable(LibFunc_log2l); TLI.setUnavailable(LibFunc_logbl); TLI.setUnavailable(LibFunc_nearbyintl); TLI.setUnavailable(LibFunc_rintl); TLI.setUnavailable(LibFunc_roundl); TLI.setUnavailable(LibFunc_truncl); // Win32 does not support these functions, but // they are generally available on POSIX-compliant systems. TLI.setUnavailable(LibFunc_access); TLI.setUnavailable(LibFunc_bcmp); TLI.setUnavailable(LibFunc_bcopy); TLI.setUnavailable(LibFunc_bzero); TLI.setUnavailable(LibFunc_chmod); TLI.setUnavailable(LibFunc_chown); TLI.setUnavailable(LibFunc_closedir); TLI.setUnavailable(LibFunc_ctermid); TLI.setUnavailable(LibFunc_fdopen); TLI.setUnavailable(LibFunc_ffs); TLI.setUnavailable(LibFunc_fileno); TLI.setUnavailable(LibFunc_flockfile); TLI.setUnavailable(LibFunc_fseeko); TLI.setUnavailable(LibFunc_fstat); TLI.setUnavailable(LibFunc_fstatvfs); TLI.setUnavailable(LibFunc_ftello); TLI.setUnavailable(LibFunc_ftrylockfile); TLI.setUnavailable(LibFunc_funlockfile); TLI.setUnavailable(LibFunc_getitimer); TLI.setUnavailable(LibFunc_getlogin_r); TLI.setUnavailable(LibFunc_getpwnam); TLI.setUnavailable(LibFunc_gettimeofday); TLI.setUnavailable(LibFunc_htonl); TLI.setUnavailable(LibFunc_htons); TLI.setUnavailable(LibFunc_lchown); TLI.setUnavailable(LibFunc_lstat); TLI.setUnavailable(LibFunc_memccpy); TLI.setUnavailable(LibFunc_mkdir); TLI.setUnavailable(LibFunc_ntohl); TLI.setUnavailable(LibFunc_ntohs); TLI.setUnavailable(LibFunc_open); TLI.setUnavailable(LibFunc_opendir); TLI.setUnavailable(LibFunc_pclose); TLI.setUnavailable(LibFunc_popen); TLI.setUnavailable(LibFunc_pread); TLI.setUnavailable(LibFunc_pwrite); TLI.setUnavailable(LibFunc_read); TLI.setUnavailable(LibFunc_readlink); TLI.setUnavailable(LibFunc_realpath); TLI.setUnavailable(LibFunc_rmdir); TLI.setUnavailable(LibFunc_setitimer); TLI.setUnavailable(LibFunc_stat); TLI.setUnavailable(LibFunc_statvfs); TLI.setUnavailable(LibFunc_stpcpy); TLI.setUnavailable(LibFunc_stpncpy); TLI.setUnavailable(LibFunc_strcasecmp); TLI.setUnavailable(LibFunc_strncasecmp); TLI.setUnavailable(LibFunc_times); TLI.setUnavailable(LibFunc_uname); TLI.setUnavailable(LibFunc_unlink); TLI.setUnavailable(LibFunc_unsetenv); TLI.setUnavailable(LibFunc_utime); TLI.setUnavailable(LibFunc_utimes); TLI.setUnavailable(LibFunc_write); } switch (T.getOS()) { case Triple::MacOSX: // exp10 and exp10f are not available on OS X until 10.9 and iOS until 7.0 // and their names are __exp10 and __exp10f. exp10l is not available on // OS X or iOS. TLI.setUnavailable(LibFunc_exp10l); if (T.isMacOSXVersionLT(10, 9)) { TLI.setUnavailable(LibFunc_exp10); TLI.setUnavailable(LibFunc_exp10f); } else { TLI.setAvailableWithName(LibFunc_exp10, "__exp10"); TLI.setAvailableWithName(LibFunc_exp10f, "__exp10f"); } break; case Triple::IOS: case Triple::TvOS: case Triple::WatchOS: TLI.setUnavailable(LibFunc_exp10l); if (!T.isWatchOS() && (T.isOSVersionLT(7, 0) || (T.isOSVersionLT(9, 0) && T.isX86()))) { TLI.setUnavailable(LibFunc_exp10); TLI.setUnavailable(LibFunc_exp10f); } else { TLI.setAvailableWithName(LibFunc_exp10, "__exp10"); TLI.setAvailableWithName(LibFunc_exp10f, "__exp10f"); } break; case Triple::Linux: // exp10, exp10f, exp10l is available on Linux (GLIBC) but are extremely // buggy prior to glibc version 2.18. Until this version is widely deployed // or we have a reasonable detection strategy, we cannot use exp10 reliably // on Linux. // // Fall through to disable all of them. LLVM_FALLTHROUGH; default: TLI.setUnavailable(LibFunc_exp10); TLI.setUnavailable(LibFunc_exp10f); TLI.setUnavailable(LibFunc_exp10l); } // ffsl is available on at least Darwin, Mac OS X, iOS, FreeBSD, and // Linux (GLIBC): // http://developer.apple.com/library/mac/#documentation/Darwin/Reference/ManPages/man3/ffsl.3.html // http://svn.freebsd.org/base/head/lib/libc/string/ffsl.c // http://www.gnu.org/software/gnulib/manual/html_node/ffsl.html switch (T.getOS()) { case Triple::Darwin: case Triple::MacOSX: case Triple::IOS: case Triple::TvOS: case Triple::WatchOS: case Triple::FreeBSD: case Triple::Linux: break; default: TLI.setUnavailable(LibFunc_ffsl); } // ffsll is available on at least FreeBSD and Linux (GLIBC): // http://svn.freebsd.org/base/head/lib/libc/string/ffsll.c // http://www.gnu.org/software/gnulib/manual/html_node/ffsll.html switch (T.getOS()) { case Triple::Darwin: case Triple::MacOSX: case Triple::IOS: case Triple::TvOS: case Triple::WatchOS: case Triple::FreeBSD: case Triple::Linux: break; default: TLI.setUnavailable(LibFunc_ffsll); } // The following functions are available on at least FreeBSD: // http://svn.freebsd.org/base/head/lib/libc/string/fls.c // http://svn.freebsd.org/base/head/lib/libc/string/flsl.c // http://svn.freebsd.org/base/head/lib/libc/string/flsll.c if (!T.isOSFreeBSD()) { TLI.setUnavailable(LibFunc_fls); TLI.setUnavailable(LibFunc_flsl); TLI.setUnavailable(LibFunc_flsll); } // The following functions are only available on GNU/Linux (using glibc). // Linux variants without glibc (eg: bionic, musl) may have some subset. if (!T.isOSLinux() || !T.isGNUEnvironment()) { TLI.setUnavailable(LibFunc_dunder_strdup); TLI.setUnavailable(LibFunc_dunder_strtok_r); TLI.setUnavailable(LibFunc_dunder_isoc99_scanf); TLI.setUnavailable(LibFunc_dunder_isoc99_sscanf); TLI.setUnavailable(LibFunc_under_IO_getc); TLI.setUnavailable(LibFunc_under_IO_putc); // But, Android and musl have memalign. if (!T.isAndroid() && !T.isMusl()) TLI.setUnavailable(LibFunc_memalign); TLI.setUnavailable(LibFunc_fopen64); TLI.setUnavailable(LibFunc_fseeko64); TLI.setUnavailable(LibFunc_fstat64); TLI.setUnavailable(LibFunc_fstatvfs64); TLI.setUnavailable(LibFunc_ftello64); TLI.setUnavailable(LibFunc_lstat64); TLI.setUnavailable(LibFunc_open64); TLI.setUnavailable(LibFunc_stat64); TLI.setUnavailable(LibFunc_statvfs64); TLI.setUnavailable(LibFunc_tmpfile64); // Relaxed math functions are included in math-finite.h on Linux (GLIBC). + // Note that math-finite.h is no longer supported by top-of-tree GLIBC, + // so we keep these functions around just so that they're recognized by + // the ConstantFolder. TLI.setUnavailable(LibFunc_acos_finite); TLI.setUnavailable(LibFunc_acosf_finite); TLI.setUnavailable(LibFunc_acosl_finite); TLI.setUnavailable(LibFunc_acosh_finite); TLI.setUnavailable(LibFunc_acoshf_finite); TLI.setUnavailable(LibFunc_acoshl_finite); TLI.setUnavailable(LibFunc_asin_finite); TLI.setUnavailable(LibFunc_asinf_finite); TLI.setUnavailable(LibFunc_asinl_finite); TLI.setUnavailable(LibFunc_atan2_finite); TLI.setUnavailable(LibFunc_atan2f_finite); TLI.setUnavailable(LibFunc_atan2l_finite); TLI.setUnavailable(LibFunc_atanh_finite); TLI.setUnavailable(LibFunc_atanhf_finite); TLI.setUnavailable(LibFunc_atanhl_finite); TLI.setUnavailable(LibFunc_cosh_finite); TLI.setUnavailable(LibFunc_coshf_finite); TLI.setUnavailable(LibFunc_coshl_finite); TLI.setUnavailable(LibFunc_exp10_finite); TLI.setUnavailable(LibFunc_exp10f_finite); TLI.setUnavailable(LibFunc_exp10l_finite); TLI.setUnavailable(LibFunc_exp2_finite); TLI.setUnavailable(LibFunc_exp2f_finite); TLI.setUnavailable(LibFunc_exp2l_finite); TLI.setUnavailable(LibFunc_exp_finite); TLI.setUnavailable(LibFunc_expf_finite); TLI.setUnavailable(LibFunc_expl_finite); TLI.setUnavailable(LibFunc_log10_finite); TLI.setUnavailable(LibFunc_log10f_finite); TLI.setUnavailable(LibFunc_log10l_finite); TLI.setUnavailable(LibFunc_log2_finite); TLI.setUnavailable(LibFunc_log2f_finite); TLI.setUnavailable(LibFunc_log2l_finite); TLI.setUnavailable(LibFunc_log_finite); TLI.setUnavailable(LibFunc_logf_finite); TLI.setUnavailable(LibFunc_logl_finite); TLI.setUnavailable(LibFunc_pow_finite); TLI.setUnavailable(LibFunc_powf_finite); TLI.setUnavailable(LibFunc_powl_finite); TLI.setUnavailable(LibFunc_sinh_finite); TLI.setUnavailable(LibFunc_sinhf_finite); TLI.setUnavailable(LibFunc_sinhl_finite); } if ((T.isOSLinux() && T.isGNUEnvironment()) || (T.isAndroid() && !T.isAndroidVersionLT(28))) { // available IO unlocked variants on GNU/Linux and Android P or later TLI.setAvailable(LibFunc_getc_unlocked); TLI.setAvailable(LibFunc_getchar_unlocked); TLI.setAvailable(LibFunc_putc_unlocked); TLI.setAvailable(LibFunc_putchar_unlocked); TLI.setAvailable(LibFunc_fputc_unlocked); TLI.setAvailable(LibFunc_fgetc_unlocked); TLI.setAvailable(LibFunc_fread_unlocked); TLI.setAvailable(LibFunc_fwrite_unlocked); TLI.setAvailable(LibFunc_fputs_unlocked); TLI.setAvailable(LibFunc_fgets_unlocked); } // As currently implemented in clang, NVPTX code has no standard library to // speak of. Headers provide a standard-ish library implementation, but many // of the signatures are wrong -- for example, many libm functions are not // extern "C". // // libdevice, an IR library provided by nvidia, is linked in by the front-end, // but only used functions are provided to llvm. Moreover, most of the // functions in libdevice don't map precisely to standard library functions. // // FIXME: Having no standard library prevents e.g. many fastmath // optimizations, so this situation should be fixed. if (T.isNVPTX()) { TLI.disableAllFunctions(); TLI.setAvailable(LibFunc_nvvm_reflect); } else { TLI.setUnavailable(LibFunc_nvvm_reflect); } TLI.addVectorizableFunctionsFromVecLib(ClVectorLibrary); } TargetLibraryInfoImpl::TargetLibraryInfoImpl() { // Default to everything being available. memset(AvailableArray, -1, sizeof(AvailableArray)); initialize(*this, Triple(), StandardNames); } TargetLibraryInfoImpl::TargetLibraryInfoImpl(const Triple &T) { // Default to everything being available. memset(AvailableArray, -1, sizeof(AvailableArray)); initialize(*this, T, StandardNames); } TargetLibraryInfoImpl::TargetLibraryInfoImpl(const TargetLibraryInfoImpl &TLI) : CustomNames(TLI.CustomNames), ShouldExtI32Param(TLI.ShouldExtI32Param), ShouldExtI32Return(TLI.ShouldExtI32Return), ShouldSignExtI32Param(TLI.ShouldSignExtI32Param) { memcpy(AvailableArray, TLI.AvailableArray, sizeof(AvailableArray)); VectorDescs = TLI.VectorDescs; ScalarDescs = TLI.ScalarDescs; } TargetLibraryInfoImpl::TargetLibraryInfoImpl(TargetLibraryInfoImpl &&TLI) : CustomNames(std::move(TLI.CustomNames)), ShouldExtI32Param(TLI.ShouldExtI32Param), ShouldExtI32Return(TLI.ShouldExtI32Return), ShouldSignExtI32Param(TLI.ShouldSignExtI32Param) { std::move(std::begin(TLI.AvailableArray), std::end(TLI.AvailableArray), AvailableArray); VectorDescs = TLI.VectorDescs; ScalarDescs = TLI.ScalarDescs; } TargetLibraryInfoImpl &TargetLibraryInfoImpl::operator=(const TargetLibraryInfoImpl &TLI) { CustomNames = TLI.CustomNames; ShouldExtI32Param = TLI.ShouldExtI32Param; ShouldExtI32Return = TLI.ShouldExtI32Return; ShouldSignExtI32Param = TLI.ShouldSignExtI32Param; memcpy(AvailableArray, TLI.AvailableArray, sizeof(AvailableArray)); return *this; } TargetLibraryInfoImpl &TargetLibraryInfoImpl::operator=(TargetLibraryInfoImpl &&TLI) { CustomNames = std::move(TLI.CustomNames); ShouldExtI32Param = TLI.ShouldExtI32Param; ShouldExtI32Return = TLI.ShouldExtI32Return; ShouldSignExtI32Param = TLI.ShouldSignExtI32Param; std::move(std::begin(TLI.AvailableArray), std::end(TLI.AvailableArray), AvailableArray); return *this; } static StringRef sanitizeFunctionName(StringRef funcName) { // Filter out empty names and names containing null bytes, those can't be in // our table. if (funcName.empty() || funcName.find('\0') != StringRef::npos) return StringRef(); // Check for \01 prefix that is used to mangle __asm declarations and // strip it if present. return GlobalValue::dropLLVMManglingEscape(funcName); } bool TargetLibraryInfoImpl::getLibFunc(StringRef funcName, LibFunc &F) const { funcName = sanitizeFunctionName(funcName); if (funcName.empty()) return false; const auto *Start = std::begin(StandardNames); const auto *End = std::end(StandardNames); const auto *I = std::lower_bound(Start, End, funcName); if (I != End && *I == funcName) { F = (LibFunc)(I - Start); return true; } return false; } bool TargetLibraryInfoImpl::isValidProtoForLibFunc(const FunctionType &FTy, LibFunc F, const DataLayout *DL) const { LLVMContext &Ctx = FTy.getContext(); Type *PCharTy = Type::getInt8PtrTy(Ctx); Type *SizeTTy = DL ? DL->getIntPtrType(Ctx, /*AS=*/0) : nullptr; auto IsSizeTTy = [SizeTTy](Type *Ty) { return SizeTTy ? Ty == SizeTTy : Ty->isIntegerTy(); }; unsigned NumParams = FTy.getNumParams(); switch (F) { case LibFunc_execl: case LibFunc_execlp: case LibFunc_execle: return (NumParams >= 2 && FTy.getParamType(0)->isPointerTy() && FTy.getParamType(1)->isPointerTy() && FTy.getReturnType()->isIntegerTy(32)); case LibFunc_execv: case LibFunc_execvp: return (NumParams == 2 && FTy.getParamType(0)->isPointerTy() && FTy.getParamType(1)->isPointerTy() && FTy.getReturnType()->isIntegerTy(32)); case LibFunc_execvP: case LibFunc_execvpe: case LibFunc_execve: return (NumParams == 3 && FTy.getParamType(0)->isPointerTy() && FTy.getParamType(1)->isPointerTy() && FTy.getParamType(2)->isPointerTy() && FTy.getReturnType()->isIntegerTy(32)); case LibFunc_strlen: return (NumParams == 1 && FTy.getParamType(0)->isPointerTy() && FTy.getReturnType()->isIntegerTy()); case LibFunc_strchr: case LibFunc_strrchr: return (NumParams == 2 && FTy.getReturnType()->isPointerTy() && FTy.getParamType(0) == FTy.getReturnType() && FTy.getParamType(1)->isIntegerTy()); case LibFunc_strtol: case LibFunc_strtod: case LibFunc_strtof: case LibFunc_strtoul: case LibFunc_strtoll: case LibFunc_strtold: case LibFunc_strtoull: return ((NumParams == 2 || NumParams == 3) && FTy.getParamType(0)->isPointerTy() && FTy.getParamType(1)->isPointerTy()); case LibFunc_strcat_chk: --NumParams; if (!IsSizeTTy(FTy.getParamType(NumParams))) return false; LLVM_FALLTHROUGH; case LibFunc_strcat: return (NumParams == 2 && FTy.getReturnType()->isPointerTy() && FTy.getParamType(0) == FTy.getReturnType() && FTy.getParamType(1) == FTy.getReturnType()); case LibFunc_strncat_chk: --NumParams; if (!IsSizeTTy(FTy.getParamType(NumParams))) return false; LLVM_FALLTHROUGH; case LibFunc_strncat: return (NumParams == 3 && FTy.getReturnType()->isPointerTy() && FTy.getParamType(0) == FTy.getReturnType() && FTy.getParamType(1) == FTy.getReturnType() && IsSizeTTy(FTy.getParamType(2))); case LibFunc_strcpy_chk: case LibFunc_stpcpy_chk: --NumParams; if (!IsSizeTTy(FTy.getParamType(NumParams))) return false; LLVM_FALLTHROUGH; case LibFunc_strcpy: case LibFunc_stpcpy: return (NumParams == 2 && FTy.getReturnType() == FTy.getParamType(0) && FTy.getParamType(0) == FTy.getParamType(1) && FTy.getParamType(0) == PCharTy); case LibFunc_strlcat_chk: case LibFunc_strlcpy_chk: --NumParams; if (!IsSizeTTy(FTy.getParamType(NumParams))) return false; LLVM_FALLTHROUGH; case LibFunc_strlcat: case LibFunc_strlcpy: return NumParams == 3 && IsSizeTTy(FTy.getReturnType()) && FTy.getParamType(0)->isPointerTy() && FTy.getParamType(1)->isPointerTy() && IsSizeTTy(FTy.getParamType(2)); case LibFunc_strncpy_chk: case LibFunc_stpncpy_chk: --NumParams; if (!IsSizeTTy(FTy.getParamType(NumParams))) return false; LLVM_FALLTHROUGH; case LibFunc_strncpy: case LibFunc_stpncpy: return (NumParams == 3 && FTy.getReturnType() == FTy.getParamType(0) && FTy.getParamType(0) == FTy.getParamType(1) && FTy.getParamType(0) == PCharTy && IsSizeTTy(FTy.getParamType(2))); case LibFunc_strxfrm: return (NumParams == 3 && FTy.getParamType(0)->isPointerTy() && FTy.getParamType(1)->isPointerTy()); case LibFunc_strcmp: return (NumParams == 2 && FTy.getReturnType()->isIntegerTy(32) && FTy.getParamType(0)->isPointerTy() && FTy.getParamType(0) == FTy.getParamType(1)); case LibFunc_strncmp: return (NumParams == 3 && FTy.getReturnType()->isIntegerTy(32) && FTy.getParamType(0)->isPointerTy() && FTy.getParamType(0) == FTy.getParamType(1) && IsSizeTTy(FTy.getParamType(2))); case LibFunc_strspn: case LibFunc_strcspn: return (NumParams == 2 && FTy.getParamType(0)->isPointerTy() && FTy.getParamType(0) == FTy.getParamType(1) && FTy.getReturnType()->isIntegerTy()); case LibFunc_strcoll: case LibFunc_strcasecmp: case LibFunc_strncasecmp: return (NumParams >= 2 && FTy.getParamType(0)->isPointerTy() && FTy.getParamType(1)->isPointerTy()); case LibFunc_strstr: return (NumParams == 2 && FTy.getReturnType()->isPointerTy() && FTy.getParamType(0)->isPointerTy() && FTy.getParamType(1)->isPointerTy()); case LibFunc_strpbrk: return (NumParams == 2 && FTy.getParamType(0)->isPointerTy() && FTy.getReturnType() == FTy.getParamType(0) && FTy.getParamType(0) == FTy.getParamType(1)); case LibFunc_strtok: case LibFunc_strtok_r: return (NumParams >= 2 && FTy.getParamType(1)->isPointerTy()); case LibFunc_scanf: case LibFunc_setbuf: case LibFunc_setvbuf: return (NumParams >= 1 && FTy.getParamType(0)->isPointerTy()); case LibFunc_strdup: case LibFunc_strndup: return (NumParams >= 1 && FTy.getReturnType()->isPointerTy() && FTy.getParamType(0)->isPointerTy()); case LibFunc_sscanf: case LibFunc_stat: case LibFunc_statvfs: case LibFunc_siprintf: case LibFunc_small_sprintf: case LibFunc_sprintf: return (NumParams >= 2 && FTy.getParamType(0)->isPointerTy() && FTy.getParamType(1)->isPointerTy() && FTy.getReturnType()->isIntegerTy(32)); case LibFunc_sprintf_chk: return NumParams == 4 && FTy.getParamType(0)->isPointerTy() && FTy.getParamType(1)->isIntegerTy(32) && IsSizeTTy(FTy.getParamType(2)) && FTy.getParamType(3)->isPointerTy() && FTy.getReturnType()->isIntegerTy(32); case LibFunc_snprintf: return (NumParams == 3 && FTy.getParamType(0)->isPointerTy() && FTy.getParamType(2)->isPointerTy() && FTy.getReturnType()->isIntegerTy(32)); case LibFunc_snprintf_chk: return NumParams == 5 && FTy.getParamType(0)->isPointerTy() && IsSizeTTy(FTy.getParamType(1)) && FTy.getParamType(2)->isIntegerTy(32) && IsSizeTTy(FTy.getParamType(3)) && FTy.getParamType(4)->isPointerTy() && FTy.getReturnType()->isIntegerTy(32); case LibFunc_setitimer: return (NumParams == 3 && FTy.getParamType(1)->isPointerTy() && FTy.getParamType(2)->isPointerTy()); case LibFunc_system: return (NumParams == 1 && FTy.getParamType(0)->isPointerTy()); case LibFunc_malloc: return (NumParams == 1 && FTy.getReturnType()->isPointerTy()); case LibFunc_memcmp: return (NumParams == 3 && FTy.getReturnType()->isIntegerTy(32) && FTy.getParamType(0)->isPointerTy() && FTy.getParamType(1)->isPointerTy()); case LibFunc_memchr: case LibFunc_memrchr: return (NumParams == 3 && FTy.getReturnType()->isPointerTy() && FTy.getReturnType() == FTy.getParamType(0) && FTy.getParamType(1)->isIntegerTy(32) && IsSizeTTy(FTy.getParamType(2))); case LibFunc_modf: case LibFunc_modff: case LibFunc_modfl: return (NumParams >= 2 && FTy.getParamType(1)->isPointerTy()); case LibFunc_memcpy_chk: case LibFunc_memmove_chk: --NumParams; if (!IsSizeTTy(FTy.getParamType(NumParams))) return false; LLVM_FALLTHROUGH; case LibFunc_memcpy: case LibFunc_mempcpy: case LibFunc_memmove: return (NumParams == 3 && FTy.getReturnType() == FTy.getParamType(0) && FTy.getParamType(0)->isPointerTy() && FTy.getParamType(1)->isPointerTy() && IsSizeTTy(FTy.getParamType(2))); case LibFunc_memset_chk: --NumParams; if (!IsSizeTTy(FTy.getParamType(NumParams))) return false; LLVM_FALLTHROUGH; case LibFunc_memset: return (NumParams == 3 && FTy.getReturnType() == FTy.getParamType(0) && FTy.getParamType(0)->isPointerTy() && FTy.getParamType(1)->isIntegerTy() && IsSizeTTy(FTy.getParamType(2))); case LibFunc_memccpy_chk: --NumParams; if (!IsSizeTTy(FTy.getParamType(NumParams))) return false; LLVM_FALLTHROUGH; case LibFunc_memccpy: return (NumParams >= 2 && FTy.getParamType(1)->isPointerTy()); case LibFunc_memalign: return (FTy.getReturnType()->isPointerTy()); case LibFunc_realloc: case LibFunc_reallocf: return (NumParams == 2 && FTy.getReturnType() == PCharTy && FTy.getParamType(0) == FTy.getReturnType() && IsSizeTTy(FTy.getParamType(1))); case LibFunc_read: return (NumParams == 3 && FTy.getParamType(1)->isPointerTy()); case LibFunc_rewind: case LibFunc_rmdir: case LibFunc_remove: case LibFunc_realpath: return (NumParams >= 1 && FTy.getParamType(0)->isPointerTy()); case LibFunc_rename: return (NumParams >= 2 && FTy.getParamType(0)->isPointerTy() && FTy.getParamType(1)->isPointerTy()); case LibFunc_readlink: return (NumParams >= 2 && FTy.getParamType(0)->isPointerTy() && FTy.getParamType(1)->isPointerTy()); case LibFunc_write: return (NumParams == 3 && FTy.getParamType(1)->isPointerTy()); case LibFunc_bcopy: case LibFunc_bcmp: return (NumParams == 3 && FTy.getParamType(0)->isPointerTy() && FTy.getParamType(1)->isPointerTy()); case LibFunc_bzero: return (NumParams == 2 && FTy.getParamType(0)->isPointerTy()); case LibFunc_calloc: return (NumParams == 2 && FTy.getReturnType()->isPointerTy()); case LibFunc_atof: case LibFunc_atoi: case LibFunc_atol: case LibFunc_atoll: case LibFunc_ferror: case LibFunc_getenv: case LibFunc_getpwnam: case LibFunc_iprintf: case LibFunc_small_printf: case LibFunc_pclose: case LibFunc_perror: case LibFunc_printf: case LibFunc_puts: case LibFunc_uname: case LibFunc_under_IO_getc: case LibFunc_unlink: case LibFunc_unsetenv: return (NumParams == 1 && FTy.getParamType(0)->isPointerTy()); case LibFunc_access: case LibFunc_chmod: case LibFunc_chown: case LibFunc_clearerr: case LibFunc_closedir: case LibFunc_ctermid: case LibFunc_fclose: case LibFunc_feof: case LibFunc_fflush: case LibFunc_fgetc: case LibFunc_fgetc_unlocked: case LibFunc_fileno: case LibFunc_flockfile: case LibFunc_free: case LibFunc_fseek: case LibFunc_fseeko64: case LibFunc_fseeko: case LibFunc_fsetpos: case LibFunc_ftell: case LibFunc_ftello64: case LibFunc_ftello: case LibFunc_ftrylockfile: case LibFunc_funlockfile: case LibFunc_getc: case LibFunc_getc_unlocked: case LibFunc_getlogin_r: case LibFunc_mkdir: case LibFunc_mktime: case LibFunc_times: return (NumParams != 0 && FTy.getParamType(0)->isPointerTy()); case LibFunc_fopen: return (NumParams == 2 && FTy.getReturnType()->isPointerTy() && FTy.getParamType(0)->isPointerTy() && FTy.getParamType(1)->isPointerTy()); case LibFunc_fork: return (NumParams == 0 && FTy.getReturnType()->isIntegerTy(32)); case LibFunc_fdopen: return (NumParams == 2 && FTy.getReturnType()->isPointerTy() && FTy.getParamType(1)->isPointerTy()); case LibFunc_fputc: case LibFunc_fputc_unlocked: case LibFunc_fstat: case LibFunc_frexp: case LibFunc_frexpf: case LibFunc_frexpl: case LibFunc_fstatvfs: return (NumParams == 2 && FTy.getParamType(1)->isPointerTy()); case LibFunc_fgets: case LibFunc_fgets_unlocked: return (NumParams == 3 && FTy.getParamType(0)->isPointerTy() && FTy.getParamType(2)->isPointerTy()); case LibFunc_fread: case LibFunc_fread_unlocked: return (NumParams == 4 && FTy.getParamType(0)->isPointerTy() && FTy.getParamType(3)->isPointerTy()); case LibFunc_fwrite: case LibFunc_fwrite_unlocked: return (NumParams == 4 && FTy.getReturnType()->isIntegerTy() && FTy.getParamType(0)->isPointerTy() && FTy.getParamType(1)->isIntegerTy() && FTy.getParamType(2)->isIntegerTy() && FTy.getParamType(3)->isPointerTy()); case LibFunc_fputs: case LibFunc_fputs_unlocked: return (NumParams >= 2 && FTy.getParamType(0)->isPointerTy() && FTy.getParamType(1)->isPointerTy()); case LibFunc_fscanf: case LibFunc_fiprintf: case LibFunc_small_fprintf: case LibFunc_fprintf: return (NumParams >= 2 && FTy.getReturnType()->isIntegerTy() && FTy.getParamType(0)->isPointerTy() && FTy.getParamType(1)->isPointerTy()); case LibFunc_fgetpos: return (NumParams >= 2 && FTy.getParamType(0)->isPointerTy() && FTy.getParamType(1)->isPointerTy()); case LibFunc_getchar: case LibFunc_getchar_unlocked: return (NumParams == 0 && FTy.getReturnType()->isIntegerTy()); case LibFunc_gets: return (NumParams == 1 && FTy.getParamType(0) == PCharTy); case LibFunc_getitimer: return (NumParams == 2 && FTy.getParamType(1)->isPointerTy()); case LibFunc_ungetc: return (NumParams == 2 && FTy.getParamType(1)->isPointerTy()); case LibFunc_utime: case LibFunc_utimes: return (NumParams == 2 && FTy.getParamType(0)->isPointerTy() && FTy.getParamType(1)->isPointerTy()); case LibFunc_putc: case LibFunc_putc_unlocked: return (NumParams == 2 && FTy.getParamType(1)->isPointerTy()); case LibFunc_pread: case LibFunc_pwrite: return (NumParams == 4 && FTy.getParamType(1)->isPointerTy()); case LibFunc_popen: return (NumParams == 2 && FTy.getReturnType()->isPointerTy() && FTy.getParamType(0)->isPointerTy() && FTy.getParamType(1)->isPointerTy()); case LibFunc_vscanf: return (NumParams == 2 && FTy.getParamType(1)->isPointerTy()); case LibFunc_vsscanf: return (NumParams == 3 && FTy.getParamType(1)->isPointerTy() && FTy.getParamType(2)->isPointerTy()); case LibFunc_vfscanf: return (NumParams == 3 && FTy.getParamType(1)->isPointerTy() && FTy.getParamType(2)->isPointerTy()); case LibFunc_valloc: return (FTy.getReturnType()->isPointerTy()); case LibFunc_vprintf: return (NumParams == 2 && FTy.getParamType(0)->isPointerTy()); case LibFunc_vfprintf: case LibFunc_vsprintf: return (NumParams == 3 && FTy.getParamType(0)->isPointerTy() && FTy.getParamType(1)->isPointerTy()); case LibFunc_vsprintf_chk: return NumParams == 5 && FTy.getParamType(0)->isPointerTy() && FTy.getParamType(1)->isIntegerTy(32) && IsSizeTTy(FTy.getParamType(2)) && FTy.getParamType(3)->isPointerTy(); case LibFunc_vsnprintf: return (NumParams == 4 && FTy.getParamType(0)->isPointerTy() && FTy.getParamType(2)->isPointerTy()); case LibFunc_vsnprintf_chk: return NumParams == 6 && FTy.getParamType(0)->isPointerTy() && FTy.getParamType(2)->isIntegerTy(32) && IsSizeTTy(FTy.getParamType(3)) && FTy.getParamType(4)->isPointerTy(); case LibFunc_open: return (NumParams >= 2 && FTy.getParamType(0)->isPointerTy()); case LibFunc_opendir: return (NumParams == 1 && FTy.getReturnType()->isPointerTy() && FTy.getParamType(0)->isPointerTy()); case LibFunc_tmpfile: return (FTy.getReturnType()->isPointerTy()); case LibFunc_htonl: case LibFunc_ntohl: return (NumParams == 1 && FTy.getReturnType()->isIntegerTy(32) && FTy.getReturnType() == FTy.getParamType(0)); case LibFunc_htons: case LibFunc_ntohs: return (NumParams == 1 && FTy.getReturnType()->isIntegerTy(16) && FTy.getReturnType() == FTy.getParamType(0)); case LibFunc_lstat: return (NumParams == 2 && FTy.getParamType(0)->isPointerTy() && FTy.getParamType(1)->isPointerTy()); case LibFunc_lchown: return (NumParams == 3 && FTy.getParamType(0)->isPointerTy()); case LibFunc_qsort: return (NumParams == 4 && FTy.getParamType(3)->isPointerTy()); case LibFunc_dunder_strdup: case LibFunc_dunder_strndup: return (NumParams >= 1 && FTy.getReturnType()->isPointerTy() && FTy.getParamType(0)->isPointerTy()); case LibFunc_dunder_strtok_r: return (NumParams == 3 && FTy.getParamType(1)->isPointerTy()); case LibFunc_under_IO_putc: return (NumParams == 2 && FTy.getParamType(1)->isPointerTy()); case LibFunc_dunder_isoc99_scanf: return (NumParams >= 1 && FTy.getParamType(0)->isPointerTy()); case LibFunc_stat64: case LibFunc_lstat64: case LibFunc_statvfs64: return (NumParams == 2 && FTy.getParamType(0)->isPointerTy() && FTy.getParamType(1)->isPointerTy()); case LibFunc_dunder_isoc99_sscanf: return (NumParams >= 2 && FTy.getParamType(0)->isPointerTy() && FTy.getParamType(1)->isPointerTy()); case LibFunc_fopen64: return (NumParams == 2 && FTy.getReturnType()->isPointerTy() && FTy.getParamType(0)->isPointerTy() && FTy.getParamType(1)->isPointerTy()); case LibFunc_tmpfile64: return (FTy.getReturnType()->isPointerTy()); case LibFunc_fstat64: case LibFunc_fstatvfs64: return (NumParams == 2 && FTy.getParamType(1)->isPointerTy()); case LibFunc_open64: return (NumParams >= 2 && FTy.getParamType(0)->isPointerTy()); case LibFunc_gettimeofday: return (NumParams == 2 && FTy.getParamType(0)->isPointerTy() && FTy.getParamType(1)->isPointerTy()); // new(unsigned int); case LibFunc_Znwj: // new(unsigned long); case LibFunc_Znwm: // new[](unsigned int); case LibFunc_Znaj: // new[](unsigned long); case LibFunc_Znam: // new(unsigned int); case LibFunc_msvc_new_int: // new(unsigned long long); case LibFunc_msvc_new_longlong: // new[](unsigned int); case LibFunc_msvc_new_array_int: // new[](unsigned long long); case LibFunc_msvc_new_array_longlong: return (NumParams == 1 && FTy.getReturnType()->isPointerTy()); // new(unsigned int, nothrow); case LibFunc_ZnwjRKSt9nothrow_t: // new(unsigned long, nothrow); case LibFunc_ZnwmRKSt9nothrow_t: // new[](unsigned int, nothrow); case LibFunc_ZnajRKSt9nothrow_t: // new[](unsigned long, nothrow); case LibFunc_ZnamRKSt9nothrow_t: // new(unsigned int, nothrow); case LibFunc_msvc_new_int_nothrow: // new(unsigned long long, nothrow); case LibFunc_msvc_new_longlong_nothrow: // new[](unsigned int, nothrow); case LibFunc_msvc_new_array_int_nothrow: // new[](unsigned long long, nothrow); case LibFunc_msvc_new_array_longlong_nothrow: // new(unsigned int, align_val_t) case LibFunc_ZnwjSt11align_val_t: // new(unsigned long, align_val_t) case LibFunc_ZnwmSt11align_val_t: // new[](unsigned int, align_val_t) case LibFunc_ZnajSt11align_val_t: // new[](unsigned long, align_val_t) case LibFunc_ZnamSt11align_val_t: return (NumParams == 2 && FTy.getReturnType()->isPointerTy()); // new(unsigned int, align_val_t, nothrow) case LibFunc_ZnwjSt11align_val_tRKSt9nothrow_t: // new(unsigned long, align_val_t, nothrow) case LibFunc_ZnwmSt11align_val_tRKSt9nothrow_t: // new[](unsigned int, align_val_t, nothrow) case LibFunc_ZnajSt11align_val_tRKSt9nothrow_t: // new[](unsigned long, align_val_t, nothrow) case LibFunc_ZnamSt11align_val_tRKSt9nothrow_t: return (NumParams == 3 && FTy.getReturnType()->isPointerTy()); // void operator delete[](void*); case LibFunc_ZdaPv: // void operator delete(void*); case LibFunc_ZdlPv: // void operator delete[](void*); case LibFunc_msvc_delete_array_ptr32: // void operator delete[](void*); case LibFunc_msvc_delete_array_ptr64: // void operator delete(void*); case LibFunc_msvc_delete_ptr32: // void operator delete(void*); case LibFunc_msvc_delete_ptr64: return (NumParams == 1 && FTy.getParamType(0)->isPointerTy()); // void operator delete[](void*, nothrow); case LibFunc_ZdaPvRKSt9nothrow_t: // void operator delete[](void*, unsigned int); case LibFunc_ZdaPvj: // void operator delete[](void*, unsigned long); case LibFunc_ZdaPvm: // void operator delete(void*, nothrow); case LibFunc_ZdlPvRKSt9nothrow_t: // void operator delete(void*, unsigned int); case LibFunc_ZdlPvj: // void operator delete(void*, unsigned long); case LibFunc_ZdlPvm: // void operator delete(void*, align_val_t) case LibFunc_ZdlPvSt11align_val_t: // void operator delete[](void*, align_val_t) case LibFunc_ZdaPvSt11align_val_t: // void operator delete[](void*, unsigned int); case LibFunc_msvc_delete_array_ptr32_int: // void operator delete[](void*, nothrow); case LibFunc_msvc_delete_array_ptr32_nothrow: // void operator delete[](void*, unsigned long long); case LibFunc_msvc_delete_array_ptr64_longlong: // void operator delete[](void*, nothrow); case LibFunc_msvc_delete_array_ptr64_nothrow: // void operator delete(void*, unsigned int); case LibFunc_msvc_delete_ptr32_int: // void operator delete(void*, nothrow); case LibFunc_msvc_delete_ptr32_nothrow: // void operator delete(void*, unsigned long long); case LibFunc_msvc_delete_ptr64_longlong: // void operator delete(void*, nothrow); case LibFunc_msvc_delete_ptr64_nothrow: return (NumParams == 2 && FTy.getParamType(0)->isPointerTy()); // void operator delete(void*, align_val_t, nothrow) case LibFunc_ZdlPvSt11align_val_tRKSt9nothrow_t: // void operator delete[](void*, align_val_t, nothrow) case LibFunc_ZdaPvSt11align_val_tRKSt9nothrow_t: return (NumParams == 3 && FTy.getParamType(0)->isPointerTy()); case LibFunc_memset_pattern16: return (!FTy.isVarArg() && NumParams == 3 && FTy.getParamType(0)->isPointerTy() && FTy.getParamType(1)->isPointerTy() && FTy.getParamType(2)->isIntegerTy()); case LibFunc_cxa_guard_abort: case LibFunc_cxa_guard_acquire: case LibFunc_cxa_guard_release: case LibFunc_nvvm_reflect: return (NumParams == 1 && FTy.getParamType(0)->isPointerTy()); case LibFunc_sincospi_stret: case LibFunc_sincospif_stret: return (NumParams == 1 && FTy.getParamType(0)->isFloatingPointTy()); case LibFunc_acos: case LibFunc_acos_finite: case LibFunc_acosf: case LibFunc_acosf_finite: case LibFunc_acosh: case LibFunc_acosh_finite: case LibFunc_acoshf: case LibFunc_acoshf_finite: case LibFunc_acoshl: case LibFunc_acoshl_finite: case LibFunc_acosl: case LibFunc_acosl_finite: case LibFunc_asin: case LibFunc_asin_finite: case LibFunc_asinf: case LibFunc_asinf_finite: case LibFunc_asinh: case LibFunc_asinhf: case LibFunc_asinhl: case LibFunc_asinl: case LibFunc_asinl_finite: case LibFunc_atan: case LibFunc_atanf: case LibFunc_atanh: case LibFunc_atanh_finite: case LibFunc_atanhf: case LibFunc_atanhf_finite: case LibFunc_atanhl: case LibFunc_atanhl_finite: case LibFunc_atanl: case LibFunc_cbrt: case LibFunc_cbrtf: case LibFunc_cbrtl: case LibFunc_ceil: case LibFunc_ceilf: case LibFunc_ceill: case LibFunc_cos: case LibFunc_cosf: case LibFunc_cosh: case LibFunc_cosh_finite: case LibFunc_coshf: case LibFunc_coshf_finite: case LibFunc_coshl: case LibFunc_coshl_finite: case LibFunc_cosl: case LibFunc_exp10: case LibFunc_exp10_finite: case LibFunc_exp10f: case LibFunc_exp10f_finite: case LibFunc_exp10l: case LibFunc_exp10l_finite: case LibFunc_exp2: case LibFunc_exp2_finite: case LibFunc_exp2f: case LibFunc_exp2f_finite: case LibFunc_exp2l: case LibFunc_exp2l_finite: case LibFunc_exp: case LibFunc_exp_finite: case LibFunc_expf: case LibFunc_expf_finite: case LibFunc_expl: case LibFunc_expl_finite: case LibFunc_expm1: case LibFunc_expm1f: case LibFunc_expm1l: case LibFunc_fabs: case LibFunc_fabsf: case LibFunc_fabsl: case LibFunc_floor: case LibFunc_floorf: case LibFunc_floorl: case LibFunc_log10: case LibFunc_log10_finite: case LibFunc_log10f: case LibFunc_log10f_finite: case LibFunc_log10l: case LibFunc_log10l_finite: case LibFunc_log1p: case LibFunc_log1pf: case LibFunc_log1pl: case LibFunc_log2: case LibFunc_log2_finite: case LibFunc_log2f: case LibFunc_log2f_finite: case LibFunc_log2l: case LibFunc_log2l_finite: case LibFunc_log: case LibFunc_log_finite: case LibFunc_logb: case LibFunc_logbf: case LibFunc_logbl: case LibFunc_logf: case LibFunc_logf_finite: case LibFunc_logl: case LibFunc_logl_finite: case LibFunc_nearbyint: case LibFunc_nearbyintf: case LibFunc_nearbyintl: case LibFunc_rint: case LibFunc_rintf: case LibFunc_rintl: case LibFunc_round: case LibFunc_roundf: case LibFunc_roundl: case LibFunc_sin: case LibFunc_sinf: case LibFunc_sinh: case LibFunc_sinh_finite: case LibFunc_sinhf: case LibFunc_sinhf_finite: case LibFunc_sinhl: case LibFunc_sinhl_finite: case LibFunc_sinl: case LibFunc_sqrt: case LibFunc_sqrt_finite: case LibFunc_sqrtf: case LibFunc_sqrtf_finite: case LibFunc_sqrtl: case LibFunc_sqrtl_finite: case LibFunc_tan: case LibFunc_tanf: case LibFunc_tanh: case LibFunc_tanhf: case LibFunc_tanhl: case LibFunc_tanl: case LibFunc_trunc: case LibFunc_truncf: case LibFunc_truncl: return (NumParams == 1 && FTy.getReturnType()->isFloatingPointTy() && FTy.getReturnType() == FTy.getParamType(0)); case LibFunc_atan2: case LibFunc_atan2_finite: case LibFunc_atan2f: case LibFunc_atan2f_finite: case LibFunc_atan2l: case LibFunc_atan2l_finite: case LibFunc_fmin: case LibFunc_fminf: case LibFunc_fminl: case LibFunc_fmax: case LibFunc_fmaxf: case LibFunc_fmaxl: case LibFunc_fmod: case LibFunc_fmodf: case LibFunc_fmodl: case LibFunc_copysign: case LibFunc_copysignf: case LibFunc_copysignl: case LibFunc_pow: case LibFunc_pow_finite: case LibFunc_powf: case LibFunc_powf_finite: case LibFunc_powl: case LibFunc_powl_finite: return (NumParams == 2 && FTy.getReturnType()->isFloatingPointTy() && FTy.getReturnType() == FTy.getParamType(0) && FTy.getReturnType() == FTy.getParamType(1)); case LibFunc_ldexp: case LibFunc_ldexpf: case LibFunc_ldexpl: return (NumParams == 2 && FTy.getReturnType()->isFloatingPointTy() && FTy.getReturnType() == FTy.getParamType(0) && FTy.getParamType(1)->isIntegerTy(32)); case LibFunc_ffs: case LibFunc_ffsl: case LibFunc_ffsll: case LibFunc_fls: case LibFunc_flsl: case LibFunc_flsll: return (NumParams == 1 && FTy.getReturnType()->isIntegerTy(32) && FTy.getParamType(0)->isIntegerTy()); case LibFunc_isdigit: case LibFunc_isascii: case LibFunc_toascii: case LibFunc_putchar: case LibFunc_putchar_unlocked: return (NumParams == 1 && FTy.getReturnType()->isIntegerTy(32) && FTy.getReturnType() == FTy.getParamType(0)); case LibFunc_abs: case LibFunc_labs: case LibFunc_llabs: return (NumParams == 1 && FTy.getReturnType()->isIntegerTy() && FTy.getReturnType() == FTy.getParamType(0)); case LibFunc_cxa_atexit: return (NumParams == 3 && FTy.getReturnType()->isIntegerTy() && FTy.getParamType(0)->isPointerTy() && FTy.getParamType(1)->isPointerTy() && FTy.getParamType(2)->isPointerTy()); case LibFunc_sinpi: case LibFunc_cospi: return (NumParams == 1 && FTy.getReturnType()->isDoubleTy() && FTy.getReturnType() == FTy.getParamType(0)); case LibFunc_sinpif: case LibFunc_cospif: return (NumParams == 1 && FTy.getReturnType()->isFloatTy() && FTy.getReturnType() == FTy.getParamType(0)); case LibFunc_strnlen: return (NumParams == 2 && FTy.getReturnType() == FTy.getParamType(1) && FTy.getParamType(0) == PCharTy && FTy.getParamType(1) == SizeTTy); case LibFunc_posix_memalign: return (NumParams == 3 && FTy.getReturnType()->isIntegerTy(32) && FTy.getParamType(0)->isPointerTy() && FTy.getParamType(1) == SizeTTy && FTy.getParamType(2) == SizeTTy); case LibFunc_wcslen: return (NumParams == 1 && FTy.getParamType(0)->isPointerTy() && FTy.getReturnType()->isIntegerTy()); case LibFunc_cabs: case LibFunc_cabsf: case LibFunc_cabsl: { Type* RetTy = FTy.getReturnType(); if (!RetTy->isFloatingPointTy()) return false; // NOTE: These prototypes are target specific and currently support // "complex" passed as an array or discrete real & imaginary parameters. // Add other calling conventions to enable libcall optimizations. if (NumParams == 1) return (FTy.getParamType(0)->isArrayTy() && FTy.getParamType(0)->getArrayNumElements() == 2 && FTy.getParamType(0)->getArrayElementType() == RetTy); else if (NumParams == 2) return (FTy.getParamType(0) == RetTy && FTy.getParamType(1) == RetTy); else return false; } case LibFunc::NumLibFuncs: case LibFunc::NotLibFunc: break; } llvm_unreachable("Invalid libfunc"); } bool TargetLibraryInfoImpl::getLibFunc(const Function &FDecl, LibFunc &F) const { // Intrinsics don't overlap w/libcalls; if our module has a large number of // intrinsics, this ends up being an interesting compile time win since we // avoid string normalization and comparison. if (FDecl.isIntrinsic()) return false; const DataLayout *DL = FDecl.getParent() ? &FDecl.getParent()->getDataLayout() : nullptr; return getLibFunc(FDecl.getName(), F) && isValidProtoForLibFunc(*FDecl.getFunctionType(), F, DL); } void TargetLibraryInfoImpl::disableAllFunctions() { memset(AvailableArray, 0, sizeof(AvailableArray)); } static bool compareByScalarFnName(const VecDesc &LHS, const VecDesc &RHS) { return LHS.ScalarFnName < RHS.ScalarFnName; } static bool compareByVectorFnName(const VecDesc &LHS, const VecDesc &RHS) { return LHS.VectorFnName < RHS.VectorFnName; } static bool compareWithScalarFnName(const VecDesc &LHS, StringRef S) { return LHS.ScalarFnName < S; } static bool compareWithVectorFnName(const VecDesc &LHS, StringRef S) { return LHS.VectorFnName < S; } void TargetLibraryInfoImpl::addVectorizableFunctions(ArrayRef Fns) { VectorDescs.insert(VectorDescs.end(), Fns.begin(), Fns.end()); llvm::sort(VectorDescs, compareByScalarFnName); ScalarDescs.insert(ScalarDescs.end(), Fns.begin(), Fns.end()); llvm::sort(ScalarDescs, compareByVectorFnName); } void TargetLibraryInfoImpl::addVectorizableFunctionsFromVecLib( enum VectorLibrary VecLib) { switch (VecLib) { case Accelerate: { const VecDesc VecFuncs[] = { #define TLI_DEFINE_ACCELERATE_VECFUNCS #include "llvm/Analysis/VecFuncs.def" }; addVectorizableFunctions(VecFuncs); break; } case MASSV: { const VecDesc VecFuncs[] = { #define TLI_DEFINE_MASSV_VECFUNCS #include "llvm/Analysis/VecFuncs.def" }; addVectorizableFunctions(VecFuncs); break; } case SVML: { const VecDesc VecFuncs[] = { #define TLI_DEFINE_SVML_VECFUNCS #include "llvm/Analysis/VecFuncs.def" }; addVectorizableFunctions(VecFuncs); break; } case NoLibrary: break; } } bool TargetLibraryInfoImpl::isFunctionVectorizable(StringRef funcName) const { funcName = sanitizeFunctionName(funcName); if (funcName.empty()) return false; std::vector::const_iterator I = llvm::lower_bound(VectorDescs, funcName, compareWithScalarFnName); return I != VectorDescs.end() && StringRef(I->ScalarFnName) == funcName; } StringRef TargetLibraryInfoImpl::getVectorizedFunction(StringRef F, unsigned VF) const { F = sanitizeFunctionName(F); if (F.empty()) return F; std::vector::const_iterator I = llvm::lower_bound(VectorDescs, F, compareWithScalarFnName); while (I != VectorDescs.end() && StringRef(I->ScalarFnName) == F) { if (I->VectorizationFactor == VF) return I->VectorFnName; ++I; } return StringRef(); } StringRef TargetLibraryInfoImpl::getScalarizedFunction(StringRef F, unsigned &VF) const { F = sanitizeFunctionName(F); if (F.empty()) return F; std::vector::const_iterator I = llvm::lower_bound(ScalarDescs, F, compareWithVectorFnName); if (I == VectorDescs.end() || StringRef(I->VectorFnName) != F) return StringRef(); VF = I->VectorizationFactor; return I->ScalarFnName; } TargetLibraryInfo TargetLibraryAnalysis::run(const Function &F, FunctionAnalysisManager &) { if (!BaselineInfoImpl) BaselineInfoImpl = TargetLibraryInfoImpl(Triple(F.getParent()->getTargetTriple())); return TargetLibraryInfo(*BaselineInfoImpl, &F); } unsigned TargetLibraryInfoImpl::getWCharSize(const Module &M) const { if (auto *ShortWChar = cast_or_null( M.getModuleFlag("wchar_size"))) return cast(ShortWChar->getValue())->getZExtValue(); return 0; } TargetLibraryInfoWrapperPass::TargetLibraryInfoWrapperPass() : ImmutablePass(ID), TLA(TargetLibraryInfoImpl()) { initializeTargetLibraryInfoWrapperPassPass(*PassRegistry::getPassRegistry()); } TargetLibraryInfoWrapperPass::TargetLibraryInfoWrapperPass(const Triple &T) : ImmutablePass(ID), TLA(TargetLibraryInfoImpl(T)) { initializeTargetLibraryInfoWrapperPassPass(*PassRegistry::getPassRegistry()); } TargetLibraryInfoWrapperPass::TargetLibraryInfoWrapperPass( const TargetLibraryInfoImpl &TLIImpl) : ImmutablePass(ID), TLA(TLIImpl) { initializeTargetLibraryInfoWrapperPassPass(*PassRegistry::getPassRegistry()); } AnalysisKey TargetLibraryAnalysis::Key; // Register the basic pass. INITIALIZE_PASS(TargetLibraryInfoWrapperPass, "targetlibinfo", "Target Library Information", false, true) char TargetLibraryInfoWrapperPass::ID = 0; void TargetLibraryInfoWrapperPass::anchor() {} unsigned TargetLibraryInfoImpl::getWidestVF(StringRef ScalarF) const { ScalarF = sanitizeFunctionName(ScalarF); if (ScalarF.empty()) return 1; unsigned VF = 1; std::vector::const_iterator I = llvm::lower_bound(VectorDescs, ScalarF, compareWithScalarFnName); while (I != VectorDescs.end() && StringRef(I->ScalarFnName) == ScalarF) { if (I->VectorizationFactor > VF) VF = I->VectorizationFactor; ++I; } return VF; } diff --git a/contrib/llvm-project/llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp b/contrib/llvm-project/llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp index 80ac8b95e4ef..91404ee7728b 100644 --- a/contrib/llvm-project/llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp +++ b/contrib/llvm-project/llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp @@ -1,4826 +1,4777 @@ //===- LegalizeDAG.cpp - Implement SelectionDAG::Legalize -----------------===// // // 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 SelectionDAG::Legalize method. // //===----------------------------------------------------------------------===// #include "llvm/ADT/APFloat.h" #include "llvm/ADT/APInt.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/SetVector.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/SmallVector.h" #include "llvm/Analysis/TargetLibraryInfo.h" #include "llvm/CodeGen/ISDOpcodes.h" #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineJumpTableInfo.h" #include "llvm/CodeGen/MachineMemOperand.h" #include "llvm/CodeGen/RuntimeLibcalls.h" #include "llvm/CodeGen/SelectionDAG.h" #include "llvm/CodeGen/SelectionDAGNodes.h" #include "llvm/CodeGen/TargetFrameLowering.h" #include "llvm/CodeGen/TargetLowering.h" #include "llvm/CodeGen/TargetSubtargetInfo.h" #include "llvm/CodeGen/ValueTypes.h" #include "llvm/IR/CallingConv.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/Function.h" #include "llvm/IR/Metadata.h" #include "llvm/IR/Type.h" #include "llvm/Support/Casting.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/MachineValueType.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetOptions.h" #include #include #include #include #include using namespace llvm; #define DEBUG_TYPE "legalizedag" namespace { /// Keeps track of state when getting the sign of a floating-point value as an /// integer. struct FloatSignAsInt { EVT FloatVT; SDValue Chain; SDValue FloatPtr; SDValue IntPtr; MachinePointerInfo IntPointerInfo; MachinePointerInfo FloatPointerInfo; SDValue IntValue; APInt SignMask; uint8_t SignBit; }; //===----------------------------------------------------------------------===// /// This takes an arbitrary SelectionDAG as input and /// hacks on it until the target machine can handle it. This involves /// eliminating value sizes the machine cannot handle (promoting small sizes to /// large sizes or splitting up large values into small values) as well as /// eliminating operations the machine cannot handle. /// /// This code also does a small amount of optimization and recognition of idioms /// as part of its processing. For example, if a target does not support a /// 'setcc' instruction efficiently, but does support 'brcc' instruction, this /// will attempt merge setcc and brc instructions into brcc's. class SelectionDAGLegalize { const TargetMachine &TM; const TargetLowering &TLI; SelectionDAG &DAG; /// The set of nodes which have already been legalized. We hold a /// reference to it in order to update as necessary on node deletion. SmallPtrSetImpl &LegalizedNodes; /// A set of all the nodes updated during legalization. SmallSetVector *UpdatedNodes; EVT getSetCCResultType(EVT VT) const { return TLI.getSetCCResultType(DAG.getDataLayout(), *DAG.getContext(), VT); } // Libcall insertion helpers. public: SelectionDAGLegalize(SelectionDAG &DAG, SmallPtrSetImpl &LegalizedNodes, SmallSetVector *UpdatedNodes = nullptr) : TM(DAG.getTarget()), TLI(DAG.getTargetLoweringInfo()), DAG(DAG), LegalizedNodes(LegalizedNodes), UpdatedNodes(UpdatedNodes) {} /// Legalizes the given operation. void LegalizeOp(SDNode *Node); private: SDValue OptimizeFloatStore(StoreSDNode *ST); void LegalizeLoadOps(SDNode *Node); void LegalizeStoreOps(SDNode *Node); /// Some targets cannot handle a variable /// insertion index for the INSERT_VECTOR_ELT instruction. In this case, it /// is necessary to spill the vector being inserted into to memory, perform /// the insert there, and then read the result back. SDValue PerformInsertVectorEltInMemory(SDValue Vec, SDValue Val, SDValue Idx, const SDLoc &dl); SDValue ExpandINSERT_VECTOR_ELT(SDValue Vec, SDValue Val, SDValue Idx, const SDLoc &dl); /// Return a vector shuffle operation which /// performs the same shuffe in terms of order or result bytes, but on a type /// whose vector element type is narrower than the original shuffle type. /// e.g. <0, 1, 0, 1> -> v8i16 <0, 1, 2, 3, 0, 1, 2, 3> SDValue ShuffleWithNarrowerEltType(EVT NVT, EVT VT, const SDLoc &dl, SDValue N1, SDValue N2, ArrayRef Mask) const; bool LegalizeSetCCCondCode(EVT VT, SDValue &LHS, SDValue &RHS, SDValue &CC, bool &NeedInvert, const SDLoc &dl, SDValue &Chain, bool IsSignaling = false); SDValue ExpandLibCall(RTLIB::Libcall LC, SDNode *Node, bool isSigned); void ExpandFPLibCall(SDNode *Node, RTLIB::Libcall Call_F32, RTLIB::Libcall Call_F64, RTLIB::Libcall Call_F80, RTLIB::Libcall Call_F128, RTLIB::Libcall Call_PPCF128, SmallVectorImpl &Results); SDValue ExpandIntLibCall(SDNode *Node, bool isSigned, RTLIB::Libcall Call_I8, RTLIB::Libcall Call_I16, RTLIB::Libcall Call_I32, RTLIB::Libcall Call_I64, RTLIB::Libcall Call_I128); void ExpandArgFPLibCall(SDNode *Node, RTLIB::Libcall Call_F32, RTLIB::Libcall Call_F64, RTLIB::Libcall Call_F80, RTLIB::Libcall Call_F128, RTLIB::Libcall Call_PPCF128, SmallVectorImpl &Results); void ExpandDivRemLibCall(SDNode *Node, SmallVectorImpl &Results); void ExpandSinCosLibCall(SDNode *Node, SmallVectorImpl &Results); SDValue EmitStackConvert(SDValue SrcOp, EVT SlotVT, EVT DestVT, const SDLoc &dl); SDValue EmitStackConvert(SDValue SrcOp, EVT SlotVT, EVT DestVT, const SDLoc &dl, SDValue ChainIn); SDValue ExpandBUILD_VECTOR(SDNode *Node); SDValue ExpandSPLAT_VECTOR(SDNode *Node); SDValue ExpandSCALAR_TO_VECTOR(SDNode *Node); void ExpandDYNAMIC_STACKALLOC(SDNode *Node, SmallVectorImpl &Results); void getSignAsIntValue(FloatSignAsInt &State, const SDLoc &DL, SDValue Value) const; SDValue modifySignAsInt(const FloatSignAsInt &State, const SDLoc &DL, SDValue NewIntValue) const; SDValue ExpandFCOPYSIGN(SDNode *Node) const; SDValue ExpandFABS(SDNode *Node) const; SDValue ExpandLegalINT_TO_FP(SDNode *Node, SDValue &Chain); void PromoteLegalINT_TO_FP(SDNode *N, const SDLoc &dl, SmallVectorImpl &Results); void PromoteLegalFP_TO_INT(SDNode *N, const SDLoc &dl, SmallVectorImpl &Results); SDValue ExpandBITREVERSE(SDValue Op, const SDLoc &dl); SDValue ExpandBSWAP(SDValue Op, const SDLoc &dl); SDValue ExpandExtractFromVectorThroughStack(SDValue Op); SDValue ExpandInsertToVectorThroughStack(SDValue Op); SDValue ExpandVectorBuildThroughStack(SDNode* Node); SDValue ExpandConstantFP(ConstantFPSDNode *CFP, bool UseCP); SDValue ExpandConstant(ConstantSDNode *CP); // if ExpandNode returns false, LegalizeOp falls back to ConvertNodeToLibcall bool ExpandNode(SDNode *Node); void ConvertNodeToLibcall(SDNode *Node); void PromoteNode(SDNode *Node); public: // Node replacement helpers void ReplacedNode(SDNode *N) { LegalizedNodes.erase(N); if (UpdatedNodes) UpdatedNodes->insert(N); } void ReplaceNode(SDNode *Old, SDNode *New) { LLVM_DEBUG(dbgs() << " ... replacing: "; Old->dump(&DAG); dbgs() << " with: "; New->dump(&DAG)); assert(Old->getNumValues() == New->getNumValues() && "Replacing one node with another that produces a different number " "of values!"); DAG.ReplaceAllUsesWith(Old, New); if (UpdatedNodes) UpdatedNodes->insert(New); ReplacedNode(Old); } void ReplaceNode(SDValue Old, SDValue New) { LLVM_DEBUG(dbgs() << " ... replacing: "; Old->dump(&DAG); dbgs() << " with: "; New->dump(&DAG)); DAG.ReplaceAllUsesWith(Old, New); if (UpdatedNodes) UpdatedNodes->insert(New.getNode()); ReplacedNode(Old.getNode()); } void ReplaceNode(SDNode *Old, const SDValue *New) { LLVM_DEBUG(dbgs() << " ... replacing: "; Old->dump(&DAG)); DAG.ReplaceAllUsesWith(Old, New); for (unsigned i = 0, e = Old->getNumValues(); i != e; ++i) { LLVM_DEBUG(dbgs() << (i == 0 ? " with: " : " and: "); New[i]->dump(&DAG)); if (UpdatedNodes) UpdatedNodes->insert(New[i].getNode()); } ReplacedNode(Old); } void ReplaceNodeWithValue(SDValue Old, SDValue New) { LLVM_DEBUG(dbgs() << " ... replacing: "; Old->dump(&DAG); dbgs() << " with: "; New->dump(&DAG)); DAG.ReplaceAllUsesOfValueWith(Old, New); if (UpdatedNodes) UpdatedNodes->insert(New.getNode()); ReplacedNode(Old.getNode()); } }; } // end anonymous namespace /// Return a vector shuffle operation which /// performs the same shuffle in terms of order or result bytes, but on a type /// whose vector element type is narrower than the original shuffle type. /// e.g. <0, 1, 0, 1> -> v8i16 <0, 1, 2, 3, 0, 1, 2, 3> SDValue SelectionDAGLegalize::ShuffleWithNarrowerEltType( EVT NVT, EVT VT, const SDLoc &dl, SDValue N1, SDValue N2, ArrayRef Mask) const { unsigned NumMaskElts = VT.getVectorNumElements(); unsigned NumDestElts = NVT.getVectorNumElements(); unsigned NumEltsGrowth = NumDestElts / NumMaskElts; assert(NumEltsGrowth && "Cannot promote to vector type with fewer elts!"); if (NumEltsGrowth == 1) return DAG.getVectorShuffle(NVT, dl, N1, N2, Mask); SmallVector NewMask; for (unsigned i = 0; i != NumMaskElts; ++i) { int Idx = Mask[i]; for (unsigned j = 0; j != NumEltsGrowth; ++j) { if (Idx < 0) NewMask.push_back(-1); else NewMask.push_back(Idx * NumEltsGrowth + j); } } assert(NewMask.size() == NumDestElts && "Non-integer NumEltsGrowth?"); assert(TLI.isShuffleMaskLegal(NewMask, NVT) && "Shuffle not legal?"); return DAG.getVectorShuffle(NVT, dl, N1, N2, NewMask); } /// Expands the ConstantFP node to an integer constant or /// a load from the constant pool. SDValue SelectionDAGLegalize::ExpandConstantFP(ConstantFPSDNode *CFP, bool UseCP) { bool Extend = false; SDLoc dl(CFP); // If a FP immediate is precise when represented as a float and if the // target can do an extending load from float to double, we put it into // the constant pool as a float, even if it's is statically typed as a // double. This shrinks FP constants and canonicalizes them for targets where // an FP extending load is the same cost as a normal load (such as on the x87 // fp stack or PPC FP unit). EVT VT = CFP->getValueType(0); ConstantFP *LLVMC = const_cast(CFP->getConstantFPValue()); if (!UseCP) { assert((VT == MVT::f64 || VT == MVT::f32) && "Invalid type expansion"); return DAG.getConstant(LLVMC->getValueAPF().bitcastToAPInt(), dl, (VT == MVT::f64) ? MVT::i64 : MVT::i32); } APFloat APF = CFP->getValueAPF(); EVT OrigVT = VT; EVT SVT = VT; // We don't want to shrink SNaNs. Converting the SNaN back to its real type // can cause it to be changed into a QNaN on some platforms (e.g. on SystemZ). if (!APF.isSignaling()) { while (SVT != MVT::f32 && SVT != MVT::f16) { SVT = (MVT::SimpleValueType)(SVT.getSimpleVT().SimpleTy - 1); if (ConstantFPSDNode::isValueValidForType(SVT, APF) && // Only do this if the target has a native EXTLOAD instruction from // smaller type. TLI.isLoadExtLegal(ISD::EXTLOAD, OrigVT, SVT) && TLI.ShouldShrinkFPConstant(OrigVT)) { Type *SType = SVT.getTypeForEVT(*DAG.getContext()); LLVMC = cast(ConstantExpr::getFPTrunc(LLVMC, SType)); VT = SVT; Extend = true; } } } SDValue CPIdx = DAG.getConstantPool(LLVMC, TLI.getPointerTy(DAG.getDataLayout())); unsigned Alignment = cast(CPIdx)->getAlignment(); if (Extend) { SDValue Result = DAG.getExtLoad( ISD::EXTLOAD, dl, OrigVT, DAG.getEntryNode(), CPIdx, MachinePointerInfo::getConstantPool(DAG.getMachineFunction()), VT, Alignment); return Result; } SDValue Result = DAG.getLoad( OrigVT, dl, DAG.getEntryNode(), CPIdx, MachinePointerInfo::getConstantPool(DAG.getMachineFunction()), Alignment); return Result; } /// Expands the Constant node to a load from the constant pool. SDValue SelectionDAGLegalize::ExpandConstant(ConstantSDNode *CP) { SDLoc dl(CP); EVT VT = CP->getValueType(0); SDValue CPIdx = DAG.getConstantPool(CP->getConstantIntValue(), TLI.getPointerTy(DAG.getDataLayout())); unsigned Alignment = cast(CPIdx)->getAlignment(); SDValue Result = DAG.getLoad( VT, dl, DAG.getEntryNode(), CPIdx, MachinePointerInfo::getConstantPool(DAG.getMachineFunction()), Alignment); return Result; } /// Some target cannot handle a variable insertion index for the /// INSERT_VECTOR_ELT instruction. In this case, it /// is necessary to spill the vector being inserted into to memory, perform /// the insert there, and then read the result back. SDValue SelectionDAGLegalize::PerformInsertVectorEltInMemory(SDValue Vec, SDValue Val, SDValue Idx, const SDLoc &dl) { SDValue Tmp1 = Vec; SDValue Tmp2 = Val; SDValue Tmp3 = Idx; // If the target doesn't support this, we have to spill the input vector // to a temporary stack slot, update the element, then reload it. This is // badness. We could also load the value into a vector register (either // with a "move to register" or "extload into register" instruction, then // permute it into place, if the idx is a constant and if the idx is // supported by the target. EVT VT = Tmp1.getValueType(); EVT EltVT = VT.getVectorElementType(); SDValue StackPtr = DAG.CreateStackTemporary(VT); int SPFI = cast(StackPtr.getNode())->getIndex(); // Store the vector. SDValue Ch = DAG.getStore( DAG.getEntryNode(), dl, Tmp1, StackPtr, MachinePointerInfo::getFixedStack(DAG.getMachineFunction(), SPFI)); SDValue StackPtr2 = TLI.getVectorElementPointer(DAG, StackPtr, VT, Tmp3); // Store the scalar value. Ch = DAG.getTruncStore(Ch, dl, Tmp2, StackPtr2, MachinePointerInfo(), EltVT); // Load the updated vector. return DAG.getLoad(VT, dl, Ch, StackPtr, MachinePointerInfo::getFixedStack( DAG.getMachineFunction(), SPFI)); } SDValue SelectionDAGLegalize::ExpandINSERT_VECTOR_ELT(SDValue Vec, SDValue Val, SDValue Idx, const SDLoc &dl) { if (ConstantSDNode *InsertPos = dyn_cast(Idx)) { // SCALAR_TO_VECTOR requires that the type of the value being inserted // match the element type of the vector being created, except for // integers in which case the inserted value can be over width. EVT EltVT = Vec.getValueType().getVectorElementType(); if (Val.getValueType() == EltVT || (EltVT.isInteger() && Val.getValueType().bitsGE(EltVT))) { SDValue ScVec = DAG.getNode(ISD::SCALAR_TO_VECTOR, dl, Vec.getValueType(), Val); unsigned NumElts = Vec.getValueType().getVectorNumElements(); // We generate a shuffle of InVec and ScVec, so the shuffle mask // should be 0,1,2,3,4,5... with the appropriate element replaced with // elt 0 of the RHS. SmallVector ShufOps; for (unsigned i = 0; i != NumElts; ++i) ShufOps.push_back(i != InsertPos->getZExtValue() ? i : NumElts); return DAG.getVectorShuffle(Vec.getValueType(), dl, Vec, ScVec, ShufOps); } } return PerformInsertVectorEltInMemory(Vec, Val, Idx, dl); } SDValue SelectionDAGLegalize::OptimizeFloatStore(StoreSDNode* ST) { if (!ISD::isNormalStore(ST)) return SDValue(); LLVM_DEBUG(dbgs() << "Optimizing float store operations\n"); // Turn 'store float 1.0, Ptr' -> 'store int 0x12345678, Ptr' // FIXME: We shouldn't do this for TargetConstantFP's. // FIXME: move this to the DAG Combiner! Note that we can't regress due // to phase ordering between legalized code and the dag combiner. This // probably means that we need to integrate dag combiner and legalizer // together. // We generally can't do this one for long doubles. SDValue Chain = ST->getChain(); SDValue Ptr = ST->getBasePtr(); unsigned Alignment = ST->getAlignment(); MachineMemOperand::Flags MMOFlags = ST->getMemOperand()->getFlags(); AAMDNodes AAInfo = ST->getAAInfo(); SDLoc dl(ST); if (ConstantFPSDNode *CFP = dyn_cast(ST->getValue())) { if (CFP->getValueType(0) == MVT::f32 && TLI.isTypeLegal(MVT::i32)) { SDValue Con = DAG.getConstant(CFP->getValueAPF(). bitcastToAPInt().zextOrTrunc(32), SDLoc(CFP), MVT::i32); return DAG.getStore(Chain, dl, Con, Ptr, ST->getPointerInfo(), Alignment, MMOFlags, AAInfo); } if (CFP->getValueType(0) == MVT::f64) { // If this target supports 64-bit registers, do a single 64-bit store. if (TLI.isTypeLegal(MVT::i64)) { SDValue Con = DAG.getConstant(CFP->getValueAPF().bitcastToAPInt(). zextOrTrunc(64), SDLoc(CFP), MVT::i64); return DAG.getStore(Chain, dl, Con, Ptr, ST->getPointerInfo(), Alignment, MMOFlags, AAInfo); } if (TLI.isTypeLegal(MVT::i32) && !ST->isVolatile()) { // Otherwise, if the target supports 32-bit registers, use 2 32-bit // stores. If the target supports neither 32- nor 64-bits, this // xform is certainly not worth it. const APInt &IntVal = CFP->getValueAPF().bitcastToAPInt(); SDValue Lo = DAG.getConstant(IntVal.trunc(32), dl, MVT::i32); SDValue Hi = DAG.getConstant(IntVal.lshr(32).trunc(32), dl, MVT::i32); if (DAG.getDataLayout().isBigEndian()) std::swap(Lo, Hi); Lo = DAG.getStore(Chain, dl, Lo, Ptr, ST->getPointerInfo(), Alignment, MMOFlags, AAInfo); Ptr = DAG.getMemBasePlusOffset(Ptr, 4, dl); Hi = DAG.getStore(Chain, dl, Hi, Ptr, ST->getPointerInfo().getWithOffset(4), MinAlign(Alignment, 4U), MMOFlags, AAInfo); return DAG.getNode(ISD::TokenFactor, dl, MVT::Other, Lo, Hi); } } } return SDValue(nullptr, 0); } void SelectionDAGLegalize::LegalizeStoreOps(SDNode *Node) { StoreSDNode *ST = cast(Node); SDValue Chain = ST->getChain(); SDValue Ptr = ST->getBasePtr(); SDLoc dl(Node); unsigned Alignment = ST->getAlignment(); MachineMemOperand::Flags MMOFlags = ST->getMemOperand()->getFlags(); AAMDNodes AAInfo = ST->getAAInfo(); if (!ST->isTruncatingStore()) { LLVM_DEBUG(dbgs() << "Legalizing store operation\n"); if (SDNode *OptStore = OptimizeFloatStore(ST).getNode()) { ReplaceNode(ST, OptStore); return; } SDValue Value = ST->getValue(); MVT VT = Value.getSimpleValueType(); switch (TLI.getOperationAction(ISD::STORE, VT)) { default: llvm_unreachable("This action is not supported yet!"); case TargetLowering::Legal: { // If this is an unaligned store and the target doesn't support it, // expand it. EVT MemVT = ST->getMemoryVT(); const DataLayout &DL = DAG.getDataLayout(); if (!TLI.allowsMemoryAccessForAlignment(*DAG.getContext(), DL, MemVT, *ST->getMemOperand())) { LLVM_DEBUG(dbgs() << "Expanding unsupported unaligned store\n"); SDValue Result = TLI.expandUnalignedStore(ST, DAG); ReplaceNode(SDValue(ST, 0), Result); } else LLVM_DEBUG(dbgs() << "Legal store\n"); break; } case TargetLowering::Custom: { LLVM_DEBUG(dbgs() << "Trying custom lowering\n"); SDValue Res = TLI.LowerOperation(SDValue(Node, 0), DAG); if (Res && Res != SDValue(Node, 0)) ReplaceNode(SDValue(Node, 0), Res); return; } case TargetLowering::Promote: { MVT NVT = TLI.getTypeToPromoteTo(ISD::STORE, VT); assert(NVT.getSizeInBits() == VT.getSizeInBits() && "Can only promote stores to same size type"); Value = DAG.getNode(ISD::BITCAST, dl, NVT, Value); SDValue Result = DAG.getStore(Chain, dl, Value, Ptr, ST->getPointerInfo(), Alignment, MMOFlags, AAInfo); ReplaceNode(SDValue(Node, 0), Result); break; } } return; } LLVM_DEBUG(dbgs() << "Legalizing truncating store operations\n"); SDValue Value = ST->getValue(); EVT StVT = ST->getMemoryVT(); unsigned StWidth = StVT.getSizeInBits(); auto &DL = DAG.getDataLayout(); if (StWidth != StVT.getStoreSizeInBits()) { // Promote to a byte-sized store with upper bits zero if not // storing an integral number of bytes. For example, promote // TRUNCSTORE:i1 X -> TRUNCSTORE:i8 (and X, 1) EVT NVT = EVT::getIntegerVT(*DAG.getContext(), StVT.getStoreSizeInBits()); Value = DAG.getZeroExtendInReg(Value, dl, StVT); SDValue Result = DAG.getTruncStore(Chain, dl, Value, Ptr, ST->getPointerInfo(), NVT, Alignment, MMOFlags, AAInfo); ReplaceNode(SDValue(Node, 0), Result); } else if (StWidth & (StWidth - 1)) { // If not storing a power-of-2 number of bits, expand as two stores. assert(!StVT.isVector() && "Unsupported truncstore!"); unsigned LogStWidth = Log2_32(StWidth); assert(LogStWidth < 32); unsigned RoundWidth = 1 << LogStWidth; assert(RoundWidth < StWidth); unsigned ExtraWidth = StWidth - RoundWidth; assert(ExtraWidth < RoundWidth); assert(!(RoundWidth % 8) && !(ExtraWidth % 8) && "Store size not an integral number of bytes!"); EVT RoundVT = EVT::getIntegerVT(*DAG.getContext(), RoundWidth); EVT ExtraVT = EVT::getIntegerVT(*DAG.getContext(), ExtraWidth); SDValue Lo, Hi; unsigned IncrementSize; if (DL.isLittleEndian()) { // TRUNCSTORE:i24 X -> TRUNCSTORE:i16 X, TRUNCSTORE@+2:i8 (srl X, 16) // Store the bottom RoundWidth bits. Lo = DAG.getTruncStore(Chain, dl, Value, Ptr, ST->getPointerInfo(), RoundVT, Alignment, MMOFlags, AAInfo); // Store the remaining ExtraWidth bits. IncrementSize = RoundWidth / 8; Ptr = DAG.getMemBasePlusOffset(Ptr, IncrementSize, dl); Hi = DAG.getNode( ISD::SRL, dl, Value.getValueType(), Value, DAG.getConstant(RoundWidth, dl, TLI.getShiftAmountTy(Value.getValueType(), DL))); Hi = DAG.getTruncStore( Chain, dl, Hi, Ptr, ST->getPointerInfo().getWithOffset(IncrementSize), ExtraVT, MinAlign(Alignment, IncrementSize), MMOFlags, AAInfo); } else { // Big endian - avoid unaligned stores. // TRUNCSTORE:i24 X -> TRUNCSTORE:i16 (srl X, 8), TRUNCSTORE@+2:i8 X // Store the top RoundWidth bits. Hi = DAG.getNode( ISD::SRL, dl, Value.getValueType(), Value, DAG.getConstant(ExtraWidth, dl, TLI.getShiftAmountTy(Value.getValueType(), DL))); Hi = DAG.getTruncStore(Chain, dl, Hi, Ptr, ST->getPointerInfo(), RoundVT, Alignment, MMOFlags, AAInfo); // Store the remaining ExtraWidth bits. IncrementSize = RoundWidth / 8; Ptr = DAG.getNode(ISD::ADD, dl, Ptr.getValueType(), Ptr, DAG.getConstant(IncrementSize, dl, Ptr.getValueType())); Lo = DAG.getTruncStore( Chain, dl, Value, Ptr, ST->getPointerInfo().getWithOffset(IncrementSize), ExtraVT, MinAlign(Alignment, IncrementSize), MMOFlags, AAInfo); } // The order of the stores doesn't matter. SDValue Result = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, Lo, Hi); ReplaceNode(SDValue(Node, 0), Result); } else { switch (TLI.getTruncStoreAction(ST->getValue().getValueType(), StVT)) { default: llvm_unreachable("This action is not supported yet!"); case TargetLowering::Legal: { EVT MemVT = ST->getMemoryVT(); // If this is an unaligned store and the target doesn't support it, // expand it. if (!TLI.allowsMemoryAccessForAlignment(*DAG.getContext(), DL, MemVT, *ST->getMemOperand())) { SDValue Result = TLI.expandUnalignedStore(ST, DAG); ReplaceNode(SDValue(ST, 0), Result); } break; } case TargetLowering::Custom: { SDValue Res = TLI.LowerOperation(SDValue(Node, 0), DAG); if (Res && Res != SDValue(Node, 0)) ReplaceNode(SDValue(Node, 0), Res); return; } case TargetLowering::Expand: assert(!StVT.isVector() && "Vector Stores are handled in LegalizeVectorOps"); SDValue Result; // TRUNCSTORE:i16 i32 -> STORE i16 if (TLI.isTypeLegal(StVT)) { Value = DAG.getNode(ISD::TRUNCATE, dl, StVT, Value); Result = DAG.getStore(Chain, dl, Value, Ptr, ST->getPointerInfo(), Alignment, MMOFlags, AAInfo); } else { // The in-memory type isn't legal. Truncate to the type it would promote // to, and then do a truncstore. Value = DAG.getNode(ISD::TRUNCATE, dl, TLI.getTypeToTransformTo(*DAG.getContext(), StVT), Value); Result = DAG.getTruncStore(Chain, dl, Value, Ptr, ST->getPointerInfo(), StVT, Alignment, MMOFlags, AAInfo); } ReplaceNode(SDValue(Node, 0), Result); break; } } } void SelectionDAGLegalize::LegalizeLoadOps(SDNode *Node) { LoadSDNode *LD = cast(Node); SDValue Chain = LD->getChain(); // The chain. SDValue Ptr = LD->getBasePtr(); // The base pointer. SDValue Value; // The value returned by the load op. SDLoc dl(Node); ISD::LoadExtType ExtType = LD->getExtensionType(); if (ExtType == ISD::NON_EXTLOAD) { LLVM_DEBUG(dbgs() << "Legalizing non-extending load operation\n"); MVT VT = Node->getSimpleValueType(0); SDValue RVal = SDValue(Node, 0); SDValue RChain = SDValue(Node, 1); switch (TLI.getOperationAction(Node->getOpcode(), VT)) { default: llvm_unreachable("This action is not supported yet!"); case TargetLowering::Legal: { EVT MemVT = LD->getMemoryVT(); const DataLayout &DL = DAG.getDataLayout(); // If this is an unaligned load and the target doesn't support it, // expand it. if (!TLI.allowsMemoryAccessForAlignment(*DAG.getContext(), DL, MemVT, *LD->getMemOperand())) { std::tie(RVal, RChain) = TLI.expandUnalignedLoad(LD, DAG); } break; } case TargetLowering::Custom: if (SDValue Res = TLI.LowerOperation(RVal, DAG)) { RVal = Res; RChain = Res.getValue(1); } break; case TargetLowering::Promote: { MVT NVT = TLI.getTypeToPromoteTo(Node->getOpcode(), VT); assert(NVT.getSizeInBits() == VT.getSizeInBits() && "Can only promote loads to same size type"); SDValue Res = DAG.getLoad(NVT, dl, Chain, Ptr, LD->getMemOperand()); RVal = DAG.getNode(ISD::BITCAST, dl, VT, Res); RChain = Res.getValue(1); break; } } if (RChain.getNode() != Node) { assert(RVal.getNode() != Node && "Load must be completely replaced"); DAG.ReplaceAllUsesOfValueWith(SDValue(Node, 0), RVal); DAG.ReplaceAllUsesOfValueWith(SDValue(Node, 1), RChain); if (UpdatedNodes) { UpdatedNodes->insert(RVal.getNode()); UpdatedNodes->insert(RChain.getNode()); } ReplacedNode(Node); } return; } LLVM_DEBUG(dbgs() << "Legalizing extending load operation\n"); EVT SrcVT = LD->getMemoryVT(); unsigned SrcWidth = SrcVT.getSizeInBits(); unsigned Alignment = LD->getAlignment(); MachineMemOperand::Flags MMOFlags = LD->getMemOperand()->getFlags(); AAMDNodes AAInfo = LD->getAAInfo(); if (SrcWidth != SrcVT.getStoreSizeInBits() && // Some targets pretend to have an i1 loading operation, and actually // load an i8. This trick is correct for ZEXTLOAD because the top 7 // bits are guaranteed to be zero; it helps the optimizers understand // that these bits are zero. It is also useful for EXTLOAD, since it // tells the optimizers that those bits are undefined. It would be // nice to have an effective generic way of getting these benefits... // Until such a way is found, don't insist on promoting i1 here. (SrcVT != MVT::i1 || TLI.getLoadExtAction(ExtType, Node->getValueType(0), MVT::i1) == TargetLowering::Promote)) { // Promote to a byte-sized load if not loading an integral number of // bytes. For example, promote EXTLOAD:i20 -> EXTLOAD:i24. unsigned NewWidth = SrcVT.getStoreSizeInBits(); EVT NVT = EVT::getIntegerVT(*DAG.getContext(), NewWidth); SDValue Ch; // The extra bits are guaranteed to be zero, since we stored them that // way. A zext load from NVT thus automatically gives zext from SrcVT. ISD::LoadExtType NewExtType = ExtType == ISD::ZEXTLOAD ? ISD::ZEXTLOAD : ISD::EXTLOAD; SDValue Result = DAG.getExtLoad(NewExtType, dl, Node->getValueType(0), Chain, Ptr, LD->getPointerInfo(), NVT, Alignment, MMOFlags, AAInfo); Ch = Result.getValue(1); // The chain. if (ExtType == ISD::SEXTLOAD) // Having the top bits zero doesn't help when sign extending. Result = DAG.getNode(ISD::SIGN_EXTEND_INREG, dl, Result.getValueType(), Result, DAG.getValueType(SrcVT)); else if (ExtType == ISD::ZEXTLOAD || NVT == Result.getValueType()) // All the top bits are guaranteed to be zero - inform the optimizers. Result = DAG.getNode(ISD::AssertZext, dl, Result.getValueType(), Result, DAG.getValueType(SrcVT)); Value = Result; Chain = Ch; } else if (SrcWidth & (SrcWidth - 1)) { // If not loading a power-of-2 number of bits, expand as two loads. assert(!SrcVT.isVector() && "Unsupported extload!"); unsigned LogSrcWidth = Log2_32(SrcWidth); assert(LogSrcWidth < 32); unsigned RoundWidth = 1 << LogSrcWidth; assert(RoundWidth < SrcWidth); unsigned ExtraWidth = SrcWidth - RoundWidth; assert(ExtraWidth < RoundWidth); assert(!(RoundWidth % 8) && !(ExtraWidth % 8) && "Load size not an integral number of bytes!"); EVT RoundVT = EVT::getIntegerVT(*DAG.getContext(), RoundWidth); EVT ExtraVT = EVT::getIntegerVT(*DAG.getContext(), ExtraWidth); SDValue Lo, Hi, Ch; unsigned IncrementSize; auto &DL = DAG.getDataLayout(); if (DL.isLittleEndian()) { // EXTLOAD:i24 -> ZEXTLOAD:i16 | (shl EXTLOAD@+2:i8, 16) // Load the bottom RoundWidth bits. Lo = DAG.getExtLoad(ISD::ZEXTLOAD, dl, Node->getValueType(0), Chain, Ptr, LD->getPointerInfo(), RoundVT, Alignment, MMOFlags, AAInfo); // Load the remaining ExtraWidth bits. IncrementSize = RoundWidth / 8; Ptr = DAG.getMemBasePlusOffset(Ptr, IncrementSize, dl); Hi = DAG.getExtLoad(ExtType, dl, Node->getValueType(0), Chain, Ptr, LD->getPointerInfo().getWithOffset(IncrementSize), ExtraVT, MinAlign(Alignment, IncrementSize), MMOFlags, AAInfo); // Build a factor node to remember that this load is independent of // the other one. Ch = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, Lo.getValue(1), Hi.getValue(1)); // Move the top bits to the right place. Hi = DAG.getNode( ISD::SHL, dl, Hi.getValueType(), Hi, DAG.getConstant(RoundWidth, dl, TLI.getShiftAmountTy(Hi.getValueType(), DL))); // Join the hi and lo parts. Value = DAG.getNode(ISD::OR, dl, Node->getValueType(0), Lo, Hi); } else { // Big endian - avoid unaligned loads. // EXTLOAD:i24 -> (shl EXTLOAD:i16, 8) | ZEXTLOAD@+2:i8 // Load the top RoundWidth bits. Hi = DAG.getExtLoad(ExtType, dl, Node->getValueType(0), Chain, Ptr, LD->getPointerInfo(), RoundVT, Alignment, MMOFlags, AAInfo); // Load the remaining ExtraWidth bits. IncrementSize = RoundWidth / 8; Ptr = DAG.getMemBasePlusOffset(Ptr, IncrementSize, dl); Lo = DAG.getExtLoad(ISD::ZEXTLOAD, dl, Node->getValueType(0), Chain, Ptr, LD->getPointerInfo().getWithOffset(IncrementSize), ExtraVT, MinAlign(Alignment, IncrementSize), MMOFlags, AAInfo); // Build a factor node to remember that this load is independent of // the other one. Ch = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, Lo.getValue(1), Hi.getValue(1)); // Move the top bits to the right place. Hi = DAG.getNode( ISD::SHL, dl, Hi.getValueType(), Hi, DAG.getConstant(ExtraWidth, dl, TLI.getShiftAmountTy(Hi.getValueType(), DL))); // Join the hi and lo parts. Value = DAG.getNode(ISD::OR, dl, Node->getValueType(0), Lo, Hi); } Chain = Ch; } else { bool isCustom = false; switch (TLI.getLoadExtAction(ExtType, Node->getValueType(0), SrcVT.getSimpleVT())) { default: llvm_unreachable("This action is not supported yet!"); case TargetLowering::Custom: isCustom = true; LLVM_FALLTHROUGH; case TargetLowering::Legal: Value = SDValue(Node, 0); Chain = SDValue(Node, 1); if (isCustom) { if (SDValue Res = TLI.LowerOperation(SDValue(Node, 0), DAG)) { Value = Res; Chain = Res.getValue(1); } } else { // If this is an unaligned load and the target doesn't support it, // expand it. EVT MemVT = LD->getMemoryVT(); const DataLayout &DL = DAG.getDataLayout(); if (!TLI.allowsMemoryAccess(*DAG.getContext(), DL, MemVT, *LD->getMemOperand())) { std::tie(Value, Chain) = TLI.expandUnalignedLoad(LD, DAG); } } break; case TargetLowering::Expand: { EVT DestVT = Node->getValueType(0); if (!TLI.isLoadExtLegal(ISD::EXTLOAD, DestVT, SrcVT)) { // If the source type is not legal, see if there is a legal extload to // an intermediate type that we can then extend further. EVT LoadVT = TLI.getRegisterType(SrcVT.getSimpleVT()); if (TLI.isTypeLegal(SrcVT) || // Same as SrcVT == LoadVT? TLI.isLoadExtLegal(ExtType, LoadVT, SrcVT)) { // If we are loading a legal type, this is a non-extload followed by a // full extend. ISD::LoadExtType MidExtType = (LoadVT == SrcVT) ? ISD::NON_EXTLOAD : ExtType; SDValue Load = DAG.getExtLoad(MidExtType, dl, LoadVT, Chain, Ptr, SrcVT, LD->getMemOperand()); unsigned ExtendOp = ISD::getExtForLoadExtType(SrcVT.isFloatingPoint(), ExtType); Value = DAG.getNode(ExtendOp, dl, Node->getValueType(0), Load); Chain = Load.getValue(1); break; } // Handle the special case of fp16 extloads. EXTLOAD doesn't have the // normal undefined upper bits behavior to allow using an in-reg extend // with the illegal FP type, so load as an integer and do the // from-integer conversion. if (SrcVT.getScalarType() == MVT::f16) { EVT ISrcVT = SrcVT.changeTypeToInteger(); EVT IDestVT = DestVT.changeTypeToInteger(); EVT ILoadVT = TLI.getRegisterType(IDestVT.getSimpleVT()); SDValue Result = DAG.getExtLoad(ISD::ZEXTLOAD, dl, ILoadVT, Chain, Ptr, ISrcVT, LD->getMemOperand()); Value = DAG.getNode(ISD::FP16_TO_FP, dl, DestVT, Result); Chain = Result.getValue(1); break; } } assert(!SrcVT.isVector() && "Vector Loads are handled in LegalizeVectorOps"); // FIXME: This does not work for vectors on most targets. Sign- // and zero-extend operations are currently folded into extending // loads, whether they are legal or not, and then we end up here // without any support for legalizing them. assert(ExtType != ISD::EXTLOAD && "EXTLOAD should always be supported!"); // Turn the unsupported load into an EXTLOAD followed by an // explicit zero/sign extend inreg. SDValue Result = DAG.getExtLoad(ISD::EXTLOAD, dl, Node->getValueType(0), Chain, Ptr, SrcVT, LD->getMemOperand()); SDValue ValRes; if (ExtType == ISD::SEXTLOAD) ValRes = DAG.getNode(ISD::SIGN_EXTEND_INREG, dl, Result.getValueType(), Result, DAG.getValueType(SrcVT)); else ValRes = DAG.getZeroExtendInReg(Result, dl, SrcVT.getScalarType()); Value = ValRes; Chain = Result.getValue(1); break; } } } // Since loads produce two values, make sure to remember that we legalized // both of them. if (Chain.getNode() != Node) { assert(Value.getNode() != Node && "Load must be completely replaced"); DAG.ReplaceAllUsesOfValueWith(SDValue(Node, 0), Value); DAG.ReplaceAllUsesOfValueWith(SDValue(Node, 1), Chain); if (UpdatedNodes) { UpdatedNodes->insert(Value.getNode()); UpdatedNodes->insert(Chain.getNode()); } ReplacedNode(Node); } } /// Return a legal replacement for the given operation, with all legal operands. void SelectionDAGLegalize::LegalizeOp(SDNode *Node) { LLVM_DEBUG(dbgs() << "\nLegalizing: "; Node->dump(&DAG)); // Allow illegal target nodes and illegal registers. if (Node->getOpcode() == ISD::TargetConstant || Node->getOpcode() == ISD::Register) return; #ifndef NDEBUG for (unsigned i = 0, e = Node->getNumValues(); i != e; ++i) assert(TLI.getTypeAction(*DAG.getContext(), Node->getValueType(i)) == TargetLowering::TypeLegal && "Unexpected illegal type!"); for (const SDValue &Op : Node->op_values()) assert((TLI.getTypeAction(*DAG.getContext(), Op.getValueType()) == TargetLowering::TypeLegal || Op.getOpcode() == ISD::TargetConstant || Op.getOpcode() == ISD::Register) && "Unexpected illegal type!"); #endif // Figure out the correct action; the way to query this varies by opcode TargetLowering::LegalizeAction Action = TargetLowering::Legal; bool SimpleFinishLegalizing = true; switch (Node->getOpcode()) { case ISD::INTRINSIC_W_CHAIN: case ISD::INTRINSIC_WO_CHAIN: case ISD::INTRINSIC_VOID: case ISD::STACKSAVE: Action = TLI.getOperationAction(Node->getOpcode(), MVT::Other); break; case ISD::GET_DYNAMIC_AREA_OFFSET: Action = TLI.getOperationAction(Node->getOpcode(), Node->getValueType(0)); break; case ISD::VAARG: Action = TLI.getOperationAction(Node->getOpcode(), Node->getValueType(0)); if (Action != TargetLowering::Promote) Action = TLI.getOperationAction(Node->getOpcode(), MVT::Other); break; case ISD::FP_TO_FP16: case ISD::SINT_TO_FP: case ISD::UINT_TO_FP: case ISD::EXTRACT_VECTOR_ELT: case ISD::LROUND: case ISD::LLROUND: case ISD::LRINT: case ISD::LLRINT: Action = TLI.getOperationAction(Node->getOpcode(), Node->getOperand(0).getValueType()); break; case ISD::STRICT_SINT_TO_FP: case ISD::STRICT_UINT_TO_FP: case ISD::STRICT_LRINT: case ISD::STRICT_LLRINT: case ISD::STRICT_LROUND: case ISD::STRICT_LLROUND: // These pseudo-ops are the same as the other STRICT_ ops except // they are registered with setOperationAction() using the input type // instead of the output type. Action = TLI.getOperationAction(Node->getOpcode(), Node->getOperand(1).getValueType()); break; case ISD::SIGN_EXTEND_INREG: { EVT InnerType = cast(Node->getOperand(1))->getVT(); Action = TLI.getOperationAction(Node->getOpcode(), InnerType); break; } case ISD::ATOMIC_STORE: Action = TLI.getOperationAction(Node->getOpcode(), Node->getOperand(2).getValueType()); break; case ISD::SELECT_CC: case ISD::STRICT_FSETCC: case ISD::STRICT_FSETCCS: case ISD::SETCC: case ISD::BR_CC: { unsigned CCOperand = Node->getOpcode() == ISD::SELECT_CC ? 4 : Node->getOpcode() == ISD::STRICT_FSETCC ? 3 : Node->getOpcode() == ISD::STRICT_FSETCCS ? 3 : Node->getOpcode() == ISD::SETCC ? 2 : 1; unsigned CompareOperand = Node->getOpcode() == ISD::BR_CC ? 2 : Node->getOpcode() == ISD::STRICT_FSETCC ? 1 : Node->getOpcode() == ISD::STRICT_FSETCCS ? 1 : 0; MVT OpVT = Node->getOperand(CompareOperand).getSimpleValueType(); ISD::CondCode CCCode = cast(Node->getOperand(CCOperand))->get(); Action = TLI.getCondCodeAction(CCCode, OpVT); if (Action == TargetLowering::Legal) { if (Node->getOpcode() == ISD::SELECT_CC) Action = TLI.getOperationAction(Node->getOpcode(), Node->getValueType(0)); else Action = TLI.getOperationAction(Node->getOpcode(), OpVT); } break; } case ISD::LOAD: case ISD::STORE: // FIXME: Model these properly. LOAD and STORE are complicated, and // STORE expects the unlegalized operand in some cases. SimpleFinishLegalizing = false; break; case ISD::CALLSEQ_START: case ISD::CALLSEQ_END: // FIXME: This shouldn't be necessary. These nodes have special properties // dealing with the recursive nature of legalization. Removing this // special case should be done as part of making LegalizeDAG non-recursive. SimpleFinishLegalizing = false; break; case ISD::EXTRACT_ELEMENT: case ISD::FLT_ROUNDS_: case ISD::MERGE_VALUES: case ISD::EH_RETURN: case ISD::FRAME_TO_ARGS_OFFSET: case ISD::EH_DWARF_CFA: case ISD::EH_SJLJ_SETJMP: case ISD::EH_SJLJ_LONGJMP: case ISD::EH_SJLJ_SETUP_DISPATCH: // These operations lie about being legal: when they claim to be legal, // they should actually be expanded. Action = TLI.getOperationAction(Node->getOpcode(), Node->getValueType(0)); if (Action == TargetLowering::Legal) Action = TargetLowering::Expand; break; case ISD::INIT_TRAMPOLINE: case ISD::ADJUST_TRAMPOLINE: case ISD::FRAMEADDR: case ISD::RETURNADDR: case ISD::ADDROFRETURNADDR: case ISD::SPONENTRY: // These operations lie about being legal: when they claim to be legal, // they should actually be custom-lowered. Action = TLI.getOperationAction(Node->getOpcode(), Node->getValueType(0)); if (Action == TargetLowering::Legal) Action = TargetLowering::Custom; break; case ISD::READCYCLECOUNTER: // READCYCLECOUNTER returns an i64, even if type legalization might have // expanded that to several smaller types. Action = TLI.getOperationAction(Node->getOpcode(), MVT::i64); break; case ISD::READ_REGISTER: case ISD::WRITE_REGISTER: // Named register is legal in the DAG, but blocked by register name // selection if not implemented by target (to chose the correct register) // They'll be converted to Copy(To/From)Reg. Action = TargetLowering::Legal; break; case ISD::DEBUGTRAP: Action = TLI.getOperationAction(Node->getOpcode(), Node->getValueType(0)); if (Action == TargetLowering::Expand) { // replace ISD::DEBUGTRAP with ISD::TRAP SDValue NewVal; NewVal = DAG.getNode(ISD::TRAP, SDLoc(Node), Node->getVTList(), Node->getOperand(0)); ReplaceNode(Node, NewVal.getNode()); LegalizeOp(NewVal.getNode()); return; } break; case ISD::SADDSAT: case ISD::UADDSAT: case ISD::SSUBSAT: case ISD::USUBSAT: { Action = TLI.getOperationAction(Node->getOpcode(), Node->getValueType(0)); break; } case ISD::SMULFIX: case ISD::SMULFIXSAT: case ISD::UMULFIX: case ISD::UMULFIXSAT: case ISD::SDIVFIX: case ISD::UDIVFIX: { unsigned Scale = Node->getConstantOperandVal(2); Action = TLI.getFixedPointOperationAction(Node->getOpcode(), Node->getValueType(0), Scale); break; } case ISD::MSCATTER: Action = TLI.getOperationAction(Node->getOpcode(), cast(Node)->getValue().getValueType()); break; case ISD::MSTORE: Action = TLI.getOperationAction(Node->getOpcode(), cast(Node)->getValue().getValueType()); break; case ISD::VECREDUCE_FADD: case ISD::VECREDUCE_FMUL: case ISD::VECREDUCE_ADD: case ISD::VECREDUCE_MUL: case ISD::VECREDUCE_AND: case ISD::VECREDUCE_OR: case ISD::VECREDUCE_XOR: case ISD::VECREDUCE_SMAX: case ISD::VECREDUCE_SMIN: case ISD::VECREDUCE_UMAX: case ISD::VECREDUCE_UMIN: case ISD::VECREDUCE_FMAX: case ISD::VECREDUCE_FMIN: Action = TLI.getOperationAction( Node->getOpcode(), Node->getOperand(0).getValueType()); break; default: if (Node->getOpcode() >= ISD::BUILTIN_OP_END) { Action = TargetLowering::Legal; } else { Action = TLI.getOperationAction(Node->getOpcode(), Node->getValueType(0)); } break; } if (SimpleFinishLegalizing) { SDNode *NewNode = Node; switch (Node->getOpcode()) { default: break; case ISD::SHL: case ISD::SRL: case ISD::SRA: case ISD::ROTL: case ISD::ROTR: { // Legalizing shifts/rotates requires adjusting the shift amount // to the appropriate width. SDValue Op0 = Node->getOperand(0); SDValue Op1 = Node->getOperand(1); if (!Op1.getValueType().isVector()) { SDValue SAO = DAG.getShiftAmountOperand(Op0.getValueType(), Op1); // The getShiftAmountOperand() may create a new operand node or // return the existing one. If new operand is created we need // to update the parent node. // Do not try to legalize SAO here! It will be automatically legalized // in the next round. if (SAO != Op1) NewNode = DAG.UpdateNodeOperands(Node, Op0, SAO); } } break; case ISD::FSHL: case ISD::FSHR: case ISD::SRL_PARTS: case ISD::SRA_PARTS: case ISD::SHL_PARTS: { // Legalizing shifts/rotates requires adjusting the shift amount // to the appropriate width. SDValue Op0 = Node->getOperand(0); SDValue Op1 = Node->getOperand(1); SDValue Op2 = Node->getOperand(2); if (!Op2.getValueType().isVector()) { SDValue SAO = DAG.getShiftAmountOperand(Op0.getValueType(), Op2); // The getShiftAmountOperand() may create a new operand node or // return the existing one. If new operand is created we need // to update the parent node. if (SAO != Op2) NewNode = DAG.UpdateNodeOperands(Node, Op0, Op1, SAO); } break; } } if (NewNode != Node) { ReplaceNode(Node, NewNode); Node = NewNode; } switch (Action) { case TargetLowering::Legal: LLVM_DEBUG(dbgs() << "Legal node: nothing to do\n"); return; case TargetLowering::Custom: LLVM_DEBUG(dbgs() << "Trying custom legalization\n"); // FIXME: The handling for custom lowering with multiple results is // a complete mess. if (SDValue Res = TLI.LowerOperation(SDValue(Node, 0), DAG)) { if (!(Res.getNode() != Node || Res.getResNo() != 0)) return; if (Node->getNumValues() == 1) { LLVM_DEBUG(dbgs() << "Successfully custom legalized node\n"); // We can just directly replace this node with the lowered value. ReplaceNode(SDValue(Node, 0), Res); return; } SmallVector ResultVals; for (unsigned i = 0, e = Node->getNumValues(); i != e; ++i) ResultVals.push_back(Res.getValue(i)); LLVM_DEBUG(dbgs() << "Successfully custom legalized node\n"); ReplaceNode(Node, ResultVals.data()); return; } LLVM_DEBUG(dbgs() << "Could not custom legalize node\n"); LLVM_FALLTHROUGH; case TargetLowering::Expand: if (ExpandNode(Node)) return; LLVM_FALLTHROUGH; case TargetLowering::LibCall: ConvertNodeToLibcall(Node); return; case TargetLowering::Promote: PromoteNode(Node); return; } } switch (Node->getOpcode()) { default: #ifndef NDEBUG dbgs() << "NODE: "; Node->dump( &DAG); dbgs() << "\n"; #endif llvm_unreachable("Do not know how to legalize this operator!"); case ISD::CALLSEQ_START: case ISD::CALLSEQ_END: break; case ISD::LOAD: return LegalizeLoadOps(Node); case ISD::STORE: return LegalizeStoreOps(Node); } } SDValue SelectionDAGLegalize::ExpandExtractFromVectorThroughStack(SDValue Op) { SDValue Vec = Op.getOperand(0); SDValue Idx = Op.getOperand(1); SDLoc dl(Op); // Before we generate a new store to a temporary stack slot, see if there is // already one that we can use. There often is because when we scalarize // vector operations (using SelectionDAG::UnrollVectorOp for example) a whole // series of EXTRACT_VECTOR_ELT nodes are generated, one for each element in // the vector. If all are expanded here, we don't want one store per vector // element. // Caches for hasPredecessorHelper SmallPtrSet Visited; SmallVector Worklist; Visited.insert(Op.getNode()); Worklist.push_back(Idx.getNode()); SDValue StackPtr, Ch; for (SDNode::use_iterator UI = Vec.getNode()->use_begin(), UE = Vec.getNode()->use_end(); UI != UE; ++UI) { SDNode *User = *UI; if (StoreSDNode *ST = dyn_cast(User)) { if (ST->isIndexed() || ST->isTruncatingStore() || ST->getValue() != Vec) continue; // Make sure that nothing else could have stored into the destination of // this store. if (!ST->getChain().reachesChainWithoutSideEffects(DAG.getEntryNode())) continue; // If the index is dependent on the store we will introduce a cycle when // creating the load (the load uses the index, and by replacing the chain // we will make the index dependent on the load). Also, the store might be // dependent on the extractelement and introduce a cycle when creating // the load. if (SDNode::hasPredecessorHelper(ST, Visited, Worklist) || ST->hasPredecessor(Op.getNode())) continue; StackPtr = ST->getBasePtr(); Ch = SDValue(ST, 0); break; } } EVT VecVT = Vec.getValueType(); if (!Ch.getNode()) { // Store the value to a temporary stack slot, then LOAD the returned part. StackPtr = DAG.CreateStackTemporary(VecVT); Ch = DAG.getStore(DAG.getEntryNode(), dl, Vec, StackPtr, MachinePointerInfo()); } StackPtr = TLI.getVectorElementPointer(DAG, StackPtr, VecVT, Idx); SDValue NewLoad; if (Op.getValueType().isVector()) NewLoad = DAG.getLoad(Op.getValueType(), dl, Ch, StackPtr, MachinePointerInfo()); else NewLoad = DAG.getExtLoad(ISD::EXTLOAD, dl, Op.getValueType(), Ch, StackPtr, MachinePointerInfo(), VecVT.getVectorElementType()); // Replace the chain going out of the store, by the one out of the load. DAG.ReplaceAllUsesOfValueWith(Ch, SDValue(NewLoad.getNode(), 1)); // We introduced a cycle though, so update the loads operands, making sure // to use the original store's chain as an incoming chain. SmallVector NewLoadOperands(NewLoad->op_begin(), NewLoad->op_end()); NewLoadOperands[0] = Ch; NewLoad = SDValue(DAG.UpdateNodeOperands(NewLoad.getNode(), NewLoadOperands), 0); return NewLoad; } SDValue SelectionDAGLegalize::ExpandInsertToVectorThroughStack(SDValue Op) { assert(Op.getValueType().isVector() && "Non-vector insert subvector!"); SDValue Vec = Op.getOperand(0); SDValue Part = Op.getOperand(1); SDValue Idx = Op.getOperand(2); SDLoc dl(Op); // Store the value to a temporary stack slot, then LOAD the returned part. EVT VecVT = Vec.getValueType(); SDValue StackPtr = DAG.CreateStackTemporary(VecVT); int FI = cast(StackPtr.getNode())->getIndex(); MachinePointerInfo PtrInfo = MachinePointerInfo::getFixedStack(DAG.getMachineFunction(), FI); // First store the whole vector. SDValue Ch = DAG.getStore(DAG.getEntryNode(), dl, Vec, StackPtr, PtrInfo); // Then store the inserted part. SDValue SubStackPtr = TLI.getVectorElementPointer(DAG, StackPtr, VecVT, Idx); // Store the subvector. Ch = DAG.getStore(Ch, dl, Part, SubStackPtr, MachinePointerInfo()); // Finally, load the updated vector. return DAG.getLoad(Op.getValueType(), dl, Ch, StackPtr, PtrInfo); } SDValue SelectionDAGLegalize::ExpandVectorBuildThroughStack(SDNode* Node) { // We can't handle this case efficiently. Allocate a sufficiently // aligned object on the stack, store each element into it, then load // the result as a vector. // Create the stack frame object. EVT VT = Node->getValueType(0); EVT EltVT = VT.getVectorElementType(); SDLoc dl(Node); SDValue FIPtr = DAG.CreateStackTemporary(VT); int FI = cast(FIPtr.getNode())->getIndex(); MachinePointerInfo PtrInfo = MachinePointerInfo::getFixedStack(DAG.getMachineFunction(), FI); // Emit a store of each element to the stack slot. SmallVector Stores; unsigned TypeByteSize = EltVT.getSizeInBits() / 8; assert(TypeByteSize > 0 && "Vector element type too small for stack store!"); // Store (in the right endianness) the elements to memory. for (unsigned i = 0, e = Node->getNumOperands(); i != e; ++i) { // Ignore undef elements. if (Node->getOperand(i).isUndef()) continue; unsigned Offset = TypeByteSize*i; SDValue Idx = DAG.getConstant(Offset, dl, FIPtr.getValueType()); Idx = DAG.getMemBasePlusOffset(FIPtr, Idx, dl); // If the destination vector element type is narrower than the source // element type, only store the bits necessary. if (EltVT.bitsLT(Node->getOperand(i).getValueType().getScalarType())) { Stores.push_back(DAG.getTruncStore(DAG.getEntryNode(), dl, Node->getOperand(i), Idx, PtrInfo.getWithOffset(Offset), EltVT)); } else Stores.push_back(DAG.getStore(DAG.getEntryNode(), dl, Node->getOperand(i), Idx, PtrInfo.getWithOffset(Offset))); } SDValue StoreChain; if (!Stores.empty()) // Not all undef elements? StoreChain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, Stores); else StoreChain = DAG.getEntryNode(); // Result is a load from the stack slot. return DAG.getLoad(VT, dl, StoreChain, FIPtr, PtrInfo); } /// Bitcast a floating-point value to an integer value. Only bitcast the part /// containing the sign bit if the target has no integer value capable of /// holding all bits of the floating-point value. void SelectionDAGLegalize::getSignAsIntValue(FloatSignAsInt &State, const SDLoc &DL, SDValue Value) const { EVT FloatVT = Value.getValueType(); unsigned NumBits = FloatVT.getSizeInBits(); State.FloatVT = FloatVT; EVT IVT = EVT::getIntegerVT(*DAG.getContext(), NumBits); // Convert to an integer of the same size. if (TLI.isTypeLegal(IVT)) { State.IntValue = DAG.getNode(ISD::BITCAST, DL, IVT, Value); State.SignMask = APInt::getSignMask(NumBits); State.SignBit = NumBits - 1; return; } auto &DataLayout = DAG.getDataLayout(); // Store the float to memory, then load the sign part out as an integer. MVT LoadTy = TLI.getRegisterType(*DAG.getContext(), MVT::i8); // First create a temporary that is aligned for both the load and store. SDValue StackPtr = DAG.CreateStackTemporary(FloatVT, LoadTy); int FI = cast(StackPtr.getNode())->getIndex(); // Then store the float to it. State.FloatPtr = StackPtr; MachineFunction &MF = DAG.getMachineFunction(); State.FloatPointerInfo = MachinePointerInfo::getFixedStack(MF, FI); State.Chain = DAG.getStore(DAG.getEntryNode(), DL, Value, State.FloatPtr, State.FloatPointerInfo); SDValue IntPtr; if (DataLayout.isBigEndian()) { assert(FloatVT.isByteSized() && "Unsupported floating point type!"); // Load out a legal integer with the same sign bit as the float. IntPtr = StackPtr; State.IntPointerInfo = State.FloatPointerInfo; } else { // Advance the pointer so that the loaded byte will contain the sign bit. unsigned ByteOffset = (FloatVT.getSizeInBits() / 8) - 1; IntPtr = DAG.getMemBasePlusOffset(StackPtr, ByteOffset, DL); State.IntPointerInfo = MachinePointerInfo::getFixedStack(MF, FI, ByteOffset); } State.IntPtr = IntPtr; State.IntValue = DAG.getExtLoad(ISD::EXTLOAD, DL, LoadTy, State.Chain, IntPtr, State.IntPointerInfo, MVT::i8); State.SignMask = APInt::getOneBitSet(LoadTy.getSizeInBits(), 7); State.SignBit = 7; } /// Replace the integer value produced by getSignAsIntValue() with a new value /// and cast the result back to a floating-point type. SDValue SelectionDAGLegalize::modifySignAsInt(const FloatSignAsInt &State, const SDLoc &DL, SDValue NewIntValue) const { if (!State.Chain) return DAG.getNode(ISD::BITCAST, DL, State.FloatVT, NewIntValue); // Override the part containing the sign bit in the value stored on the stack. SDValue Chain = DAG.getTruncStore(State.Chain, DL, NewIntValue, State.IntPtr, State.IntPointerInfo, MVT::i8); return DAG.getLoad(State.FloatVT, DL, Chain, State.FloatPtr, State.FloatPointerInfo); } SDValue SelectionDAGLegalize::ExpandFCOPYSIGN(SDNode *Node) const { SDLoc DL(Node); SDValue Mag = Node->getOperand(0); SDValue Sign = Node->getOperand(1); // Get sign bit into an integer value. FloatSignAsInt SignAsInt; getSignAsIntValue(SignAsInt, DL, Sign); EVT IntVT = SignAsInt.IntValue.getValueType(); SDValue SignMask = DAG.getConstant(SignAsInt.SignMask, DL, IntVT); SDValue SignBit = DAG.getNode(ISD::AND, DL, IntVT, SignAsInt.IntValue, SignMask); // If FABS is legal transform FCOPYSIGN(x, y) => sign(x) ? -FABS(x) : FABS(X) EVT FloatVT = Mag.getValueType(); if (TLI.isOperationLegalOrCustom(ISD::FABS, FloatVT) && TLI.isOperationLegalOrCustom(ISD::FNEG, FloatVT)) { SDValue AbsValue = DAG.getNode(ISD::FABS, DL, FloatVT, Mag); SDValue NegValue = DAG.getNode(ISD::FNEG, DL, FloatVT, AbsValue); SDValue Cond = DAG.getSetCC(DL, getSetCCResultType(IntVT), SignBit, DAG.getConstant(0, DL, IntVT), ISD::SETNE); return DAG.getSelect(DL, FloatVT, Cond, NegValue, AbsValue); } // Transform Mag value to integer, and clear the sign bit. FloatSignAsInt MagAsInt; getSignAsIntValue(MagAsInt, DL, Mag); EVT MagVT = MagAsInt.IntValue.getValueType(); SDValue ClearSignMask = DAG.getConstant(~MagAsInt.SignMask, DL, MagVT); SDValue ClearedSign = DAG.getNode(ISD::AND, DL, MagVT, MagAsInt.IntValue, ClearSignMask); // Get the signbit at the right position for MagAsInt. int ShiftAmount = SignAsInt.SignBit - MagAsInt.SignBit; EVT ShiftVT = IntVT; if (SignBit.getValueSizeInBits() < ClearedSign.getValueSizeInBits()) { SignBit = DAG.getNode(ISD::ZERO_EXTEND, DL, MagVT, SignBit); ShiftVT = MagVT; } if (ShiftAmount > 0) { SDValue ShiftCnst = DAG.getConstant(ShiftAmount, DL, ShiftVT); SignBit = DAG.getNode(ISD::SRL, DL, ShiftVT, SignBit, ShiftCnst); } else if (ShiftAmount < 0) { SDValue ShiftCnst = DAG.getConstant(-ShiftAmount, DL, ShiftVT); SignBit = DAG.getNode(ISD::SHL, DL, ShiftVT, SignBit, ShiftCnst); } if (SignBit.getValueSizeInBits() > ClearedSign.getValueSizeInBits()) { SignBit = DAG.getNode(ISD::TRUNCATE, DL, MagVT, SignBit); } // Store the part with the modified sign and convert back to float. SDValue CopiedSign = DAG.getNode(ISD::OR, DL, MagVT, ClearedSign, SignBit); return modifySignAsInt(MagAsInt, DL, CopiedSign); } SDValue SelectionDAGLegalize::ExpandFABS(SDNode *Node) const { SDLoc DL(Node); SDValue Value = Node->getOperand(0); // Transform FABS(x) => FCOPYSIGN(x, 0.0) if FCOPYSIGN is legal. EVT FloatVT = Value.getValueType(); if (TLI.isOperationLegalOrCustom(ISD::FCOPYSIGN, FloatVT)) { SDValue Zero = DAG.getConstantFP(0.0, DL, FloatVT); return DAG.getNode(ISD::FCOPYSIGN, DL, FloatVT, Value, Zero); } // Transform value to integer, clear the sign bit and transform back. FloatSignAsInt ValueAsInt; getSignAsIntValue(ValueAsInt, DL, Value); EVT IntVT = ValueAsInt.IntValue.getValueType(); SDValue ClearSignMask = DAG.getConstant(~ValueAsInt.SignMask, DL, IntVT); SDValue ClearedSign = DAG.getNode(ISD::AND, DL, IntVT, ValueAsInt.IntValue, ClearSignMask); return modifySignAsInt(ValueAsInt, DL, ClearedSign); } void SelectionDAGLegalize::ExpandDYNAMIC_STACKALLOC(SDNode* Node, SmallVectorImpl &Results) { unsigned SPReg = TLI.getStackPointerRegisterToSaveRestore(); assert(SPReg && "Target cannot require DYNAMIC_STACKALLOC expansion and" " not tell us which reg is the stack pointer!"); SDLoc dl(Node); EVT VT = Node->getValueType(0); SDValue Tmp1 = SDValue(Node, 0); SDValue Tmp2 = SDValue(Node, 1); SDValue Tmp3 = Node->getOperand(2); SDValue Chain = Tmp1.getOperand(0); // Chain the dynamic stack allocation so that it doesn't modify the stack // pointer when other instructions are using the stack. Chain = DAG.getCALLSEQ_START(Chain, 0, 0, dl); SDValue Size = Tmp2.getOperand(1); SDValue SP = DAG.getCopyFromReg(Chain, dl, SPReg, VT); Chain = SP.getValue(1); unsigned Align = cast(Tmp3)->getZExtValue(); unsigned StackAlign = DAG.getSubtarget().getFrameLowering()->getStackAlignment(); Tmp1 = DAG.getNode(ISD::SUB, dl, VT, SP, Size); // Value if (Align > StackAlign) Tmp1 = DAG.getNode(ISD::AND, dl, VT, Tmp1, DAG.getConstant(-(uint64_t)Align, dl, VT)); Chain = DAG.getCopyToReg(Chain, dl, SPReg, Tmp1); // Output chain Tmp2 = DAG.getCALLSEQ_END(Chain, DAG.getIntPtrConstant(0, dl, true), DAG.getIntPtrConstant(0, dl, true), SDValue(), dl); Results.push_back(Tmp1); Results.push_back(Tmp2); } /// Legalize a SETCC with given LHS and RHS and condition code CC on the current /// target. /// /// If the SETCC has been legalized using AND / OR, then the legalized node /// will be stored in LHS. RHS and CC will be set to SDValue(). NeedInvert /// will be set to false. /// /// If the SETCC has been legalized by using getSetCCSwappedOperands(), /// then the values of LHS and RHS will be swapped, CC will be set to the /// new condition, and NeedInvert will be set to false. /// /// If the SETCC has been legalized using the inverse condcode, then LHS and /// RHS will be unchanged, CC will set to the inverted condcode, and NeedInvert /// will be set to true. The caller must invert the result of the SETCC with /// SelectionDAG::getLogicalNOT() or take equivalent action to swap the effect /// of a true/false result. /// /// \returns true if the SetCC has been legalized, false if it hasn't. bool SelectionDAGLegalize::LegalizeSetCCCondCode( EVT VT, SDValue &LHS, SDValue &RHS, SDValue &CC, bool &NeedInvert, const SDLoc &dl, SDValue &Chain, bool IsSignaling) { MVT OpVT = LHS.getSimpleValueType(); ISD::CondCode CCCode = cast(CC)->get(); NeedInvert = false; switch (TLI.getCondCodeAction(CCCode, OpVT)) { default: llvm_unreachable("Unknown condition code action!"); case TargetLowering::Legal: // Nothing to do. break; case TargetLowering::Expand: { ISD::CondCode InvCC = ISD::getSetCCSwappedOperands(CCCode); if (TLI.isCondCodeLegalOrCustom(InvCC, OpVT)) { std::swap(LHS, RHS); CC = DAG.getCondCode(InvCC); return true; } // Swapping operands didn't work. Try inverting the condition. bool NeedSwap = false; InvCC = getSetCCInverse(CCCode, OpVT); if (!TLI.isCondCodeLegalOrCustom(InvCC, OpVT)) { // If inverting the condition is not enough, try swapping operands // on top of it. InvCC = ISD::getSetCCSwappedOperands(InvCC); NeedSwap = true; } if (TLI.isCondCodeLegalOrCustom(InvCC, OpVT)) { CC = DAG.getCondCode(InvCC); NeedInvert = true; if (NeedSwap) std::swap(LHS, RHS); return true; } ISD::CondCode CC1 = ISD::SETCC_INVALID, CC2 = ISD::SETCC_INVALID; unsigned Opc = 0; switch (CCCode) { default: llvm_unreachable("Don't know how to expand this condition!"); case ISD::SETO: assert(TLI.isCondCodeLegal(ISD::SETOEQ, OpVT) && "If SETO is expanded, SETOEQ must be legal!"); CC1 = ISD::SETOEQ; CC2 = ISD::SETOEQ; Opc = ISD::AND; break; case ISD::SETUO: assert(TLI.isCondCodeLegal(ISD::SETUNE, OpVT) && "If SETUO is expanded, SETUNE must be legal!"); CC1 = ISD::SETUNE; CC2 = ISD::SETUNE; Opc = ISD::OR; break; case ISD::SETOEQ: case ISD::SETOGT: case ISD::SETOGE: case ISD::SETOLT: case ISD::SETOLE: case ISD::SETONE: case ISD::SETUEQ: case ISD::SETUNE: case ISD::SETUGT: case ISD::SETUGE: case ISD::SETULT: case ISD::SETULE: // If we are floating point, assign and break, otherwise fall through. if (!OpVT.isInteger()) { // We can use the 4th bit to tell if we are the unordered // or ordered version of the opcode. CC2 = ((unsigned)CCCode & 0x8U) ? ISD::SETUO : ISD::SETO; Opc = ((unsigned)CCCode & 0x8U) ? ISD::OR : ISD::AND; CC1 = (ISD::CondCode)(((int)CCCode & 0x7) | 0x10); break; } // Fallthrough if we are unsigned integer. LLVM_FALLTHROUGH; case ISD::SETLE: case ISD::SETGT: case ISD::SETGE: case ISD::SETLT: case ISD::SETNE: case ISD::SETEQ: // If all combinations of inverting the condition and swapping operands // didn't work then we have no means to expand the condition. llvm_unreachable("Don't know how to expand this condition!"); } SDValue SetCC1, SetCC2; if (CCCode != ISD::SETO && CCCode != ISD::SETUO) { // If we aren't the ordered or unorder operation, // then the pattern is (LHS CC1 RHS) Opc (LHS CC2 RHS). SetCC1 = DAG.getSetCC(dl, VT, LHS, RHS, CC1, Chain, IsSignaling); SetCC2 = DAG.getSetCC(dl, VT, LHS, RHS, CC2, Chain, IsSignaling); } else { // Otherwise, the pattern is (LHS CC1 LHS) Opc (RHS CC2 RHS) SetCC1 = DAG.getSetCC(dl, VT, LHS, LHS, CC1, Chain, IsSignaling); SetCC2 = DAG.getSetCC(dl, VT, RHS, RHS, CC2, Chain, IsSignaling); } if (Chain) Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, SetCC1.getValue(1), SetCC2.getValue(1)); LHS = DAG.getNode(Opc, dl, VT, SetCC1, SetCC2); RHS = SDValue(); CC = SDValue(); return true; } } return false; } /// Emit a store/load combination to the stack. This stores /// SrcOp to a stack slot of type SlotVT, truncating it if needed. It then does /// a load from the stack slot to DestVT, extending it if needed. /// The resultant code need not be legal. SDValue SelectionDAGLegalize::EmitStackConvert(SDValue SrcOp, EVT SlotVT, EVT DestVT, const SDLoc &dl) { return EmitStackConvert(SrcOp, SlotVT, DestVT, dl, DAG.getEntryNode()); } SDValue SelectionDAGLegalize::EmitStackConvert(SDValue SrcOp, EVT SlotVT, EVT DestVT, const SDLoc &dl, SDValue Chain) { // Create the stack frame object. unsigned SrcAlign = DAG.getDataLayout().getPrefTypeAlignment( SrcOp.getValueType().getTypeForEVT(*DAG.getContext())); SDValue FIPtr = DAG.CreateStackTemporary(SlotVT, SrcAlign); FrameIndexSDNode *StackPtrFI = cast(FIPtr); int SPFI = StackPtrFI->getIndex(); MachinePointerInfo PtrInfo = MachinePointerInfo::getFixedStack(DAG.getMachineFunction(), SPFI); unsigned SrcSize = SrcOp.getValueSizeInBits(); unsigned SlotSize = SlotVT.getSizeInBits(); unsigned DestSize = DestVT.getSizeInBits(); Type *DestType = DestVT.getTypeForEVT(*DAG.getContext()); unsigned DestAlign = DAG.getDataLayout().getPrefTypeAlignment(DestType); // Emit a store to the stack slot. Use a truncstore if the input value is // later than DestVT. SDValue Store; if (SrcSize > SlotSize) Store = DAG.getTruncStore(Chain, dl, SrcOp, FIPtr, PtrInfo, SlotVT, SrcAlign); else { assert(SrcSize == SlotSize && "Invalid store"); Store = DAG.getStore(Chain, dl, SrcOp, FIPtr, PtrInfo, SrcAlign); } // Result is a load from the stack slot. if (SlotSize == DestSize) return DAG.getLoad(DestVT, dl, Store, FIPtr, PtrInfo, DestAlign); assert(SlotSize < DestSize && "Unknown extension!"); return DAG.getExtLoad(ISD::EXTLOAD, dl, DestVT, Store, FIPtr, PtrInfo, SlotVT, DestAlign); } SDValue SelectionDAGLegalize::ExpandSCALAR_TO_VECTOR(SDNode *Node) { SDLoc dl(Node); // Create a vector sized/aligned stack slot, store the value to element #0, // then load the whole vector back out. SDValue StackPtr = DAG.CreateStackTemporary(Node->getValueType(0)); FrameIndexSDNode *StackPtrFI = cast(StackPtr); int SPFI = StackPtrFI->getIndex(); SDValue Ch = DAG.getTruncStore( DAG.getEntryNode(), dl, Node->getOperand(0), StackPtr, MachinePointerInfo::getFixedStack(DAG.getMachineFunction(), SPFI), Node->getValueType(0).getVectorElementType()); return DAG.getLoad( Node->getValueType(0), dl, Ch, StackPtr, MachinePointerInfo::getFixedStack(DAG.getMachineFunction(), SPFI)); } static bool ExpandBVWithShuffles(SDNode *Node, SelectionDAG &DAG, const TargetLowering &TLI, SDValue &Res) { unsigned NumElems = Node->getNumOperands(); SDLoc dl(Node); EVT VT = Node->getValueType(0); // Try to group the scalars into pairs, shuffle the pairs together, then // shuffle the pairs of pairs together, etc. until the vector has // been built. This will work only if all of the necessary shuffle masks // are legal. // We do this in two phases; first to check the legality of the shuffles, // and next, assuming that all shuffles are legal, to create the new nodes. for (int Phase = 0; Phase < 2; ++Phase) { SmallVector>, 16> IntermedVals, NewIntermedVals; for (unsigned i = 0; i < NumElems; ++i) { SDValue V = Node->getOperand(i); if (V.isUndef()) continue; SDValue Vec; if (Phase) Vec = DAG.getNode(ISD::SCALAR_TO_VECTOR, dl, VT, V); IntermedVals.push_back(std::make_pair(Vec, SmallVector(1, i))); } while (IntermedVals.size() > 2) { NewIntermedVals.clear(); for (unsigned i = 0, e = (IntermedVals.size() & ~1u); i < e; i += 2) { // This vector and the next vector are shuffled together (simply to // append the one to the other). SmallVector ShuffleVec(NumElems, -1); SmallVector FinalIndices; FinalIndices.reserve(IntermedVals[i].second.size() + IntermedVals[i+1].second.size()); int k = 0; for (unsigned j = 0, f = IntermedVals[i].second.size(); j != f; ++j, ++k) { ShuffleVec[k] = j; FinalIndices.push_back(IntermedVals[i].second[j]); } for (unsigned j = 0, f = IntermedVals[i+1].second.size(); j != f; ++j, ++k) { ShuffleVec[k] = NumElems + j; FinalIndices.push_back(IntermedVals[i+1].second[j]); } SDValue Shuffle; if (Phase) Shuffle = DAG.getVectorShuffle(VT, dl, IntermedVals[i].first, IntermedVals[i+1].first, ShuffleVec); else if (!TLI.isShuffleMaskLegal(ShuffleVec, VT)) return false; NewIntermedVals.push_back( std::make_pair(Shuffle, std::move(FinalIndices))); } // If we had an odd number of defined values, then append the last // element to the array of new vectors. if ((IntermedVals.size() & 1) != 0) NewIntermedVals.push_back(IntermedVals.back()); IntermedVals.swap(NewIntermedVals); } assert(IntermedVals.size() <= 2 && IntermedVals.size() > 0 && "Invalid number of intermediate vectors"); SDValue Vec1 = IntermedVals[0].first; SDValue Vec2; if (IntermedVals.size() > 1) Vec2 = IntermedVals[1].first; else if (Phase) Vec2 = DAG.getUNDEF(VT); SmallVector ShuffleVec(NumElems, -1); for (unsigned i = 0, e = IntermedVals[0].second.size(); i != e; ++i) ShuffleVec[IntermedVals[0].second[i]] = i; for (unsigned i = 0, e = IntermedVals[1].second.size(); i != e; ++i) ShuffleVec[IntermedVals[1].second[i]] = NumElems + i; if (Phase) Res = DAG.getVectorShuffle(VT, dl, Vec1, Vec2, ShuffleVec); else if (!TLI.isShuffleMaskLegal(ShuffleVec, VT)) return false; } return true; } /// Expand a BUILD_VECTOR node on targets that don't /// support the operation, but do support the resultant vector type. SDValue SelectionDAGLegalize::ExpandBUILD_VECTOR(SDNode *Node) { unsigned NumElems = Node->getNumOperands(); SDValue Value1, Value2; SDLoc dl(Node); EVT VT = Node->getValueType(0); EVT OpVT = Node->getOperand(0).getValueType(); EVT EltVT = VT.getVectorElementType(); // If the only non-undef value is the low element, turn this into a // SCALAR_TO_VECTOR node. If this is { X, X, X, X }, determine X. bool isOnlyLowElement = true; bool MoreThanTwoValues = false; bool isConstant = true; for (unsigned i = 0; i < NumElems; ++i) { SDValue V = Node->getOperand(i); if (V.isUndef()) continue; if (i > 0) isOnlyLowElement = false; if (!isa(V) && !isa(V)) isConstant = false; if (!Value1.getNode()) { Value1 = V; } else if (!Value2.getNode()) { if (V != Value1) Value2 = V; } else if (V != Value1 && V != Value2) { MoreThanTwoValues = true; } } if (!Value1.getNode()) return DAG.getUNDEF(VT); if (isOnlyLowElement) return DAG.getNode(ISD::SCALAR_TO_VECTOR, dl, VT, Node->getOperand(0)); // If all elements are constants, create a load from the constant pool. if (isConstant) { SmallVector CV; for (unsigned i = 0, e = NumElems; i != e; ++i) { if (ConstantFPSDNode *V = dyn_cast(Node->getOperand(i))) { CV.push_back(const_cast(V->getConstantFPValue())); } else if (ConstantSDNode *V = dyn_cast(Node->getOperand(i))) { if (OpVT==EltVT) CV.push_back(const_cast(V->getConstantIntValue())); else { // If OpVT and EltVT don't match, EltVT is not legal and the // element values have been promoted/truncated earlier. Undo this; // we don't want a v16i8 to become a v16i32 for example. const ConstantInt *CI = V->getConstantIntValue(); CV.push_back(ConstantInt::get(EltVT.getTypeForEVT(*DAG.getContext()), CI->getZExtValue())); } } else { assert(Node->getOperand(i).isUndef()); Type *OpNTy = EltVT.getTypeForEVT(*DAG.getContext()); CV.push_back(UndefValue::get(OpNTy)); } } Constant *CP = ConstantVector::get(CV); SDValue CPIdx = DAG.getConstantPool(CP, TLI.getPointerTy(DAG.getDataLayout())); unsigned Alignment = cast(CPIdx)->getAlignment(); return DAG.getLoad( VT, dl, DAG.getEntryNode(), CPIdx, MachinePointerInfo::getConstantPool(DAG.getMachineFunction()), Alignment); } SmallSet DefinedValues; for (unsigned i = 0; i < NumElems; ++i) { if (Node->getOperand(i).isUndef()) continue; DefinedValues.insert(Node->getOperand(i)); } if (TLI.shouldExpandBuildVectorWithShuffles(VT, DefinedValues.size())) { if (!MoreThanTwoValues) { SmallVector ShuffleVec(NumElems, -1); for (unsigned i = 0; i < NumElems; ++i) { SDValue V = Node->getOperand(i); if (V.isUndef()) continue; ShuffleVec[i] = V == Value1 ? 0 : NumElems; } if (TLI.isShuffleMaskLegal(ShuffleVec, Node->getValueType(0))) { // Get the splatted value into the low element of a vector register. SDValue Vec1 = DAG.getNode(ISD::SCALAR_TO_VECTOR, dl, VT, Value1); SDValue Vec2; if (Value2.getNode()) Vec2 = DAG.getNode(ISD::SCALAR_TO_VECTOR, dl, VT, Value2); else Vec2 = DAG.getUNDEF(VT); // Return shuffle(LowValVec, undef, <0,0,0,0>) return DAG.getVectorShuffle(VT, dl, Vec1, Vec2, ShuffleVec); } } else { SDValue Res; if (ExpandBVWithShuffles(Node, DAG, TLI, Res)) return Res; } } // Otherwise, we can't handle this case efficiently. return ExpandVectorBuildThroughStack(Node); } SDValue SelectionDAGLegalize::ExpandSPLAT_VECTOR(SDNode *Node) { SDLoc DL(Node); EVT VT = Node->getValueType(0); SDValue SplatVal = Node->getOperand(0); return DAG.getSplatBuildVector(VT, DL, SplatVal); } // Expand a node into a call to a libcall. If the result value // does not fit into a register, return the lo part and set the hi part to the // by-reg argument. If it does fit into a single register, return the result // and leave the Hi part unset. SDValue SelectionDAGLegalize::ExpandLibCall(RTLIB::Libcall LC, SDNode *Node, bool isSigned) { TargetLowering::ArgListTy Args; TargetLowering::ArgListEntry Entry; for (const SDValue &Op : Node->op_values()) { EVT ArgVT = Op.getValueType(); Type *ArgTy = ArgVT.getTypeForEVT(*DAG.getContext()); Entry.Node = Op; Entry.Ty = ArgTy; Entry.IsSExt = TLI.shouldSignExtendTypeInLibCall(ArgVT, isSigned); Entry.IsZExt = !TLI.shouldSignExtendTypeInLibCall(ArgVT, isSigned); Args.push_back(Entry); } SDValue Callee = DAG.getExternalSymbol(TLI.getLibcallName(LC), TLI.getPointerTy(DAG.getDataLayout())); EVT RetVT = Node->getValueType(0); Type *RetTy = RetVT.getTypeForEVT(*DAG.getContext()); // By default, the input chain to this libcall is the entry node of the // function. If the libcall is going to be emitted as a tail call then // TLI.isUsedByReturnOnly will change it to the right chain if the return // node which is being folded has a non-entry input chain. SDValue InChain = DAG.getEntryNode(); // isTailCall may be true since the callee does not reference caller stack // frame. Check if it's in the right position and that the return types match. SDValue TCChain = InChain; const Function &F = DAG.getMachineFunction().getFunction(); bool isTailCall = TLI.isInTailCallPosition(DAG, Node, TCChain) && (RetTy == F.getReturnType() || F.getReturnType()->isVoidTy()); if (isTailCall) InChain = TCChain; TargetLowering::CallLoweringInfo CLI(DAG); bool signExtend = TLI.shouldSignExtendTypeInLibCall(RetVT, isSigned); CLI.setDebugLoc(SDLoc(Node)) .setChain(InChain) .setLibCallee(TLI.getLibcallCallingConv(LC), RetTy, Callee, std::move(Args)) .setTailCall(isTailCall) .setSExtResult(signExtend) .setZExtResult(!signExtend) .setIsPostTypeLegalization(true); std::pair CallInfo = TLI.LowerCallTo(CLI); if (!CallInfo.second.getNode()) { LLVM_DEBUG(dbgs() << "Created tailcall: "; DAG.getRoot().dump(&DAG)); // It's a tailcall, return the chain (which is the DAG root). return DAG.getRoot(); } LLVM_DEBUG(dbgs() << "Created libcall: "; CallInfo.first.dump(&DAG)); return CallInfo.first; } void SelectionDAGLegalize::ExpandFPLibCall(SDNode* Node, RTLIB::Libcall Call_F32, RTLIB::Libcall Call_F64, RTLIB::Libcall Call_F80, RTLIB::Libcall Call_F128, RTLIB::Libcall Call_PPCF128, SmallVectorImpl &Results) { RTLIB::Libcall LC; switch (Node->getSimpleValueType(0).SimpleTy) { default: llvm_unreachable("Unexpected request for libcall!"); case MVT::f32: LC = Call_F32; break; case MVT::f64: LC = Call_F64; break; case MVT::f80: LC = Call_F80; break; case MVT::f128: LC = Call_F128; break; case MVT::ppcf128: LC = Call_PPCF128; break; } if (Node->isStrictFPOpcode()) { EVT RetVT = Node->getValueType(0); SmallVector Ops(Node->op_begin() + 1, Node->op_end()); TargetLowering::MakeLibCallOptions CallOptions; // FIXME: This doesn't support tail calls. std::pair Tmp = TLI.makeLibCall(DAG, LC, RetVT, Ops, CallOptions, SDLoc(Node), Node->getOperand(0)); Results.push_back(Tmp.first); Results.push_back(Tmp.second); } else { SDValue Tmp = ExpandLibCall(LC, Node, false); Results.push_back(Tmp); } } SDValue SelectionDAGLegalize::ExpandIntLibCall(SDNode* Node, bool isSigned, RTLIB::Libcall Call_I8, RTLIB::Libcall Call_I16, RTLIB::Libcall Call_I32, RTLIB::Libcall Call_I64, RTLIB::Libcall Call_I128) { RTLIB::Libcall LC; switch (Node->getSimpleValueType(0).SimpleTy) { default: llvm_unreachable("Unexpected request for libcall!"); case MVT::i8: LC = Call_I8; break; case MVT::i16: LC = Call_I16; break; case MVT::i32: LC = Call_I32; break; case MVT::i64: LC = Call_I64; break; case MVT::i128: LC = Call_I128; break; } return ExpandLibCall(LC, Node, isSigned); } /// Expand the node to a libcall based on first argument type (for instance /// lround and its variant). void SelectionDAGLegalize::ExpandArgFPLibCall(SDNode* Node, RTLIB::Libcall Call_F32, RTLIB::Libcall Call_F64, RTLIB::Libcall Call_F80, RTLIB::Libcall Call_F128, RTLIB::Libcall Call_PPCF128, SmallVectorImpl &Results) { EVT InVT = Node->getOperand(Node->isStrictFPOpcode() ? 1 : 0).getValueType(); RTLIB::Libcall LC; switch (InVT.getSimpleVT().SimpleTy) { default: llvm_unreachable("Unexpected request for libcall!"); case MVT::f32: LC = Call_F32; break; case MVT::f64: LC = Call_F64; break; case MVT::f80: LC = Call_F80; break; case MVT::f128: LC = Call_F128; break; case MVT::ppcf128: LC = Call_PPCF128; break; } if (Node->isStrictFPOpcode()) { EVT RetVT = Node->getValueType(0); SmallVector Ops(Node->op_begin() + 1, Node->op_end()); TargetLowering::MakeLibCallOptions CallOptions; // FIXME: This doesn't support tail calls. std::pair Tmp = TLI.makeLibCall(DAG, LC, RetVT, Ops, CallOptions, SDLoc(Node), Node->getOperand(0)); Results.push_back(Tmp.first); Results.push_back(Tmp.second); } else { SDValue Tmp = ExpandLibCall(LC, Node, false); Results.push_back(Tmp); } } /// Issue libcalls to __{u}divmod to compute div / rem pairs. void SelectionDAGLegalize::ExpandDivRemLibCall(SDNode *Node, SmallVectorImpl &Results) { unsigned Opcode = Node->getOpcode(); bool isSigned = Opcode == ISD::SDIVREM; RTLIB::Libcall LC; switch (Node->getSimpleValueType(0).SimpleTy) { default: llvm_unreachable("Unexpected request for libcall!"); case MVT::i8: LC= isSigned ? RTLIB::SDIVREM_I8 : RTLIB::UDIVREM_I8; break; case MVT::i16: LC= isSigned ? RTLIB::SDIVREM_I16 : RTLIB::UDIVREM_I16; break; case MVT::i32: LC= isSigned ? RTLIB::SDIVREM_I32 : RTLIB::UDIVREM_I32; break; case MVT::i64: LC= isSigned ? RTLIB::SDIVREM_I64 : RTLIB::UDIVREM_I64; break; case MVT::i128: LC= isSigned ? RTLIB::SDIVREM_I128:RTLIB::UDIVREM_I128; break; } // The input chain to this libcall is the entry node of the function. // Legalizing the call will automatically add the previous call to the // dependence. SDValue InChain = DAG.getEntryNode(); EVT RetVT = Node->getValueType(0); Type *RetTy = RetVT.getTypeForEVT(*DAG.getContext()); TargetLowering::ArgListTy Args; TargetLowering::ArgListEntry Entry; for (const SDValue &Op : Node->op_values()) { EVT ArgVT = Op.getValueType(); Type *ArgTy = ArgVT.getTypeForEVT(*DAG.getContext()); Entry.Node = Op; Entry.Ty = ArgTy; Entry.IsSExt = isSigned; Entry.IsZExt = !isSigned; Args.push_back(Entry); } // Also pass the return address of the remainder. SDValue FIPtr = DAG.CreateStackTemporary(RetVT); Entry.Node = FIPtr; Entry.Ty = RetTy->getPointerTo(); Entry.IsSExt = isSigned; Entry.IsZExt = !isSigned; Args.push_back(Entry); SDValue Callee = DAG.getExternalSymbol(TLI.getLibcallName(LC), TLI.getPointerTy(DAG.getDataLayout())); SDLoc dl(Node); TargetLowering::CallLoweringInfo CLI(DAG); CLI.setDebugLoc(dl) .setChain(InChain) .setLibCallee(TLI.getLibcallCallingConv(LC), RetTy, Callee, std::move(Args)) .setSExtResult(isSigned) .setZExtResult(!isSigned); std::pair CallInfo = TLI.LowerCallTo(CLI); // Remainder is loaded back from the stack frame. SDValue Rem = DAG.getLoad(RetVT, dl, CallInfo.second, FIPtr, MachinePointerInfo()); Results.push_back(CallInfo.first); Results.push_back(Rem); } /// Return true if sincos libcall is available. static bool isSinCosLibcallAvailable(SDNode *Node, const TargetLowering &TLI) { RTLIB::Libcall LC; switch (Node->getSimpleValueType(0).SimpleTy) { default: llvm_unreachable("Unexpected request for libcall!"); case MVT::f32: LC = RTLIB::SINCOS_F32; break; case MVT::f64: LC = RTLIB::SINCOS_F64; break; case MVT::f80: LC = RTLIB::SINCOS_F80; break; case MVT::f128: LC = RTLIB::SINCOS_F128; break; case MVT::ppcf128: LC = RTLIB::SINCOS_PPCF128; break; } return TLI.getLibcallName(LC) != nullptr; } /// Only issue sincos libcall if both sin and cos are needed. static bool useSinCos(SDNode *Node) { unsigned OtherOpcode = Node->getOpcode() == ISD::FSIN ? ISD::FCOS : ISD::FSIN; SDValue Op0 = Node->getOperand(0); for (SDNode::use_iterator UI = Op0.getNode()->use_begin(), UE = Op0.getNode()->use_end(); UI != UE; ++UI) { SDNode *User = *UI; if (User == Node) continue; // The other user might have been turned into sincos already. if (User->getOpcode() == OtherOpcode || User->getOpcode() == ISD::FSINCOS) return true; } return false; } /// Issue libcalls to sincos to compute sin / cos pairs. void SelectionDAGLegalize::ExpandSinCosLibCall(SDNode *Node, SmallVectorImpl &Results) { RTLIB::Libcall LC; switch (Node->getSimpleValueType(0).SimpleTy) { default: llvm_unreachable("Unexpected request for libcall!"); case MVT::f32: LC = RTLIB::SINCOS_F32; break; case MVT::f64: LC = RTLIB::SINCOS_F64; break; case MVT::f80: LC = RTLIB::SINCOS_F80; break; case MVT::f128: LC = RTLIB::SINCOS_F128; break; case MVT::ppcf128: LC = RTLIB::SINCOS_PPCF128; break; } // The input chain to this libcall is the entry node of the function. // Legalizing the call will automatically add the previous call to the // dependence. SDValue InChain = DAG.getEntryNode(); EVT RetVT = Node->getValueType(0); Type *RetTy = RetVT.getTypeForEVT(*DAG.getContext()); TargetLowering::ArgListTy Args; TargetLowering::ArgListEntry Entry; // Pass the argument. Entry.Node = Node->getOperand(0); Entry.Ty = RetTy; Entry.IsSExt = false; Entry.IsZExt = false; Args.push_back(Entry); // Pass the return address of sin. SDValue SinPtr = DAG.CreateStackTemporary(RetVT); Entry.Node = SinPtr; Entry.Ty = RetTy->getPointerTo(); Entry.IsSExt = false; Entry.IsZExt = false; Args.push_back(Entry); // Also pass the return address of the cos. SDValue CosPtr = DAG.CreateStackTemporary(RetVT); Entry.Node = CosPtr; Entry.Ty = RetTy->getPointerTo(); Entry.IsSExt = false; Entry.IsZExt = false; Args.push_back(Entry); SDValue Callee = DAG.getExternalSymbol(TLI.getLibcallName(LC), TLI.getPointerTy(DAG.getDataLayout())); SDLoc dl(Node); TargetLowering::CallLoweringInfo CLI(DAG); CLI.setDebugLoc(dl).setChain(InChain).setLibCallee( TLI.getLibcallCallingConv(LC), Type::getVoidTy(*DAG.getContext()), Callee, std::move(Args)); std::pair CallInfo = TLI.LowerCallTo(CLI); Results.push_back( DAG.getLoad(RetVT, dl, CallInfo.second, SinPtr, MachinePointerInfo())); Results.push_back( DAG.getLoad(RetVT, dl, CallInfo.second, CosPtr, MachinePointerInfo())); } /// This function is responsible for legalizing a /// INT_TO_FP operation of the specified operand when the target requests that /// we expand it. At this point, we know that the result and operand types are /// legal for the target. SDValue SelectionDAGLegalize::ExpandLegalINT_TO_FP(SDNode *Node, SDValue &Chain) { bool isSigned = (Node->getOpcode() == ISD::STRICT_SINT_TO_FP || Node->getOpcode() == ISD::SINT_TO_FP); EVT DestVT = Node->getValueType(0); SDLoc dl(Node); unsigned OpNo = Node->isStrictFPOpcode() ? 1 : 0; SDValue Op0 = Node->getOperand(OpNo); EVT SrcVT = Op0.getValueType(); // TODO: Should any fast-math-flags be set for the created nodes? LLVM_DEBUG(dbgs() << "Legalizing INT_TO_FP\n"); if (SrcVT == MVT::i32 && TLI.isTypeLegal(MVT::f64)) { LLVM_DEBUG(dbgs() << "32-bit [signed|unsigned] integer to float/double " "expansion\n"); // Get the stack frame index of a 8 byte buffer. SDValue StackSlot = DAG.CreateStackTemporary(MVT::f64); // word offset constant for Hi/Lo address computation SDValue WordOff = DAG.getConstant(sizeof(int), dl, StackSlot.getValueType()); // set up Hi and Lo (into buffer) address based on endian SDValue Hi = StackSlot; SDValue Lo = DAG.getNode(ISD::ADD, dl, StackSlot.getValueType(), StackSlot, WordOff); if (DAG.getDataLayout().isLittleEndian()) std::swap(Hi, Lo); // if signed map to unsigned space SDValue Op0Mapped; if (isSigned) { // constant used to invert sign bit (signed to unsigned mapping) SDValue SignBit = DAG.getConstant(0x80000000u, dl, MVT::i32); Op0Mapped = DAG.getNode(ISD::XOR, dl, MVT::i32, Op0, SignBit); } else { Op0Mapped = Op0; } // store the lo of the constructed double - based on integer input SDValue Store1 = DAG.getStore(DAG.getEntryNode(), dl, Op0Mapped, Lo, MachinePointerInfo()); // initial hi portion of constructed double SDValue InitialHi = DAG.getConstant(0x43300000u, dl, MVT::i32); // store the hi of the constructed double - biased exponent SDValue Store2 = DAG.getStore(Store1, dl, InitialHi, Hi, MachinePointerInfo()); // load the constructed double SDValue Load = DAG.getLoad(MVT::f64, dl, Store2, StackSlot, MachinePointerInfo()); // FP constant to bias correct the final result SDValue Bias = DAG.getConstantFP(isSigned ? BitsToDouble(0x4330000080000000ULL) : BitsToDouble(0x4330000000000000ULL), dl, MVT::f64); // Subtract the bias and get the final result. SDValue Sub; SDValue Result; if (Node->isStrictFPOpcode()) { Sub = DAG.getNode(ISD::STRICT_FSUB, dl, {MVT::f64, MVT::Other}, {Node->getOperand(0), Load, Bias}); Chain = Sub.getValue(1); if (DestVT != Sub.getValueType()) { std::pair ResultPair; ResultPair = DAG.getStrictFPExtendOrRound(Sub, Chain, dl, DestVT); Result = ResultPair.first; Chain = ResultPair.second; } else Result = Sub; } else { Sub = DAG.getNode(ISD::FSUB, dl, MVT::f64, Load, Bias); Result = DAG.getFPExtendOrRound(Sub, dl, DestVT); } return Result; } assert(!isSigned && "Legalize cannot Expand SINT_TO_FP for i64 yet"); // Code below here assumes !isSigned without checking again. // FIXME: This can produce slightly incorrect results. See details in // FIXME: https://reviews.llvm.org/D69275 SDValue Tmp1; if (Node->isStrictFPOpcode()) { Tmp1 = DAG.getNode(ISD::STRICT_SINT_TO_FP, dl, { DestVT, MVT::Other }, { Node->getOperand(0), Op0 }); } else Tmp1 = DAG.getNode(ISD::SINT_TO_FP, dl, DestVT, Op0); SDValue SignSet = DAG.getSetCC(dl, getSetCCResultType(SrcVT), Op0, DAG.getConstant(0, dl, SrcVT), ISD::SETLT); SDValue Zero = DAG.getIntPtrConstant(0, dl), Four = DAG.getIntPtrConstant(4, dl); SDValue CstOffset = DAG.getSelect(dl, Zero.getValueType(), SignSet, Four, Zero); // If the sign bit of the integer is set, the large number will be treated // as a negative number. To counteract this, the dynamic code adds an // offset depending on the data type. uint64_t FF; switch (SrcVT.getSimpleVT().SimpleTy) { default: llvm_unreachable("Unsupported integer type!"); case MVT::i8 : FF = 0x43800000ULL; break; // 2^8 (as a float) case MVT::i16: FF = 0x47800000ULL; break; // 2^16 (as a float) case MVT::i32: FF = 0x4F800000ULL; break; // 2^32 (as a float) case MVT::i64: FF = 0x5F800000ULL; break; // 2^64 (as a float) } if (DAG.getDataLayout().isLittleEndian()) FF <<= 32; Constant *FudgeFactor = ConstantInt::get( Type::getInt64Ty(*DAG.getContext()), FF); SDValue CPIdx = DAG.getConstantPool(FudgeFactor, TLI.getPointerTy(DAG.getDataLayout())); unsigned Alignment = cast(CPIdx)->getAlignment(); CPIdx = DAG.getNode(ISD::ADD, dl, CPIdx.getValueType(), CPIdx, CstOffset); Alignment = std::min(Alignment, 4u); SDValue FudgeInReg; if (DestVT == MVT::f32) FudgeInReg = DAG.getLoad( MVT::f32, dl, DAG.getEntryNode(), CPIdx, MachinePointerInfo::getConstantPool(DAG.getMachineFunction()), Alignment); else { SDValue Load = DAG.getExtLoad( ISD::EXTLOAD, dl, DestVT, DAG.getEntryNode(), CPIdx, MachinePointerInfo::getConstantPool(DAG.getMachineFunction()), MVT::f32, Alignment); HandleSDNode Handle(Load); LegalizeOp(Load.getNode()); FudgeInReg = Handle.getValue(); } if (Node->isStrictFPOpcode()) { SDValue Result = DAG.getNode(ISD::STRICT_FADD, dl, { DestVT, MVT::Other }, { Tmp1.getValue(1), Tmp1, FudgeInReg }); Chain = Result.getValue(1); return Result; } return DAG.getNode(ISD::FADD, dl, DestVT, Tmp1, FudgeInReg); } /// This function is responsible for legalizing a /// *INT_TO_FP operation of the specified operand when the target requests that /// we promote it. At this point, we know that the result and operand types are /// legal for the target, and that there is a legal UINT_TO_FP or SINT_TO_FP /// operation that takes a larger input. void SelectionDAGLegalize::PromoteLegalINT_TO_FP( SDNode *N, const SDLoc &dl, SmallVectorImpl &Results) { bool IsStrict = N->isStrictFPOpcode(); bool IsSigned = N->getOpcode() == ISD::SINT_TO_FP || N->getOpcode() == ISD::STRICT_SINT_TO_FP; EVT DestVT = N->getValueType(0); SDValue LegalOp = N->getOperand(IsStrict ? 1 : 0); unsigned UIntOp = IsStrict ? ISD::STRICT_UINT_TO_FP : ISD::UINT_TO_FP; unsigned SIntOp = IsStrict ? ISD::STRICT_SINT_TO_FP : ISD::SINT_TO_FP; // First step, figure out the appropriate *INT_TO_FP operation to use. EVT NewInTy = LegalOp.getValueType(); unsigned OpToUse = 0; // Scan for the appropriate larger type to use. while (true) { NewInTy = (MVT::SimpleValueType)(NewInTy.getSimpleVT().SimpleTy+1); assert(NewInTy.isInteger() && "Ran out of possibilities!"); // If the target supports SINT_TO_FP of this type, use it. if (TLI.isOperationLegalOrCustom(SIntOp, NewInTy)) { OpToUse = SIntOp; break; } if (IsSigned) continue; // If the target supports UINT_TO_FP of this type, use it. if (TLI.isOperationLegalOrCustom(UIntOp, NewInTy)) { OpToUse = UIntOp; break; } // Otherwise, try a larger type. } // Okay, we found the operation and type to use. Zero extend our input to the // desired type then run the operation on it. if (IsStrict) { SDValue Res = DAG.getNode(OpToUse, dl, {DestVT, MVT::Other}, {N->getOperand(0), DAG.getNode(IsSigned ? ISD::SIGN_EXTEND : ISD::ZERO_EXTEND, dl, NewInTy, LegalOp)}); Results.push_back(Res); Results.push_back(Res.getValue(1)); return; } Results.push_back( DAG.getNode(OpToUse, dl, DestVT, DAG.getNode(IsSigned ? ISD::SIGN_EXTEND : ISD::ZERO_EXTEND, dl, NewInTy, LegalOp))); } /// This function is responsible for legalizing a /// FP_TO_*INT operation of the specified operand when the target requests that /// we promote it. At this point, we know that the result and operand types are /// legal for the target, and that there is a legal FP_TO_UINT or FP_TO_SINT /// operation that returns a larger result. void SelectionDAGLegalize::PromoteLegalFP_TO_INT(SDNode *N, const SDLoc &dl, SmallVectorImpl &Results) { bool IsStrict = N->isStrictFPOpcode(); bool IsSigned = N->getOpcode() == ISD::FP_TO_SINT || N->getOpcode() == ISD::STRICT_FP_TO_SINT; EVT DestVT = N->getValueType(0); SDValue LegalOp = N->getOperand(IsStrict ? 1 : 0); // First step, figure out the appropriate FP_TO*INT operation to use. EVT NewOutTy = DestVT; unsigned OpToUse = 0; // Scan for the appropriate larger type to use. while (true) { NewOutTy = (MVT::SimpleValueType)(NewOutTy.getSimpleVT().SimpleTy+1); assert(NewOutTy.isInteger() && "Ran out of possibilities!"); // A larger signed type can hold all unsigned values of the requested type, // so using FP_TO_SINT is valid OpToUse = IsStrict ? ISD::STRICT_FP_TO_SINT : ISD::FP_TO_SINT; if (TLI.isOperationLegalOrCustom(OpToUse, NewOutTy)) break; // However, if the value may be < 0.0, we *must* use some FP_TO_SINT. OpToUse = IsStrict ? ISD::STRICT_FP_TO_UINT : ISD::FP_TO_UINT; if (!IsSigned && TLI.isOperationLegalOrCustom(OpToUse, NewOutTy)) break; // Otherwise, try a larger type. } // Okay, we found the operation and type to use. SDValue Operation; if (IsStrict) { SDVTList VTs = DAG.getVTList(NewOutTy, MVT::Other); Operation = DAG.getNode(OpToUse, dl, VTs, N->getOperand(0), LegalOp); } else Operation = DAG.getNode(OpToUse, dl, NewOutTy, LegalOp); // Truncate the result of the extended FP_TO_*INT operation to the desired // size. SDValue Trunc = DAG.getNode(ISD::TRUNCATE, dl, DestVT, Operation); Results.push_back(Trunc); if (IsStrict) Results.push_back(Operation.getValue(1)); } /// Legalize a BITREVERSE scalar/vector operation as a series of mask + shifts. SDValue SelectionDAGLegalize::ExpandBITREVERSE(SDValue Op, const SDLoc &dl) { EVT VT = Op.getValueType(); EVT SHVT = TLI.getShiftAmountTy(VT, DAG.getDataLayout()); unsigned Sz = VT.getScalarSizeInBits(); SDValue Tmp, Tmp2, Tmp3; // If we can, perform BSWAP first and then the mask+swap the i4, then i2 // and finally the i1 pairs. // TODO: We can easily support i4/i2 legal types if any target ever does. if (Sz >= 8 && isPowerOf2_32(Sz)) { // Create the masks - repeating the pattern every byte. APInt MaskHi4 = APInt::getSplat(Sz, APInt(8, 0xF0)); APInt MaskHi2 = APInt::getSplat(Sz, APInt(8, 0xCC)); APInt MaskHi1 = APInt::getSplat(Sz, APInt(8, 0xAA)); APInt MaskLo4 = APInt::getSplat(Sz, APInt(8, 0x0F)); APInt MaskLo2 = APInt::getSplat(Sz, APInt(8, 0x33)); APInt MaskLo1 = APInt::getSplat(Sz, APInt(8, 0x55)); // BSWAP if the type is wider than a single byte. Tmp = (Sz > 8 ? DAG.getNode(ISD::BSWAP, dl, VT, Op) : Op); // swap i4: ((V & 0xF0) >> 4) | ((V & 0x0F) << 4) Tmp2 = DAG.getNode(ISD::AND, dl, VT, Tmp, DAG.getConstant(MaskHi4, dl, VT)); Tmp3 = DAG.getNode(ISD::AND, dl, VT, Tmp, DAG.getConstant(MaskLo4, dl, VT)); Tmp2 = DAG.getNode(ISD::SRL, dl, VT, Tmp2, DAG.getConstant(4, dl, SHVT)); Tmp3 = DAG.getNode(ISD::SHL, dl, VT, Tmp3, DAG.getConstant(4, dl, SHVT)); Tmp = DAG.getNode(ISD::OR, dl, VT, Tmp2, Tmp3); // swap i2: ((V & 0xCC) >> 2) | ((V & 0x33) << 2) Tmp2 = DAG.getNode(ISD::AND, dl, VT, Tmp, DAG.getConstant(MaskHi2, dl, VT)); Tmp3 = DAG.getNode(ISD::AND, dl, VT, Tmp, DAG.getConstant(MaskLo2, dl, VT)); Tmp2 = DAG.getNode(ISD::SRL, dl, VT, Tmp2, DAG.getConstant(2, dl, SHVT)); Tmp3 = DAG.getNode(ISD::SHL, dl, VT, Tmp3, DAG.getConstant(2, dl, SHVT)); Tmp = DAG.getNode(ISD::OR, dl, VT, Tmp2, Tmp3); // swap i1: ((V & 0xAA) >> 1) | ((V & 0x55) << 1) Tmp2 = DAG.getNode(ISD::AND, dl, VT, Tmp, DAG.getConstant(MaskHi1, dl, VT)); Tmp3 = DAG.getNode(ISD::AND, dl, VT, Tmp, DAG.getConstant(MaskLo1, dl, VT)); Tmp2 = DAG.getNode(ISD::SRL, dl, VT, Tmp2, DAG.getConstant(1, dl, SHVT)); Tmp3 = DAG.getNode(ISD::SHL, dl, VT, Tmp3, DAG.getConstant(1, dl, SHVT)); Tmp = DAG.getNode(ISD::OR, dl, VT, Tmp2, Tmp3); return Tmp; } Tmp = DAG.getConstant(0, dl, VT); for (unsigned I = 0, J = Sz-1; I < Sz; ++I, --J) { if (I < J) Tmp2 = DAG.getNode(ISD::SHL, dl, VT, Op, DAG.getConstant(J - I, dl, SHVT)); else Tmp2 = DAG.getNode(ISD::SRL, dl, VT, Op, DAG.getConstant(I - J, dl, SHVT)); APInt Shift(Sz, 1); Shift <<= J; Tmp2 = DAG.getNode(ISD::AND, dl, VT, Tmp2, DAG.getConstant(Shift, dl, VT)); Tmp = DAG.getNode(ISD::OR, dl, VT, Tmp, Tmp2); } return Tmp; } /// Open code the operations for BSWAP of the specified operation. SDValue SelectionDAGLegalize::ExpandBSWAP(SDValue Op, const SDLoc &dl) { EVT VT = Op.getValueType(); EVT SHVT = TLI.getShiftAmountTy(VT, DAG.getDataLayout()); SDValue Tmp1, Tmp2, Tmp3, Tmp4, Tmp5, Tmp6, Tmp7, Tmp8; switch (VT.getSimpleVT().getScalarType().SimpleTy) { default: llvm_unreachable("Unhandled Expand type in BSWAP!"); case MVT::i16: // Use a rotate by 8. This can be further expanded if necessary. return DAG.getNode(ISD::ROTL, dl, VT, Op, DAG.getConstant(8, dl, SHVT)); case MVT::i32: Tmp4 = DAG.getNode(ISD::SHL, dl, VT, Op, DAG.getConstant(24, dl, SHVT)); Tmp3 = DAG.getNode(ISD::SHL, dl, VT, Op, DAG.getConstant(8, dl, SHVT)); Tmp2 = DAG.getNode(ISD::SRL, dl, VT, Op, DAG.getConstant(8, dl, SHVT)); Tmp1 = DAG.getNode(ISD::SRL, dl, VT, Op, DAG.getConstant(24, dl, SHVT)); Tmp3 = DAG.getNode(ISD::AND, dl, VT, Tmp3, DAG.getConstant(0xFF0000, dl, VT)); Tmp2 = DAG.getNode(ISD::AND, dl, VT, Tmp2, DAG.getConstant(0xFF00, dl, VT)); Tmp4 = DAG.getNode(ISD::OR, dl, VT, Tmp4, Tmp3); Tmp2 = DAG.getNode(ISD::OR, dl, VT, Tmp2, Tmp1); return DAG.getNode(ISD::OR, dl, VT, Tmp4, Tmp2); case MVT::i64: Tmp8 = DAG.getNode(ISD::SHL, dl, VT, Op, DAG.getConstant(56, dl, SHVT)); Tmp7 = DAG.getNode(ISD::SHL, dl, VT, Op, DAG.getConstant(40, dl, SHVT)); Tmp6 = DAG.getNode(ISD::SHL, dl, VT, Op, DAG.getConstant(24, dl, SHVT)); Tmp5 = DAG.getNode(ISD::SHL, dl, VT, Op, DAG.getConstant(8, dl, SHVT)); Tmp4 = DAG.getNode(ISD::SRL, dl, VT, Op, DAG.getConstant(8, dl, SHVT)); Tmp3 = DAG.getNode(ISD::SRL, dl, VT, Op, DAG.getConstant(24, dl, SHVT)); Tmp2 = DAG.getNode(ISD::SRL, dl, VT, Op, DAG.getConstant(40, dl, SHVT)); Tmp1 = DAG.getNode(ISD::SRL, dl, VT, Op, DAG.getConstant(56, dl, SHVT)); Tmp7 = DAG.getNode(ISD::AND, dl, VT, Tmp7, DAG.getConstant(255ULL<<48, dl, VT)); Tmp6 = DAG.getNode(ISD::AND, dl, VT, Tmp6, DAG.getConstant(255ULL<<40, dl, VT)); Tmp5 = DAG.getNode(ISD::AND, dl, VT, Tmp5, DAG.getConstant(255ULL<<32, dl, VT)); Tmp4 = DAG.getNode(ISD::AND, dl, VT, Tmp4, DAG.getConstant(255ULL<<24, dl, VT)); Tmp3 = DAG.getNode(ISD::AND, dl, VT, Tmp3, DAG.getConstant(255ULL<<16, dl, VT)); Tmp2 = DAG.getNode(ISD::AND, dl, VT, Tmp2, DAG.getConstant(255ULL<<8 , dl, VT)); Tmp8 = DAG.getNode(ISD::OR, dl, VT, Tmp8, Tmp7); Tmp6 = DAG.getNode(ISD::OR, dl, VT, Tmp6, Tmp5); Tmp4 = DAG.getNode(ISD::OR, dl, VT, Tmp4, Tmp3); Tmp2 = DAG.getNode(ISD::OR, dl, VT, Tmp2, Tmp1); Tmp8 = DAG.getNode(ISD::OR, dl, VT, Tmp8, Tmp6); Tmp4 = DAG.getNode(ISD::OR, dl, VT, Tmp4, Tmp2); return DAG.getNode(ISD::OR, dl, VT, Tmp8, Tmp4); } } bool SelectionDAGLegalize::ExpandNode(SDNode *Node) { LLVM_DEBUG(dbgs() << "Trying to expand node\n"); SmallVector Results; SDLoc dl(Node); SDValue Tmp1, Tmp2, Tmp3, Tmp4; bool NeedInvert; switch (Node->getOpcode()) { case ISD::ABS: if (TLI.expandABS(Node, Tmp1, DAG)) Results.push_back(Tmp1); break; case ISD::CTPOP: if (TLI.expandCTPOP(Node, Tmp1, DAG)) Results.push_back(Tmp1); break; case ISD::CTLZ: case ISD::CTLZ_ZERO_UNDEF: if (TLI.expandCTLZ(Node, Tmp1, DAG)) Results.push_back(Tmp1); break; case ISD::CTTZ: case ISD::CTTZ_ZERO_UNDEF: if (TLI.expandCTTZ(Node, Tmp1, DAG)) Results.push_back(Tmp1); break; case ISD::BITREVERSE: Results.push_back(ExpandBITREVERSE(Node->getOperand(0), dl)); break; case ISD::BSWAP: Results.push_back(ExpandBSWAP(Node->getOperand(0), dl)); break; case ISD::FRAMEADDR: case ISD::RETURNADDR: case ISD::FRAME_TO_ARGS_OFFSET: Results.push_back(DAG.getConstant(0, dl, Node->getValueType(0))); break; case ISD::EH_DWARF_CFA: { SDValue CfaArg = DAG.getSExtOrTrunc(Node->getOperand(0), dl, TLI.getPointerTy(DAG.getDataLayout())); SDValue Offset = DAG.getNode(ISD::ADD, dl, CfaArg.getValueType(), DAG.getNode(ISD::FRAME_TO_ARGS_OFFSET, dl, CfaArg.getValueType()), CfaArg); SDValue FA = DAG.getNode( ISD::FRAMEADDR, dl, TLI.getPointerTy(DAG.getDataLayout()), DAG.getConstant(0, dl, TLI.getPointerTy(DAG.getDataLayout()))); Results.push_back(DAG.getNode(ISD::ADD, dl, FA.getValueType(), FA, Offset)); break; } case ISD::FLT_ROUNDS_: Results.push_back(DAG.getConstant(1, dl, Node->getValueType(0))); break; case ISD::EH_RETURN: case ISD::EH_LABEL: case ISD::PREFETCH: case ISD::VAEND: case ISD::EH_SJLJ_LONGJMP: // If the target didn't expand these, there's nothing to do, so just // preserve the chain and be done. Results.push_back(Node->getOperand(0)); break; case ISD::READCYCLECOUNTER: // If the target didn't expand this, just return 'zero' and preserve the // chain. Results.append(Node->getNumValues() - 1, DAG.getConstant(0, dl, Node->getValueType(0))); Results.push_back(Node->getOperand(0)); break; case ISD::EH_SJLJ_SETJMP: // If the target didn't expand this, just return 'zero' and preserve the // chain. Results.push_back(DAG.getConstant(0, dl, MVT::i32)); Results.push_back(Node->getOperand(0)); break; case ISD::ATOMIC_LOAD: { // There is no libcall for atomic load; fake it with ATOMIC_CMP_SWAP. SDValue Zero = DAG.getConstant(0, dl, Node->getValueType(0)); SDVTList VTs = DAG.getVTList(Node->getValueType(0), MVT::Other); SDValue Swap = DAG.getAtomicCmpSwap( ISD::ATOMIC_CMP_SWAP, dl, cast(Node)->getMemoryVT(), VTs, Node->getOperand(0), Node->getOperand(1), Zero, Zero, cast(Node)->getMemOperand()); Results.push_back(Swap.getValue(0)); Results.push_back(Swap.getValue(1)); break; } case ISD::ATOMIC_STORE: { // There is no libcall for atomic store; fake it with ATOMIC_SWAP. SDValue Swap = DAG.getAtomic(ISD::ATOMIC_SWAP, dl, cast(Node)->getMemoryVT(), Node->getOperand(0), Node->getOperand(1), Node->getOperand(2), cast(Node)->getMemOperand()); Results.push_back(Swap.getValue(1)); break; } case ISD::ATOMIC_CMP_SWAP_WITH_SUCCESS: { // Expanding an ATOMIC_CMP_SWAP_WITH_SUCCESS produces an ATOMIC_CMP_SWAP and // splits out the success value as a comparison. Expanding the resulting // ATOMIC_CMP_SWAP will produce a libcall. SDVTList VTs = DAG.getVTList(Node->getValueType(0), MVT::Other); SDValue Res = DAG.getAtomicCmpSwap( ISD::ATOMIC_CMP_SWAP, dl, cast(Node)->getMemoryVT(), VTs, Node->getOperand(0), Node->getOperand(1), Node->getOperand(2), Node->getOperand(3), cast(Node)->getMemOperand()); SDValue ExtRes = Res; SDValue LHS = Res; SDValue RHS = Node->getOperand(1); EVT AtomicType = cast(Node)->getMemoryVT(); EVT OuterType = Node->getValueType(0); switch (TLI.getExtendForAtomicOps()) { case ISD::SIGN_EXTEND: LHS = DAG.getNode(ISD::AssertSext, dl, OuterType, Res, DAG.getValueType(AtomicType)); RHS = DAG.getNode(ISD::SIGN_EXTEND_INREG, dl, OuterType, Node->getOperand(2), DAG.getValueType(AtomicType)); ExtRes = LHS; break; case ISD::ZERO_EXTEND: LHS = DAG.getNode(ISD::AssertZext, dl, OuterType, Res, DAG.getValueType(AtomicType)); RHS = DAG.getZeroExtendInReg(Node->getOperand(2), dl, AtomicType); ExtRes = LHS; break; case ISD::ANY_EXTEND: LHS = DAG.getZeroExtendInReg(Res, dl, AtomicType); RHS = DAG.getZeroExtendInReg(Node->getOperand(2), dl, AtomicType); break; default: llvm_unreachable("Invalid atomic op extension"); } SDValue Success = DAG.getSetCC(dl, Node->getValueType(1), LHS, RHS, ISD::SETEQ); Results.push_back(ExtRes.getValue(0)); Results.push_back(Success); Results.push_back(Res.getValue(1)); break; } case ISD::DYNAMIC_STACKALLOC: ExpandDYNAMIC_STACKALLOC(Node, Results); break; case ISD::MERGE_VALUES: for (unsigned i = 0; i < Node->getNumValues(); i++) Results.push_back(Node->getOperand(i)); break; case ISD::UNDEF: { EVT VT = Node->getValueType(0); if (VT.isInteger()) Results.push_back(DAG.getConstant(0, dl, VT)); else { assert(VT.isFloatingPoint() && "Unknown value type!"); Results.push_back(DAG.getConstantFP(0, dl, VT)); } break; } case ISD::STRICT_FP_ROUND: // When strict mode is enforced we can't do expansion because it // does not honor the "strict" properties. Only libcall is allowed. if (TLI.isStrictFPEnabled()) break; // We might as well mutate to FP_ROUND when FP_ROUND operation is legal // since this operation is more efficient than stack operation. if (TLI.getStrictFPOperationAction(Node->getOpcode(), Node->getValueType(0)) == TargetLowering::Legal) break; // We fall back to use stack operation when the FP_ROUND operation // isn't available. Tmp1 = EmitStackConvert(Node->getOperand(1), Node->getValueType(0), Node->getValueType(0), dl, Node->getOperand(0)); ReplaceNode(Node, Tmp1.getNode()); LLVM_DEBUG(dbgs() << "Successfully expanded STRICT_FP_ROUND node\n"); return true; case ISD::FP_ROUND: case ISD::BITCAST: Tmp1 = EmitStackConvert(Node->getOperand(0), Node->getValueType(0), Node->getValueType(0), dl); Results.push_back(Tmp1); break; case ISD::STRICT_FP_EXTEND: // When strict mode is enforced we can't do expansion because it // does not honor the "strict" properties. Only libcall is allowed. if (TLI.isStrictFPEnabled()) break; // We might as well mutate to FP_EXTEND when FP_EXTEND operation is legal // since this operation is more efficient than stack operation. if (TLI.getStrictFPOperationAction(Node->getOpcode(), Node->getValueType(0)) == TargetLowering::Legal) break; // We fall back to use stack operation when the FP_EXTEND operation // isn't available. Tmp1 = EmitStackConvert(Node->getOperand(1), Node->getOperand(1).getValueType(), Node->getValueType(0), dl, Node->getOperand(0)); ReplaceNode(Node, Tmp1.getNode()); LLVM_DEBUG(dbgs() << "Successfully expanded STRICT_FP_EXTEND node\n"); return true; case ISD::FP_EXTEND: Tmp1 = EmitStackConvert(Node->getOperand(0), Node->getOperand(0).getValueType(), Node->getValueType(0), dl); Results.push_back(Tmp1); break; case ISD::SIGN_EXTEND_INREG: { EVT ExtraVT = cast(Node->getOperand(1))->getVT(); EVT VT = Node->getValueType(0); // An in-register sign-extend of a boolean is a negation: // 'true' (1) sign-extended is -1. // 'false' (0) sign-extended is 0. // However, we must mask the high bits of the source operand because the // SIGN_EXTEND_INREG does not guarantee that the high bits are already zero. // TODO: Do this for vectors too? if (ExtraVT.getSizeInBits() == 1) { SDValue One = DAG.getConstant(1, dl, VT); SDValue And = DAG.getNode(ISD::AND, dl, VT, Node->getOperand(0), One); SDValue Zero = DAG.getConstant(0, dl, VT); SDValue Neg = DAG.getNode(ISD::SUB, dl, VT, Zero, And); Results.push_back(Neg); break; } // NOTE: we could fall back on load/store here too for targets without // SRA. However, it is doubtful that any exist. EVT ShiftAmountTy = TLI.getShiftAmountTy(VT, DAG.getDataLayout()); unsigned BitsDiff = VT.getScalarSizeInBits() - ExtraVT.getScalarSizeInBits(); SDValue ShiftCst = DAG.getConstant(BitsDiff, dl, ShiftAmountTy); Tmp1 = DAG.getNode(ISD::SHL, dl, Node->getValueType(0), Node->getOperand(0), ShiftCst); Tmp1 = DAG.getNode(ISD::SRA, dl, Node->getValueType(0), Tmp1, ShiftCst); Results.push_back(Tmp1); break; } case ISD::UINT_TO_FP: case ISD::STRICT_UINT_TO_FP: if (TLI.expandUINT_TO_FP(Node, Tmp1, Tmp2, DAG)) { Results.push_back(Tmp1); if (Node->isStrictFPOpcode()) Results.push_back(Tmp2); break; } LLVM_FALLTHROUGH; case ISD::SINT_TO_FP: case ISD::STRICT_SINT_TO_FP: Tmp1 = ExpandLegalINT_TO_FP(Node, Tmp2); Results.push_back(Tmp1); if (Node->isStrictFPOpcode()) Results.push_back(Tmp2); break; case ISD::FP_TO_SINT: if (TLI.expandFP_TO_SINT(Node, Tmp1, DAG)) Results.push_back(Tmp1); break; case ISD::STRICT_FP_TO_SINT: if (TLI.expandFP_TO_SINT(Node, Tmp1, DAG)) { ReplaceNode(Node, Tmp1.getNode()); LLVM_DEBUG(dbgs() << "Successfully expanded STRICT_FP_TO_SINT node\n"); return true; } break; case ISD::FP_TO_UINT: if (TLI.expandFP_TO_UINT(Node, Tmp1, Tmp2, DAG)) Results.push_back(Tmp1); break; case ISD::STRICT_FP_TO_UINT: if (TLI.expandFP_TO_UINT(Node, Tmp1, Tmp2, DAG)) { // Relink the chain. DAG.ReplaceAllUsesOfValueWith(SDValue(Node,1), Tmp2); // Replace the new UINT result. ReplaceNodeWithValue(SDValue(Node, 0), Tmp1); LLVM_DEBUG(dbgs() << "Successfully expanded STRICT_FP_TO_UINT node\n"); return true; } break; case ISD::VAARG: Results.push_back(DAG.expandVAArg(Node)); Results.push_back(Results[0].getValue(1)); break; case ISD::VACOPY: Results.push_back(DAG.expandVACopy(Node)); break; case ISD::EXTRACT_VECTOR_ELT: if (Node->getOperand(0).getValueType().getVectorNumElements() == 1) // This must be an access of the only element. Return it. Tmp1 = DAG.getNode(ISD::BITCAST, dl, Node->getValueType(0), Node->getOperand(0)); else Tmp1 = ExpandExtractFromVectorThroughStack(SDValue(Node, 0)); Results.push_back(Tmp1); break; case ISD::EXTRACT_SUBVECTOR: Results.push_back(ExpandExtractFromVectorThroughStack(SDValue(Node, 0))); break; case ISD::INSERT_SUBVECTOR: Results.push_back(ExpandInsertToVectorThroughStack(SDValue(Node, 0))); break; case ISD::CONCAT_VECTORS: Results.push_back(ExpandVectorBuildThroughStack(Node)); break; case ISD::SCALAR_TO_VECTOR: Results.push_back(ExpandSCALAR_TO_VECTOR(Node)); break; case ISD::INSERT_VECTOR_ELT: Results.push_back(ExpandINSERT_VECTOR_ELT(Node->getOperand(0), Node->getOperand(1), Node->getOperand(2), dl)); break; case ISD::VECTOR_SHUFFLE: { SmallVector NewMask; ArrayRef Mask = cast(Node)->getMask(); EVT VT = Node->getValueType(0); EVT EltVT = VT.getVectorElementType(); SDValue Op0 = Node->getOperand(0); SDValue Op1 = Node->getOperand(1); if (!TLI.isTypeLegal(EltVT)) { EVT NewEltVT = TLI.getTypeToTransformTo(*DAG.getContext(), EltVT); // BUILD_VECTOR operands are allowed to be wider than the element type. // But if NewEltVT is smaller that EltVT the BUILD_VECTOR does not accept // it. if (NewEltVT.bitsLT(EltVT)) { // Convert shuffle node. // If original node was v4i64 and the new EltVT is i32, // cast operands to v8i32 and re-build the mask. // Calculate new VT, the size of the new VT should be equal to original. EVT NewVT = EVT::getVectorVT(*DAG.getContext(), NewEltVT, VT.getSizeInBits() / NewEltVT.getSizeInBits()); assert(NewVT.bitsEq(VT)); // cast operands to new VT Op0 = DAG.getNode(ISD::BITCAST, dl, NewVT, Op0); Op1 = DAG.getNode(ISD::BITCAST, dl, NewVT, Op1); // Convert the shuffle mask unsigned int factor = NewVT.getVectorNumElements()/VT.getVectorNumElements(); // EltVT gets smaller assert(factor > 0); for (unsigned i = 0; i < VT.getVectorNumElements(); ++i) { if (Mask[i] < 0) { for (unsigned fi = 0; fi < factor; ++fi) NewMask.push_back(Mask[i]); } else { for (unsigned fi = 0; fi < factor; ++fi) NewMask.push_back(Mask[i]*factor+fi); } } Mask = NewMask; VT = NewVT; } EltVT = NewEltVT; } unsigned NumElems = VT.getVectorNumElements(); SmallVector Ops; for (unsigned i = 0; i != NumElems; ++i) { if (Mask[i] < 0) { Ops.push_back(DAG.getUNDEF(EltVT)); continue; } unsigned Idx = Mask[i]; if (Idx < NumElems) Ops.push_back(DAG.getNode( ISD::EXTRACT_VECTOR_ELT, dl, EltVT, Op0, DAG.getConstant(Idx, dl, TLI.getVectorIdxTy(DAG.getDataLayout())))); else Ops.push_back(DAG.getNode( ISD::EXTRACT_VECTOR_ELT, dl, EltVT, Op1, DAG.getConstant(Idx - NumElems, dl, TLI.getVectorIdxTy(DAG.getDataLayout())))); } Tmp1 = DAG.getBuildVector(VT, dl, Ops); // We may have changed the BUILD_VECTOR type. Cast it back to the Node type. Tmp1 = DAG.getNode(ISD::BITCAST, dl, Node->getValueType(0), Tmp1); Results.push_back(Tmp1); break; } case ISD::EXTRACT_ELEMENT: { EVT OpTy = Node->getOperand(0).getValueType(); if (cast(Node->getOperand(1))->getZExtValue()) { // 1 -> Hi Tmp1 = DAG.getNode(ISD::SRL, dl, OpTy, Node->getOperand(0), DAG.getConstant(OpTy.getSizeInBits() / 2, dl, TLI.getShiftAmountTy( Node->getOperand(0).getValueType(), DAG.getDataLayout()))); Tmp1 = DAG.getNode(ISD::TRUNCATE, dl, Node->getValueType(0), Tmp1); } else { // 0 -> Lo Tmp1 = DAG.getNode(ISD::TRUNCATE, dl, Node->getValueType(0), Node->getOperand(0)); } Results.push_back(Tmp1); break; } case ISD::STACKSAVE: // Expand to CopyFromReg if the target set // StackPointerRegisterToSaveRestore. if (unsigned SP = TLI.getStackPointerRegisterToSaveRestore()) { Results.push_back(DAG.getCopyFromReg(Node->getOperand(0), dl, SP, Node->getValueType(0))); Results.push_back(Results[0].getValue(1)); } else { Results.push_back(DAG.getUNDEF(Node->getValueType(0))); Results.push_back(Node->getOperand(0)); } break; case ISD::STACKRESTORE: // Expand to CopyToReg if the target set // StackPointerRegisterToSaveRestore. if (unsigned SP = TLI.getStackPointerRegisterToSaveRestore()) { Results.push_back(DAG.getCopyToReg(Node->getOperand(0), dl, SP, Node->getOperand(1))); } else { Results.push_back(Node->getOperand(0)); } break; case ISD::GET_DYNAMIC_AREA_OFFSET: Results.push_back(DAG.getConstant(0, dl, Node->getValueType(0))); Results.push_back(Results[0].getValue(0)); break; case ISD::FCOPYSIGN: Results.push_back(ExpandFCOPYSIGN(Node)); break; case ISD::FNEG: // Expand Y = FNEG(X) -> Y = SUB -0.0, X Tmp1 = DAG.getConstantFP(-0.0, dl, Node->getValueType(0)); // TODO: If FNEG has fast-math-flags, propagate them to the FSUB. Tmp1 = DAG.getNode(ISD::FSUB, dl, Node->getValueType(0), Tmp1, Node->getOperand(0)); Results.push_back(Tmp1); break; case ISD::FABS: Results.push_back(ExpandFABS(Node)); break; case ISD::SMIN: case ISD::SMAX: case ISD::UMIN: case ISD::UMAX: { // Expand Y = MAX(A, B) -> Y = (A > B) ? A : B ISD::CondCode Pred; switch (Node->getOpcode()) { default: llvm_unreachable("How did we get here?"); case ISD::SMAX: Pred = ISD::SETGT; break; case ISD::SMIN: Pred = ISD::SETLT; break; case ISD::UMAX: Pred = ISD::SETUGT; break; case ISD::UMIN: Pred = ISD::SETULT; break; } Tmp1 = Node->getOperand(0); Tmp2 = Node->getOperand(1); Tmp1 = DAG.getSelectCC(dl, Tmp1, Tmp2, Tmp1, Tmp2, Pred); Results.push_back(Tmp1); break; } case ISD::FMINNUM: case ISD::FMAXNUM: { if (SDValue Expanded = TLI.expandFMINNUM_FMAXNUM(Node, DAG)) Results.push_back(Expanded); break; } case ISD::FSIN: case ISD::FCOS: { EVT VT = Node->getValueType(0); // Turn fsin / fcos into ISD::FSINCOS node if there are a pair of fsin / // fcos which share the same operand and both are used. if ((TLI.isOperationLegalOrCustom(ISD::FSINCOS, VT) || isSinCosLibcallAvailable(Node, TLI)) && useSinCos(Node)) { SDVTList VTs = DAG.getVTList(VT, VT); Tmp1 = DAG.getNode(ISD::FSINCOS, dl, VTs, Node->getOperand(0)); if (Node->getOpcode() == ISD::FCOS) Tmp1 = Tmp1.getValue(1); Results.push_back(Tmp1); } break; } case ISD::FMAD: llvm_unreachable("Illegal fmad should never be formed"); case ISD::FP16_TO_FP: if (Node->getValueType(0) != MVT::f32) { // We can extend to types bigger than f32 in two steps without changing // the result. Since "f16 -> f32" is much more commonly available, give // CodeGen the option of emitting that before resorting to a libcall. SDValue Res = DAG.getNode(ISD::FP16_TO_FP, dl, MVT::f32, Node->getOperand(0)); Results.push_back( DAG.getNode(ISD::FP_EXTEND, dl, Node->getValueType(0), Res)); } break; case ISD::FP_TO_FP16: LLVM_DEBUG(dbgs() << "Legalizing FP_TO_FP16\n"); if (!TLI.useSoftFloat() && TM.Options.UnsafeFPMath) { SDValue Op = Node->getOperand(0); MVT SVT = Op.getSimpleValueType(); if ((SVT == MVT::f64 || SVT == MVT::f80) && TLI.isOperationLegalOrCustom(ISD::FP_TO_FP16, MVT::f32)) { // Under fastmath, we can expand this node into a fround followed by // a float-half conversion. SDValue FloatVal = DAG.getNode(ISD::FP_ROUND, dl, MVT::f32, Op, DAG.getIntPtrConstant(0, dl)); Results.push_back( DAG.getNode(ISD::FP_TO_FP16, dl, Node->getValueType(0), FloatVal)); } } break; case ISD::ConstantFP: { ConstantFPSDNode *CFP = cast(Node); // Check to see if this FP immediate is already legal. // If this is a legal constant, turn it into a TargetConstantFP node. if (!TLI.isFPImmLegal(CFP->getValueAPF(), Node->getValueType(0), DAG.getMachineFunction().getFunction().hasOptSize())) Results.push_back(ExpandConstantFP(CFP, true)); break; } case ISD::Constant: { ConstantSDNode *CP = cast(Node); Results.push_back(ExpandConstant(CP)); break; } case ISD::FSUB: { EVT VT = Node->getValueType(0); if (TLI.isOperationLegalOrCustom(ISD::FADD, VT) && TLI.isOperationLegalOrCustom(ISD::FNEG, VT)) { const SDNodeFlags Flags = Node->getFlags(); Tmp1 = DAG.getNode(ISD::FNEG, dl, VT, Node->getOperand(1)); Tmp1 = DAG.getNode(ISD::FADD, dl, VT, Node->getOperand(0), Tmp1, Flags); Results.push_back(Tmp1); } break; } case ISD::SUB: { EVT VT = Node->getValueType(0); assert(TLI.isOperationLegalOrCustom(ISD::ADD, VT) && TLI.isOperationLegalOrCustom(ISD::XOR, VT) && "Don't know how to expand this subtraction!"); Tmp1 = DAG.getNode(ISD::XOR, dl, VT, Node->getOperand(1), DAG.getConstant(APInt::getAllOnesValue(VT.getSizeInBits()), dl, VT)); Tmp1 = DAG.getNode(ISD::ADD, dl, VT, Tmp1, DAG.getConstant(1, dl, VT)); Results.push_back(DAG.getNode(ISD::ADD, dl, VT, Node->getOperand(0), Tmp1)); break; } case ISD::UREM: case ISD::SREM: { EVT VT = Node->getValueType(0); bool isSigned = Node->getOpcode() == ISD::SREM; unsigned DivOpc = isSigned ? ISD::SDIV : ISD::UDIV; unsigned DivRemOpc = isSigned ? ISD::SDIVREM : ISD::UDIVREM; Tmp2 = Node->getOperand(0); Tmp3 = Node->getOperand(1); if (TLI.isOperationLegalOrCustom(DivRemOpc, VT)) { SDVTList VTs = DAG.getVTList(VT, VT); Tmp1 = DAG.getNode(DivRemOpc, dl, VTs, Tmp2, Tmp3).getValue(1); Results.push_back(Tmp1); } else if (TLI.isOperationLegalOrCustom(DivOpc, VT)) { // X % Y -> X-X/Y*Y Tmp1 = DAG.getNode(DivOpc, dl, VT, Tmp2, Tmp3); Tmp1 = DAG.getNode(ISD::MUL, dl, VT, Tmp1, Tmp3); Tmp1 = DAG.getNode(ISD::SUB, dl, VT, Tmp2, Tmp1); Results.push_back(Tmp1); } break; } case ISD::UDIV: case ISD::SDIV: { bool isSigned = Node->getOpcode() == ISD::SDIV; unsigned DivRemOpc = isSigned ? ISD::SDIVREM : ISD::UDIVREM; EVT VT = Node->getValueType(0); if (TLI.isOperationLegalOrCustom(DivRemOpc, VT)) { SDVTList VTs = DAG.getVTList(VT, VT); Tmp1 = DAG.getNode(DivRemOpc, dl, VTs, Node->getOperand(0), Node->getOperand(1)); Results.push_back(Tmp1); } break; } case ISD::MULHU: case ISD::MULHS: { unsigned ExpandOpcode = Node->getOpcode() == ISD::MULHU ? ISD::UMUL_LOHI : ISD::SMUL_LOHI; EVT VT = Node->getValueType(0); SDVTList VTs = DAG.getVTList(VT, VT); Tmp1 = DAG.getNode(ExpandOpcode, dl, VTs, Node->getOperand(0), Node->getOperand(1)); Results.push_back(Tmp1.getValue(1)); break; } case ISD::UMUL_LOHI: case ISD::SMUL_LOHI: { SDValue LHS = Node->getOperand(0); SDValue RHS = Node->getOperand(1); MVT VT = LHS.getSimpleValueType(); unsigned MULHOpcode = Node->getOpcode() == ISD::UMUL_LOHI ? ISD::MULHU : ISD::MULHS; if (TLI.isOperationLegalOrCustom(MULHOpcode, VT)) { Results.push_back(DAG.getNode(ISD::MUL, dl, VT, LHS, RHS)); Results.push_back(DAG.getNode(MULHOpcode, dl, VT, LHS, RHS)); break; } SmallVector Halves; EVT HalfType = EVT(VT).getHalfSizedIntegerVT(*DAG.getContext()); assert(TLI.isTypeLegal(HalfType)); if (TLI.expandMUL_LOHI(Node->getOpcode(), VT, Node, LHS, RHS, Halves, HalfType, DAG, TargetLowering::MulExpansionKind::Always)) { for (unsigned i = 0; i < 2; ++i) { SDValue Lo = DAG.getNode(ISD::ZERO_EXTEND, dl, VT, Halves[2 * i]); SDValue Hi = DAG.getNode(ISD::ANY_EXTEND, dl, VT, Halves[2 * i + 1]); SDValue Shift = DAG.getConstant( HalfType.getScalarSizeInBits(), dl, TLI.getShiftAmountTy(HalfType, DAG.getDataLayout())); Hi = DAG.getNode(ISD::SHL, dl, VT, Hi, Shift); Results.push_back(DAG.getNode(ISD::OR, dl, VT, Lo, Hi)); } break; } break; } case ISD::MUL: { EVT VT = Node->getValueType(0); SDVTList VTs = DAG.getVTList(VT, VT); // See if multiply or divide can be lowered using two-result operations. // We just need the low half of the multiply; try both the signed // and unsigned forms. If the target supports both SMUL_LOHI and // UMUL_LOHI, form a preference by checking which forms of plain // MULH it supports. bool HasSMUL_LOHI = TLI.isOperationLegalOrCustom(ISD::SMUL_LOHI, VT); bool HasUMUL_LOHI = TLI.isOperationLegalOrCustom(ISD::UMUL_LOHI, VT); bool HasMULHS = TLI.isOperationLegalOrCustom(ISD::MULHS, VT); bool HasMULHU = TLI.isOperationLegalOrCustom(ISD::MULHU, VT); unsigned OpToUse = 0; if (HasSMUL_LOHI && !HasMULHS) { OpToUse = ISD::SMUL_LOHI; } else if (HasUMUL_LOHI && !HasMULHU) { OpToUse = ISD::UMUL_LOHI; } else if (HasSMUL_LOHI) { OpToUse = ISD::SMUL_LOHI; } else if (HasUMUL_LOHI) { OpToUse = ISD::UMUL_LOHI; } if (OpToUse) { Results.push_back(DAG.getNode(OpToUse, dl, VTs, Node->getOperand(0), Node->getOperand(1))); break; } SDValue Lo, Hi; EVT HalfType = VT.getHalfSizedIntegerVT(*DAG.getContext()); if (TLI.isOperationLegalOrCustom(ISD::ZERO_EXTEND, VT) && TLI.isOperationLegalOrCustom(ISD::ANY_EXTEND, VT) && TLI.isOperationLegalOrCustom(ISD::SHL, VT) && TLI.isOperationLegalOrCustom(ISD::OR, VT) && TLI.expandMUL(Node, Lo, Hi, HalfType, DAG, TargetLowering::MulExpansionKind::OnlyLegalOrCustom)) { Lo = DAG.getNode(ISD::ZERO_EXTEND, dl, VT, Lo); Hi = DAG.getNode(ISD::ANY_EXTEND, dl, VT, Hi); SDValue Shift = DAG.getConstant(HalfType.getSizeInBits(), dl, TLI.getShiftAmountTy(HalfType, DAG.getDataLayout())); Hi = DAG.getNode(ISD::SHL, dl, VT, Hi, Shift); Results.push_back(DAG.getNode(ISD::OR, dl, VT, Lo, Hi)); } break; } case ISD::FSHL: case ISD::FSHR: if (TLI.expandFunnelShift(Node, Tmp1, DAG)) Results.push_back(Tmp1); break; case ISD::ROTL: case ISD::ROTR: if (TLI.expandROT(Node, Tmp1, DAG)) Results.push_back(Tmp1); break; case ISD::SADDSAT: case ISD::UADDSAT: case ISD::SSUBSAT: case ISD::USUBSAT: Results.push_back(TLI.expandAddSubSat(Node, DAG)); break; case ISD::SMULFIX: case ISD::SMULFIXSAT: case ISD::UMULFIX: case ISD::UMULFIXSAT: Results.push_back(TLI.expandFixedPointMul(Node, DAG)); break; case ISD::SDIVFIX: case ISD::UDIVFIX: if (SDValue V = TLI.expandFixedPointDiv(Node->getOpcode(), SDLoc(Node), Node->getOperand(0), Node->getOperand(1), Node->getConstantOperandVal(2), DAG)) { Results.push_back(V); break; } // FIXME: We might want to retry here with a wider type if we fail, if that // type is legal. // FIXME: Technically, so long as we only have sdivfixes where BW+Scale is // <= 128 (which is the case for all of the default Embedded-C types), // we will only get here with types and scales that we could always expand // if we were allowed to generate libcalls to division functions of illegal // type. But we cannot do that. llvm_unreachable("Cannot expand DIVFIX!"); case ISD::ADDCARRY: case ISD::SUBCARRY: { SDValue LHS = Node->getOperand(0); SDValue RHS = Node->getOperand(1); SDValue Carry = Node->getOperand(2); bool IsAdd = Node->getOpcode() == ISD::ADDCARRY; // Initial add of the 2 operands. unsigned Op = IsAdd ? ISD::ADD : ISD::SUB; EVT VT = LHS.getValueType(); SDValue Sum = DAG.getNode(Op, dl, VT, LHS, RHS); // Initial check for overflow. EVT CarryType = Node->getValueType(1); EVT SetCCType = getSetCCResultType(Node->getValueType(0)); ISD::CondCode CC = IsAdd ? ISD::SETULT : ISD::SETUGT; SDValue Overflow = DAG.getSetCC(dl, SetCCType, Sum, LHS, CC); // Add of the sum and the carry. SDValue CarryExt = DAG.getZeroExtendInReg(DAG.getZExtOrTrunc(Carry, dl, VT), dl, MVT::i1); SDValue Sum2 = DAG.getNode(Op, dl, VT, Sum, CarryExt); // Second check for overflow. If we are adding, we can only overflow if the // initial sum is all 1s ang the carry is set, resulting in a new sum of 0. // If we are subtracting, we can only overflow if the initial sum is 0 and // the carry is set, resulting in a new sum of all 1s. SDValue Zero = DAG.getConstant(0, dl, VT); SDValue Overflow2 = IsAdd ? DAG.getSetCC(dl, SetCCType, Sum2, Zero, ISD::SETEQ) : DAG.getSetCC(dl, SetCCType, Sum, Zero, ISD::SETEQ); Overflow2 = DAG.getNode(ISD::AND, dl, SetCCType, Overflow2, DAG.getZExtOrTrunc(Carry, dl, SetCCType)); SDValue ResultCarry = DAG.getNode(ISD::OR, dl, SetCCType, Overflow, Overflow2); Results.push_back(Sum2); Results.push_back(DAG.getBoolExtOrTrunc(ResultCarry, dl, CarryType, VT)); break; } case ISD::SADDO: case ISD::SSUBO: { SDValue Result, Overflow; TLI.expandSADDSUBO(Node, Result, Overflow, DAG); Results.push_back(Result); Results.push_back(Overflow); break; } case ISD::UADDO: case ISD::USUBO: { SDValue Result, Overflow; TLI.expandUADDSUBO(Node, Result, Overflow, DAG); Results.push_back(Result); Results.push_back(Overflow); break; } case ISD::UMULO: case ISD::SMULO: { SDValue Result, Overflow; if (TLI.expandMULO(Node, Result, Overflow, DAG)) { Results.push_back(Result); Results.push_back(Overflow); } break; } case ISD::BUILD_PAIR: { EVT PairTy = Node->getValueType(0); Tmp1 = DAG.getNode(ISD::ZERO_EXTEND, dl, PairTy, Node->getOperand(0)); Tmp2 = DAG.getNode(ISD::ANY_EXTEND, dl, PairTy, Node->getOperand(1)); Tmp2 = DAG.getNode( ISD::SHL, dl, PairTy, Tmp2, DAG.getConstant(PairTy.getSizeInBits() / 2, dl, TLI.getShiftAmountTy(PairTy, DAG.getDataLayout()))); Results.push_back(DAG.getNode(ISD::OR, dl, PairTy, Tmp1, Tmp2)); break; } case ISD::SELECT: Tmp1 = Node->getOperand(0); Tmp2 = Node->getOperand(1); Tmp3 = Node->getOperand(2); if (Tmp1.getOpcode() == ISD::SETCC) { Tmp1 = DAG.getSelectCC(dl, Tmp1.getOperand(0), Tmp1.getOperand(1), Tmp2, Tmp3, cast(Tmp1.getOperand(2))->get()); } else { Tmp1 = DAG.getSelectCC(dl, Tmp1, DAG.getConstant(0, dl, Tmp1.getValueType()), Tmp2, Tmp3, ISD::SETNE); } Tmp1->setFlags(Node->getFlags()); Results.push_back(Tmp1); break; case ISD::BR_JT: { SDValue Chain = Node->getOperand(0); SDValue Table = Node->getOperand(1); SDValue Index = Node->getOperand(2); const DataLayout &TD = DAG.getDataLayout(); EVT PTy = TLI.getPointerTy(TD); unsigned EntrySize = DAG.getMachineFunction().getJumpTableInfo()->getEntrySize(TD); // For power-of-two jumptable entry sizes convert multiplication to a shift. // This transformation needs to be done here since otherwise the MIPS // backend will end up emitting a three instruction multiply sequence // instead of a single shift and MSP430 will call a runtime function. if (llvm::isPowerOf2_32(EntrySize)) Index = DAG.getNode( ISD::SHL, dl, Index.getValueType(), Index, DAG.getConstant(llvm::Log2_32(EntrySize), dl, Index.getValueType())); else Index = DAG.getNode(ISD::MUL, dl, Index.getValueType(), Index, DAG.getConstant(EntrySize, dl, Index.getValueType())); SDValue Addr = DAG.getNode(ISD::ADD, dl, Index.getValueType(), Index, Table); EVT MemVT = EVT::getIntegerVT(*DAG.getContext(), EntrySize * 8); SDValue LD = DAG.getExtLoad( ISD::SEXTLOAD, dl, PTy, Chain, Addr, MachinePointerInfo::getJumpTable(DAG.getMachineFunction()), MemVT); Addr = LD; if (TLI.isJumpTableRelative()) { // For PIC, the sequence is: // BRIND(load(Jumptable + index) + RelocBase) // RelocBase can be JumpTable, GOT or some sort of global base. Addr = DAG.getNode(ISD::ADD, dl, PTy, Addr, TLI.getPICJumpTableRelocBase(Table, DAG)); } Tmp1 = TLI.expandIndirectJTBranch(dl, LD.getValue(1), Addr, DAG); Results.push_back(Tmp1); break; } case ISD::BRCOND: // Expand brcond's setcc into its constituent parts and create a BR_CC // Node. Tmp1 = Node->getOperand(0); Tmp2 = Node->getOperand(1); if (Tmp2.getOpcode() == ISD::SETCC) { Tmp1 = DAG.getNode(ISD::BR_CC, dl, MVT::Other, Tmp1, Tmp2.getOperand(2), Tmp2.getOperand(0), Tmp2.getOperand(1), Node->getOperand(2)); } else { // We test only the i1 bit. Skip the AND if UNDEF or another AND. if (Tmp2.isUndef() || (Tmp2.getOpcode() == ISD::AND && isa(Tmp2.getOperand(1)) && cast(Tmp2.getOperand(1))->getZExtValue() == 1)) Tmp3 = Tmp2; else Tmp3 = DAG.getNode(ISD::AND, dl, Tmp2.getValueType(), Tmp2, DAG.getConstant(1, dl, Tmp2.getValueType())); Tmp1 = DAG.getNode(ISD::BR_CC, dl, MVT::Other, Tmp1, DAG.getCondCode(ISD::SETNE), Tmp3, DAG.getConstant(0, dl, Tmp3.getValueType()), Node->getOperand(2)); } Results.push_back(Tmp1); break; case ISD::SETCC: case ISD::STRICT_FSETCC: case ISD::STRICT_FSETCCS: { bool IsStrict = Node->getOpcode() != ISD::SETCC; bool IsSignaling = Node->getOpcode() == ISD::STRICT_FSETCCS; SDValue Chain = IsStrict ? Node->getOperand(0) : SDValue(); unsigned Offset = IsStrict ? 1 : 0; Tmp1 = Node->getOperand(0 + Offset); Tmp2 = Node->getOperand(1 + Offset); Tmp3 = Node->getOperand(2 + Offset); bool Legalized = LegalizeSetCCCondCode(Node->getValueType(0), Tmp1, Tmp2, Tmp3, NeedInvert, dl, Chain, IsSignaling); if (Legalized) { // If we expanded the SETCC by swapping LHS and RHS, or by inverting the // condition code, create a new SETCC node. if (Tmp3.getNode()) Tmp1 = DAG.getNode(ISD::SETCC, dl, Node->getValueType(0), Tmp1, Tmp2, Tmp3, Node->getFlags()); // If we expanded the SETCC by inverting the condition code, then wrap // the existing SETCC in a NOT to restore the intended condition. if (NeedInvert) Tmp1 = DAG.getLogicalNOT(dl, Tmp1, Tmp1->getValueType(0)); Results.push_back(Tmp1); if (IsStrict) Results.push_back(Chain); break; } // FIXME: It seems Legalized is false iff CCCode is Legal. I don't // understand if this code is useful for strict nodes. assert(!IsStrict && "Don't know how to expand for strict nodes."); // Otherwise, SETCC for the given comparison type must be completely // illegal; expand it into a SELECT_CC. EVT VT = Node->getValueType(0); int TrueValue; switch (TLI.getBooleanContents(Tmp1.getValueType())) { case TargetLowering::ZeroOrOneBooleanContent: case TargetLowering::UndefinedBooleanContent: TrueValue = 1; break; case TargetLowering::ZeroOrNegativeOneBooleanContent: TrueValue = -1; break; } Tmp1 = DAG.getNode(ISD::SELECT_CC, dl, VT, Tmp1, Tmp2, DAG.getConstant(TrueValue, dl, VT), DAG.getConstant(0, dl, VT), Tmp3); Tmp1->setFlags(Node->getFlags()); Results.push_back(Tmp1); break; } case ISD::SELECT_CC: { // TODO: need to add STRICT_SELECT_CC and STRICT_SELECT_CCS Tmp1 = Node->getOperand(0); // LHS Tmp2 = Node->getOperand(1); // RHS Tmp3 = Node->getOperand(2); // True Tmp4 = Node->getOperand(3); // False EVT VT = Node->getValueType(0); SDValue Chain; SDValue CC = Node->getOperand(4); ISD::CondCode CCOp = cast(CC)->get(); if (TLI.isCondCodeLegalOrCustom(CCOp, Tmp1.getSimpleValueType())) { // If the condition code is legal, then we need to expand this // node using SETCC and SELECT. EVT CmpVT = Tmp1.getValueType(); assert(!TLI.isOperationExpand(ISD::SELECT, VT) && "Cannot expand ISD::SELECT_CC when ISD::SELECT also needs to be " "expanded."); EVT CCVT = getSetCCResultType(CmpVT); SDValue Cond = DAG.getNode(ISD::SETCC, dl, CCVT, Tmp1, Tmp2, CC, Node->getFlags()); Results.push_back(DAG.getSelect(dl, VT, Cond, Tmp3, Tmp4)); break; } // SELECT_CC is legal, so the condition code must not be. bool Legalized = false; // Try to legalize by inverting the condition. This is for targets that // might support an ordered version of a condition, but not the unordered // version (or vice versa). ISD::CondCode InvCC = ISD::getSetCCInverse(CCOp, Tmp1.getValueType()); if (TLI.isCondCodeLegalOrCustom(InvCC, Tmp1.getSimpleValueType())) { // Use the new condition code and swap true and false Legalized = true; Tmp1 = DAG.getSelectCC(dl, Tmp1, Tmp2, Tmp4, Tmp3, InvCC); Tmp1->setFlags(Node->getFlags()); } else { // If The inverse is not legal, then try to swap the arguments using // the inverse condition code. ISD::CondCode SwapInvCC = ISD::getSetCCSwappedOperands(InvCC); if (TLI.isCondCodeLegalOrCustom(SwapInvCC, Tmp1.getSimpleValueType())) { // The swapped inverse condition is legal, so swap true and false, // lhs and rhs. Legalized = true; Tmp1 = DAG.getSelectCC(dl, Tmp2, Tmp1, Tmp4, Tmp3, SwapInvCC); Tmp1->setFlags(Node->getFlags()); } } if (!Legalized) { Legalized = LegalizeSetCCCondCode(getSetCCResultType(Tmp1.getValueType()), Tmp1, Tmp2, CC, NeedInvert, dl, Chain); assert(Legalized && "Can't legalize SELECT_CC with legal condition!"); // If we expanded the SETCC by inverting the condition code, then swap // the True/False operands to match. if (NeedInvert) std::swap(Tmp3, Tmp4); // If we expanded the SETCC by swapping LHS and RHS, or by inverting the // condition code, create a new SELECT_CC node. if (CC.getNode()) { Tmp1 = DAG.getNode(ISD::SELECT_CC, dl, Node->getValueType(0), Tmp1, Tmp2, Tmp3, Tmp4, CC); } else { Tmp2 = DAG.getConstant(0, dl, Tmp1.getValueType()); CC = DAG.getCondCode(ISD::SETNE); Tmp1 = DAG.getNode(ISD::SELECT_CC, dl, Node->getValueType(0), Tmp1, Tmp2, Tmp3, Tmp4, CC); } Tmp1->setFlags(Node->getFlags()); } Results.push_back(Tmp1); break; } case ISD::BR_CC: { // TODO: need to add STRICT_BR_CC and STRICT_BR_CCS SDValue Chain; Tmp1 = Node->getOperand(0); // Chain Tmp2 = Node->getOperand(2); // LHS Tmp3 = Node->getOperand(3); // RHS Tmp4 = Node->getOperand(1); // CC bool Legalized = LegalizeSetCCCondCode(getSetCCResultType(Tmp2.getValueType()), Tmp2, Tmp3, Tmp4, NeedInvert, dl, Chain); (void)Legalized; assert(Legalized && "Can't legalize BR_CC with legal condition!"); assert(!NeedInvert && "Don't know how to invert BR_CC!"); // If we expanded the SETCC by swapping LHS and RHS, create a new BR_CC // node. if (Tmp4.getNode()) { Tmp1 = DAG.getNode(ISD::BR_CC, dl, Node->getValueType(0), Tmp1, Tmp4, Tmp2, Tmp3, Node->getOperand(4)); } else { Tmp3 = DAG.getConstant(0, dl, Tmp2.getValueType()); Tmp4 = DAG.getCondCode(ISD::SETNE); Tmp1 = DAG.getNode(ISD::BR_CC, dl, Node->getValueType(0), Tmp1, Tmp4, Tmp2, Tmp3, Node->getOperand(4)); } Results.push_back(Tmp1); break; } case ISD::BUILD_VECTOR: Results.push_back(ExpandBUILD_VECTOR(Node)); break; case ISD::SPLAT_VECTOR: Results.push_back(ExpandSPLAT_VECTOR(Node)); break; case ISD::SRA: case ISD::SRL: case ISD::SHL: { // Scalarize vector SRA/SRL/SHL. EVT VT = Node->getValueType(0); assert(VT.isVector() && "Unable to legalize non-vector shift"); assert(TLI.isTypeLegal(VT.getScalarType())&& "Element type must be legal"); unsigned NumElem = VT.getVectorNumElements(); SmallVector Scalars; for (unsigned Idx = 0; Idx < NumElem; Idx++) { SDValue Ex = DAG.getNode( ISD::EXTRACT_VECTOR_ELT, dl, VT.getScalarType(), Node->getOperand(0), DAG.getConstant(Idx, dl, TLI.getVectorIdxTy(DAG.getDataLayout()))); SDValue Sh = DAG.getNode( ISD::EXTRACT_VECTOR_ELT, dl, VT.getScalarType(), Node->getOperand(1), DAG.getConstant(Idx, dl, TLI.getVectorIdxTy(DAG.getDataLayout()))); Scalars.push_back(DAG.getNode(Node->getOpcode(), dl, VT.getScalarType(), Ex, Sh)); } SDValue Result = DAG.getBuildVector(Node->getValueType(0), dl, Scalars); Results.push_back(Result); break; } case ISD::VECREDUCE_FADD: case ISD::VECREDUCE_FMUL: case ISD::VECREDUCE_ADD: case ISD::VECREDUCE_MUL: case ISD::VECREDUCE_AND: case ISD::VECREDUCE_OR: case ISD::VECREDUCE_XOR: case ISD::VECREDUCE_SMAX: case ISD::VECREDUCE_SMIN: case ISD::VECREDUCE_UMAX: case ISD::VECREDUCE_UMIN: case ISD::VECREDUCE_FMAX: case ISD::VECREDUCE_FMIN: Results.push_back(TLI.expandVecReduce(Node, DAG)); break; case ISD::GLOBAL_OFFSET_TABLE: case ISD::GlobalAddress: case ISD::GlobalTLSAddress: case ISD::ExternalSymbol: case ISD::ConstantPool: case ISD::JumpTable: case ISD::INTRINSIC_W_CHAIN: case ISD::INTRINSIC_WO_CHAIN: case ISD::INTRINSIC_VOID: // FIXME: Custom lowering for these operations shouldn't return null! // Return true so that we don't call ConvertNodeToLibcall which also won't // do anything. return true; } if (!TLI.isStrictFPEnabled() && Results.empty() && Node->isStrictFPOpcode()) { // FIXME: We were asked to expand a strict floating-point operation, // but there is currently no expansion implemented that would preserve // the "strict" properties. For now, we just fall back to the non-strict // version if that is legal on the target. The actual mutation of the // operation will happen in SelectionDAGISel::DoInstructionSelection. switch (Node->getOpcode()) { default: if (TLI.getStrictFPOperationAction(Node->getOpcode(), Node->getValueType(0)) == TargetLowering::Legal) return true; break; case ISD::STRICT_LRINT: case ISD::STRICT_LLRINT: case ISD::STRICT_LROUND: case ISD::STRICT_LLROUND: // These are registered by the operand type instead of the value // type. Reflect that here. if (TLI.getStrictFPOperationAction(Node->getOpcode(), Node->getOperand(1).getValueType()) == TargetLowering::Legal) return true; break; } } // Replace the original node with the legalized result. if (Results.empty()) { LLVM_DEBUG(dbgs() << "Cannot expand node\n"); return false; } LLVM_DEBUG(dbgs() << "Successfully expanded node\n"); ReplaceNode(Node, Results.data()); return true; } void SelectionDAGLegalize::ConvertNodeToLibcall(SDNode *Node) { LLVM_DEBUG(dbgs() << "Trying to convert node to libcall\n"); SmallVector Results; SDLoc dl(Node); // FIXME: Check flags on the node to see if we can use a finite call. - bool CanUseFiniteLibCall = TM.Options.NoInfsFPMath && TM.Options.NoNaNsFPMath; unsigned Opc = Node->getOpcode(); switch (Opc) { case ISD::ATOMIC_FENCE: { // If the target didn't lower this, lower it to '__sync_synchronize()' call // FIXME: handle "fence singlethread" more efficiently. TargetLowering::ArgListTy Args; TargetLowering::CallLoweringInfo CLI(DAG); CLI.setDebugLoc(dl) .setChain(Node->getOperand(0)) .setLibCallee( CallingConv::C, Type::getVoidTy(*DAG.getContext()), DAG.getExternalSymbol("__sync_synchronize", TLI.getPointerTy(DAG.getDataLayout())), std::move(Args)); std::pair CallResult = TLI.LowerCallTo(CLI); Results.push_back(CallResult.second); break; } // By default, atomic intrinsics are marked Legal and lowered. Targets // which don't support them directly, however, may want libcalls, in which // case they mark them Expand, and we get here. case ISD::ATOMIC_SWAP: case ISD::ATOMIC_LOAD_ADD: case ISD::ATOMIC_LOAD_SUB: case ISD::ATOMIC_LOAD_AND: case ISD::ATOMIC_LOAD_CLR: case ISD::ATOMIC_LOAD_OR: case ISD::ATOMIC_LOAD_XOR: case ISD::ATOMIC_LOAD_NAND: case ISD::ATOMIC_LOAD_MIN: case ISD::ATOMIC_LOAD_MAX: case ISD::ATOMIC_LOAD_UMIN: case ISD::ATOMIC_LOAD_UMAX: case ISD::ATOMIC_CMP_SWAP: { MVT VT = cast(Node)->getMemoryVT().getSimpleVT(); RTLIB::Libcall LC = RTLIB::getSYNC(Opc, VT); assert(LC != RTLIB::UNKNOWN_LIBCALL && "Unexpected atomic op or value type!"); EVT RetVT = Node->getValueType(0); SmallVector Ops(Node->op_begin() + 1, Node->op_end()); TargetLowering::MakeLibCallOptions CallOptions; std::pair Tmp = TLI.makeLibCall(DAG, LC, RetVT, Ops, CallOptions, SDLoc(Node), Node->getOperand(0)); Results.push_back(Tmp.first); Results.push_back(Tmp.second); break; } case ISD::TRAP: { // If this operation is not supported, lower it to 'abort()' call TargetLowering::ArgListTy Args; TargetLowering::CallLoweringInfo CLI(DAG); CLI.setDebugLoc(dl) .setChain(Node->getOperand(0)) .setLibCallee(CallingConv::C, Type::getVoidTy(*DAG.getContext()), DAG.getExternalSymbol( "abort", TLI.getPointerTy(DAG.getDataLayout())), std::move(Args)); std::pair CallResult = TLI.LowerCallTo(CLI); Results.push_back(CallResult.second); break; } case ISD::FMINNUM: case ISD::STRICT_FMINNUM: ExpandFPLibCall(Node, RTLIB::FMIN_F32, RTLIB::FMIN_F64, RTLIB::FMIN_F80, RTLIB::FMIN_F128, RTLIB::FMIN_PPCF128, Results); break; case ISD::FMAXNUM: case ISD::STRICT_FMAXNUM: ExpandFPLibCall(Node, RTLIB::FMAX_F32, RTLIB::FMAX_F64, RTLIB::FMAX_F80, RTLIB::FMAX_F128, RTLIB::FMAX_PPCF128, Results); break; case ISD::FSQRT: case ISD::STRICT_FSQRT: ExpandFPLibCall(Node, RTLIB::SQRT_F32, RTLIB::SQRT_F64, RTLIB::SQRT_F80, RTLIB::SQRT_F128, RTLIB::SQRT_PPCF128, Results); break; case ISD::FCBRT: ExpandFPLibCall(Node, RTLIB::CBRT_F32, RTLIB::CBRT_F64, RTLIB::CBRT_F80, RTLIB::CBRT_F128, RTLIB::CBRT_PPCF128, Results); break; case ISD::FSIN: case ISD::STRICT_FSIN: ExpandFPLibCall(Node, RTLIB::SIN_F32, RTLIB::SIN_F64, RTLIB::SIN_F80, RTLIB::SIN_F128, RTLIB::SIN_PPCF128, Results); break; case ISD::FCOS: case ISD::STRICT_FCOS: ExpandFPLibCall(Node, RTLIB::COS_F32, RTLIB::COS_F64, RTLIB::COS_F80, RTLIB::COS_F128, RTLIB::COS_PPCF128, Results); break; case ISD::FSINCOS: // Expand into sincos libcall. ExpandSinCosLibCall(Node, Results); break; case ISD::FLOG: case ISD::STRICT_FLOG: - if (CanUseFiniteLibCall && DAG.getLibInfo().has(LibFunc_log_finite)) - ExpandFPLibCall(Node, RTLIB::LOG_FINITE_F32, - RTLIB::LOG_FINITE_F64, - RTLIB::LOG_FINITE_F80, - RTLIB::LOG_FINITE_F128, - RTLIB::LOG_FINITE_PPCF128, Results); - else - ExpandFPLibCall(Node, RTLIB::LOG_F32, RTLIB::LOG_F64, - RTLIB::LOG_F80, RTLIB::LOG_F128, - RTLIB::LOG_PPCF128, Results); + ExpandFPLibCall(Node, RTLIB::LOG_F32, RTLIB::LOG_F64, RTLIB::LOG_F80, + RTLIB::LOG_F128, RTLIB::LOG_PPCF128, Results); break; case ISD::FLOG2: case ISD::STRICT_FLOG2: - if (CanUseFiniteLibCall && DAG.getLibInfo().has(LibFunc_log2_finite)) - ExpandFPLibCall(Node, RTLIB::LOG2_FINITE_F32, - RTLIB::LOG2_FINITE_F64, - RTLIB::LOG2_FINITE_F80, - RTLIB::LOG2_FINITE_F128, - RTLIB::LOG2_FINITE_PPCF128, Results); - else - ExpandFPLibCall(Node, RTLIB::LOG2_F32, RTLIB::LOG2_F64, - RTLIB::LOG2_F80, RTLIB::LOG2_F128, - RTLIB::LOG2_PPCF128, Results); + ExpandFPLibCall(Node, RTLIB::LOG2_F32, RTLIB::LOG2_F64, RTLIB::LOG2_F80, + RTLIB::LOG2_F128, RTLIB::LOG2_PPCF128, Results); break; case ISD::FLOG10: case ISD::STRICT_FLOG10: - if (CanUseFiniteLibCall && DAG.getLibInfo().has(LibFunc_log10_finite)) - ExpandFPLibCall(Node, RTLIB::LOG10_FINITE_F32, - RTLIB::LOG10_FINITE_F64, - RTLIB::LOG10_FINITE_F80, - RTLIB::LOG10_FINITE_F128, - RTLIB::LOG10_FINITE_PPCF128, Results); - else - ExpandFPLibCall(Node, RTLIB::LOG10_F32, RTLIB::LOG10_F64, - RTLIB::LOG10_F80, RTLIB::LOG10_F128, - RTLIB::LOG10_PPCF128, Results); + ExpandFPLibCall(Node, RTLIB::LOG10_F32, RTLIB::LOG10_F64, RTLIB::LOG10_F80, + RTLIB::LOG10_F128, RTLIB::LOG10_PPCF128, Results); break; case ISD::FEXP: case ISD::STRICT_FEXP: - if (CanUseFiniteLibCall && DAG.getLibInfo().has(LibFunc_exp_finite)) - ExpandFPLibCall(Node, RTLIB::EXP_FINITE_F32, - RTLIB::EXP_FINITE_F64, - RTLIB::EXP_FINITE_F80, - RTLIB::EXP_FINITE_F128, - RTLIB::EXP_FINITE_PPCF128, Results); - else - ExpandFPLibCall(Node, RTLIB::EXP_F32, RTLIB::EXP_F64, - RTLIB::EXP_F80, RTLIB::EXP_F128, - RTLIB::EXP_PPCF128, Results); + ExpandFPLibCall(Node, RTLIB::EXP_F32, RTLIB::EXP_F64, RTLIB::EXP_F80, + RTLIB::EXP_F128, RTLIB::EXP_PPCF128, Results); break; case ISD::FEXP2: case ISD::STRICT_FEXP2: - if (CanUseFiniteLibCall && DAG.getLibInfo().has(LibFunc_exp2_finite)) - ExpandFPLibCall(Node, RTLIB::EXP2_FINITE_F32, - RTLIB::EXP2_FINITE_F64, - RTLIB::EXP2_FINITE_F80, - RTLIB::EXP2_FINITE_F128, - RTLIB::EXP2_FINITE_PPCF128, Results); - else - ExpandFPLibCall(Node, RTLIB::EXP2_F32, RTLIB::EXP2_F64, - RTLIB::EXP2_F80, RTLIB::EXP2_F128, - RTLIB::EXP2_PPCF128, Results); + ExpandFPLibCall(Node, RTLIB::EXP2_F32, RTLIB::EXP2_F64, RTLIB::EXP2_F80, + RTLIB::EXP2_F128, RTLIB::EXP2_PPCF128, Results); break; case ISD::FTRUNC: case ISD::STRICT_FTRUNC: ExpandFPLibCall(Node, RTLIB::TRUNC_F32, RTLIB::TRUNC_F64, RTLIB::TRUNC_F80, RTLIB::TRUNC_F128, RTLIB::TRUNC_PPCF128, Results); break; case ISD::FFLOOR: case ISD::STRICT_FFLOOR: ExpandFPLibCall(Node, RTLIB::FLOOR_F32, RTLIB::FLOOR_F64, RTLIB::FLOOR_F80, RTLIB::FLOOR_F128, RTLIB::FLOOR_PPCF128, Results); break; case ISD::FCEIL: case ISD::STRICT_FCEIL: ExpandFPLibCall(Node, RTLIB::CEIL_F32, RTLIB::CEIL_F64, RTLIB::CEIL_F80, RTLIB::CEIL_F128, RTLIB::CEIL_PPCF128, Results); break; case ISD::FRINT: case ISD::STRICT_FRINT: ExpandFPLibCall(Node, RTLIB::RINT_F32, RTLIB::RINT_F64, RTLIB::RINT_F80, RTLIB::RINT_F128, RTLIB::RINT_PPCF128, Results); break; case ISD::FNEARBYINT: case ISD::STRICT_FNEARBYINT: ExpandFPLibCall(Node, RTLIB::NEARBYINT_F32, RTLIB::NEARBYINT_F64, RTLIB::NEARBYINT_F80, RTLIB::NEARBYINT_F128, RTLIB::NEARBYINT_PPCF128, Results); break; case ISD::FROUND: case ISD::STRICT_FROUND: ExpandFPLibCall(Node, RTLIB::ROUND_F32, RTLIB::ROUND_F64, RTLIB::ROUND_F80, RTLIB::ROUND_F128, RTLIB::ROUND_PPCF128, Results); break; case ISD::FPOWI: case ISD::STRICT_FPOWI: { RTLIB::Libcall LC; switch (Node->getSimpleValueType(0).SimpleTy) { default: llvm_unreachable("Unexpected request for libcall!"); case MVT::f32: LC = RTLIB::POWI_F32; break; case MVT::f64: LC = RTLIB::POWI_F64; break; case MVT::f80: LC = RTLIB::POWI_F80; break; case MVT::f128: LC = RTLIB::POWI_F128; break; case MVT::ppcf128: LC = RTLIB::POWI_PPCF128; break; } if (!TLI.getLibcallName(LC)) { // Some targets don't have a powi libcall; use pow instead. SDValue Exponent = DAG.getNode(ISD::SINT_TO_FP, SDLoc(Node), Node->getValueType(0), Node->getOperand(1)); Results.push_back(DAG.getNode(ISD::FPOW, SDLoc(Node), Node->getValueType(0), Node->getOperand(0), Exponent)); break; } ExpandFPLibCall(Node, RTLIB::POWI_F32, RTLIB::POWI_F64, RTLIB::POWI_F80, RTLIB::POWI_F128, RTLIB::POWI_PPCF128, Results); break; } case ISD::FPOW: case ISD::STRICT_FPOW: - if (CanUseFiniteLibCall && DAG.getLibInfo().has(LibFunc_pow_finite)) - ExpandFPLibCall(Node, RTLIB::POW_FINITE_F32, - RTLIB::POW_FINITE_F64, - RTLIB::POW_FINITE_F80, - RTLIB::POW_FINITE_F128, - RTLIB::POW_FINITE_PPCF128, Results); - else - ExpandFPLibCall(Node, RTLIB::POW_F32, RTLIB::POW_F64, - RTLIB::POW_F80, RTLIB::POW_F128, - RTLIB::POW_PPCF128, Results); + ExpandFPLibCall(Node, RTLIB::POW_F32, RTLIB::POW_F64, RTLIB::POW_F80, + RTLIB::POW_F128, RTLIB::POW_PPCF128, Results); break; case ISD::LROUND: case ISD::STRICT_LROUND: ExpandArgFPLibCall(Node, RTLIB::LROUND_F32, RTLIB::LROUND_F64, RTLIB::LROUND_F80, RTLIB::LROUND_F128, RTLIB::LROUND_PPCF128, Results); break; case ISD::LLROUND: case ISD::STRICT_LLROUND: ExpandArgFPLibCall(Node, RTLIB::LLROUND_F32, RTLIB::LLROUND_F64, RTLIB::LLROUND_F80, RTLIB::LLROUND_F128, RTLIB::LLROUND_PPCF128, Results); break; case ISD::LRINT: case ISD::STRICT_LRINT: ExpandArgFPLibCall(Node, RTLIB::LRINT_F32, RTLIB::LRINT_F64, RTLIB::LRINT_F80, RTLIB::LRINT_F128, RTLIB::LRINT_PPCF128, Results); break; case ISD::LLRINT: case ISD::STRICT_LLRINT: ExpandArgFPLibCall(Node, RTLIB::LLRINT_F32, RTLIB::LLRINT_F64, RTLIB::LLRINT_F80, RTLIB::LLRINT_F128, RTLIB::LLRINT_PPCF128, Results); break; case ISD::FDIV: case ISD::STRICT_FDIV: ExpandFPLibCall(Node, RTLIB::DIV_F32, RTLIB::DIV_F64, RTLIB::DIV_F80, RTLIB::DIV_F128, RTLIB::DIV_PPCF128, Results); break; case ISD::FREM: case ISD::STRICT_FREM: ExpandFPLibCall(Node, RTLIB::REM_F32, RTLIB::REM_F64, RTLIB::REM_F80, RTLIB::REM_F128, RTLIB::REM_PPCF128, Results); break; case ISD::FMA: case ISD::STRICT_FMA: ExpandFPLibCall(Node, RTLIB::FMA_F32, RTLIB::FMA_F64, RTLIB::FMA_F80, RTLIB::FMA_F128, RTLIB::FMA_PPCF128, Results); break; case ISD::FADD: case ISD::STRICT_FADD: ExpandFPLibCall(Node, RTLIB::ADD_F32, RTLIB::ADD_F64, RTLIB::ADD_F80, RTLIB::ADD_F128, RTLIB::ADD_PPCF128, Results); break; case ISD::FMUL: case ISD::STRICT_FMUL: ExpandFPLibCall(Node, RTLIB::MUL_F32, RTLIB::MUL_F64, RTLIB::MUL_F80, RTLIB::MUL_F128, RTLIB::MUL_PPCF128, Results); break; case ISD::FP16_TO_FP: if (Node->getValueType(0) == MVT::f32) { Results.push_back(ExpandLibCall(RTLIB::FPEXT_F16_F32, Node, false)); } break; case ISD::FP_TO_FP16: { RTLIB::Libcall LC = RTLIB::getFPROUND(Node->getOperand(0).getValueType(), MVT::f16); assert(LC != RTLIB::UNKNOWN_LIBCALL && "Unable to expand fp_to_fp16"); Results.push_back(ExpandLibCall(LC, Node, false)); break; } case ISD::FSUB: case ISD::STRICT_FSUB: ExpandFPLibCall(Node, RTLIB::SUB_F32, RTLIB::SUB_F64, RTLIB::SUB_F80, RTLIB::SUB_F128, RTLIB::SUB_PPCF128, Results); break; case ISD::SREM: Results.push_back(ExpandIntLibCall(Node, true, RTLIB::SREM_I8, RTLIB::SREM_I16, RTLIB::SREM_I32, RTLIB::SREM_I64, RTLIB::SREM_I128)); break; case ISD::UREM: Results.push_back(ExpandIntLibCall(Node, false, RTLIB::UREM_I8, RTLIB::UREM_I16, RTLIB::UREM_I32, RTLIB::UREM_I64, RTLIB::UREM_I128)); break; case ISD::SDIV: Results.push_back(ExpandIntLibCall(Node, true, RTLIB::SDIV_I8, RTLIB::SDIV_I16, RTLIB::SDIV_I32, RTLIB::SDIV_I64, RTLIB::SDIV_I128)); break; case ISD::UDIV: Results.push_back(ExpandIntLibCall(Node, false, RTLIB::UDIV_I8, RTLIB::UDIV_I16, RTLIB::UDIV_I32, RTLIB::UDIV_I64, RTLIB::UDIV_I128)); break; case ISD::SDIVREM: case ISD::UDIVREM: // Expand into divrem libcall ExpandDivRemLibCall(Node, Results); break; case ISD::MUL: Results.push_back(ExpandIntLibCall(Node, false, RTLIB::MUL_I8, RTLIB::MUL_I16, RTLIB::MUL_I32, RTLIB::MUL_I64, RTLIB::MUL_I128)); break; case ISD::CTLZ_ZERO_UNDEF: switch (Node->getSimpleValueType(0).SimpleTy) { default: llvm_unreachable("LibCall explicitly requested, but not available"); case MVT::i32: Results.push_back(ExpandLibCall(RTLIB::CTLZ_I32, Node, false)); break; case MVT::i64: Results.push_back(ExpandLibCall(RTLIB::CTLZ_I64, Node, false)); break; case MVT::i128: Results.push_back(ExpandLibCall(RTLIB::CTLZ_I128, Node, false)); break; } break; } // Replace the original node with the legalized result. if (!Results.empty()) { LLVM_DEBUG(dbgs() << "Successfully converted node to libcall\n"); ReplaceNode(Node, Results.data()); } else LLVM_DEBUG(dbgs() << "Could not convert node to libcall\n"); } // Determine the vector type to use in place of an original scalar element when // promoting equally sized vectors. static MVT getPromotedVectorElementType(const TargetLowering &TLI, MVT EltVT, MVT NewEltVT) { unsigned OldEltsPerNewElt = EltVT.getSizeInBits() / NewEltVT.getSizeInBits(); MVT MidVT = MVT::getVectorVT(NewEltVT, OldEltsPerNewElt); assert(TLI.isTypeLegal(MidVT) && "unexpected"); return MidVT; } void SelectionDAGLegalize::PromoteNode(SDNode *Node) { LLVM_DEBUG(dbgs() << "Trying to promote node\n"); SmallVector Results; MVT OVT = Node->getSimpleValueType(0); if (Node->getOpcode() == ISD::UINT_TO_FP || Node->getOpcode() == ISD::SINT_TO_FP || Node->getOpcode() == ISD::SETCC || Node->getOpcode() == ISD::EXTRACT_VECTOR_ELT || Node->getOpcode() == ISD::INSERT_VECTOR_ELT) { OVT = Node->getOperand(0).getSimpleValueType(); } if (Node->getOpcode() == ISD::STRICT_UINT_TO_FP || Node->getOpcode() == ISD::STRICT_SINT_TO_FP) OVT = Node->getOperand(1).getSimpleValueType(); if (Node->getOpcode() == ISD::BR_CC) OVT = Node->getOperand(2).getSimpleValueType(); MVT NVT = TLI.getTypeToPromoteTo(Node->getOpcode(), OVT); SDLoc dl(Node); SDValue Tmp1, Tmp2, Tmp3; switch (Node->getOpcode()) { case ISD::CTTZ: case ISD::CTTZ_ZERO_UNDEF: case ISD::CTLZ: case ISD::CTLZ_ZERO_UNDEF: case ISD::CTPOP: // Zero extend the argument. Tmp1 = DAG.getNode(ISD::ZERO_EXTEND, dl, NVT, Node->getOperand(0)); if (Node->getOpcode() == ISD::CTTZ) { // The count is the same in the promoted type except if the original // value was zero. This can be handled by setting the bit just off // the top of the original type. auto TopBit = APInt::getOneBitSet(NVT.getSizeInBits(), OVT.getSizeInBits()); Tmp1 = DAG.getNode(ISD::OR, dl, NVT, Tmp1, DAG.getConstant(TopBit, dl, NVT)); } // Perform the larger operation. For CTPOP and CTTZ_ZERO_UNDEF, this is // already the correct result. Tmp1 = DAG.getNode(Node->getOpcode(), dl, NVT, Tmp1); if (Node->getOpcode() == ISD::CTLZ || Node->getOpcode() == ISD::CTLZ_ZERO_UNDEF) { // Tmp1 = Tmp1 - (sizeinbits(NVT) - sizeinbits(Old VT)) Tmp1 = DAG.getNode(ISD::SUB, dl, NVT, Tmp1, DAG.getConstant(NVT.getSizeInBits() - OVT.getSizeInBits(), dl, NVT)); } Results.push_back(DAG.getNode(ISD::TRUNCATE, dl, OVT, Tmp1)); break; case ISD::BITREVERSE: case ISD::BSWAP: { unsigned DiffBits = NVT.getSizeInBits() - OVT.getSizeInBits(); Tmp1 = DAG.getNode(ISD::ZERO_EXTEND, dl, NVT, Node->getOperand(0)); Tmp1 = DAG.getNode(Node->getOpcode(), dl, NVT, Tmp1); Tmp1 = DAG.getNode( ISD::SRL, dl, NVT, Tmp1, DAG.getConstant(DiffBits, dl, TLI.getShiftAmountTy(NVT, DAG.getDataLayout()))); Results.push_back(DAG.getNode(ISD::TRUNCATE, dl, OVT, Tmp1)); break; } case ISD::FP_TO_UINT: case ISD::STRICT_FP_TO_UINT: case ISD::FP_TO_SINT: case ISD::STRICT_FP_TO_SINT: PromoteLegalFP_TO_INT(Node, dl, Results); break; case ISD::UINT_TO_FP: case ISD::STRICT_UINT_TO_FP: case ISD::SINT_TO_FP: case ISD::STRICT_SINT_TO_FP: PromoteLegalINT_TO_FP(Node, dl, Results); break; case ISD::VAARG: { SDValue Chain = Node->getOperand(0); // Get the chain. SDValue Ptr = Node->getOperand(1); // Get the pointer. unsigned TruncOp; if (OVT.isVector()) { TruncOp = ISD::BITCAST; } else { assert(OVT.isInteger() && "VAARG promotion is supported only for vectors or integer types"); TruncOp = ISD::TRUNCATE; } // Perform the larger operation, then convert back Tmp1 = DAG.getVAArg(NVT, dl, Chain, Ptr, Node->getOperand(2), Node->getConstantOperandVal(3)); Chain = Tmp1.getValue(1); Tmp2 = DAG.getNode(TruncOp, dl, OVT, Tmp1); // Modified the chain result - switch anything that used the old chain to // use the new one. DAG.ReplaceAllUsesOfValueWith(SDValue(Node, 0), Tmp2); DAG.ReplaceAllUsesOfValueWith(SDValue(Node, 1), Chain); if (UpdatedNodes) { UpdatedNodes->insert(Tmp2.getNode()); UpdatedNodes->insert(Chain.getNode()); } ReplacedNode(Node); break; } case ISD::MUL: case ISD::SDIV: case ISD::SREM: case ISD::UDIV: case ISD::UREM: case ISD::AND: case ISD::OR: case ISD::XOR: { unsigned ExtOp, TruncOp; if (OVT.isVector()) { ExtOp = ISD::BITCAST; TruncOp = ISD::BITCAST; } else { assert(OVT.isInteger() && "Cannot promote logic operation"); switch (Node->getOpcode()) { default: ExtOp = ISD::ANY_EXTEND; break; case ISD::SDIV: case ISD::SREM: ExtOp = ISD::SIGN_EXTEND; break; case ISD::UDIV: case ISD::UREM: ExtOp = ISD::ZERO_EXTEND; break; } TruncOp = ISD::TRUNCATE; } // Promote each of the values to the new type. Tmp1 = DAG.getNode(ExtOp, dl, NVT, Node->getOperand(0)); Tmp2 = DAG.getNode(ExtOp, dl, NVT, Node->getOperand(1)); // Perform the larger operation, then convert back Tmp1 = DAG.getNode(Node->getOpcode(), dl, NVT, Tmp1, Tmp2); Results.push_back(DAG.getNode(TruncOp, dl, OVT, Tmp1)); break; } case ISD::UMUL_LOHI: case ISD::SMUL_LOHI: { // Promote to a multiply in a wider integer type. unsigned ExtOp = Node->getOpcode() == ISD::UMUL_LOHI ? ISD::ZERO_EXTEND : ISD::SIGN_EXTEND; Tmp1 = DAG.getNode(ExtOp, dl, NVT, Node->getOperand(0)); Tmp2 = DAG.getNode(ExtOp, dl, NVT, Node->getOperand(1)); Tmp1 = DAG.getNode(ISD::MUL, dl, NVT, Tmp1, Tmp2); auto &DL = DAG.getDataLayout(); unsigned OriginalSize = OVT.getScalarSizeInBits(); Tmp2 = DAG.getNode( ISD::SRL, dl, NVT, Tmp1, DAG.getConstant(OriginalSize, dl, TLI.getScalarShiftAmountTy(DL, NVT))); Results.push_back(DAG.getNode(ISD::TRUNCATE, dl, OVT, Tmp1)); Results.push_back(DAG.getNode(ISD::TRUNCATE, dl, OVT, Tmp2)); break; } case ISD::SELECT: { unsigned ExtOp, TruncOp; if (Node->getValueType(0).isVector() || Node->getValueType(0).getSizeInBits() == NVT.getSizeInBits()) { ExtOp = ISD::BITCAST; TruncOp = ISD::BITCAST; } else if (Node->getValueType(0).isInteger()) { ExtOp = ISD::ANY_EXTEND; TruncOp = ISD::TRUNCATE; } else { ExtOp = ISD::FP_EXTEND; TruncOp = ISD::FP_ROUND; } Tmp1 = Node->getOperand(0); // Promote each of the values to the new type. Tmp2 = DAG.getNode(ExtOp, dl, NVT, Node->getOperand(1)); Tmp3 = DAG.getNode(ExtOp, dl, NVT, Node->getOperand(2)); // Perform the larger operation, then round down. Tmp1 = DAG.getSelect(dl, NVT, Tmp1, Tmp2, Tmp3); Tmp1->setFlags(Node->getFlags()); if (TruncOp != ISD::FP_ROUND) Tmp1 = DAG.getNode(TruncOp, dl, Node->getValueType(0), Tmp1); else Tmp1 = DAG.getNode(TruncOp, dl, Node->getValueType(0), Tmp1, DAG.getIntPtrConstant(0, dl)); Results.push_back(Tmp1); break; } case ISD::VECTOR_SHUFFLE: { ArrayRef Mask = cast(Node)->getMask(); // Cast the two input vectors. Tmp1 = DAG.getNode(ISD::BITCAST, dl, NVT, Node->getOperand(0)); Tmp2 = DAG.getNode(ISD::BITCAST, dl, NVT, Node->getOperand(1)); // Convert the shuffle mask to the right # elements. Tmp1 = ShuffleWithNarrowerEltType(NVT, OVT, dl, Tmp1, Tmp2, Mask); Tmp1 = DAG.getNode(ISD::BITCAST, dl, OVT, Tmp1); Results.push_back(Tmp1); break; } case ISD::SETCC: { unsigned ExtOp = ISD::FP_EXTEND; if (NVT.isInteger()) { ISD::CondCode CCCode = cast(Node->getOperand(2))->get(); ExtOp = isSignedIntSetCC(CCCode) ? ISD::SIGN_EXTEND : ISD::ZERO_EXTEND; } Tmp1 = DAG.getNode(ExtOp, dl, NVT, Node->getOperand(0)); Tmp2 = DAG.getNode(ExtOp, dl, NVT, Node->getOperand(1)); Results.push_back(DAG.getNode(ISD::SETCC, dl, Node->getValueType(0), Tmp1, Tmp2, Node->getOperand(2), Node->getFlags())); break; } case ISD::BR_CC: { unsigned ExtOp = ISD::FP_EXTEND; if (NVT.isInteger()) { ISD::CondCode CCCode = cast(Node->getOperand(1))->get(); ExtOp = isSignedIntSetCC(CCCode) ? ISD::SIGN_EXTEND : ISD::ZERO_EXTEND; } Tmp1 = DAG.getNode(ExtOp, dl, NVT, Node->getOperand(2)); Tmp2 = DAG.getNode(ExtOp, dl, NVT, Node->getOperand(3)); Results.push_back(DAG.getNode(ISD::BR_CC, dl, Node->getValueType(0), Node->getOperand(0), Node->getOperand(1), Tmp1, Tmp2, Node->getOperand(4))); break; } case ISD::FADD: case ISD::FSUB: case ISD::FMUL: case ISD::FDIV: case ISD::FREM: case ISD::FMINNUM: case ISD::FMAXNUM: case ISD::FPOW: Tmp1 = DAG.getNode(ISD::FP_EXTEND, dl, NVT, Node->getOperand(0)); Tmp2 = DAG.getNode(ISD::FP_EXTEND, dl, NVT, Node->getOperand(1)); Tmp3 = DAG.getNode(Node->getOpcode(), dl, NVT, Tmp1, Tmp2, Node->getFlags()); Results.push_back(DAG.getNode(ISD::FP_ROUND, dl, OVT, Tmp3, DAG.getIntPtrConstant(0, dl))); break; case ISD::STRICT_FREM: case ISD::STRICT_FPOW: Tmp1 = DAG.getNode(ISD::STRICT_FP_EXTEND, dl, {NVT, MVT::Other}, {Node->getOperand(0), Node->getOperand(1)}); Tmp2 = DAG.getNode(ISD::STRICT_FP_EXTEND, dl, {NVT, MVT::Other}, {Node->getOperand(0), Node->getOperand(2)}); Tmp3 = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, Tmp1.getValue(1), Tmp2.getValue(1)); Tmp1 = DAG.getNode(Node->getOpcode(), dl, {NVT, MVT::Other}, {Tmp3, Tmp1, Tmp2}); Tmp1 = DAG.getNode(ISD::STRICT_FP_ROUND, dl, {OVT, MVT::Other}, {Tmp1.getValue(1), Tmp1, DAG.getIntPtrConstant(0, dl)}); Results.push_back(Tmp1); Results.push_back(Tmp1.getValue(1)); break; case ISD::FMA: Tmp1 = DAG.getNode(ISD::FP_EXTEND, dl, NVT, Node->getOperand(0)); Tmp2 = DAG.getNode(ISD::FP_EXTEND, dl, NVT, Node->getOperand(1)); Tmp3 = DAG.getNode(ISD::FP_EXTEND, dl, NVT, Node->getOperand(2)); Results.push_back( DAG.getNode(ISD::FP_ROUND, dl, OVT, DAG.getNode(Node->getOpcode(), dl, NVT, Tmp1, Tmp2, Tmp3), DAG.getIntPtrConstant(0, dl))); break; case ISD::FCOPYSIGN: case ISD::FPOWI: { Tmp1 = DAG.getNode(ISD::FP_EXTEND, dl, NVT, Node->getOperand(0)); Tmp2 = Node->getOperand(1); Tmp3 = DAG.getNode(Node->getOpcode(), dl, NVT, Tmp1, Tmp2); // fcopysign doesn't change anything but the sign bit, so // (fp_round (fcopysign (fpext a), b)) // is as precise as // (fp_round (fpext a)) // which is a no-op. Mark it as a TRUNCating FP_ROUND. const bool isTrunc = (Node->getOpcode() == ISD::FCOPYSIGN); Results.push_back(DAG.getNode(ISD::FP_ROUND, dl, OVT, Tmp3, DAG.getIntPtrConstant(isTrunc, dl))); break; } case ISD::FFLOOR: case ISD::FCEIL: case ISD::FRINT: case ISD::FNEARBYINT: case ISD::FROUND: case ISD::FTRUNC: case ISD::FNEG: case ISD::FSQRT: case ISD::FSIN: case ISD::FCOS: case ISD::FLOG: case ISD::FLOG2: case ISD::FLOG10: case ISD::FABS: case ISD::FEXP: case ISD::FEXP2: Tmp1 = DAG.getNode(ISD::FP_EXTEND, dl, NVT, Node->getOperand(0)); Tmp2 = DAG.getNode(Node->getOpcode(), dl, NVT, Tmp1); Results.push_back(DAG.getNode(ISD::FP_ROUND, dl, OVT, Tmp2, DAG.getIntPtrConstant(0, dl))); break; case ISD::STRICT_FFLOOR: case ISD::STRICT_FCEIL: case ISD::STRICT_FSIN: case ISD::STRICT_FCOS: case ISD::STRICT_FLOG: case ISD::STRICT_FLOG10: case ISD::STRICT_FEXP: Tmp1 = DAG.getNode(ISD::STRICT_FP_EXTEND, dl, {NVT, MVT::Other}, {Node->getOperand(0), Node->getOperand(1)}); Tmp2 = DAG.getNode(Node->getOpcode(), dl, {NVT, MVT::Other}, {Tmp1.getValue(1), Tmp1}); Tmp3 = DAG.getNode(ISD::STRICT_FP_ROUND, dl, {OVT, MVT::Other}, {Tmp2.getValue(1), Tmp2, DAG.getIntPtrConstant(0, dl)}); Results.push_back(Tmp3); Results.push_back(Tmp3.getValue(1)); break; case ISD::BUILD_VECTOR: { MVT EltVT = OVT.getVectorElementType(); MVT NewEltVT = NVT.getVectorElementType(); // Handle bitcasts to a different vector type with the same total bit size // // e.g. v2i64 = build_vector i64:x, i64:y => v4i32 // => // v4i32 = concat_vectors (v2i32 (bitcast i64:x)), (v2i32 (bitcast i64:y)) assert(NVT.isVector() && OVT.getSizeInBits() == NVT.getSizeInBits() && "Invalid promote type for build_vector"); assert(NewEltVT.bitsLT(EltVT) && "not handled"); MVT MidVT = getPromotedVectorElementType(TLI, EltVT, NewEltVT); SmallVector NewOps; for (unsigned I = 0, E = Node->getNumOperands(); I != E; ++I) { SDValue Op = Node->getOperand(I); NewOps.push_back(DAG.getNode(ISD::BITCAST, SDLoc(Op), MidVT, Op)); } SDLoc SL(Node); SDValue Concat = DAG.getNode(ISD::CONCAT_VECTORS, SL, NVT, NewOps); SDValue CvtVec = DAG.getNode(ISD::BITCAST, SL, OVT, Concat); Results.push_back(CvtVec); break; } case ISD::EXTRACT_VECTOR_ELT: { MVT EltVT = OVT.getVectorElementType(); MVT NewEltVT = NVT.getVectorElementType(); // Handle bitcasts to a different vector type with the same total bit size. // // e.g. v2i64 = extract_vector_elt x:v2i64, y:i32 // => // v4i32:castx = bitcast x:v2i64 // // i64 = bitcast // (v2i32 build_vector (i32 (extract_vector_elt castx, (2 * y))), // (i32 (extract_vector_elt castx, (2 * y + 1))) // assert(NVT.isVector() && OVT.getSizeInBits() == NVT.getSizeInBits() && "Invalid promote type for extract_vector_elt"); assert(NewEltVT.bitsLT(EltVT) && "not handled"); MVT MidVT = getPromotedVectorElementType(TLI, EltVT, NewEltVT); unsigned NewEltsPerOldElt = MidVT.getVectorNumElements(); SDValue Idx = Node->getOperand(1); EVT IdxVT = Idx.getValueType(); SDLoc SL(Node); SDValue Factor = DAG.getConstant(NewEltsPerOldElt, SL, IdxVT); SDValue NewBaseIdx = DAG.getNode(ISD::MUL, SL, IdxVT, Idx, Factor); SDValue CastVec = DAG.getNode(ISD::BITCAST, SL, NVT, Node->getOperand(0)); SmallVector NewOps; for (unsigned I = 0; I < NewEltsPerOldElt; ++I) { SDValue IdxOffset = DAG.getConstant(I, SL, IdxVT); SDValue TmpIdx = DAG.getNode(ISD::ADD, SL, IdxVT, NewBaseIdx, IdxOffset); SDValue Elt = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, SL, NewEltVT, CastVec, TmpIdx); NewOps.push_back(Elt); } SDValue NewVec = DAG.getBuildVector(MidVT, SL, NewOps); Results.push_back(DAG.getNode(ISD::BITCAST, SL, EltVT, NewVec)); break; } case ISD::INSERT_VECTOR_ELT: { MVT EltVT = OVT.getVectorElementType(); MVT NewEltVT = NVT.getVectorElementType(); // Handle bitcasts to a different vector type with the same total bit size // // e.g. v2i64 = insert_vector_elt x:v2i64, y:i64, z:i32 // => // v4i32:castx = bitcast x:v2i64 // v2i32:casty = bitcast y:i64 // // v2i64 = bitcast // (v4i32 insert_vector_elt // (v4i32 insert_vector_elt v4i32:castx, // (extract_vector_elt casty, 0), 2 * z), // (extract_vector_elt casty, 1), (2 * z + 1)) assert(NVT.isVector() && OVT.getSizeInBits() == NVT.getSizeInBits() && "Invalid promote type for insert_vector_elt"); assert(NewEltVT.bitsLT(EltVT) && "not handled"); MVT MidVT = getPromotedVectorElementType(TLI, EltVT, NewEltVT); unsigned NewEltsPerOldElt = MidVT.getVectorNumElements(); SDValue Val = Node->getOperand(1); SDValue Idx = Node->getOperand(2); EVT IdxVT = Idx.getValueType(); SDLoc SL(Node); SDValue Factor = DAG.getConstant(NewEltsPerOldElt, SDLoc(), IdxVT); SDValue NewBaseIdx = DAG.getNode(ISD::MUL, SL, IdxVT, Idx, Factor); SDValue CastVec = DAG.getNode(ISD::BITCAST, SL, NVT, Node->getOperand(0)); SDValue CastVal = DAG.getNode(ISD::BITCAST, SL, MidVT, Val); SDValue NewVec = CastVec; for (unsigned I = 0; I < NewEltsPerOldElt; ++I) { SDValue IdxOffset = DAG.getConstant(I, SL, IdxVT); SDValue InEltIdx = DAG.getNode(ISD::ADD, SL, IdxVT, NewBaseIdx, IdxOffset); SDValue Elt = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, SL, NewEltVT, CastVal, IdxOffset); NewVec = DAG.getNode(ISD::INSERT_VECTOR_ELT, SL, NVT, NewVec, Elt, InEltIdx); } Results.push_back(DAG.getNode(ISD::BITCAST, SL, OVT, NewVec)); break; } case ISD::SCALAR_TO_VECTOR: { MVT EltVT = OVT.getVectorElementType(); MVT NewEltVT = NVT.getVectorElementType(); // Handle bitcasts to different vector type with the same total bit size. // // e.g. v2i64 = scalar_to_vector x:i64 // => // concat_vectors (v2i32 bitcast x:i64), (v2i32 undef) // MVT MidVT = getPromotedVectorElementType(TLI, EltVT, NewEltVT); SDValue Val = Node->getOperand(0); SDLoc SL(Node); SDValue CastVal = DAG.getNode(ISD::BITCAST, SL, MidVT, Val); SDValue Undef = DAG.getUNDEF(MidVT); SmallVector NewElts; NewElts.push_back(CastVal); for (unsigned I = 1, NElts = OVT.getVectorNumElements(); I != NElts; ++I) NewElts.push_back(Undef); SDValue Concat = DAG.getNode(ISD::CONCAT_VECTORS, SL, NVT, NewElts); SDValue CvtVec = DAG.getNode(ISD::BITCAST, SL, OVT, Concat); Results.push_back(CvtVec); break; } case ISD::ATOMIC_SWAP: { AtomicSDNode *AM = cast(Node); SDLoc SL(Node); SDValue CastVal = DAG.getNode(ISD::BITCAST, SL, NVT, AM->getVal()); assert(NVT.getSizeInBits() == OVT.getSizeInBits() && "unexpected promotion type"); assert(AM->getMemoryVT().getSizeInBits() == NVT.getSizeInBits() && "unexpected atomic_swap with illegal type"); SDValue NewAtomic = DAG.getAtomic(ISD::ATOMIC_SWAP, SL, NVT, DAG.getVTList(NVT, MVT::Other), { AM->getChain(), AM->getBasePtr(), CastVal }, AM->getMemOperand()); Results.push_back(DAG.getNode(ISD::BITCAST, SL, OVT, NewAtomic)); Results.push_back(NewAtomic.getValue(1)); break; } } // Replace the original node with the legalized result. if (!Results.empty()) { LLVM_DEBUG(dbgs() << "Successfully promoted node\n"); ReplaceNode(Node, Results.data()); } else LLVM_DEBUG(dbgs() << "Could not promote node\n"); } /// This is the entry point for the file. void SelectionDAG::Legalize() { AssignTopologicalOrder(); SmallPtrSet LegalizedNodes; // Use a delete listener to remove nodes which were deleted during // legalization from LegalizeNodes. This is needed to handle the situation // where a new node is allocated by the object pool to the same address of a // previously deleted node. DAGNodeDeletedListener DeleteListener( *this, [&LegalizedNodes](SDNode *N, SDNode *E) { LegalizedNodes.erase(N); }); SelectionDAGLegalize Legalizer(*this, LegalizedNodes); // Visit all the nodes. We start in topological order, so that we see // nodes with their original operands intact. Legalization can produce // new nodes which may themselves need to be legalized. Iterate until all // nodes have been legalized. while (true) { bool AnyLegalized = false; for (auto NI = allnodes_end(); NI != allnodes_begin();) { --NI; SDNode *N = &*NI; if (N->use_empty() && N != getRoot().getNode()) { ++NI; DeleteNode(N); continue; } if (LegalizedNodes.insert(N).second) { AnyLegalized = true; Legalizer.LegalizeOp(N); if (N->use_empty() && N != getRoot().getNode()) { ++NI; DeleteNode(N); } } } if (!AnyLegalized) break; } // Remove dead nodes now. RemoveDeadNodes(); } bool SelectionDAG::LegalizeOp(SDNode *N, SmallSetVector &UpdatedNodes) { SmallPtrSet LegalizedNodes; SelectionDAGLegalize Legalizer(*this, LegalizedNodes, &UpdatedNodes); // Directly insert the node in question, and legalize it. This will recurse // as needed through operands. LegalizedNodes.insert(N); Legalizer.LegalizeOp(N); return LegalizedNodes.count(N); } diff --git a/contrib/llvm-project/llvm/lib/Support/CRC.cpp b/contrib/llvm-project/llvm/lib/Support/CRC.cpp index 2bc668beed32..7ff09debe3b7 100644 --- a/contrib/llvm-project/llvm/lib/Support/CRC.cpp +++ b/contrib/llvm-project/llvm/lib/Support/CRC.cpp @@ -1,107 +1,107 @@ //===--- CRC.cpp - Cyclic Redundancy Check implementation -----------------===// // // 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 contains implementations of CRC functions. // // The implementation technique is the one mentioned in: // D. V. Sarwate. 1988. Computation of cyclic redundancy checks via table // look-up. Commun. ACM 31, 8 (August 1988) // // See also Ross N. Williams "A Painless Guide to CRC Error Detection // Algorithms" (https://zlib.net/crc_v3.txt) or Hacker's Delight (2nd ed.) // Chapter 14 (Figure 14-7 in particular) for how the algorithm works. // //===----------------------------------------------------------------------===// #include "llvm/Support/CRC.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/Config/config.h" using namespace llvm; -#if !LLVM_ENABLE_ZLIB +#if LLVM_ENABLE_ZLIB == 0 || !HAVE_ZLIB_H static const uint32_t CRCTable[256] = { 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d}; uint32_t llvm::crc32(uint32_t CRC, ArrayRef Data) { CRC ^= 0xFFFFFFFFU; for (uint8_t Byte : Data) { int TableIdx = (CRC ^ Byte) & 0xff; CRC = CRCTable[TableIdx] ^ (CRC >> 8); } return CRC ^ 0xFFFFFFFFU; } #else #include uint32_t llvm::crc32(uint32_t CRC, ArrayRef Data) { // Zlib's crc32() only takes a 32-bit length, so we have to iterate for larger // sizes. One could use crc32_z() instead, but that's a recent (2017) addition // and may not be available on all systems. do { ArrayRef Slice = Data.take_front(UINT32_MAX); CRC = ::crc32(CRC, (const Bytef *)Slice.data(), (uInt)Slice.size()); Data = Data.drop_front(Slice.size()); } while (Data.size() > 0); return CRC; } #endif uint32_t llvm::crc32(ArrayRef Data) { return crc32(0, Data); } void JamCRC::update(ArrayRef Data) { CRC ^= 0xFFFFFFFFU; // Undo CRC-32 Init. CRC = crc32(CRC, Data); CRC ^= 0xFFFFFFFFU; // Undo CRC-32 XorOut. } diff --git a/contrib/llvm-project/llvm/lib/Support/Compression.cpp b/contrib/llvm-project/llvm/lib/Support/Compression.cpp index 4165a2740cd0..97d5ffaadf82 100644 --- a/contrib/llvm-project/llvm/lib/Support/Compression.cpp +++ b/contrib/llvm-project/llvm/lib/Support/Compression.cpp @@ -1,106 +1,106 @@ //===--- Compression.cpp - Compression implementation ---------------------===// // // 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 compression functions. // //===----------------------------------------------------------------------===// #include "llvm/Support/Compression.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/Config/config.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/Error.h" #include "llvm/Support/ErrorHandling.h" -#if LLVM_ENABLE_ZLIB +#if LLVM_ENABLE_ZLIB == 1 && HAVE_ZLIB_H #include #endif using namespace llvm; -#if LLVM_ENABLE_ZLIB +#if LLVM_ENABLE_ZLIB == 1 && HAVE_LIBZ static Error createError(StringRef Err) { return make_error(Err, inconvertibleErrorCode()); } static StringRef convertZlibCodeToString(int Code) { switch (Code) { case Z_MEM_ERROR: return "zlib error: Z_MEM_ERROR"; case Z_BUF_ERROR: return "zlib error: Z_BUF_ERROR"; case Z_STREAM_ERROR: return "zlib error: Z_STREAM_ERROR"; case Z_DATA_ERROR: return "zlib error: Z_DATA_ERROR"; case Z_OK: default: llvm_unreachable("unknown or unexpected zlib status code"); } } bool zlib::isAvailable() { return true; } Error zlib::compress(StringRef InputBuffer, SmallVectorImpl &CompressedBuffer, int Level) { unsigned long CompressedSize = ::compressBound(InputBuffer.size()); CompressedBuffer.reserve(CompressedSize); int Res = ::compress2((Bytef *)CompressedBuffer.data(), &CompressedSize, (const Bytef *)InputBuffer.data(), InputBuffer.size(), Level); // Tell MemorySanitizer that zlib output buffer is fully initialized. // This avoids a false report when running LLVM with uninstrumented ZLib. __msan_unpoison(CompressedBuffer.data(), CompressedSize); CompressedBuffer.set_size(CompressedSize); return Res ? createError(convertZlibCodeToString(Res)) : Error::success(); } Error zlib::uncompress(StringRef InputBuffer, char *UncompressedBuffer, size_t &UncompressedSize) { int Res = ::uncompress((Bytef *)UncompressedBuffer, (uLongf *)&UncompressedSize, (const Bytef *)InputBuffer.data(), InputBuffer.size()); // Tell MemorySanitizer that zlib output buffer is fully initialized. // This avoids a false report when running LLVM with uninstrumented ZLib. __msan_unpoison(UncompressedBuffer, UncompressedSize); return Res ? createError(convertZlibCodeToString(Res)) : Error::success(); } Error zlib::uncompress(StringRef InputBuffer, SmallVectorImpl &UncompressedBuffer, size_t UncompressedSize) { UncompressedBuffer.resize(UncompressedSize); Error E = uncompress(InputBuffer, UncompressedBuffer.data(), UncompressedSize); UncompressedBuffer.resize(UncompressedSize); return E; } uint32_t zlib::crc32(StringRef Buffer) { return ::crc32(0, (const Bytef *)Buffer.data(), Buffer.size()); } #else bool zlib::isAvailable() { return false; } Error zlib::compress(StringRef InputBuffer, SmallVectorImpl &CompressedBuffer, int Level) { llvm_unreachable("zlib::compress is unavailable"); } Error zlib::uncompress(StringRef InputBuffer, char *UncompressedBuffer, size_t &UncompressedSize) { llvm_unreachable("zlib::uncompress is unavailable"); } Error zlib::uncompress(StringRef InputBuffer, SmallVectorImpl &UncompressedBuffer, size_t UncompressedSize) { llvm_unreachable("zlib::uncompress is unavailable"); } uint32_t zlib::crc32(StringRef Buffer) { llvm_unreachable("zlib::crc32 is unavailable"); } #endif diff --git a/contrib/llvm-project/llvm/lib/Support/CrashRecoveryContext.cpp b/contrib/llvm-project/llvm/lib/Support/CrashRecoveryContext.cpp index 356835609830..ec7d7d641dce 100644 --- a/contrib/llvm-project/llvm/lib/Support/CrashRecoveryContext.cpp +++ b/contrib/llvm-project/llvm/lib/Support/CrashRecoveryContext.cpp @@ -1,483 +1,483 @@ //===--- CrashRecoveryContext.cpp - Crash Recovery ------------------------===// // // 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 // //===----------------------------------------------------------------------===// #include "llvm/Support/CrashRecoveryContext.h" #include "llvm/Config/llvm-config.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/Signals.h" #include "llvm/Support/ThreadLocal.h" #include #include #if LLVM_ON_UNIX #include // EX_IOERR #endif using namespace llvm; namespace { struct CrashRecoveryContextImpl; static ManagedStatic< sys::ThreadLocal > CurrentContext; struct CrashRecoveryContextImpl { // When threads are disabled, this links up all active // CrashRecoveryContextImpls. When threads are enabled there's one thread // per CrashRecoveryContext and CurrentContext is a thread-local, so only one // CrashRecoveryContextImpl is active per thread and this is always null. const CrashRecoveryContextImpl *Next; CrashRecoveryContext *CRC; ::jmp_buf JumpBuffer; volatile unsigned Failed : 1; unsigned SwitchedThread : 1; unsigned ValidJumpBuffer : 1; public: CrashRecoveryContextImpl(CrashRecoveryContext *CRC) noexcept : CRC(CRC), Failed(false), SwitchedThread(false), ValidJumpBuffer(false) { Next = CurrentContext->get(); CurrentContext->set(this); } ~CrashRecoveryContextImpl() { if (!SwitchedThread) CurrentContext->set(Next); } /// Called when the separate crash-recovery thread was finished, to /// indicate that we don't need to clear the thread-local CurrentContext. void setSwitchedThread() { #if defined(LLVM_ENABLE_THREADS) && LLVM_ENABLE_THREADS != 0 SwitchedThread = true; #endif } // If the function ran by the CrashRecoveryContext crashes or fails, then // 'RetCode' represents the returned error code, as if it was returned by a // process. 'Context' represents the signal type on Unix; on Windows, it is // the ExceptionContext. void HandleCrash(int RetCode, uintptr_t Context) { // Eliminate the current context entry, to avoid re-entering in case the // cleanup code crashes. CurrentContext->set(Next); assert(!Failed && "Crash recovery context already failed!"); Failed = true; if (CRC->DumpStackAndCleanupOnFailure) sys::CleanupOnSignal(Context); CRC->RetCode = RetCode; // Jump back to the RunSafely we were called under. if (ValidJumpBuffer) longjmp(JumpBuffer, 1); // Otherwise let the caller decide of the outcome of the crash. Currently // this occurs when using SEH on Windows with MSVC or clang-cl. } }; } static ManagedStatic gCrashRecoveryContextMutex; static bool gCrashRecoveryEnabled = false; static ManagedStatic> tlIsRecoveringFromCrash; static void installExceptionOrSignalHandlers(); static void uninstallExceptionOrSignalHandlers(); CrashRecoveryContextCleanup::~CrashRecoveryContextCleanup() {} CrashRecoveryContext::~CrashRecoveryContext() { // Reclaim registered resources. CrashRecoveryContextCleanup *i = head; const CrashRecoveryContext *PC = tlIsRecoveringFromCrash->get(); tlIsRecoveringFromCrash->set(this); while (i) { CrashRecoveryContextCleanup *tmp = i; i = tmp->next; tmp->cleanupFired = true; tmp->recoverResources(); delete tmp; } tlIsRecoveringFromCrash->set(PC); CrashRecoveryContextImpl *CRCI = (CrashRecoveryContextImpl *) Impl; delete CRCI; } bool CrashRecoveryContext::isRecoveringFromCrash() { return tlIsRecoveringFromCrash->get() != nullptr; } CrashRecoveryContext *CrashRecoveryContext::GetCurrent() { if (!gCrashRecoveryEnabled) return nullptr; const CrashRecoveryContextImpl *CRCI = CurrentContext->get(); if (!CRCI) return nullptr; return CRCI->CRC; } void CrashRecoveryContext::Enable() { std::lock_guard L(*gCrashRecoveryContextMutex); // FIXME: Shouldn't this be a refcount or something? if (gCrashRecoveryEnabled) return; gCrashRecoveryEnabled = true; installExceptionOrSignalHandlers(); } void CrashRecoveryContext::Disable() { std::lock_guard L(*gCrashRecoveryContextMutex); if (!gCrashRecoveryEnabled) return; gCrashRecoveryEnabled = false; uninstallExceptionOrSignalHandlers(); } void CrashRecoveryContext::registerCleanup(CrashRecoveryContextCleanup *cleanup) { if (!cleanup) return; if (head) head->prev = cleanup; cleanup->next = head; head = cleanup; } void CrashRecoveryContext::unregisterCleanup(CrashRecoveryContextCleanup *cleanup) { if (!cleanup) return; if (cleanup == head) { head = cleanup->next; if (head) head->prev = nullptr; } else { cleanup->prev->next = cleanup->next; if (cleanup->next) cleanup->next->prev = cleanup->prev; } delete cleanup; } #if defined(_MSC_VER) #include // for GetExceptionInformation // If _MSC_VER is defined, we must have SEH. Use it if it's available. It's way // better than VEH. Vectored exception handling catches all exceptions happening // on the thread with installed exception handlers, so it can interfere with // internal exception handling of other libraries on that thread. SEH works // exactly as you would expect normal exception handling to work: it only // catches exceptions if they would bubble out from the stack frame with __try / // __except. static void installExceptionOrSignalHandlers() {} static void uninstallExceptionOrSignalHandlers() {} // We need this function because the call to GetExceptionInformation() can only // occur inside the __except evaluation block static int ExceptionFilter(_EXCEPTION_POINTERS *Except) { // Lookup the current thread local recovery object. const CrashRecoveryContextImpl *CRCI = CurrentContext->get(); if (!CRCI) { // Something has gone horribly wrong, so let's just tell everyone // to keep searching CrashRecoveryContext::Disable(); return EXCEPTION_CONTINUE_SEARCH; } int RetCode = (int)Except->ExceptionRecord->ExceptionCode; if ((RetCode & 0xF0000000) == 0xE0000000) RetCode &= ~0xF0000000; // this crash was generated by sys::Process::Exit // Handle the crash const_cast(CRCI)->HandleCrash( RetCode, reinterpret_cast(Except)); return EXCEPTION_EXECUTE_HANDLER; } #if defined(__clang__) && defined(_M_IX86) // Work around PR44697. __attribute__((optnone)) #endif bool CrashRecoveryContext::RunSafely(function_ref Fn) { if (!gCrashRecoveryEnabled) { Fn(); return true; } assert(!Impl && "Crash recovery context already initialized!"); Impl = new CrashRecoveryContextImpl(this); __try { Fn(); } __except (ExceptionFilter(GetExceptionInformation())) { return false; } return true; } #else // !_MSC_VER #if defined(_WIN32) // This is a non-MSVC compiler, probably mingw gcc or clang without // -fms-extensions. Use vectored exception handling (VEH). // // On Windows, we can make use of vectored exception handling to catch most // crashing situations. Note that this does mean we will be alerted of // exceptions *before* structured exception handling has the opportunity to // catch it. Unfortunately, this causes problems in practice with other code // running on threads with LLVM crash recovery contexts, so we would like to // eventually move away from VEH. // // Vectored works on a per-thread basis, which is an advantage over // SetUnhandledExceptionFilter. SetUnhandledExceptionFilter also doesn't have // any native support for chaining exception handlers, but VEH allows more than // one. // // The vectored exception handler functionality was added in Windows // XP, so if support for older versions of Windows is required, // it will have to be added. -#include "Windows/WindowsSupport.h" +#include "llvm/Support/Windows/WindowsSupport.h" static LONG CALLBACK ExceptionHandler(PEXCEPTION_POINTERS ExceptionInfo) { // DBG_PRINTEXCEPTION_WIDE_C is not properly defined on all supported // compilers and platforms, so we define it manually. constexpr ULONG DbgPrintExceptionWideC = 0x4001000AL; switch (ExceptionInfo->ExceptionRecord->ExceptionCode) { case DBG_PRINTEXCEPTION_C: case DbgPrintExceptionWideC: case 0x406D1388: // set debugger thread name return EXCEPTION_CONTINUE_EXECUTION; } // Lookup the current thread local recovery object. const CrashRecoveryContextImpl *CRCI = CurrentContext->get(); if (!CRCI) { // Something has gone horribly wrong, so let's just tell everyone // to keep searching CrashRecoveryContext::Disable(); return EXCEPTION_CONTINUE_SEARCH; } // TODO: We can capture the stack backtrace here and store it on the // implementation if we so choose. int RetCode = (int)ExceptionInfo->ExceptionRecord->ExceptionCode; if ((RetCode & 0xF0000000) == 0xE0000000) RetCode &= ~0xF0000000; // this crash was generated by sys::Process::Exit // Handle the crash const_cast(CRCI)->HandleCrash( RetCode, reinterpret_cast(ExceptionInfo)); // Note that we don't actually get here because HandleCrash calls // longjmp, which means the HandleCrash function never returns. llvm_unreachable("Handled the crash, should have longjmp'ed out of here"); } // Because the Enable and Disable calls are static, it means that // there may not actually be an Impl available, or even a current // CrashRecoveryContext at all. So we make use of a thread-local // exception table. The handles contained in here will either be // non-NULL, valid VEH handles, or NULL. static sys::ThreadLocal sCurrentExceptionHandle; static void installExceptionOrSignalHandlers() { // We can set up vectored exception handling now. We will install our // handler as the front of the list, though there's no assurances that // it will remain at the front (another call could install itself before // our handler). This 1) isn't likely, and 2) shouldn't cause problems. PVOID handle = ::AddVectoredExceptionHandler(1, ExceptionHandler); sCurrentExceptionHandle.set(handle); } static void uninstallExceptionOrSignalHandlers() { PVOID currentHandle = const_cast(sCurrentExceptionHandle.get()); if (currentHandle) { // Now we can remove the vectored exception handler from the chain ::RemoveVectoredExceptionHandler(currentHandle); // Reset the handle in our thread-local set. sCurrentExceptionHandle.set(NULL); } } #else // !_WIN32 // Generic POSIX implementation. // // This implementation relies on synchronous signals being delivered to the // current thread. We use a thread local object to keep track of the active // crash recovery context, and install signal handlers to invoke HandleCrash on // the active object. // // This implementation does not attempt to chain signal handlers in any // reliable fashion -- if we get a signal outside of a crash recovery context we // simply disable crash recovery and raise the signal again. #include static const int Signals[] = { SIGABRT, SIGBUS, SIGFPE, SIGILL, SIGSEGV, SIGTRAP }; static const unsigned NumSignals = array_lengthof(Signals); static struct sigaction PrevActions[NumSignals]; static void CrashRecoverySignalHandler(int Signal) { // Lookup the current thread local recovery object. const CrashRecoveryContextImpl *CRCI = CurrentContext->get(); if (!CRCI) { // We didn't find a crash recovery context -- this means either we got a // signal on a thread we didn't expect it on, the application got a signal // outside of a crash recovery context, or something else went horribly // wrong. // // Disable crash recovery and raise the signal again. The assumption here is // that the enclosing application will terminate soon, and we won't want to // attempt crash recovery again. // // This call of Disable isn't thread safe, but it doesn't actually matter. CrashRecoveryContext::Disable(); raise(Signal); // The signal will be thrown once the signal mask is restored. return; } // Unblock the signal we received. sigset_t SigMask; sigemptyset(&SigMask); sigaddset(&SigMask, Signal); sigprocmask(SIG_UNBLOCK, &SigMask, nullptr); // As per convention, -2 indicates a crash or timeout as opposed to failure to // execute (see llvm/include/llvm/Support/Program.h) int RetCode = -2; // Don't consider a broken pipe as a crash (see clang/lib/Driver/Driver.cpp) if (Signal == SIGPIPE) RetCode = EX_IOERR; if (CRCI) const_cast(CRCI)->HandleCrash(RetCode, Signal); } static void installExceptionOrSignalHandlers() { // Setup the signal handler. struct sigaction Handler; Handler.sa_handler = CrashRecoverySignalHandler; Handler.sa_flags = 0; sigemptyset(&Handler.sa_mask); for (unsigned i = 0; i != NumSignals; ++i) { sigaction(Signals[i], &Handler, &PrevActions[i]); } } static void uninstallExceptionOrSignalHandlers() { // Restore the previous signal handlers. for (unsigned i = 0; i != NumSignals; ++i) sigaction(Signals[i], &PrevActions[i], nullptr); } #endif // !_WIN32 bool CrashRecoveryContext::RunSafely(function_ref Fn) { // If crash recovery is disabled, do nothing. if (gCrashRecoveryEnabled) { assert(!Impl && "Crash recovery context already initialized!"); CrashRecoveryContextImpl *CRCI = new CrashRecoveryContextImpl(this); Impl = CRCI; CRCI->ValidJumpBuffer = true; if (setjmp(CRCI->JumpBuffer) != 0) { return false; } } Fn(); return true; } #endif // !_MSC_VER LLVM_ATTRIBUTE_NORETURN void CrashRecoveryContext::HandleExit(int RetCode) { #if defined(_WIN32) // SEH and VEH ::RaiseException(0xE0000000 | RetCode, 0, 0, NULL); #else // On Unix we don't need to raise an exception, we go directly to // HandleCrash(), then longjmp will unwind the stack for us. CrashRecoveryContextImpl *CRCI = (CrashRecoveryContextImpl *)Impl; assert(CRCI && "Crash recovery context never initialized!"); CRCI->HandleCrash(RetCode, 0 /*no sig num*/); #endif llvm_unreachable("Most likely setjmp wasn't called!"); } // FIXME: Portability. static void setThreadBackgroundPriority() { #ifdef __APPLE__ setpriority(PRIO_DARWIN_THREAD, 0, PRIO_DARWIN_BG); #endif } static bool hasThreadBackgroundPriority() { #ifdef __APPLE__ return getpriority(PRIO_DARWIN_THREAD, 0) == 1; #else return false; #endif } namespace { struct RunSafelyOnThreadInfo { function_ref Fn; CrashRecoveryContext *CRC; bool UseBackgroundPriority; bool Result; }; } static void RunSafelyOnThread_Dispatch(void *UserData) { RunSafelyOnThreadInfo *Info = reinterpret_cast(UserData); if (Info->UseBackgroundPriority) setThreadBackgroundPriority(); Info->Result = Info->CRC->RunSafely(Info->Fn); } bool CrashRecoveryContext::RunSafelyOnThread(function_ref Fn, unsigned RequestedStackSize) { bool UseBackgroundPriority = hasThreadBackgroundPriority(); RunSafelyOnThreadInfo Info = { Fn, this, UseBackgroundPriority, false }; llvm_execute_on_thread(RunSafelyOnThread_Dispatch, &Info, RequestedStackSize == 0 ? llvm::None : llvm::Optional(RequestedStackSize)); if (CrashRecoveryContextImpl *CRC = (CrashRecoveryContextImpl *)Impl) CRC->setSwitchedThread(); return Info.Result; } diff --git a/contrib/llvm-project/llvm/lib/Support/InitLLVM.cpp b/contrib/llvm-project/llvm/lib/Support/InitLLVM.cpp index bb9b569d2de6..5c56b773ea69 100644 --- a/contrib/llvm-project/llvm/lib/Support/InitLLVM.cpp +++ b/contrib/llvm-project/llvm/lib/Support/InitLLVM.cpp @@ -1,56 +1,56 @@ //===-- InitLLVM.cpp -----------------------------------------------------===// // // 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 // //===----------------------------------------------------------------------===// #include "llvm/Support/InitLLVM.h" #include "llvm/Support/Error.h" #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/PrettyStackTrace.h" #include "llvm/Support/Process.h" #include "llvm/Support/Signals.h" #include #ifdef _WIN32 -#include "Windows/WindowsSupport.h" +#include "llvm/Support/Windows/WindowsSupport.h" #endif using namespace llvm; using namespace llvm::sys; InitLLVM::InitLLVM(int &Argc, const char **&Argv, bool InstallPipeSignalExitHandler) : StackPrinter(Argc, Argv) { if (InstallPipeSignalExitHandler) sys::SetOneShotPipeSignalFunction(sys::DefaultOneShotPipeSignalHandler); sys::PrintStackTraceOnErrorSignal(Argv[0]); install_out_of_memory_new_handler(); #ifdef _WIN32 // We use UTF-8 as the internal character encoding. On Windows, // arguments passed to main() may not be encoded in UTF-8. In order // to reliably detect encoding of command line arguments, we use an // Windows API to obtain arguments, convert them to UTF-8, and then // write them back to the Argv vector. // // There's probably other way to do the same thing (e.g. using // wmain() instead of main()), but this way seems less intrusive // than that. std::string Banner = std::string(Argv[0]) + ": "; ExitOnError ExitOnErr(Banner); ExitOnErr(errorCodeToError(windows::GetCommandLineArguments(Args, Alloc))); // GetCommandLineArguments doesn't terminate the vector with a // nullptr. Do it to make it compatible with the real argv. Args.push_back(nullptr); Argc = Args.size() - 1; Argv = Args.data(); #endif } InitLLVM::~InitLLVM() { llvm_shutdown(); } diff --git a/contrib/llvm-project/llvm/lib/Support/RandomNumberGenerator.cpp b/contrib/llvm-project/llvm/lib/Support/RandomNumberGenerator.cpp index 09fad1979985..f9c41ee5eaaf 100644 --- a/contrib/llvm-project/llvm/lib/Support/RandomNumberGenerator.cpp +++ b/contrib/llvm-project/llvm/lib/Support/RandomNumberGenerator.cpp @@ -1,84 +1,84 @@ //===-- RandomNumberGenerator.cpp - Implement RNG class -------------------===// // // 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 deterministic random number generation (RNG). // The current implementation is NOT cryptographically secure as it uses // the C++11 facilities. // //===----------------------------------------------------------------------===// #include "llvm/Support/RandomNumberGenerator.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" #ifdef _WIN32 -#include "Windows/WindowsSupport.h" +#include "llvm/Support/Windows/WindowsSupport.h" #else #include "Unix/Unix.h" #endif using namespace llvm; #define DEBUG_TYPE "rng" static cl::opt Seed("rng-seed", cl::value_desc("seed"), cl::Hidden, cl::desc("Seed for the random number generator"), cl::init(0)); RandomNumberGenerator::RandomNumberGenerator(StringRef Salt) { LLVM_DEBUG(if (Seed == 0) dbgs() << "Warning! Using unseeded random number generator.\n"); // Combine seed and salts using std::seed_seq. // Data: Seed-low, Seed-high, Salt // Note: std::seed_seq can only store 32-bit values, even though we // are using a 64-bit RNG. This isn't a problem since the Mersenne // twister constructor copies these correctly into its initial state. std::vector Data; Data.resize(2 + Salt.size()); Data[0] = Seed; Data[1] = Seed >> 32; llvm::copy(Salt, Data.begin() + 2); std::seed_seq SeedSeq(Data.begin(), Data.end()); Generator.seed(SeedSeq); } RandomNumberGenerator::result_type RandomNumberGenerator::operator()() { return Generator(); } // Get random vector of specified size std::error_code llvm::getRandomBytes(void *Buffer, size_t Size) { #ifdef _WIN32 HCRYPTPROV hProvider; if (CryptAcquireContext(&hProvider, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) { ScopedCryptContext ScopedHandle(hProvider); if (CryptGenRandom(hProvider, Size, static_cast(Buffer))) return std::error_code(); } return std::error_code(GetLastError(), std::system_category()); #else int Fd = open("/dev/urandom", O_RDONLY); if (Fd != -1) { std::error_code Ret; ssize_t BytesRead = read(Fd, Buffer, Size); if (BytesRead == -1) Ret = std::error_code(errno, std::system_category()); else if (BytesRead != static_cast(Size)) Ret = std::error_code(EIO, std::system_category()); if (close(Fd) == -1) Ret = std::error_code(errno, std::system_category()); return Ret; } return std::error_code(errno, std::system_category()); #endif } diff --git a/contrib/llvm-project/llvm/lib/Support/Windows/DynamicLibrary.inc b/contrib/llvm-project/llvm/lib/Support/Windows/DynamicLibrary.inc index 71b206c4cf9e..a3f78fb0d6ba 100644 --- a/contrib/llvm-project/llvm/lib/Support/Windows/DynamicLibrary.inc +++ b/contrib/llvm-project/llvm/lib/Support/Windows/DynamicLibrary.inc @@ -1,202 +1,202 @@ //===- Win32/DynamicLibrary.cpp - Win32 DL Implementation -------*- 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 the Win32 specific implementation of DynamicLibrary. // //===----------------------------------------------------------------------===// -#include "WindowsSupport.h" +#include "llvm/Support/Windows/WindowsSupport.h" #include "llvm/Support/ConvertUTF.h" #include "llvm/Support/raw_ostream.h" #include //===----------------------------------------------------------------------===// //=== WARNING: Implementation here must contain only Win32 specific code //=== and must not be UNIX code. //===----------------------------------------------------------------------===// DynamicLibrary::HandleSet::~HandleSet() { for (void *Handle : llvm::reverse(Handles)) FreeLibrary(HMODULE(Handle)); // 'Process' should not be released on Windows. assert((!Process || Process==this) && "Bad Handle"); // llvm_shutdown called, Return to default DynamicLibrary::SearchOrder = DynamicLibrary::SO_Linker; } void *DynamicLibrary::HandleSet::DLOpen(const char *File, std::string *Err) { // Create the instance and return it to be the *Process* handle // simillar to dlopen(NULL, RTLD_LAZY|RTLD_GLOBAL) if (!File) return &(*OpenedHandles); SmallVector FileUnicode; if (std::error_code ec = windows::UTF8ToUTF16(File, FileUnicode)) { SetLastError(ec.value()); MakeErrMsg(Err, std::string(File) + ": Can't convert to UTF-16"); return &DynamicLibrary::Invalid; } HMODULE Handle = LoadLibraryW(FileUnicode.data()); if (Handle == NULL) { MakeErrMsg(Err, std::string(File) + ": Can't open"); return &DynamicLibrary::Invalid; } return reinterpret_cast(Handle); } static DynamicLibrary::HandleSet *IsOpenedHandlesInstance(void *Handle) { if (!OpenedHandles.isConstructed()) return nullptr; DynamicLibrary::HandleSet &Inst = *OpenedHandles; return Handle == &Inst ? &Inst : nullptr; } void DynamicLibrary::HandleSet::DLClose(void *Handle) { if (HandleSet* HS = IsOpenedHandlesInstance(Handle)) HS->Process = nullptr; // Just drop the *Process* handle. else FreeLibrary((HMODULE)Handle); } static bool GetProcessModules(HANDLE H, DWORD &Bytes, HMODULE *Data = nullptr) { // EnumProcessModules will fail on Windows 64 while some versions of // MingW-32 don't have EnumProcessModulesEx. if ( #ifdef _WIN64 !EnumProcessModulesEx(H, Data, Bytes, &Bytes, LIST_MODULES_64BIT) #else !EnumProcessModules(H, Data, Bytes, &Bytes) #endif ) { std::string Err; if (MakeErrMsg(&Err, "EnumProcessModules failure")) llvm::errs() << Err << "\n"; return false; } return true; } void *DynamicLibrary::HandleSet::DLSym(void *Handle, const char *Symbol) { HandleSet* HS = IsOpenedHandlesInstance(Handle); if (!HS) return (void *)uintptr_t(GetProcAddress((HMODULE)Handle, Symbol)); // Could have done a dlclose on the *Process* handle if (!HS->Process) return nullptr; // Trials indicate EnumProcessModulesEx is consistantly faster than using // EnumerateLoadedModules64 or CreateToolhelp32Snapshot. // // | Handles | DbgHelp.dll | CreateSnapshot | EnumProcessModulesEx // |=========|=============|======================================== // | 37 | 0.0000585 * | 0.0003031 | 0.0000152 // | 1020 | 0.0026310 * | 0.0121598 | 0.0002683 // | 2084 | 0.0149418 * | 0.0369936 | 0.0005610 // // * Not including the load time of Dbghelp.dll (~.005 sec) // // There's still a case to somehow cache the result of EnumProcessModulesEx // across invocations, but the complication of doing that properly... // Possibly using LdrRegisterDllNotification to invalidate the cache? DWORD Bytes = 0; HMODULE Self = HMODULE(GetCurrentProcess()); if (!GetProcessModules(Self, Bytes)) return nullptr; // Get the most recent list in case any modules added/removed between calls // to EnumProcessModulesEx that gets the amount of, then copies the HMODULES. // MSDN is pretty clear that if the module list changes during the call to // EnumProcessModulesEx the results should not be used. std::vector Handles; do { assert(Bytes && ((Bytes % sizeof(HMODULE)) == 0) && "Should have at least one module and be aligned"); Handles.resize(Bytes / sizeof(HMODULE)); if (!GetProcessModules(Self, Bytes, Handles.data())) return nullptr; } while (Bytes != (Handles.size() * sizeof(HMODULE))); // Try EXE first, mirroring what dlsym(dlopen(NULL)) does. if (FARPROC Ptr = GetProcAddress(HMODULE(Handles.front()), Symbol)) return (void *) uintptr_t(Ptr); if (Handles.size() > 1) { // This is different behaviour than what Posix dlsym(dlopen(NULL)) does. // Doing that here is causing real problems for the JIT where msvc.dll // and ucrt.dll can define the same symbols. The runtime linker will choose // symbols from ucrt.dll first, but iterating NOT in reverse here would // mean that the msvc.dll versions would be returned. for (auto I = Handles.rbegin(), E = Handles.rend()-1; I != E; ++I) { if (FARPROC Ptr = GetProcAddress(HMODULE(*I), Symbol)) return (void *) uintptr_t(Ptr); } } return nullptr; } // Stack probing routines are in the support library (e.g. libgcc), but we don't // have dynamic linking on windows. Provide a hook. #define EXPLICIT_SYMBOL(SYM) \ extern "C" { extern void *SYM; } #define EXPLICIT_SYMBOL2(SYMFROM, SYMTO) EXPLICIT_SYMBOL(SYMTO) #ifdef _M_IX86 // Win32 on x86 implements certain single-precision math functions as macros. // These functions are not exported by the DLL, but will still be needed // for symbol-resolution by the JIT loader. Therefore, this Support libray // provides helper functions with the same implementation. #define INLINE_DEF_SYMBOL1(TYP, SYM) \ extern "C" TYP inline_##SYM(TYP _X) { return SYM(_X); } #define INLINE_DEF_SYMBOL2(TYP, SYM) \ extern "C" TYP inline_##SYM(TYP _X, TYP _Y) { return SYM(_X, _Y); } #endif #include "explicit_symbols.inc" #undef EXPLICIT_SYMBOL #undef EXPLICIT_SYMBOL2 #undef INLINE_DEF_SYMBOL1 #undef INLINE_DEF_SYMBOL2 static void *DoSearch(const char *SymbolName) { #define EXPLICIT_SYMBOL(SYM) \ if (!strcmp(SymbolName, #SYM)) \ return (void *)&SYM; #define EXPLICIT_SYMBOL2(SYMFROM, SYMTO) \ if (!strcmp(SymbolName, #SYMFROM)) \ return (void *)&SYMTO; #ifdef _M_IX86 #define INLINE_DEF_SYMBOL1(TYP, SYM) \ if (!strcmp(SymbolName, #SYM)) \ return (void *)&inline_##SYM; #define INLINE_DEF_SYMBOL2(TYP, SYM) INLINE_DEF_SYMBOL1(TYP, SYM) #endif { #include "explicit_symbols.inc" } #undef EXPLICIT_SYMBOL #undef EXPLICIT_SYMBOL2 #undef INLINE_DEF_SYMBOL1 #undef INLINE_DEF_SYMBOL2 return nullptr; } diff --git a/contrib/llvm-project/llvm/lib/Support/Windows/Host.inc b/contrib/llvm-project/llvm/lib/Support/Windows/Host.inc index 21b947f26df3..5583db909045 100644 --- a/contrib/llvm-project/llvm/lib/Support/Windows/Host.inc +++ b/contrib/llvm-project/llvm/lib/Support/Windows/Host.inc @@ -1,33 +1,33 @@ //===- llvm/Support/Win32/Host.inc ------------------------------*- 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 implements the Win32 Host support. // //===----------------------------------------------------------------------===// -#include "WindowsSupport.h" +#include "llvm/Support/Windows/WindowsSupport.h" #include #include using namespace llvm; static std::string updateTripleOSVersion(std::string Triple) { return Triple; } std::string sys::getDefaultTargetTriple() { const char *Triple = LLVM_DEFAULT_TARGET_TRIPLE; // Override the default target with an environment variable named by LLVM_TARGET_TRIPLE_ENV. #if defined(LLVM_TARGET_TRIPLE_ENV) if (const char *EnvTriple = std::getenv(LLVM_TARGET_TRIPLE_ENV)) Triple = EnvTriple; #endif return Triple; } diff --git a/contrib/llvm-project/llvm/lib/Support/Windows/Memory.inc b/contrib/llvm-project/llvm/lib/Support/Windows/Memory.inc index c5566f9910a5..1b2de1915ec4 100644 --- a/contrib/llvm-project/llvm/lib/Support/Windows/Memory.inc +++ b/contrib/llvm-project/llvm/lib/Support/Windows/Memory.inc @@ -1,196 +1,196 @@ //===- Win32/Memory.cpp - Win32 Memory Implementation -----------*- 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 the Win32 specific implementation of various Memory // management utilities // //===----------------------------------------------------------------------===// #include "llvm/Support/DataTypes.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/Process.h" #include "llvm/Support/WindowsError.h" // The Windows.h header must be the last one included. -#include "WindowsSupport.h" +#include "llvm/Support/Windows/WindowsSupport.h" static DWORD getWindowsProtectionFlags(unsigned Flags) { switch (Flags & llvm::sys::Memory::MF_RWE_MASK) { // Contrary to what you might expect, the Windows page protection flags // are not a bitwise combination of RWX values case llvm::sys::Memory::MF_READ: return PAGE_READONLY; case llvm::sys::Memory::MF_WRITE: // Note: PAGE_WRITE is not supported by VirtualProtect return PAGE_READWRITE; case llvm::sys::Memory::MF_READ|llvm::sys::Memory::MF_WRITE: return PAGE_READWRITE; case llvm::sys::Memory::MF_READ|llvm::sys::Memory::MF_EXEC: return PAGE_EXECUTE_READ; case llvm::sys::Memory::MF_READ | llvm::sys::Memory::MF_WRITE | llvm::sys::Memory::MF_EXEC: return PAGE_EXECUTE_READWRITE; case llvm::sys::Memory::MF_EXEC: return PAGE_EXECUTE; default: llvm_unreachable("Illegal memory protection flag specified!"); } // Provide a default return value as required by some compilers. return PAGE_NOACCESS; } // While we'd be happy to allocate single pages, the Windows allocation // granularity may be larger than a single page (in practice, it is 64K) // so mapping less than that will create an unreachable fragment of memory. static size_t getAllocationGranularity() { SYSTEM_INFO Info; ::GetSystemInfo(&Info); if (Info.dwPageSize > Info.dwAllocationGranularity) return Info.dwPageSize; else return Info.dwAllocationGranularity; } // Large/huge memory pages need explicit process permissions in order to be // used. See https://blogs.msdn.microsoft.com/oldnewthing/20110128-00/?p=11643 // Also large pages need to be manually enabled on your OS. If all this is // sucessfull, we return the minimal large memory page size. static size_t enableProcessLargePages() { HANDLE Token = 0; size_t LargePageMin = GetLargePageMinimum(); if (LargePageMin) OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &Token); if (!Token) return 0; LUID Luid; if (!LookupPrivilegeValue(0, SE_LOCK_MEMORY_NAME, &Luid)) { CloseHandle(Token); return 0; } TOKEN_PRIVILEGES TP{}; TP.PrivilegeCount = 1; TP.Privileges[0].Luid = Luid; TP.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; if (!AdjustTokenPrivileges(Token, FALSE, &TP, 0, 0, 0)) { CloseHandle(Token); return 0; } DWORD E = GetLastError(); CloseHandle(Token); if (E == ERROR_SUCCESS) return LargePageMin; return 0; } namespace llvm { namespace sys { //===----------------------------------------------------------------------===// //=== WARNING: Implementation here must contain only Win32 specific code //=== and must not be UNIX code //===----------------------------------------------------------------------===// MemoryBlock Memory::allocateMappedMemory(size_t NumBytes, const MemoryBlock *const NearBlock, unsigned Flags, std::error_code &EC) { EC = std::error_code(); if (NumBytes == 0) return MemoryBlock(); static size_t DefaultGranularity = getAllocationGranularity(); static size_t LargePageGranularity = enableProcessLargePages(); DWORD AllocType = MEM_RESERVE | MEM_COMMIT; bool HugePages = false; size_t Granularity = DefaultGranularity; if ((Flags & MF_HUGE_HINT) && LargePageGranularity > 0) { AllocType |= MEM_LARGE_PAGES; HugePages = true; Granularity = LargePageGranularity; } size_t NumBlocks = (NumBytes + Granularity - 1) / Granularity; uintptr_t Start = NearBlock ? reinterpret_cast(NearBlock->base()) + NearBlock->allocatedSize() : 0; // If the requested address is not aligned to the allocation granularity, // round up to get beyond NearBlock. VirtualAlloc would have rounded down. if (Start && Start % Granularity != 0) Start += Granularity - Start % Granularity; DWORD Protect = getWindowsProtectionFlags(Flags); size_t AllocSize = NumBlocks * Granularity; void *PA = ::VirtualAlloc(reinterpret_cast(Start), AllocSize, AllocType, Protect); if (PA == NULL) { if (NearBlock || HugePages) { // Try again without the NearBlock hint and without large memory pages return allocateMappedMemory(NumBytes, NULL, Flags & ~MF_HUGE_HINT, EC); } EC = mapWindowsError(::GetLastError()); return MemoryBlock(); } MemoryBlock Result; Result.Address = PA; Result.AllocatedSize = AllocSize; Result.Flags = (Flags & ~MF_HUGE_HINT) | (HugePages ? MF_HUGE_HINT : 0); if (Flags & MF_EXEC) Memory::InvalidateInstructionCache(Result.Address, AllocSize); return Result; } std::error_code Memory::releaseMappedMemory(MemoryBlock &M) { if (M.Address == 0 || M.AllocatedSize == 0) return std::error_code(); if (!VirtualFree(M.Address, 0, MEM_RELEASE)) return mapWindowsError(::GetLastError()); M.Address = 0; M.AllocatedSize = 0; return std::error_code(); } std::error_code Memory::protectMappedMemory(const MemoryBlock &M, unsigned Flags) { if (M.Address == 0 || M.AllocatedSize == 0) return std::error_code(); DWORD Protect = getWindowsProtectionFlags(Flags); DWORD OldFlags; if (!VirtualProtect(M.Address, M.AllocatedSize, Protect, &OldFlags)) return mapWindowsError(::GetLastError()); if (Flags & MF_EXEC) Memory::InvalidateInstructionCache(M.Address, M.AllocatedSize); return std::error_code(); } /// InvalidateInstructionCache - Before the JIT can run a block of code /// that has been emitted it must invalidate the instruction cache on some /// platforms. void Memory::InvalidateInstructionCache( const void *Addr, size_t Len) { FlushInstructionCache(GetCurrentProcess(), Addr, Len); } } // namespace sys } // namespace llvm diff --git a/contrib/llvm-project/llvm/lib/Support/Windows/Path.inc b/contrib/llvm-project/llvm/lib/Support/Windows/Path.inc index c3b13abef5de..d634c123fbdc 100644 --- a/contrib/llvm-project/llvm/lib/Support/Windows/Path.inc +++ b/contrib/llvm-project/llvm/lib/Support/Windows/Path.inc @@ -1,1498 +1,1498 @@ //===- llvm/Support/Windows/Path.inc - Windows Path Impl --------*- 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 implements the Windows specific implementation of the Path API. // //===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===// //=== WARNING: Implementation here must contain only generic Windows code that //=== is guaranteed to work on *all* Windows variants. //===----------------------------------------------------------------------===// #include "llvm/ADT/STLExtras.h" #include "llvm/Support/ConvertUTF.h" #include "llvm/Support/WindowsError.h" #include #include #include #include // These two headers must be included last, and make sure shlobj is required // after Windows.h to make sure it picks up our definition of _WIN32_WINNT -#include "WindowsSupport.h" +#include "llvm/Support/Windows/WindowsSupport.h" #include #include #undef max // MinGW doesn't define this. #ifndef _ERRNO_T_DEFINED #define _ERRNO_T_DEFINED typedef int errno_t; #endif #ifdef _MSC_VER # pragma comment(lib, "advapi32.lib") // This provides CryptAcquireContextW. # pragma comment(lib, "ole32.lib") // This provides CoTaskMemFree #endif using namespace llvm; using llvm::sys::windows::UTF8ToUTF16; using llvm::sys::windows::CurCPToUTF16; using llvm::sys::windows::UTF16ToUTF8; using llvm::sys::path::widenPath; static bool is_separator(const wchar_t value) { switch (value) { case L'\\': case L'/': return true; default: return false; } } namespace llvm { namespace sys { namespace path { // Convert a UTF-8 path to UTF-16. Also, if the absolute equivalent of the // path is longer than CreateDirectory can tolerate, make it absolute and // prefixed by '\\?\'. std::error_code widenPath(const Twine &Path8, SmallVectorImpl &Path16) { const size_t MaxDirLen = MAX_PATH - 12; // Must leave room for 8.3 filename. // Several operations would convert Path8 to SmallString; more efficient to // do it once up front. SmallString<128> Path8Str; Path8.toVector(Path8Str); // If we made this path absolute, how much longer would it get? size_t CurPathLen; if (llvm::sys::path::is_absolute(Twine(Path8Str))) CurPathLen = 0; // No contribution from current_path needed. else { CurPathLen = ::GetCurrentDirectoryW(0, NULL); if (CurPathLen == 0) return mapWindowsError(::GetLastError()); } // Would the absolute path be longer than our limit? if ((Path8Str.size() + CurPathLen) >= MaxDirLen && !Path8Str.startswith("\\\\?\\")) { SmallString<2*MAX_PATH> FullPath("\\\\?\\"); if (CurPathLen) { SmallString<80> CurPath; if (std::error_code EC = llvm::sys::fs::current_path(CurPath)) return EC; FullPath.append(CurPath); } // Traverse the requested path, canonicalizing . and .. (because the \\?\ // prefix is documented to treat them as real components). Ignore // separators, which can be returned from the iterator if the path has a // drive name. We don't need to call native() on the result since append() // always attaches preferred_separator. for (llvm::sys::path::const_iterator I = llvm::sys::path::begin(Path8Str), E = llvm::sys::path::end(Path8Str); I != E; ++I) { if (I->size() == 1 && is_separator((*I)[0])) continue; if (I->size() == 1 && *I == ".") continue; if (I->size() == 2 && *I == "..") llvm::sys::path::remove_filename(FullPath); else llvm::sys::path::append(FullPath, *I); } return UTF8ToUTF16(FullPath, Path16); } // Just use the caller's original path. return UTF8ToUTF16(Path8Str, Path16); } } // end namespace path namespace fs { const file_t kInvalidFile = INVALID_HANDLE_VALUE; std::string getMainExecutable(const char *argv0, void *MainExecAddr) { SmallVector PathName; DWORD Size = ::GetModuleFileNameW(NULL, PathName.data(), PathName.capacity()); // A zero return value indicates a failure other than insufficient space. if (Size == 0) return ""; // Insufficient space is determined by a return value equal to the size of // the buffer passed in. if (Size == PathName.capacity()) return ""; // On success, GetModuleFileNameW returns the number of characters written to // the buffer not including the NULL terminator. PathName.set_size(Size); // Convert the result from UTF-16 to UTF-8. SmallVector PathNameUTF8; if (UTF16ToUTF8(PathName.data(), PathName.size(), PathNameUTF8)) return ""; return std::string(PathNameUTF8.data()); } UniqueID file_status::getUniqueID() const { // The file is uniquely identified by the volume serial number along // with the 64-bit file identifier. uint64_t FileID = (static_cast(FileIndexHigh) << 32ULL) | static_cast(FileIndexLow); return UniqueID(VolumeSerialNumber, FileID); } ErrorOr disk_space(const Twine &Path) { ULARGE_INTEGER Avail, Total, Free; if (!::GetDiskFreeSpaceExA(Path.str().c_str(), &Avail, &Total, &Free)) return mapWindowsError(::GetLastError()); space_info SpaceInfo; SpaceInfo.capacity = (static_cast(Total.HighPart) << 32) + Total.LowPart; SpaceInfo.free = (static_cast(Free.HighPart) << 32) + Free.LowPart; SpaceInfo.available = (static_cast(Avail.HighPart) << 32) + Avail.LowPart; return SpaceInfo; } TimePoint<> basic_file_status::getLastAccessedTime() const { FILETIME Time; Time.dwLowDateTime = LastAccessedTimeLow; Time.dwHighDateTime = LastAccessedTimeHigh; return toTimePoint(Time); } TimePoint<> basic_file_status::getLastModificationTime() const { FILETIME Time; Time.dwLowDateTime = LastWriteTimeLow; Time.dwHighDateTime = LastWriteTimeHigh; return toTimePoint(Time); } uint32_t file_status::getLinkCount() const { return NumLinks; } std::error_code current_path(SmallVectorImpl &result) { SmallVector cur_path; DWORD len = MAX_PATH; do { cur_path.reserve(len); len = ::GetCurrentDirectoryW(cur_path.capacity(), cur_path.data()); // A zero return value indicates a failure other than insufficient space. if (len == 0) return mapWindowsError(::GetLastError()); // If there's insufficient space, the len returned is larger than the len // given. } while (len > cur_path.capacity()); // On success, GetCurrentDirectoryW returns the number of characters not // including the null-terminator. cur_path.set_size(len); return UTF16ToUTF8(cur_path.begin(), cur_path.size(), result); } std::error_code set_current_path(const Twine &path) { // Convert to utf-16. SmallVector wide_path; if (std::error_code ec = widenPath(path, wide_path)) return ec; if (!::SetCurrentDirectoryW(wide_path.begin())) return mapWindowsError(::GetLastError()); return std::error_code(); } std::error_code create_directory(const Twine &path, bool IgnoreExisting, perms Perms) { SmallVector path_utf16; if (std::error_code ec = widenPath(path, path_utf16)) return ec; if (!::CreateDirectoryW(path_utf16.begin(), NULL)) { DWORD LastError = ::GetLastError(); if (LastError != ERROR_ALREADY_EXISTS || !IgnoreExisting) return mapWindowsError(LastError); } return std::error_code(); } // We can't use symbolic links for windows. std::error_code create_link(const Twine &to, const Twine &from) { // Convert to utf-16. SmallVector wide_from; SmallVector wide_to; if (std::error_code ec = widenPath(from, wide_from)) return ec; if (std::error_code ec = widenPath(to, wide_to)) return ec; if (!::CreateHardLinkW(wide_from.begin(), wide_to.begin(), NULL)) return mapWindowsError(::GetLastError()); return std::error_code(); } std::error_code create_hard_link(const Twine &to, const Twine &from) { return create_link(to, from); } std::error_code remove(const Twine &path, bool IgnoreNonExisting) { SmallVector path_utf16; if (std::error_code ec = widenPath(path, path_utf16)) return ec; // We don't know whether this is a file or a directory, and remove() can // accept both. The usual way to delete a file or directory is to use one of // the DeleteFile or RemoveDirectory functions, but that requires you to know // which one it is. We could stat() the file to determine that, but that would // cost us additional system calls, which can be slow in a directory // containing a large number of files. So instead we call CreateFile directly. // The important part is the FILE_FLAG_DELETE_ON_CLOSE flag, which causes the // file to be deleted once it is closed. We also use the flags // FILE_FLAG_BACKUP_SEMANTICS (which allows us to open directories), and // FILE_FLAG_OPEN_REPARSE_POINT (don't follow symlinks). ScopedFileHandle h(::CreateFileW( c_str(path_utf16), DELETE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_DELETE_ON_CLOSE, NULL)); if (!h) { std::error_code EC = mapWindowsError(::GetLastError()); if (EC != errc::no_such_file_or_directory || !IgnoreNonExisting) return EC; } return std::error_code(); } static std::error_code is_local_internal(SmallVectorImpl &Path, bool &Result) { SmallVector VolumePath; size_t Len = 128; while (true) { VolumePath.resize(Len); BOOL Success = ::GetVolumePathNameW(Path.data(), VolumePath.data(), VolumePath.size()); if (Success) break; DWORD Err = ::GetLastError(); if (Err != ERROR_INSUFFICIENT_BUFFER) return mapWindowsError(Err); Len *= 2; } // If the output buffer has exactly enough space for the path name, but not // the null terminator, it will leave the output unterminated. Push a null // terminator onto the end to ensure that this never happens. VolumePath.push_back(L'\0'); VolumePath.set_size(wcslen(VolumePath.data())); const wchar_t *P = VolumePath.data(); UINT Type = ::GetDriveTypeW(P); switch (Type) { case DRIVE_FIXED: Result = true; return std::error_code(); case DRIVE_REMOTE: case DRIVE_CDROM: case DRIVE_RAMDISK: case DRIVE_REMOVABLE: Result = false; return std::error_code(); default: return make_error_code(errc::no_such_file_or_directory); } llvm_unreachable("Unreachable!"); } std::error_code is_local(const Twine &path, bool &result) { if (!llvm::sys::fs::exists(path) || !llvm::sys::path::has_root_path(path)) return make_error_code(errc::no_such_file_or_directory); SmallString<128> Storage; StringRef P = path.toStringRef(Storage); // Convert to utf-16. SmallVector WidePath; if (std::error_code ec = widenPath(P, WidePath)) return ec; return is_local_internal(WidePath, result); } static std::error_code realPathFromHandle(HANDLE H, SmallVectorImpl &Buffer) { DWORD CountChars = ::GetFinalPathNameByHandleW( H, Buffer.begin(), Buffer.capacity() - 1, FILE_NAME_NORMALIZED); if (CountChars > Buffer.capacity()) { // The buffer wasn't big enough, try again. In this case the return value // *does* indicate the size of the null terminator. Buffer.reserve(CountChars); CountChars = ::GetFinalPathNameByHandleW( H, Buffer.data(), Buffer.capacity() - 1, FILE_NAME_NORMALIZED); } if (CountChars == 0) return mapWindowsError(GetLastError()); Buffer.set_size(CountChars); return std::error_code(); } static std::error_code realPathFromHandle(HANDLE H, SmallVectorImpl &RealPath) { RealPath.clear(); SmallVector Buffer; if (std::error_code EC = realPathFromHandle(H, Buffer)) return EC; // Strip the \\?\ prefix. We don't want it ending up in output, and such // paths don't get canonicalized by file APIs. wchar_t *Data = Buffer.data(); DWORD CountChars = Buffer.size(); if (CountChars >= 8 && ::memcmp(Data, L"\\\\?\\UNC\\", 16) == 0) { // Convert \\?\UNC\foo\bar to \\foo\bar CountChars -= 6; Data += 6; Data[0] = '\\'; } else if (CountChars >= 4 && ::memcmp(Data, L"\\\\?\\", 8) == 0) { // Convert \\?\c:\foo to c:\foo CountChars -= 4; Data += 4; } // Convert the result from UTF-16 to UTF-8. return UTF16ToUTF8(Data, CountChars, RealPath); } std::error_code is_local(int FD, bool &Result) { SmallVector FinalPath; HANDLE Handle = reinterpret_cast(_get_osfhandle(FD)); if (std::error_code EC = realPathFromHandle(Handle, FinalPath)) return EC; return is_local_internal(FinalPath, Result); } static std::error_code setDeleteDisposition(HANDLE Handle, bool Delete) { FILE_DISPOSITION_INFO Disposition; Disposition.DeleteFile = Delete; if (!SetFileInformationByHandle(Handle, FileDispositionInfo, &Disposition, sizeof(Disposition))) return mapWindowsError(::GetLastError()); return std::error_code(); } static std::error_code rename_internal(HANDLE FromHandle, const Twine &To, bool ReplaceIfExists) { SmallVector ToWide; if (auto EC = widenPath(To, ToWide)) return EC; std::vector RenameInfoBuf(sizeof(FILE_RENAME_INFO) - sizeof(wchar_t) + (ToWide.size() * sizeof(wchar_t))); FILE_RENAME_INFO &RenameInfo = *reinterpret_cast(RenameInfoBuf.data()); RenameInfo.ReplaceIfExists = ReplaceIfExists; RenameInfo.RootDirectory = 0; RenameInfo.FileNameLength = ToWide.size() * sizeof(wchar_t); std::copy(ToWide.begin(), ToWide.end(), &RenameInfo.FileName[0]); SetLastError(ERROR_SUCCESS); if (!SetFileInformationByHandle(FromHandle, FileRenameInfo, &RenameInfo, RenameInfoBuf.size())) { unsigned Error = GetLastError(); if (Error == ERROR_SUCCESS) Error = ERROR_CALL_NOT_IMPLEMENTED; // Wine doesn't always set error code. return mapWindowsError(Error); } return std::error_code(); } static std::error_code rename_handle(HANDLE FromHandle, const Twine &To) { SmallVector WideTo; if (std::error_code EC = widenPath(To, WideTo)) return EC; // We normally expect this loop to succeed after a few iterations. If it // requires more than 200 tries, it's more likely that the failures are due to // a true error, so stop trying. for (unsigned Retry = 0; Retry != 200; ++Retry) { auto EC = rename_internal(FromHandle, To, true); if (EC == std::error_code(ERROR_CALL_NOT_IMPLEMENTED, std::system_category())) { // Wine doesn't support SetFileInformationByHandle in rename_internal. // Fall back to MoveFileEx. SmallVector WideFrom; if (std::error_code EC2 = realPathFromHandle(FromHandle, WideFrom)) return EC2; if (::MoveFileExW(WideFrom.begin(), WideTo.begin(), MOVEFILE_REPLACE_EXISTING)) return std::error_code(); return mapWindowsError(GetLastError()); } if (!EC || EC != errc::permission_denied) return EC; // The destination file probably exists and is currently open in another // process, either because the file was opened without FILE_SHARE_DELETE or // it is mapped into memory (e.g. using MemoryBuffer). Rename it in order to // move it out of the way of the source file. Use FILE_FLAG_DELETE_ON_CLOSE // to arrange for the destination file to be deleted when the other process // closes it. ScopedFileHandle ToHandle( ::CreateFileW(WideTo.begin(), GENERIC_READ | DELETE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, NULL)); if (!ToHandle) { auto EC = mapWindowsError(GetLastError()); // Another process might have raced with us and moved the existing file // out of the way before we had a chance to open it. If that happens, try // to rename the source file again. if (EC == errc::no_such_file_or_directory) continue; return EC; } BY_HANDLE_FILE_INFORMATION FI; if (!GetFileInformationByHandle(ToHandle, &FI)) return mapWindowsError(GetLastError()); // Try to find a unique new name for the destination file. for (unsigned UniqueId = 0; UniqueId != 200; ++UniqueId) { std::string TmpFilename = (To + ".tmp" + utostr(UniqueId)).str(); if (auto EC = rename_internal(ToHandle, TmpFilename, false)) { if (EC == errc::file_exists || EC == errc::permission_denied) { // Again, another process might have raced with us and moved the file // before we could move it. Check whether this is the case, as it // might have caused the permission denied error. If that was the // case, we don't need to move it ourselves. ScopedFileHandle ToHandle2(::CreateFileW( WideTo.begin(), 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)); if (!ToHandle2) { auto EC = mapWindowsError(GetLastError()); if (EC == errc::no_such_file_or_directory) break; return EC; } BY_HANDLE_FILE_INFORMATION FI2; if (!GetFileInformationByHandle(ToHandle2, &FI2)) return mapWindowsError(GetLastError()); if (FI.nFileIndexHigh != FI2.nFileIndexHigh || FI.nFileIndexLow != FI2.nFileIndexLow || FI.dwVolumeSerialNumber != FI2.dwVolumeSerialNumber) break; continue; } return EC; } break; } // Okay, the old destination file has probably been moved out of the way at // this point, so try to rename the source file again. Still, another // process might have raced with us to create and open the destination // file, so we need to keep doing this until we succeed. } // The most likely root cause. return errc::permission_denied; } static std::error_code rename_fd(int FromFD, const Twine &To) { HANDLE FromHandle = reinterpret_cast(_get_osfhandle(FromFD)); return rename_handle(FromHandle, To); } std::error_code rename(const Twine &From, const Twine &To) { // Convert to utf-16. SmallVector WideFrom; if (std::error_code EC = widenPath(From, WideFrom)) return EC; ScopedFileHandle FromHandle; // Retry this a few times to defeat badly behaved file system scanners. for (unsigned Retry = 0; Retry != 200; ++Retry) { if (Retry != 0) ::Sleep(10); FromHandle = ::CreateFileW(WideFrom.begin(), GENERIC_READ | DELETE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (FromHandle) break; } if (!FromHandle) return mapWindowsError(GetLastError()); return rename_handle(FromHandle, To); } std::error_code resize_file(int FD, uint64_t Size) { #ifdef HAVE__CHSIZE_S errno_t error = ::_chsize_s(FD, Size); #else errno_t error = ::_chsize(FD, Size); #endif return std::error_code(error, std::generic_category()); } std::error_code access(const Twine &Path, AccessMode Mode) { SmallVector PathUtf16; if (std::error_code EC = widenPath(Path, PathUtf16)) return EC; DWORD Attributes = ::GetFileAttributesW(PathUtf16.begin()); if (Attributes == INVALID_FILE_ATTRIBUTES) { // See if the file didn't actually exist. DWORD LastError = ::GetLastError(); if (LastError != ERROR_FILE_NOT_FOUND && LastError != ERROR_PATH_NOT_FOUND) return mapWindowsError(LastError); return errc::no_such_file_or_directory; } if (Mode == AccessMode::Write && (Attributes & FILE_ATTRIBUTE_READONLY)) return errc::permission_denied; return std::error_code(); } bool can_execute(const Twine &Path) { return !access(Path, AccessMode::Execute) || !access(Path + ".exe", AccessMode::Execute); } bool equivalent(file_status A, file_status B) { assert(status_known(A) && status_known(B)); return A.FileIndexHigh == B.FileIndexHigh && A.FileIndexLow == B.FileIndexLow && A.FileSizeHigh == B.FileSizeHigh && A.FileSizeLow == B.FileSizeLow && A.LastAccessedTimeHigh == B.LastAccessedTimeHigh && A.LastAccessedTimeLow == B.LastAccessedTimeLow && A.LastWriteTimeHigh == B.LastWriteTimeHigh && A.LastWriteTimeLow == B.LastWriteTimeLow && A.VolumeSerialNumber == B.VolumeSerialNumber; } std::error_code equivalent(const Twine &A, const Twine &B, bool &result) { file_status fsA, fsB; if (std::error_code ec = status(A, fsA)) return ec; if (std::error_code ec = status(B, fsB)) return ec; result = equivalent(fsA, fsB); return std::error_code(); } static bool isReservedName(StringRef path) { // This list of reserved names comes from MSDN, at: // http://msdn.microsoft.com/en-us/library/aa365247%28v=vs.85%29.aspx static const char *const sReservedNames[] = { "nul", "con", "prn", "aux", "com1", "com2", "com3", "com4", "com5", "com6", "com7", "com8", "com9", "lpt1", "lpt2", "lpt3", "lpt4", "lpt5", "lpt6", "lpt7", "lpt8", "lpt9" }; // First, check to see if this is a device namespace, which always // starts with \\.\, since device namespaces are not legal file paths. if (path.startswith("\\\\.\\")) return true; // Then compare against the list of ancient reserved names. for (size_t i = 0; i < array_lengthof(sReservedNames); ++i) { if (path.equals_lower(sReservedNames[i])) return true; } // The path isn't what we consider reserved. return false; } static file_type file_type_from_attrs(DWORD Attrs) { return (Attrs & FILE_ATTRIBUTE_DIRECTORY) ? file_type::directory_file : file_type::regular_file; } static perms perms_from_attrs(DWORD Attrs) { return (Attrs & FILE_ATTRIBUTE_READONLY) ? (all_read | all_exe) : all_all; } static std::error_code getStatus(HANDLE FileHandle, file_status &Result) { if (FileHandle == INVALID_HANDLE_VALUE) goto handle_status_error; switch (::GetFileType(FileHandle)) { default: llvm_unreachable("Don't know anything about this file type"); case FILE_TYPE_UNKNOWN: { DWORD Err = ::GetLastError(); if (Err != NO_ERROR) return mapWindowsError(Err); Result = file_status(file_type::type_unknown); return std::error_code(); } case FILE_TYPE_DISK: break; case FILE_TYPE_CHAR: Result = file_status(file_type::character_file); return std::error_code(); case FILE_TYPE_PIPE: Result = file_status(file_type::fifo_file); return std::error_code(); } BY_HANDLE_FILE_INFORMATION Info; if (!::GetFileInformationByHandle(FileHandle, &Info)) goto handle_status_error; Result = file_status( file_type_from_attrs(Info.dwFileAttributes), perms_from_attrs(Info.dwFileAttributes), Info.nNumberOfLinks, Info.ftLastAccessTime.dwHighDateTime, Info.ftLastAccessTime.dwLowDateTime, Info.ftLastWriteTime.dwHighDateTime, Info.ftLastWriteTime.dwLowDateTime, Info.dwVolumeSerialNumber, Info.nFileSizeHigh, Info.nFileSizeLow, Info.nFileIndexHigh, Info.nFileIndexLow); return std::error_code(); handle_status_error: DWORD LastError = ::GetLastError(); if (LastError == ERROR_FILE_NOT_FOUND || LastError == ERROR_PATH_NOT_FOUND) Result = file_status(file_type::file_not_found); else if (LastError == ERROR_SHARING_VIOLATION) Result = file_status(file_type::type_unknown); else Result = file_status(file_type::status_error); return mapWindowsError(LastError); } std::error_code status(const Twine &path, file_status &result, bool Follow) { SmallString<128> path_storage; SmallVector path_utf16; StringRef path8 = path.toStringRef(path_storage); if (isReservedName(path8)) { result = file_status(file_type::character_file); return std::error_code(); } if (std::error_code ec = widenPath(path8, path_utf16)) return ec; DWORD attr = ::GetFileAttributesW(path_utf16.begin()); if (attr == INVALID_FILE_ATTRIBUTES) return getStatus(INVALID_HANDLE_VALUE, result); DWORD Flags = FILE_FLAG_BACKUP_SEMANTICS; // Handle reparse points. if (!Follow && (attr & FILE_ATTRIBUTE_REPARSE_POINT)) Flags |= FILE_FLAG_OPEN_REPARSE_POINT; ScopedFileHandle h( ::CreateFileW(path_utf16.begin(), 0, // Attributes only. FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, Flags, 0)); if (!h) return getStatus(INVALID_HANDLE_VALUE, result); return getStatus(h, result); } std::error_code status(int FD, file_status &Result) { HANDLE FileHandle = reinterpret_cast(_get_osfhandle(FD)); return getStatus(FileHandle, Result); } std::error_code status(file_t FileHandle, file_status &Result) { return getStatus(FileHandle, Result); } unsigned getUmask() { return 0; } std::error_code setPermissions(const Twine &Path, perms Permissions) { SmallVector PathUTF16; if (std::error_code EC = widenPath(Path, PathUTF16)) return EC; DWORD Attributes = ::GetFileAttributesW(PathUTF16.begin()); if (Attributes == INVALID_FILE_ATTRIBUTES) return mapWindowsError(GetLastError()); // There are many Windows file attributes that are not to do with the file // permissions (e.g. FILE_ATTRIBUTE_HIDDEN). We need to be careful to preserve // them. if (Permissions & all_write) { Attributes &= ~FILE_ATTRIBUTE_READONLY; if (Attributes == 0) // FILE_ATTRIBUTE_NORMAL indicates no other attributes are set. Attributes |= FILE_ATTRIBUTE_NORMAL; } else { Attributes |= FILE_ATTRIBUTE_READONLY; // FILE_ATTRIBUTE_NORMAL is not compatible with any other attributes, so // remove it, if it is present. Attributes &= ~FILE_ATTRIBUTE_NORMAL; } if (!::SetFileAttributesW(PathUTF16.begin(), Attributes)) return mapWindowsError(GetLastError()); return std::error_code(); } std::error_code setPermissions(int FD, perms Permissions) { // FIXME Not implemented. return std::make_error_code(std::errc::not_supported); } std::error_code setLastAccessAndModificationTime(int FD, TimePoint<> AccessTime, TimePoint<> ModificationTime) { FILETIME AccessFT = toFILETIME(AccessTime); FILETIME ModifyFT = toFILETIME(ModificationTime); HANDLE FileHandle = reinterpret_cast(_get_osfhandle(FD)); if (!SetFileTime(FileHandle, NULL, &AccessFT, &ModifyFT)) return mapWindowsError(::GetLastError()); return std::error_code(); } std::error_code mapped_file_region::init(sys::fs::file_t OrigFileHandle, uint64_t Offset, mapmode Mode) { this->Mode = Mode; if (OrigFileHandle == INVALID_HANDLE_VALUE) return make_error_code(errc::bad_file_descriptor); DWORD flprotect; switch (Mode) { case readonly: flprotect = PAGE_READONLY; break; case readwrite: flprotect = PAGE_READWRITE; break; case priv: flprotect = PAGE_WRITECOPY; break; } HANDLE FileMappingHandle = ::CreateFileMappingW(OrigFileHandle, 0, flprotect, Hi_32(Size), Lo_32(Size), 0); if (FileMappingHandle == NULL) { std::error_code ec = mapWindowsError(GetLastError()); return ec; } DWORD dwDesiredAccess; switch (Mode) { case readonly: dwDesiredAccess = FILE_MAP_READ; break; case readwrite: dwDesiredAccess = FILE_MAP_WRITE; break; case priv: dwDesiredAccess = FILE_MAP_COPY; break; } Mapping = ::MapViewOfFile(FileMappingHandle, dwDesiredAccess, Offset >> 32, Offset & 0xffffffff, Size); if (Mapping == NULL) { std::error_code ec = mapWindowsError(GetLastError()); ::CloseHandle(FileMappingHandle); return ec; } if (Size == 0) { MEMORY_BASIC_INFORMATION mbi; SIZE_T Result = VirtualQuery(Mapping, &mbi, sizeof(mbi)); if (Result == 0) { std::error_code ec = mapWindowsError(GetLastError()); ::UnmapViewOfFile(Mapping); ::CloseHandle(FileMappingHandle); return ec; } Size = mbi.RegionSize; } // Close the file mapping handle, as it's kept alive by the file mapping. But // neither the file mapping nor the file mapping handle keep the file handle // alive, so we need to keep a reference to the file in case all other handles // are closed and the file is deleted, which may cause invalid data to be read // from the file. ::CloseHandle(FileMappingHandle); if (!::DuplicateHandle(::GetCurrentProcess(), OrigFileHandle, ::GetCurrentProcess(), &FileHandle, 0, 0, DUPLICATE_SAME_ACCESS)) { std::error_code ec = mapWindowsError(GetLastError()); ::UnmapViewOfFile(Mapping); return ec; } return std::error_code(); } mapped_file_region::mapped_file_region(sys::fs::file_t fd, mapmode mode, size_t length, uint64_t offset, std::error_code &ec) : Size(length), Mapping() { ec = init(fd, offset, mode); if (ec) Mapping = 0; } static bool hasFlushBufferKernelBug() { static bool Ret{GetWindowsOSVersion() < llvm::VersionTuple(10, 0, 0, 17763)}; return Ret; } static bool isEXE(StringRef Magic) { static const char PEMagic[] = {'P', 'E', '\0', '\0'}; if (Magic.startswith(StringRef("MZ")) && Magic.size() >= 0x3c + 4) { uint32_t off = read32le(Magic.data() + 0x3c); // PE/COFF file, either EXE or DLL. if (Magic.substr(off).startswith(StringRef(PEMagic, sizeof(PEMagic)))) return true; } return false; } mapped_file_region::~mapped_file_region() { if (Mapping) { bool Exe = isEXE(StringRef((char *)Mapping, Size)); ::UnmapViewOfFile(Mapping); if (Mode == mapmode::readwrite && Exe && hasFlushBufferKernelBug()) { // There is a Windows kernel bug, the exact trigger conditions of which // are not well understood. When triggered, dirty pages are not properly // flushed and subsequent process's attempts to read a file can return // invalid data. Calling FlushFileBuffers on the write handle is // sufficient to ensure that this bug is not triggered. // The bug only occurs when writing an executable and executing it right // after, under high I/O pressure. ::FlushFileBuffers(FileHandle); } ::CloseHandle(FileHandle); } } size_t mapped_file_region::size() const { assert(Mapping && "Mapping failed but used anyway!"); return Size; } char *mapped_file_region::data() const { assert(Mapping && "Mapping failed but used anyway!"); return reinterpret_cast(Mapping); } const char *mapped_file_region::const_data() const { assert(Mapping && "Mapping failed but used anyway!"); return reinterpret_cast(Mapping); } int mapped_file_region::alignment() { SYSTEM_INFO SysInfo; ::GetSystemInfo(&SysInfo); return SysInfo.dwAllocationGranularity; } static basic_file_status status_from_find_data(WIN32_FIND_DATAW *FindData) { return basic_file_status(file_type_from_attrs(FindData->dwFileAttributes), perms_from_attrs(FindData->dwFileAttributes), FindData->ftLastAccessTime.dwHighDateTime, FindData->ftLastAccessTime.dwLowDateTime, FindData->ftLastWriteTime.dwHighDateTime, FindData->ftLastWriteTime.dwLowDateTime, FindData->nFileSizeHigh, FindData->nFileSizeLow); } std::error_code detail::directory_iterator_construct(detail::DirIterState &IT, StringRef Path, bool FollowSymlinks) { SmallVector PathUTF16; if (std::error_code EC = widenPath(Path, PathUTF16)) return EC; // Convert path to the format that Windows is happy with. if (PathUTF16.size() > 0 && !is_separator(PathUTF16[Path.size() - 1]) && PathUTF16[Path.size() - 1] != L':') { PathUTF16.push_back(L'\\'); PathUTF16.push_back(L'*'); } else { PathUTF16.push_back(L'*'); } // Get the first directory entry. WIN32_FIND_DATAW FirstFind; ScopedFindHandle FindHandle(::FindFirstFileExW( c_str(PathUTF16), FindExInfoBasic, &FirstFind, FindExSearchNameMatch, NULL, FIND_FIRST_EX_LARGE_FETCH)); if (!FindHandle) return mapWindowsError(::GetLastError()); size_t FilenameLen = ::wcslen(FirstFind.cFileName); while ((FilenameLen == 1 && FirstFind.cFileName[0] == L'.') || (FilenameLen == 2 && FirstFind.cFileName[0] == L'.' && FirstFind.cFileName[1] == L'.')) if (!::FindNextFileW(FindHandle, &FirstFind)) { DWORD LastError = ::GetLastError(); // Check for end. if (LastError == ERROR_NO_MORE_FILES) return detail::directory_iterator_destruct(IT); return mapWindowsError(LastError); } else FilenameLen = ::wcslen(FirstFind.cFileName); // Construct the current directory entry. SmallString<128> DirectoryEntryNameUTF8; if (std::error_code EC = UTF16ToUTF8(FirstFind.cFileName, ::wcslen(FirstFind.cFileName), DirectoryEntryNameUTF8)) return EC; IT.IterationHandle = intptr_t(FindHandle.take()); SmallString<128> DirectoryEntryPath(Path); path::append(DirectoryEntryPath, DirectoryEntryNameUTF8); IT.CurrentEntry = directory_entry(DirectoryEntryPath, FollowSymlinks, file_type_from_attrs(FirstFind.dwFileAttributes), status_from_find_data(&FirstFind)); return std::error_code(); } std::error_code detail::directory_iterator_destruct(detail::DirIterState &IT) { if (IT.IterationHandle != 0) // Closes the handle if it's valid. ScopedFindHandle close(HANDLE(IT.IterationHandle)); IT.IterationHandle = 0; IT.CurrentEntry = directory_entry(); return std::error_code(); } std::error_code detail::directory_iterator_increment(detail::DirIterState &IT) { WIN32_FIND_DATAW FindData; if (!::FindNextFileW(HANDLE(IT.IterationHandle), &FindData)) { DWORD LastError = ::GetLastError(); // Check for end. if (LastError == ERROR_NO_MORE_FILES) return detail::directory_iterator_destruct(IT); return mapWindowsError(LastError); } size_t FilenameLen = ::wcslen(FindData.cFileName); if ((FilenameLen == 1 && FindData.cFileName[0] == L'.') || (FilenameLen == 2 && FindData.cFileName[0] == L'.' && FindData.cFileName[1] == L'.')) return directory_iterator_increment(IT); SmallString<128> DirectoryEntryPathUTF8; if (std::error_code EC = UTF16ToUTF8(FindData.cFileName, ::wcslen(FindData.cFileName), DirectoryEntryPathUTF8)) return EC; IT.CurrentEntry.replace_filename( Twine(DirectoryEntryPathUTF8), file_type_from_attrs(FindData.dwFileAttributes), status_from_find_data(&FindData)); return std::error_code(); } ErrorOr directory_entry::status() const { return Status; } static std::error_code nativeFileToFd(Expected H, int &ResultFD, OpenFlags Flags) { int CrtOpenFlags = 0; if (Flags & OF_Append) CrtOpenFlags |= _O_APPEND; if (Flags & OF_Text) CrtOpenFlags |= _O_TEXT; ResultFD = -1; if (!H) return errorToErrorCode(H.takeError()); ResultFD = ::_open_osfhandle(intptr_t(*H), CrtOpenFlags); if (ResultFD == -1) { ::CloseHandle(*H); return mapWindowsError(ERROR_INVALID_HANDLE); } return std::error_code(); } static DWORD nativeDisposition(CreationDisposition Disp, OpenFlags Flags) { // This is a compatibility hack. Really we should respect the creation // disposition, but a lot of old code relied on the implicit assumption that // OF_Append implied it would open an existing file. Since the disposition is // now explicit and defaults to CD_CreateAlways, this assumption would cause // any usage of OF_Append to append to a new file, even if the file already // existed. A better solution might have two new creation dispositions: // CD_AppendAlways and CD_AppendNew. This would also address the problem of // OF_Append being used on a read-only descriptor, which doesn't make sense. if (Flags & OF_Append) return OPEN_ALWAYS; switch (Disp) { case CD_CreateAlways: return CREATE_ALWAYS; case CD_CreateNew: return CREATE_NEW; case CD_OpenAlways: return OPEN_ALWAYS; case CD_OpenExisting: return OPEN_EXISTING; } llvm_unreachable("unreachable!"); } static DWORD nativeAccess(FileAccess Access, OpenFlags Flags) { DWORD Result = 0; if (Access & FA_Read) Result |= GENERIC_READ; if (Access & FA_Write) Result |= GENERIC_WRITE; if (Flags & OF_Delete) Result |= DELETE; if (Flags & OF_UpdateAtime) Result |= FILE_WRITE_ATTRIBUTES; return Result; } static std::error_code openNativeFileInternal(const Twine &Name, file_t &ResultFile, DWORD Disp, DWORD Access, DWORD Flags, bool Inherit = false) { SmallVector PathUTF16; if (std::error_code EC = widenPath(Name, PathUTF16)) return EC; SECURITY_ATTRIBUTES SA; SA.nLength = sizeof(SA); SA.lpSecurityDescriptor = nullptr; SA.bInheritHandle = Inherit; HANDLE H = ::CreateFileW(PathUTF16.begin(), Access, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, &SA, Disp, Flags, NULL); if (H == INVALID_HANDLE_VALUE) { DWORD LastError = ::GetLastError(); std::error_code EC = mapWindowsError(LastError); // Provide a better error message when trying to open directories. // This only runs if we failed to open the file, so there is probably // no performances issues. if (LastError != ERROR_ACCESS_DENIED) return EC; if (is_directory(Name)) return make_error_code(errc::is_a_directory); return EC; } ResultFile = H; return std::error_code(); } Expected openNativeFile(const Twine &Name, CreationDisposition Disp, FileAccess Access, OpenFlags Flags, unsigned Mode) { // Verify that we don't have both "append" and "excl". assert((!(Disp == CD_CreateNew) || !(Flags & OF_Append)) && "Cannot specify both 'CreateNew' and 'Append' file creation flags!"); DWORD NativeDisp = nativeDisposition(Disp, Flags); DWORD NativeAccess = nativeAccess(Access, Flags); bool Inherit = false; if (Flags & OF_ChildInherit) Inherit = true; file_t Result; std::error_code EC = openNativeFileInternal( Name, Result, NativeDisp, NativeAccess, FILE_ATTRIBUTE_NORMAL, Inherit); if (EC) return errorCodeToError(EC); if (Flags & OF_UpdateAtime) { FILETIME FileTime; SYSTEMTIME SystemTime; GetSystemTime(&SystemTime); if (SystemTimeToFileTime(&SystemTime, &FileTime) == 0 || SetFileTime(Result, NULL, &FileTime, NULL) == 0) { DWORD LastError = ::GetLastError(); ::CloseHandle(Result); return errorCodeToError(mapWindowsError(LastError)); } } if (Flags & OF_Delete) { if ((EC = setDeleteDisposition(Result, true))) { ::CloseHandle(Result); return errorCodeToError(EC); } } return Result; } std::error_code openFile(const Twine &Name, int &ResultFD, CreationDisposition Disp, FileAccess Access, OpenFlags Flags, unsigned int Mode) { Expected Result = openNativeFile(Name, Disp, Access, Flags); if (!Result) return errorToErrorCode(Result.takeError()); return nativeFileToFd(*Result, ResultFD, Flags); } static std::error_code directoryRealPath(const Twine &Name, SmallVectorImpl &RealPath) { file_t File; std::error_code EC = openNativeFileInternal( Name, File, OPEN_EXISTING, GENERIC_READ, FILE_FLAG_BACKUP_SEMANTICS); if (EC) return EC; EC = realPathFromHandle(File, RealPath); ::CloseHandle(File); return EC; } std::error_code openFileForRead(const Twine &Name, int &ResultFD, OpenFlags Flags, SmallVectorImpl *RealPath) { Expected NativeFile = openNativeFileForRead(Name, Flags, RealPath); return nativeFileToFd(std::move(NativeFile), ResultFD, OF_None); } Expected openNativeFileForRead(const Twine &Name, OpenFlags Flags, SmallVectorImpl *RealPath) { Expected Result = openNativeFile(Name, CD_OpenExisting, FA_Read, Flags); // Fetch the real name of the file, if the user asked if (Result && RealPath) realPathFromHandle(*Result, *RealPath); return Result; } file_t convertFDToNativeFile(int FD) { return reinterpret_cast(::_get_osfhandle(FD)); } file_t getStdinHandle() { return ::GetStdHandle(STD_INPUT_HANDLE); } file_t getStdoutHandle() { return ::GetStdHandle(STD_OUTPUT_HANDLE); } file_t getStderrHandle() { return ::GetStdHandle(STD_ERROR_HANDLE); } Expected readNativeFileImpl(file_t FileHandle, MutableArrayRef Buf, OVERLAPPED *Overlap) { // ReadFile can only read 2GB at a time. The caller should check the number of // bytes and read in a loop until termination. DWORD BytesToRead = std::min(size_t(std::numeric_limits::max()), Buf.size()); DWORD BytesRead = 0; if (::ReadFile(FileHandle, Buf.data(), BytesToRead, &BytesRead, Overlap)) return BytesRead; DWORD Err = ::GetLastError(); // EOF is not an error. if (Err == ERROR_BROKEN_PIPE || Err == ERROR_HANDLE_EOF) return BytesRead; return errorCodeToError(mapWindowsError(Err)); } Expected readNativeFile(file_t FileHandle, MutableArrayRef Buf) { return readNativeFileImpl(FileHandle, Buf, /*Overlap=*/nullptr); } Expected readNativeFileSlice(file_t FileHandle, MutableArrayRef Buf, uint64_t Offset) { OVERLAPPED Overlapped = {}; Overlapped.Offset = uint32_t(Offset); Overlapped.OffsetHigh = uint32_t(Offset >> 32); return readNativeFileImpl(FileHandle, Buf, &Overlapped); } std::error_code closeFile(file_t &F) { file_t TmpF = F; F = kInvalidFile; if (!::CloseHandle(TmpF)) return mapWindowsError(::GetLastError()); return std::error_code(); } std::error_code remove_directories(const Twine &path, bool IgnoreErrors) { // Convert to utf-16. SmallVector Path16; std::error_code EC = widenPath(path, Path16); if (EC && !IgnoreErrors) return EC; // SHFileOperation() accepts a list of paths, and so must be double null- // terminated to indicate the end of the list. The buffer is already null // terminated, but since that null character is not considered part of the // vector's size, pushing another one will just consume that byte. So we // need to push 2 null terminators. Path16.push_back(0); Path16.push_back(0); SHFILEOPSTRUCTW shfos = {}; shfos.wFunc = FO_DELETE; shfos.pFrom = Path16.data(); shfos.fFlags = FOF_NO_UI; int result = ::SHFileOperationW(&shfos); if (result != 0 && !IgnoreErrors) return mapWindowsError(result); return std::error_code(); } static void expandTildeExpr(SmallVectorImpl &Path) { // Path does not begin with a tilde expression. if (Path.empty() || Path[0] != '~') return; StringRef PathStr(Path.begin(), Path.size()); PathStr = PathStr.drop_front(); StringRef Expr = PathStr.take_until([](char c) { return path::is_separator(c); }); if (!Expr.empty()) { // This is probably a ~username/ expression. Don't support this on Windows. return; } SmallString<128> HomeDir; if (!path::home_directory(HomeDir)) { // For some reason we couldn't get the home directory. Just exit. return; } // Overwrite the first character and insert the rest. Path[0] = HomeDir[0]; Path.insert(Path.begin() + 1, HomeDir.begin() + 1, HomeDir.end()); } void expand_tilde(const Twine &path, SmallVectorImpl &dest) { dest.clear(); if (path.isTriviallyEmpty()) return; path.toVector(dest); expandTildeExpr(dest); return; } std::error_code real_path(const Twine &path, SmallVectorImpl &dest, bool expand_tilde) { dest.clear(); if (path.isTriviallyEmpty()) return std::error_code(); if (expand_tilde) { SmallString<128> Storage; path.toVector(Storage); expandTildeExpr(Storage); return real_path(Storage, dest, false); } if (is_directory(path)) return directoryRealPath(path, dest); int fd; if (std::error_code EC = llvm::sys::fs::openFileForRead(path, fd, OF_None, &dest)) return EC; ::close(fd); return std::error_code(); } } // end namespace fs namespace path { static bool getKnownFolderPath(KNOWNFOLDERID folderId, SmallVectorImpl &result) { wchar_t *path = nullptr; if (::SHGetKnownFolderPath(folderId, KF_FLAG_CREATE, nullptr, &path) != S_OK) return false; bool ok = !UTF16ToUTF8(path, ::wcslen(path), result); ::CoTaskMemFree(path); return ok; } bool home_directory(SmallVectorImpl &result) { return getKnownFolderPath(FOLDERID_Profile, result); } static bool getTempDirEnvVar(const wchar_t *Var, SmallVectorImpl &Res) { SmallVector Buf; size_t Size = 1024; do { Buf.reserve(Size); Size = GetEnvironmentVariableW(Var, Buf.data(), Buf.capacity()); if (Size == 0) return false; // Try again with larger buffer. } while (Size > Buf.capacity()); Buf.set_size(Size); return !windows::UTF16ToUTF8(Buf.data(), Size, Res); } static bool getTempDirEnvVar(SmallVectorImpl &Res) { const wchar_t *EnvironmentVariables[] = {L"TMP", L"TEMP", L"USERPROFILE"}; for (auto *Env : EnvironmentVariables) { if (getTempDirEnvVar(Env, Res)) return true; } return false; } void system_temp_directory(bool ErasedOnReboot, SmallVectorImpl &Result) { (void)ErasedOnReboot; Result.clear(); // Check whether the temporary directory is specified by an environment var. // This matches GetTempPath logic to some degree. GetTempPath is not used // directly as it cannot handle evn var longer than 130 chars on Windows 7 // (fixed on Windows 8). if (getTempDirEnvVar(Result)) { assert(!Result.empty() && "Unexpected empty path"); native(Result); // Some Unix-like shells use Unix path separator in $TMP. fs::make_absolute(Result); // Make it absolute if not already. return; } // Fall back to a system default. const char *DefaultResult = "C:\\Temp"; Result.append(DefaultResult, DefaultResult + strlen(DefaultResult)); } } // end namespace path namespace windows { std::error_code CodePageToUTF16(unsigned codepage, llvm::StringRef original, llvm::SmallVectorImpl &utf16) { if (!original.empty()) { int len = ::MultiByteToWideChar(codepage, MB_ERR_INVALID_CHARS, original.begin(), original.size(), utf16.begin(), 0); if (len == 0) { return mapWindowsError(::GetLastError()); } utf16.reserve(len + 1); utf16.set_size(len); len = ::MultiByteToWideChar(codepage, MB_ERR_INVALID_CHARS, original.begin(), original.size(), utf16.begin(), utf16.size()); if (len == 0) { return mapWindowsError(::GetLastError()); } } // Make utf16 null terminated. utf16.push_back(0); utf16.pop_back(); return std::error_code(); } std::error_code UTF8ToUTF16(llvm::StringRef utf8, llvm::SmallVectorImpl &utf16) { return CodePageToUTF16(CP_UTF8, utf8, utf16); } std::error_code CurCPToUTF16(llvm::StringRef curcp, llvm::SmallVectorImpl &utf16) { return CodePageToUTF16(CP_ACP, curcp, utf16); } static std::error_code UTF16ToCodePage(unsigned codepage, const wchar_t *utf16, size_t utf16_len, llvm::SmallVectorImpl &converted) { if (utf16_len) { // Get length. int len = ::WideCharToMultiByte(codepage, 0, utf16, utf16_len, converted.begin(), 0, NULL, NULL); if (len == 0) { return mapWindowsError(::GetLastError()); } converted.reserve(len); converted.set_size(len); // Now do the actual conversion. len = ::WideCharToMultiByte(codepage, 0, utf16, utf16_len, converted.data(), converted.size(), NULL, NULL); if (len == 0) { return mapWindowsError(::GetLastError()); } } // Make the new string null terminated. converted.push_back(0); converted.pop_back(); return std::error_code(); } std::error_code UTF16ToUTF8(const wchar_t *utf16, size_t utf16_len, llvm::SmallVectorImpl &utf8) { return UTF16ToCodePage(CP_UTF8, utf16, utf16_len, utf8); } std::error_code UTF16ToCurCP(const wchar_t *utf16, size_t utf16_len, llvm::SmallVectorImpl &curcp) { return UTF16ToCodePage(CP_ACP, utf16, utf16_len, curcp); } } // end namespace windows } // end namespace sys } // end namespace llvm diff --git a/contrib/llvm-project/llvm/lib/Support/Windows/Process.inc b/contrib/llvm-project/llvm/lib/Support/Windows/Process.inc index 3526e3dee6fa..518ecdb98896 100644 --- a/contrib/llvm-project/llvm/lib/Support/Windows/Process.inc +++ b/contrib/llvm-project/llvm/lib/Support/Windows/Process.inc @@ -1,478 +1,478 @@ //===- Win32/Process.cpp - Win32 Process Implementation ------- -*- 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 the Win32 specific implementation of the Process class. // //===----------------------------------------------------------------------===// #include "llvm/Support/Allocator.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/ConvertUTF.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/StringSaver.h" #include "llvm/Support/WindowsError.h" #include // The Windows.h header must be after LLVM and standard headers. -#include "WindowsSupport.h" +#include "llvm/Support/Windows/WindowsSupport.h" #include #include #include #include #if !defined(__MINGW32__) #pragma comment(lib, "psapi.lib") #pragma comment(lib, "shell32.lib") #endif //===----------------------------------------------------------------------===// //=== WARNING: Implementation here must contain only Win32 specific code //=== and must not be UNIX code //===----------------------------------------------------------------------===// #ifdef __MINGW32__ // This ban should be lifted when MinGW 1.0+ has defined this value. # define _HEAPOK (-2) #endif using namespace llvm; // This function retrieves the page size using GetNativeSystemInfo() and is // present solely so it can be called once to initialize the self_process member // below. static unsigned computePageSize() { // GetNativeSystemInfo() provides the physical page size which may differ // from GetSystemInfo() in 32-bit applications running under WOW64. SYSTEM_INFO info; GetNativeSystemInfo(&info); // FIXME: FileOffset in MapViewOfFile() should be aligned to not dwPageSize, // but dwAllocationGranularity. return static_cast(info.dwPageSize); } Expected Process::getPageSize() { static unsigned Ret = computePageSize(); return Ret; } size_t Process::GetMallocUsage() { _HEAPINFO hinfo; hinfo._pentry = NULL; size_t size = 0; while (_heapwalk(&hinfo) == _HEAPOK) size += hinfo._size; return size; } void Process::GetTimeUsage(TimePoint<> &elapsed, std::chrono::nanoseconds &user_time, std::chrono::nanoseconds &sys_time) { elapsed = std::chrono::system_clock::now();; FILETIME ProcCreate, ProcExit, KernelTime, UserTime; if (GetProcessTimes(GetCurrentProcess(), &ProcCreate, &ProcExit, &KernelTime, &UserTime) == 0) return; user_time = toDuration(UserTime); sys_time = toDuration(KernelTime); } // Some LLVM programs such as bugpoint produce core files as a normal part of // their operation. To prevent the disk from filling up, this configuration // item does what's necessary to prevent their generation. void Process::PreventCoreFiles() { // Windows does have the concept of core files, called minidumps. However, // disabling minidumps for a particular application extends past the lifetime // of that application, which is the incorrect behavior for this API. // Additionally, the APIs require elevated privileges to disable and re- // enable minidumps, which makes this untenable. For more information, see // WerAddExcludedApplication and WerRemoveExcludedApplication (Vista and // later). // // Windows also has modal pop-up message boxes. As this method is used by // bugpoint, preventing these pop-ups is additionally important. SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX); coreFilesPrevented = true; } /// Returns the environment variable \arg Name's value as a string encoded in /// UTF-8. \arg Name is assumed to be in UTF-8 encoding. Optional Process::GetEnv(StringRef Name) { // Convert the argument to UTF-16 to pass it to _wgetenv(). SmallVector NameUTF16; if (windows::UTF8ToUTF16(Name, NameUTF16)) return None; // Environment variable can be encoded in non-UTF8 encoding, and there's no // way to know what the encoding is. The only reliable way to look up // multibyte environment variable is to use GetEnvironmentVariableW(). SmallVector Buf; size_t Size = MAX_PATH; do { Buf.reserve(Size); SetLastError(NO_ERROR); Size = GetEnvironmentVariableW(NameUTF16.data(), Buf.data(), Buf.capacity()); if (Size == 0 && GetLastError() == ERROR_ENVVAR_NOT_FOUND) return None; // Try again with larger buffer. } while (Size > Buf.capacity()); Buf.set_size(Size); // Convert the result from UTF-16 to UTF-8. SmallVector Res; if (windows::UTF16ToUTF8(Buf.data(), Size, Res)) return None; return std::string(Res.data()); } /// Perform wildcard expansion of Arg, or just push it into Args if it doesn't /// have wildcards or doesn't match any files. static std::error_code WildcardExpand(StringRef Arg, SmallVectorImpl &Args, StringSaver &Saver) { std::error_code EC; // Don't expand Arg if it does not contain any wildcard characters. This is // the common case. Also don't wildcard expand /?. Always treat it as an // option. if (Arg.find_first_of("*?") == StringRef::npos || Arg == "/?" || Arg == "-?") { Args.push_back(Arg.data()); return EC; } // Convert back to UTF-16 so we can call FindFirstFileW. SmallVector ArgW; EC = windows::UTF8ToUTF16(Arg, ArgW); if (EC) return EC; // Search for matching files. // FIXME: This assumes the wildcard is only in the file name and not in the // directory portion of the file path. For example, it doesn't handle // "*\foo.c" nor "s?c\bar.cpp". WIN32_FIND_DATAW FileData; HANDLE FindHandle = FindFirstFileW(ArgW.data(), &FileData); if (FindHandle == INVALID_HANDLE_VALUE) { Args.push_back(Arg.data()); return EC; } // Extract any directory part of the argument. SmallString Dir = Arg; sys::path::remove_filename(Dir); const int DirSize = Dir.size(); do { SmallString FileName; EC = windows::UTF16ToUTF8(FileData.cFileName, wcslen(FileData.cFileName), FileName); if (EC) break; // Append FileName to Dir, and remove it afterwards. llvm::sys::path::append(Dir, FileName); Args.push_back(Saver.save(StringRef(Dir)).data()); Dir.resize(DirSize); } while (FindNextFileW(FindHandle, &FileData)); FindClose(FindHandle); return EC; } static std::error_code GetExecutableName(SmallVectorImpl &Filename) { // The first argument may contain just the name of the executable (e.g., // "clang") rather than the full path, so swap it with the full path. wchar_t ModuleName[MAX_PATH]; size_t Length = ::GetModuleFileNameW(NULL, ModuleName, MAX_PATH); if (Length == 0 || Length == MAX_PATH) { return mapWindowsError(GetLastError()); } // If the first argument is a shortened (8.3) name (which is possible even // if we got the module name), the driver will have trouble distinguishing it // (e.g., clang.exe v. clang++.exe), so expand it now. Length = GetLongPathNameW(ModuleName, ModuleName, MAX_PATH); if (Length == 0) return mapWindowsError(GetLastError()); if (Length > MAX_PATH) { // We're not going to try to deal with paths longer than MAX_PATH, so we'll // treat this as an error. GetLastError() returns ERROR_SUCCESS, which // isn't useful, so we'll hardcode an appropriate error value. return mapWindowsError(ERROR_INSUFFICIENT_BUFFER); } std::error_code EC = windows::UTF16ToUTF8(ModuleName, Length, Filename); if (EC) return EC; StringRef Base = sys::path::filename(Filename.data()); Filename.assign(Base.begin(), Base.end()); return std::error_code(); } std::error_code windows::GetCommandLineArguments(SmallVectorImpl &Args, BumpPtrAllocator &Alloc) { const wchar_t *CmdW = GetCommandLineW(); assert(CmdW); std::error_code EC; SmallString Cmd; EC = windows::UTF16ToUTF8(CmdW, wcslen(CmdW), Cmd); if (EC) return EC; SmallVector TmpArgs; StringSaver Saver(Alloc); cl::TokenizeWindowsCommandLine(Cmd, Saver, TmpArgs, /*MarkEOLs=*/false); for (const char *Arg : TmpArgs) { EC = WildcardExpand(Arg, Args, Saver); if (EC) return EC; } SmallVector Arg0(Args[0], Args[0] + strlen(Args[0])); SmallVector Filename; sys::path::remove_filename(Arg0); EC = GetExecutableName(Filename); if (EC) return EC; sys::path::append(Arg0, Filename); Args[0] = Saver.save(Arg0).data(); return std::error_code(); } std::error_code Process::FixupStandardFileDescriptors() { return std::error_code(); } std::error_code Process::SafelyCloseFileDescriptor(int FD) { if (::close(FD) < 0) return std::error_code(errno, std::generic_category()); return std::error_code(); } bool Process::StandardInIsUserInput() { return FileDescriptorIsDisplayed(0); } bool Process::StandardOutIsDisplayed() { return FileDescriptorIsDisplayed(1); } bool Process::StandardErrIsDisplayed() { return FileDescriptorIsDisplayed(2); } bool Process::FileDescriptorIsDisplayed(int fd) { DWORD Mode; // Unused return (GetConsoleMode((HANDLE)_get_osfhandle(fd), &Mode) != 0); } unsigned Process::StandardOutColumns() { unsigned Columns = 0; CONSOLE_SCREEN_BUFFER_INFO csbi; if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi)) Columns = csbi.dwSize.X; return Columns; } unsigned Process::StandardErrColumns() { unsigned Columns = 0; CONSOLE_SCREEN_BUFFER_INFO csbi; if (GetConsoleScreenBufferInfo(GetStdHandle(STD_ERROR_HANDLE), &csbi)) Columns = csbi.dwSize.X; return Columns; } // The terminal always has colors. bool Process::FileDescriptorHasColors(int fd) { return FileDescriptorIsDisplayed(fd); } bool Process::StandardOutHasColors() { return FileDescriptorHasColors(1); } bool Process::StandardErrHasColors() { return FileDescriptorHasColors(2); } static bool UseANSI = false; void Process::UseANSIEscapeCodes(bool enable) { #if defined(ENABLE_VIRTUAL_TERMINAL_PROCESSING) if (enable) { HANDLE Console = GetStdHandle(STD_OUTPUT_HANDLE); DWORD Mode; GetConsoleMode(Console, &Mode); Mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING; SetConsoleMode(Console, Mode); } #endif UseANSI = enable; } namespace { class DefaultColors { private: WORD defaultColor; public: DefaultColors() :defaultColor(GetCurrentColor()) {} static unsigned GetCurrentColor() { CONSOLE_SCREEN_BUFFER_INFO csbi; if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi)) return csbi.wAttributes; return 0; } WORD operator()() const { return defaultColor; } }; DefaultColors defaultColors; WORD fg_color(WORD color) { return color & (FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_INTENSITY | FOREGROUND_RED); } WORD bg_color(WORD color) { return color & (BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_INTENSITY | BACKGROUND_RED); } } bool Process::ColorNeedsFlush() { return !UseANSI; } const char *Process::OutputBold(bool bg) { if (UseANSI) return "\033[1m"; WORD colors = DefaultColors::GetCurrentColor(); if (bg) colors |= BACKGROUND_INTENSITY; else colors |= FOREGROUND_INTENSITY; SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), colors); return 0; } const char *Process::OutputColor(char code, bool bold, bool bg) { if (UseANSI) return colorcodes[bg?1:0][bold?1:0][code&7]; WORD current = DefaultColors::GetCurrentColor(); WORD colors; if (bg) { colors = ((code&1) ? BACKGROUND_RED : 0) | ((code&2) ? BACKGROUND_GREEN : 0 ) | ((code&4) ? BACKGROUND_BLUE : 0); if (bold) colors |= BACKGROUND_INTENSITY; colors |= fg_color(current); } else { colors = ((code&1) ? FOREGROUND_RED : 0) | ((code&2) ? FOREGROUND_GREEN : 0 ) | ((code&4) ? FOREGROUND_BLUE : 0); if (bold) colors |= FOREGROUND_INTENSITY; colors |= bg_color(current); } SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), colors); return 0; } static WORD GetConsoleTextAttribute(HANDLE hConsoleOutput) { CONSOLE_SCREEN_BUFFER_INFO info; GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &info); return info.wAttributes; } const char *Process::OutputReverse() { if (UseANSI) return "\033[7m"; const WORD attributes = GetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE)); const WORD foreground_mask = FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY; const WORD background_mask = BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_INTENSITY; const WORD color_mask = foreground_mask | background_mask; WORD new_attributes = ((attributes & FOREGROUND_BLUE )?BACKGROUND_BLUE :0) | ((attributes & FOREGROUND_GREEN )?BACKGROUND_GREEN :0) | ((attributes & FOREGROUND_RED )?BACKGROUND_RED :0) | ((attributes & FOREGROUND_INTENSITY)?BACKGROUND_INTENSITY:0) | ((attributes & BACKGROUND_BLUE )?FOREGROUND_BLUE :0) | ((attributes & BACKGROUND_GREEN )?FOREGROUND_GREEN :0) | ((attributes & BACKGROUND_RED )?FOREGROUND_RED :0) | ((attributes & BACKGROUND_INTENSITY)?FOREGROUND_INTENSITY:0) | 0; new_attributes = (attributes & ~color_mask) | (new_attributes & color_mask); SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), new_attributes); return 0; } const char *Process::ResetColor() { if (UseANSI) return "\033[0m"; SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), defaultColors()); return 0; } unsigned Process::GetRandomNumber() { HCRYPTPROV HCPC; if (!::CryptAcquireContextW(&HCPC, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) ReportLastErrorFatal("Could not acquire a cryptographic context"); ScopedCryptContext CryptoProvider(HCPC); unsigned Ret; if (!::CryptGenRandom(CryptoProvider, sizeof(Ret), reinterpret_cast(&Ret))) ReportLastErrorFatal("Could not generate a random number"); return Ret; } typedef NTSTATUS(WINAPI* RtlGetVersionPtr)(PRTL_OSVERSIONINFOW); #define STATUS_SUCCESS ((NTSTATUS)0x00000000L) llvm::VersionTuple llvm::GetWindowsOSVersion() { HMODULE hMod = ::GetModuleHandleW(L"ntdll.dll"); if (hMod) { auto getVer = (RtlGetVersionPtr)::GetProcAddress(hMod, "RtlGetVersion"); if (getVer) { RTL_OSVERSIONINFOEXW info{}; info.dwOSVersionInfoSize = sizeof(info); if (getVer((PRTL_OSVERSIONINFOW)&info) == STATUS_SUCCESS) { return llvm::VersionTuple(info.dwMajorVersion, info.dwMinorVersion, 0, info.dwBuildNumber); } } } return llvm::VersionTuple(0, 0, 0, 0); } bool llvm::RunningWindows8OrGreater() { // Windows 8 is version 6.2, service pack 0. return GetWindowsOSVersion() >= llvm::VersionTuple(6, 2, 0, 0); } diff --git a/contrib/llvm-project/llvm/lib/Support/Windows/Program.inc b/contrib/llvm-project/llvm/lib/Support/Windows/Program.inc index a1482bf17c60..c4285d5d6563 100644 --- a/contrib/llvm-project/llvm/lib/Support/Windows/Program.inc +++ b/contrib/llvm-project/llvm/lib/Support/Windows/Program.inc @@ -1,523 +1,523 @@ //===- Win32/Program.cpp - Win32 Program Implementation ------- -*- 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 the Win32 specific implementation of the Program class. // //===----------------------------------------------------------------------===// -#include "WindowsSupport.h" +#include "llvm/Support/Windows/WindowsSupport.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Support/ConvertUTF.h" #include "llvm/Support/Errc.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" #include "llvm/Support/WindowsError.h" #include "llvm/Support/raw_ostream.h" #include #include #include #include #include //===----------------------------------------------------------------------===// //=== WARNING: Implementation here must contain only Win32 specific code //=== and must not be UNIX code //===----------------------------------------------------------------------===// namespace llvm { ProcessInfo::ProcessInfo() : Pid(0), Process(0), ReturnCode(0) {} ErrorOr sys::findProgramByName(StringRef Name, ArrayRef Paths) { assert(!Name.empty() && "Must have a name!"); if (Name.find_first_of("/\\") != StringRef::npos) return std::string(Name); const wchar_t *Path = nullptr; std::wstring PathStorage; if (!Paths.empty()) { PathStorage.reserve(Paths.size() * MAX_PATH); for (unsigned i = 0; i < Paths.size(); ++i) { if (i) PathStorage.push_back(L';'); StringRef P = Paths[i]; SmallVector TmpPath; if (std::error_code EC = windows::UTF8ToUTF16(P, TmpPath)) return EC; PathStorage.append(TmpPath.begin(), TmpPath.end()); } Path = PathStorage.c_str(); } SmallVector U16Name; if (std::error_code EC = windows::UTF8ToUTF16(Name, U16Name)) return EC; SmallVector PathExts; PathExts.push_back(""); PathExts.push_back(".exe"); // FIXME: This must be in %PATHEXT%. if (const char *PathExtEnv = std::getenv("PATHEXT")) SplitString(PathExtEnv, PathExts, ";"); SmallVector U16Result; DWORD Len = MAX_PATH; for (StringRef Ext : PathExts) { SmallVector U16Ext; if (std::error_code EC = windows::UTF8ToUTF16(Ext, U16Ext)) return EC; do { U16Result.reserve(Len); // Lets attach the extension manually. That is needed for files // with a point in name like aaa.bbb. SearchPathW will not add extension // from its argument to such files because it thinks they already had one. SmallVector U16NameExt; if (std::error_code EC = windows::UTF8ToUTF16(Twine(Name + Ext).str(), U16NameExt)) return EC; Len = ::SearchPathW(Path, c_str(U16NameExt), nullptr, U16Result.capacity(), U16Result.data(), nullptr); } while (Len > U16Result.capacity()); if (Len != 0) break; // Found it. } if (Len == 0) return mapWindowsError(::GetLastError()); U16Result.set_size(Len); SmallVector U8Result; if (std::error_code EC = windows::UTF16ToUTF8(U16Result.data(), U16Result.size(), U8Result)) return EC; return std::string(U8Result.begin(), U8Result.end()); } bool MakeErrMsg(std::string *ErrMsg, const std::string &prefix) { if (!ErrMsg) return true; char *buffer = NULL; DWORD LastError = GetLastError(); DWORD R = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_MAX_WIDTH_MASK, NULL, LastError, 0, (LPSTR)&buffer, 1, NULL); if (R) *ErrMsg = prefix + ": " + buffer; else *ErrMsg = prefix + ": Unknown error"; *ErrMsg += " (0x" + llvm::utohexstr(LastError) + ")"; LocalFree(buffer); return R != 0; } static HANDLE RedirectIO(Optional Path, int fd, std::string *ErrMsg) { HANDLE h; if (!Path) { if (!DuplicateHandle(GetCurrentProcess(), (HANDLE)_get_osfhandle(fd), GetCurrentProcess(), &h, 0, TRUE, DUPLICATE_SAME_ACCESS)) return INVALID_HANDLE_VALUE; return h; } std::string fname; if (Path->empty()) fname = "NUL"; else fname = *Path; SECURITY_ATTRIBUTES sa; sa.nLength = sizeof(sa); sa.lpSecurityDescriptor = 0; sa.bInheritHandle = TRUE; SmallVector fnameUnicode; if (Path->empty()) { // Don't play long-path tricks on "NUL". if (windows::UTF8ToUTF16(fname, fnameUnicode)) return INVALID_HANDLE_VALUE; } else { if (path::widenPath(fname, fnameUnicode)) return INVALID_HANDLE_VALUE; } h = CreateFileW(fnameUnicode.data(), fd ? GENERIC_WRITE : GENERIC_READ, FILE_SHARE_READ, &sa, fd == 0 ? OPEN_EXISTING : CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (h == INVALID_HANDLE_VALUE) { MakeErrMsg(ErrMsg, fname + ": Can't open file for " + (fd ? "input" : "output")); } return h; } } static bool Execute(ProcessInfo &PI, StringRef Program, ArrayRef Args, Optional> Env, ArrayRef> Redirects, unsigned MemoryLimit, std::string *ErrMsg) { if (!sys::fs::can_execute(Program)) { if (ErrMsg) *ErrMsg = "program not executable"; return false; } // can_execute may succeed by looking at Program + ".exe". CreateProcessW // will implicitly add the .exe if we provide a command line without an // executable path, but since we use an explicit executable, we have to add // ".exe" ourselves. SmallString<64> ProgramStorage; if (!sys::fs::exists(Program)) Program = Twine(Program + ".exe").toStringRef(ProgramStorage); // Windows wants a command line, not an array of args, to pass to the new // process. We have to concatenate them all, while quoting the args that // have embedded spaces (or are empty). std::string Command = flattenWindowsCommandLine(Args); // The pointer to the environment block for the new process. std::vector EnvBlock; if (Env) { // An environment block consists of a null-terminated block of // null-terminated strings. Convert the array of environment variables to // an environment block by concatenating them. for (StringRef E : *Env) { SmallVector EnvString; if (std::error_code ec = windows::UTF8ToUTF16(E, EnvString)) { SetLastError(ec.value()); MakeErrMsg(ErrMsg, "Unable to convert environment variable to UTF-16"); return false; } EnvBlock.insert(EnvBlock.end(), EnvString.begin(), EnvString.end()); EnvBlock.push_back(0); } EnvBlock.push_back(0); } // Create a child process. STARTUPINFOW si; memset(&si, 0, sizeof(si)); si.cb = sizeof(si); si.hStdInput = INVALID_HANDLE_VALUE; si.hStdOutput = INVALID_HANDLE_VALUE; si.hStdError = INVALID_HANDLE_VALUE; if (!Redirects.empty()) { si.dwFlags = STARTF_USESTDHANDLES; si.hStdInput = RedirectIO(Redirects[0], 0, ErrMsg); if (si.hStdInput == INVALID_HANDLE_VALUE) { MakeErrMsg(ErrMsg, "can't redirect stdin"); return false; } si.hStdOutput = RedirectIO(Redirects[1], 1, ErrMsg); if (si.hStdOutput == INVALID_HANDLE_VALUE) { CloseHandle(si.hStdInput); MakeErrMsg(ErrMsg, "can't redirect stdout"); return false; } if (Redirects[1] && Redirects[2] && *Redirects[1] == *Redirects[2]) { // If stdout and stderr should go to the same place, redirect stderr // to the handle already open for stdout. if (!DuplicateHandle(GetCurrentProcess(), si.hStdOutput, GetCurrentProcess(), &si.hStdError, 0, TRUE, DUPLICATE_SAME_ACCESS)) { CloseHandle(si.hStdInput); CloseHandle(si.hStdOutput); MakeErrMsg(ErrMsg, "can't dup stderr to stdout"); return false; } } else { // Just redirect stderr si.hStdError = RedirectIO(Redirects[2], 2, ErrMsg); if (si.hStdError == INVALID_HANDLE_VALUE) { CloseHandle(si.hStdInput); CloseHandle(si.hStdOutput); MakeErrMsg(ErrMsg, "can't redirect stderr"); return false; } } } PROCESS_INFORMATION pi; memset(&pi, 0, sizeof(pi)); fflush(stdout); fflush(stderr); SmallVector ProgramUtf16; if (std::error_code ec = path::widenPath(Program, ProgramUtf16)) { SetLastError(ec.value()); MakeErrMsg(ErrMsg, std::string("Unable to convert application name to UTF-16")); return false; } SmallVector CommandUtf16; if (std::error_code ec = windows::UTF8ToUTF16(Command, CommandUtf16)) { SetLastError(ec.value()); MakeErrMsg(ErrMsg, std::string("Unable to convert command-line to UTF-16")); return false; } BOOL rc = CreateProcessW(ProgramUtf16.data(), CommandUtf16.data(), 0, 0, TRUE, CREATE_UNICODE_ENVIRONMENT, EnvBlock.empty() ? 0 : EnvBlock.data(), 0, &si, &pi); DWORD err = GetLastError(); // Regardless of whether the process got created or not, we are done with // the handles we created for it to inherit. CloseHandle(si.hStdInput); CloseHandle(si.hStdOutput); CloseHandle(si.hStdError); // Now return an error if the process didn't get created. if (!rc) { SetLastError(err); MakeErrMsg(ErrMsg, std::string("Couldn't execute program '") + Program.str() + "'"); return false; } PI.Pid = pi.dwProcessId; PI.Process = pi.hProcess; // Make sure these get closed no matter what. ScopedCommonHandle hThread(pi.hThread); // Assign the process to a job if a memory limit is defined. ScopedJobHandle hJob; if (MemoryLimit != 0) { hJob = CreateJobObjectW(0, 0); bool success = false; if (hJob) { JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli; memset(&jeli, 0, sizeof(jeli)); jeli.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_PROCESS_MEMORY; jeli.ProcessMemoryLimit = uintptr_t(MemoryLimit) * 1048576; if (SetInformationJobObject(hJob, JobObjectExtendedLimitInformation, &jeli, sizeof(jeli))) { if (AssignProcessToJobObject(hJob, pi.hProcess)) success = true; } } if (!success) { SetLastError(GetLastError()); MakeErrMsg(ErrMsg, std::string("Unable to set memory limit")); TerminateProcess(pi.hProcess, 1); WaitForSingleObject(pi.hProcess, INFINITE); return false; } } return true; } static bool argNeedsQuotes(StringRef Arg) { if (Arg.empty()) return true; return StringRef::npos != Arg.find_first_of("\t \"&\'()*<>\\`^|\n"); } static std::string quoteSingleArg(StringRef Arg) { std::string Result; Result.push_back('"'); while (!Arg.empty()) { size_t FirstNonBackslash = Arg.find_first_not_of('\\'); size_t BackslashCount = FirstNonBackslash; if (FirstNonBackslash == StringRef::npos) { // The entire remainder of the argument is backslashes. Escape all of // them and just early out. BackslashCount = Arg.size(); Result.append(BackslashCount * 2, '\\'); break; } if (Arg[FirstNonBackslash] == '\"') { // This is an embedded quote. Escape all preceding backslashes, then // add one additional backslash to escape the quote. Result.append(BackslashCount * 2 + 1, '\\'); Result.push_back('\"'); } else { // This is just a normal character. Don't escape any of the preceding // backslashes, just append them as they are and then append the // character. Result.append(BackslashCount, '\\'); Result.push_back(Arg[FirstNonBackslash]); } // Drop all the backslashes, plus the following character. Arg = Arg.drop_front(FirstNonBackslash + 1); } Result.push_back('"'); return Result; } namespace llvm { std::string sys::flattenWindowsCommandLine(ArrayRef Args) { std::string Command; for (StringRef Arg : Args) { if (argNeedsQuotes(Arg)) Command += quoteSingleArg(Arg); else Command += Arg; Command.push_back(' '); } return Command; } ProcessInfo sys::Wait(const ProcessInfo &PI, unsigned SecondsToWait, bool WaitUntilChildTerminates, std::string *ErrMsg) { assert(PI.Pid && "invalid pid to wait on, process not started?"); assert((PI.Process && PI.Process != INVALID_HANDLE_VALUE) && "invalid process handle to wait on, process not started?"); DWORD milliSecondsToWait = 0; if (WaitUntilChildTerminates) milliSecondsToWait = INFINITE; else if (SecondsToWait > 0) milliSecondsToWait = SecondsToWait * 1000; ProcessInfo WaitResult = PI; DWORD WaitStatus = WaitForSingleObject(PI.Process, milliSecondsToWait); if (WaitStatus == WAIT_TIMEOUT) { if (SecondsToWait) { if (!TerminateProcess(PI.Process, 1)) { if (ErrMsg) MakeErrMsg(ErrMsg, "Failed to terminate timed-out program"); // -2 indicates a crash or timeout as opposed to failure to execute. WaitResult.ReturnCode = -2; CloseHandle(PI.Process); return WaitResult; } WaitForSingleObject(PI.Process, INFINITE); CloseHandle(PI.Process); } else { // Non-blocking wait. return ProcessInfo(); } } // Get its exit status. DWORD status; BOOL rc = GetExitCodeProcess(PI.Process, &status); DWORD err = GetLastError(); if (err != ERROR_INVALID_HANDLE) CloseHandle(PI.Process); if (!rc) { SetLastError(err); if (ErrMsg) MakeErrMsg(ErrMsg, "Failed getting status for program"); // -2 indicates a crash or timeout as opposed to failure to execute. WaitResult.ReturnCode = -2; return WaitResult; } if (!status) return WaitResult; // Pass 10(Warning) and 11(Error) to the callee as negative value. if ((status & 0xBFFF0000U) == 0x80000000U) WaitResult.ReturnCode = static_cast(status); else if (status & 0xFF) WaitResult.ReturnCode = status & 0x7FFFFFFF; else WaitResult.ReturnCode = 1; return WaitResult; } std::error_code sys::ChangeStdinToBinary() { int result = _setmode(_fileno(stdin), _O_BINARY); if (result == -1) return std::error_code(errno, std::generic_category()); return std::error_code(); } std::error_code sys::ChangeStdoutToBinary() { int result = _setmode(_fileno(stdout), _O_BINARY); if (result == -1) return std::error_code(errno, std::generic_category()); return std::error_code(); } std::error_code llvm::sys::writeFileWithEncoding(StringRef FileName, StringRef Contents, WindowsEncodingMethod Encoding) { std::error_code EC; llvm::raw_fd_ostream OS(FileName, EC, llvm::sys::fs::OF_Text); if (EC) return EC; if (Encoding == WEM_UTF8) { OS << Contents; } else if (Encoding == WEM_CurrentCodePage) { SmallVector ArgsUTF16; SmallVector ArgsCurCP; if ((EC = windows::UTF8ToUTF16(Contents, ArgsUTF16))) return EC; if ((EC = windows::UTF16ToCurCP( ArgsUTF16.data(), ArgsUTF16.size(), ArgsCurCP))) return EC; OS.write(ArgsCurCP.data(), ArgsCurCP.size()); } else if (Encoding == WEM_UTF16) { SmallVector ArgsUTF16; if ((EC = windows::UTF8ToUTF16(Contents, ArgsUTF16))) return EC; // Endianness guessing char BOM[2]; uint16_t src = UNI_UTF16_BYTE_ORDER_MARK_NATIVE; memcpy(BOM, &src, 2); OS.write(BOM, 2); OS.write((char *)ArgsUTF16.data(), ArgsUTF16.size() << 1); } else { llvm_unreachable("Unknown encoding"); } if (OS.has_error()) return make_error_code(errc::io_error); return EC; } bool llvm::sys::commandLineFitsWithinSystemLimits(StringRef Program, ArrayRef Args) { // The documented max length of the command line passed to CreateProcess. static const size_t MaxCommandStringLength = 32768; SmallVector FullArgs; FullArgs.push_back(Program); FullArgs.append(Args.begin(), Args.end()); std::string Result = flattenWindowsCommandLine(FullArgs); return (Result.size() + 1) <= MaxCommandStringLength; } } diff --git a/contrib/llvm-project/llvm/lib/Support/Windows/Signals.inc b/contrib/llvm-project/llvm/lib/Support/Windows/Signals.inc index 09e19ae41f1a..c7301742119e 100644 --- a/contrib/llvm-project/llvm/lib/Support/Windows/Signals.inc +++ b/contrib/llvm-project/llvm/lib/Support/Windows/Signals.inc @@ -1,864 +1,864 @@ //===- Win32/Signals.cpp - Win32 Signals Implementation ---------*- 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 the Win32 specific implementation of the Signals class. // //===----------------------------------------------------------------------===// #include "llvm/Support/ConvertUTF.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" #include "llvm/Support/Process.h" #include "llvm/Support/WindowsError.h" #include #include #include #include #include "llvm/Support/Format.h" #include "llvm/Support/raw_ostream.h" // The Windows.h header must be after LLVM and standard headers. -#include "WindowsSupport.h" +#include "llvm/Support/Windows/WindowsSupport.h" #ifdef __MINGW32__ #include #else #include #include #endif #include #ifdef _MSC_VER #pragma comment(lib, "psapi.lib") #elif __MINGW32__ // The version of g++ that comes with MinGW does *not* properly understand // the ll format specifier for printf. However, MinGW passes the format // specifiers on to the MSVCRT entirely, and the CRT understands the ll // specifier. So these warnings are spurious in this case. Since we compile // with -Wall, this will generate these warnings which should be ignored. So // we will turn off the warnings for this just file. However, MinGW also does // not support push and pop for diagnostics, so we have to manually turn it // back on at the end of the file. #pragma GCC diagnostic ignored "-Wformat" #pragma GCC diagnostic ignored "-Wformat-extra-args" #if !defined(__MINGW64_VERSION_MAJOR) // MinGW.org does not have updated support for the 64-bit versions of the // DebugHlp APIs. So we will have to load them manually. The structures and // method signatures were pulled from DbgHelp.h in the Windows Platform SDK, // and adjusted for brevity. typedef struct _IMAGEHLP_LINE64 { DWORD SizeOfStruct; PVOID Key; DWORD LineNumber; PCHAR FileName; DWORD64 Address; } IMAGEHLP_LINE64, *PIMAGEHLP_LINE64; typedef struct _IMAGEHLP_SYMBOL64 { DWORD SizeOfStruct; DWORD64 Address; DWORD Size; DWORD Flags; DWORD MaxNameLength; CHAR Name[1]; } IMAGEHLP_SYMBOL64, *PIMAGEHLP_SYMBOL64; typedef struct _tagADDRESS64 { DWORD64 Offset; WORD Segment; ADDRESS_MODE Mode; } ADDRESS64, *LPADDRESS64; typedef struct _KDHELP64 { DWORD64 Thread; DWORD ThCallbackStack; DWORD ThCallbackBStore; DWORD NextCallback; DWORD FramePointer; DWORD64 KiCallUserMode; DWORD64 KeUserCallbackDispatcher; DWORD64 SystemRangeStart; DWORD64 KiUserExceptionDispatcher; DWORD64 StackBase; DWORD64 StackLimit; DWORD64 Reserved[5]; } KDHELP64, *PKDHELP64; typedef struct _tagSTACKFRAME64 { ADDRESS64 AddrPC; ADDRESS64 AddrReturn; ADDRESS64 AddrFrame; ADDRESS64 AddrStack; ADDRESS64 AddrBStore; PVOID FuncTableEntry; DWORD64 Params[4]; BOOL Far; BOOL Virtual; DWORD64 Reserved[3]; KDHELP64 KdHelp; } STACKFRAME64, *LPSTACKFRAME64; #endif // !defined(__MINGW64_VERSION_MAJOR) #endif // __MINGW32__ typedef BOOL (__stdcall *PREAD_PROCESS_MEMORY_ROUTINE64)(HANDLE hProcess, DWORD64 qwBaseAddress, PVOID lpBuffer, DWORD nSize, LPDWORD lpNumberOfBytesRead); typedef PVOID (__stdcall *PFUNCTION_TABLE_ACCESS_ROUTINE64)( HANDLE ahProcess, DWORD64 AddrBase); typedef DWORD64 (__stdcall *PGET_MODULE_BASE_ROUTINE64)(HANDLE hProcess, DWORD64 Address); typedef DWORD64 (__stdcall *PTRANSLATE_ADDRESS_ROUTINE64)(HANDLE hProcess, HANDLE hThread, LPADDRESS64 lpaddr); typedef BOOL(WINAPI *fpMiniDumpWriteDump)(HANDLE, DWORD, HANDLE, MINIDUMP_TYPE, PMINIDUMP_EXCEPTION_INFORMATION, PMINIDUMP_USER_STREAM_INFORMATION, PMINIDUMP_CALLBACK_INFORMATION); static fpMiniDumpWriteDump fMiniDumpWriteDump; typedef BOOL (WINAPI *fpStackWalk64)(DWORD, HANDLE, HANDLE, LPSTACKFRAME64, PVOID, PREAD_PROCESS_MEMORY_ROUTINE64, PFUNCTION_TABLE_ACCESS_ROUTINE64, PGET_MODULE_BASE_ROUTINE64, PTRANSLATE_ADDRESS_ROUTINE64); static fpStackWalk64 fStackWalk64; typedef DWORD64 (WINAPI *fpSymGetModuleBase64)(HANDLE, DWORD64); static fpSymGetModuleBase64 fSymGetModuleBase64; typedef BOOL (WINAPI *fpSymGetSymFromAddr64)(HANDLE, DWORD64, PDWORD64, PIMAGEHLP_SYMBOL64); static fpSymGetSymFromAddr64 fSymGetSymFromAddr64; typedef BOOL (WINAPI *fpSymGetLineFromAddr64)(HANDLE, DWORD64, PDWORD, PIMAGEHLP_LINE64); static fpSymGetLineFromAddr64 fSymGetLineFromAddr64; typedef BOOL(WINAPI *fpSymGetModuleInfo64)(HANDLE hProcess, DWORD64 dwAddr, PIMAGEHLP_MODULE64 ModuleInfo); static fpSymGetModuleInfo64 fSymGetModuleInfo64; typedef PVOID (WINAPI *fpSymFunctionTableAccess64)(HANDLE, DWORD64); static fpSymFunctionTableAccess64 fSymFunctionTableAccess64; typedef DWORD (WINAPI *fpSymSetOptions)(DWORD); static fpSymSetOptions fSymSetOptions; typedef BOOL (WINAPI *fpSymInitialize)(HANDLE, PCSTR, BOOL); static fpSymInitialize fSymInitialize; typedef BOOL (WINAPI *fpEnumerateLoadedModules)(HANDLE,PENUMLOADED_MODULES_CALLBACK64,PVOID); static fpEnumerateLoadedModules fEnumerateLoadedModules; static bool load64BitDebugHelp(void) { HMODULE hLib = ::LoadLibraryW(L"Dbghelp.dll"); if (hLib) { fMiniDumpWriteDump = (fpMiniDumpWriteDump) ::GetProcAddress(hLib, "MiniDumpWriteDump"); fStackWalk64 = (fpStackWalk64) ::GetProcAddress(hLib, "StackWalk64"); fSymGetModuleBase64 = (fpSymGetModuleBase64) ::GetProcAddress(hLib, "SymGetModuleBase64"); fSymGetSymFromAddr64 = (fpSymGetSymFromAddr64) ::GetProcAddress(hLib, "SymGetSymFromAddr64"); fSymGetLineFromAddr64 = (fpSymGetLineFromAddr64) ::GetProcAddress(hLib, "SymGetLineFromAddr64"); fSymGetModuleInfo64 = (fpSymGetModuleInfo64) ::GetProcAddress(hLib, "SymGetModuleInfo64"); fSymFunctionTableAccess64 = (fpSymFunctionTableAccess64) ::GetProcAddress(hLib, "SymFunctionTableAccess64"); fSymSetOptions = (fpSymSetOptions)::GetProcAddress(hLib, "SymSetOptions"); fSymInitialize = (fpSymInitialize)::GetProcAddress(hLib, "SymInitialize"); fEnumerateLoadedModules = (fpEnumerateLoadedModules) ::GetProcAddress(hLib, "EnumerateLoadedModules64"); } return fStackWalk64 && fSymInitialize && fSymSetOptions && fMiniDumpWriteDump; } using namespace llvm; // Forward declare. static LONG WINAPI LLVMUnhandledExceptionFilter(LPEXCEPTION_POINTERS ep); static BOOL WINAPI LLVMConsoleCtrlHandler(DWORD dwCtrlType); // The function to call if ctrl-c is pressed. static void (*InterruptFunction)() = 0; static std::vector *FilesToRemove = NULL; static bool RegisteredUnhandledExceptionFilter = false; static bool CleanupExecuted = false; static PTOP_LEVEL_EXCEPTION_FILTER OldFilter = NULL; // Windows creates a new thread to execute the console handler when an event // (such as CTRL/C) occurs. This causes concurrency issues with the above // globals which this critical section addresses. static CRITICAL_SECTION CriticalSection; static bool CriticalSectionInitialized = false; static StringRef Argv0; enum { #if defined(_M_X64) NativeMachineType = IMAGE_FILE_MACHINE_AMD64 #elif defined(_M_ARM64) NativeMachineType = IMAGE_FILE_MACHINE_ARM64 #elif defined(_M_IX86) NativeMachineType = IMAGE_FILE_MACHINE_I386 #elif defined(_M_ARM) NativeMachineType = IMAGE_FILE_MACHINE_ARMNT #else NativeMachineType = IMAGE_FILE_MACHINE_UNKNOWN #endif }; static bool printStackTraceWithLLVMSymbolizer(llvm::raw_ostream &OS, HANDLE hProcess, HANDLE hThread, STACKFRAME64 &StackFrameOrig, CONTEXT *ContextOrig) { // StackWalk64 modifies the incoming stack frame and context, so copy them. STACKFRAME64 StackFrame = StackFrameOrig; // Copy the register context so that we don't modify it while we unwind. We // could use InitializeContext + CopyContext, but that's only required to get // at AVX registers, which typically aren't needed by StackWalk64. Reduce the // flag set to indicate that there's less data. CONTEXT Context = *ContextOrig; Context.ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER; static void *StackTrace[256]; size_t Depth = 0; while (fStackWalk64(NativeMachineType, hProcess, hThread, &StackFrame, &Context, 0, fSymFunctionTableAccess64, fSymGetModuleBase64, 0)) { if (StackFrame.AddrFrame.Offset == 0) break; StackTrace[Depth++] = (void *)(uintptr_t)StackFrame.AddrPC.Offset; if (Depth >= array_lengthof(StackTrace)) break; } return printSymbolizedStackTrace(Argv0, &StackTrace[0], Depth, OS); } namespace { struct FindModuleData { void **StackTrace; int Depth; const char **Modules; intptr_t *Offsets; StringSaver *StrPool; }; } static BOOL CALLBACK findModuleCallback(PCSTR ModuleName, DWORD64 ModuleBase, ULONG ModuleSize, void *VoidData) { FindModuleData *Data = (FindModuleData*)VoidData; intptr_t Beg = ModuleBase; intptr_t End = Beg + ModuleSize; for (int I = 0; I < Data->Depth; I++) { if (Data->Modules[I]) continue; intptr_t Addr = (intptr_t)Data->StackTrace[I]; if (Beg <= Addr && Addr < End) { Data->Modules[I] = Data->StrPool->save(ModuleName).data(); Data->Offsets[I] = Addr - Beg; } } return TRUE; } static bool findModulesAndOffsets(void **StackTrace, int Depth, const char **Modules, intptr_t *Offsets, const char *MainExecutableName, StringSaver &StrPool) { if (!fEnumerateLoadedModules) return false; FindModuleData Data; Data.StackTrace = StackTrace; Data.Depth = Depth; Data.Modules = Modules; Data.Offsets = Offsets; Data.StrPool = &StrPool; fEnumerateLoadedModules(GetCurrentProcess(), findModuleCallback, &Data); return true; } static void PrintStackTraceForThread(llvm::raw_ostream &OS, HANDLE hProcess, HANDLE hThread, STACKFRAME64 &StackFrame, CONTEXT *Context) { // Initialize the symbol handler. fSymSetOptions(SYMOPT_DEFERRED_LOADS | SYMOPT_LOAD_LINES); fSymInitialize(hProcess, NULL, TRUE); // Try llvm-symbolizer first. llvm-symbolizer knows how to deal with both PDBs // and DWARF, so it should do a good job regardless of what debug info or // linker is in use. if (printStackTraceWithLLVMSymbolizer(OS, hProcess, hThread, StackFrame, Context)) { return; } while (true) { if (!fStackWalk64(NativeMachineType, hProcess, hThread, &StackFrame, Context, 0, fSymFunctionTableAccess64, fSymGetModuleBase64, 0)) { break; } if (StackFrame.AddrFrame.Offset == 0) break; using namespace llvm; // Print the PC in hexadecimal. DWORD64 PC = StackFrame.AddrPC.Offset; #if defined(_M_X64) || defined(_M_ARM64) OS << format("0x%016llX", PC); #elif defined(_M_IX86) || defined(_M_ARM) OS << format("0x%08lX", static_cast(PC)); #endif // Print the parameters. Assume there are four. #if defined(_M_X64) || defined(_M_ARM64) OS << format(" (0x%016llX 0x%016llX 0x%016llX 0x%016llX)", StackFrame.Params[0], StackFrame.Params[1], StackFrame.Params[2], StackFrame.Params[3]); #elif defined(_M_IX86) || defined(_M_ARM) OS << format(" (0x%08lX 0x%08lX 0x%08lX 0x%08lX)", static_cast(StackFrame.Params[0]), static_cast(StackFrame.Params[1]), static_cast(StackFrame.Params[2]), static_cast(StackFrame.Params[3])); #endif // Verify the PC belongs to a module in this process. if (!fSymGetModuleBase64(hProcess, PC)) { OS << " \n"; continue; } // Print the symbol name. char buffer[512]; IMAGEHLP_SYMBOL64 *symbol = reinterpret_cast(buffer); memset(symbol, 0, sizeof(IMAGEHLP_SYMBOL64)); symbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64); symbol->MaxNameLength = 512 - sizeof(IMAGEHLP_SYMBOL64); DWORD64 dwDisp; if (!fSymGetSymFromAddr64(hProcess, PC, &dwDisp, symbol)) { OS << '\n'; continue; } buffer[511] = 0; if (dwDisp > 0) OS << format(", %s() + 0x%llX bytes(s)", (const char*)symbol->Name, dwDisp); else OS << format(", %s", (const char*)symbol->Name); // Print the source file and line number information. IMAGEHLP_LINE64 line = {}; DWORD dwLineDisp; line.SizeOfStruct = sizeof(line); if (fSymGetLineFromAddr64(hProcess, PC, &dwLineDisp, &line)) { OS << format(", %s, line %lu", line.FileName, line.LineNumber); if (dwLineDisp > 0) OS << format(" + 0x%lX byte(s)", dwLineDisp); } OS << '\n'; } } namespace llvm { //===----------------------------------------------------------------------===// //=== WARNING: Implementation here must contain only Win32 specific code //=== and must not be UNIX code //===----------------------------------------------------------------------===// #ifdef _MSC_VER /// Emulates hitting "retry" from an "abort, retry, ignore" CRT debug report /// dialog. "retry" raises an exception which ultimately triggers our stack /// dumper. static LLVM_ATTRIBUTE_UNUSED int AvoidMessageBoxHook(int ReportType, char *Message, int *Return) { // Set *Return to the retry code for the return value of _CrtDbgReport: // http://msdn.microsoft.com/en-us/library/8hyw4sy7(v=vs.71).aspx // This may also trigger just-in-time debugging via DebugBreak(). if (Return) *Return = 1; // Don't call _CrtDbgReport. return TRUE; } #endif extern "C" void HandleAbort(int Sig) { if (Sig == SIGABRT) { LLVM_BUILTIN_TRAP; } } static void InitializeThreading() { if (CriticalSectionInitialized) return; // Now's the time to create the critical section. This is the first time // through here, and there's only one thread. InitializeCriticalSection(&CriticalSection); CriticalSectionInitialized = true; } static void RegisterHandler() { // If we cannot load up the APIs (which would be unexpected as they should // exist on every version of Windows we support), we will bail out since // there would be nothing to report. if (!load64BitDebugHelp()) { assert(false && "These APIs should always be available"); return; } if (RegisteredUnhandledExceptionFilter) { EnterCriticalSection(&CriticalSection); return; } InitializeThreading(); // Enter it immediately. Now if someone hits CTRL/C, the console handler // can't proceed until the globals are updated. EnterCriticalSection(&CriticalSection); RegisteredUnhandledExceptionFilter = true; OldFilter = SetUnhandledExceptionFilter(LLVMUnhandledExceptionFilter); SetConsoleCtrlHandler(LLVMConsoleCtrlHandler, TRUE); // IMPORTANT NOTE: Caller must call LeaveCriticalSection(&CriticalSection) or // else multi-threading problems will ensue. } // The public API bool sys::RemoveFileOnSignal(StringRef Filename, std::string* ErrMsg) { RegisterHandler(); if (CleanupExecuted) { if (ErrMsg) *ErrMsg = "Process terminating -- cannot register for removal"; return true; } if (FilesToRemove == NULL) FilesToRemove = new std::vector; FilesToRemove->push_back(Filename); LeaveCriticalSection(&CriticalSection); return false; } // The public API void sys::DontRemoveFileOnSignal(StringRef Filename) { if (FilesToRemove == NULL) return; RegisterHandler(); std::vector::reverse_iterator I = find(reverse(*FilesToRemove), Filename); if (I != FilesToRemove->rend()) FilesToRemove->erase(I.base()-1); LeaveCriticalSection(&CriticalSection); } void sys::DisableSystemDialogsOnCrash() { // Crash to stack trace handler on abort. signal(SIGABRT, HandleAbort); // The following functions are not reliably accessible on MinGW. #ifdef _MSC_VER // We're already handling writing a "something went wrong" message. _set_abort_behavior(0, _WRITE_ABORT_MSG); // Disable Dr. Watson. _set_abort_behavior(0, _CALL_REPORTFAULT); _CrtSetReportHook(AvoidMessageBoxHook); #endif // Disable standard error dialog box. SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX); _set_error_mode(_OUT_TO_STDERR); } /// When an error signal (such as SIGABRT or SIGSEGV) is delivered to the /// process, print a stack trace and then exit. void sys::PrintStackTraceOnErrorSignal(StringRef Argv0, bool DisableCrashReporting) { ::Argv0 = Argv0; if (DisableCrashReporting || getenv("LLVM_DISABLE_CRASH_REPORT")) Process::PreventCoreFiles(); DisableSystemDialogsOnCrash(); RegisterHandler(); LeaveCriticalSection(&CriticalSection); } } #if defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR) // Provide a prototype for RtlCaptureContext, mingw32 from mingw.org is // missing it but mingw-w64 has it. extern "C" VOID WINAPI RtlCaptureContext(PCONTEXT ContextRecord); #endif static void LocalPrintStackTrace(raw_ostream &OS, PCONTEXT C) { STACKFRAME64 StackFrame{}; CONTEXT Context{}; if (!C) { ::RtlCaptureContext(&Context); C = &Context; } #if defined(_M_X64) StackFrame.AddrPC.Offset = Context.Rip; StackFrame.AddrStack.Offset = Context.Rsp; StackFrame.AddrFrame.Offset = Context.Rbp; #elif defined(_M_IX86) StackFrame.AddrPC.Offset = Context.Eip; StackFrame.AddrStack.Offset = Context.Esp; StackFrame.AddrFrame.Offset = Context.Ebp; #elif defined(_M_ARM64) StackFrame.AddrPC.Offset = Context.Pc; StackFrame.AddrStack.Offset = Context.Sp; StackFrame.AddrFrame.Offset = Context.Fp; #elif defined(_M_ARM) StackFrame.AddrPC.Offset = Context.Pc; StackFrame.AddrStack.Offset = Context.Sp; StackFrame.AddrFrame.Offset = Context.R11; #endif StackFrame.AddrPC.Mode = AddrModeFlat; StackFrame.AddrStack.Mode = AddrModeFlat; StackFrame.AddrFrame.Mode = AddrModeFlat; PrintStackTraceForThread(OS, GetCurrentProcess(), GetCurrentThread(), StackFrame, C); } void llvm::sys::PrintStackTrace(raw_ostream &OS) { LocalPrintStackTrace(OS, nullptr); } void llvm::sys::SetInterruptFunction(void (*IF)()) { RegisterHandler(); InterruptFunction = IF; LeaveCriticalSection(&CriticalSection); } void llvm::sys::SetInfoSignalFunction(void (*Handler)()) { // Unimplemented. } void llvm::sys::SetOneShotPipeSignalFunction(void (*Handler)()) { // Unimplemented. } void llvm::sys::DefaultOneShotPipeSignalHandler() { // Unimplemented. } /// Add a function to be called when a signal is delivered to the process. The /// handler can have a cookie passed to it to identify what instance of the /// handler it is. void llvm::sys::AddSignalHandler(sys::SignalHandlerCallback FnPtr, void *Cookie) { insertSignalHandler(FnPtr, Cookie); RegisterHandler(); LeaveCriticalSection(&CriticalSection); } static void Cleanup() { if (CleanupExecuted) return; EnterCriticalSection(&CriticalSection); // Prevent other thread from registering new files and directories for // removal, should we be executing because of the console handler callback. CleanupExecuted = true; // FIXME: open files cannot be deleted. if (FilesToRemove != NULL) while (!FilesToRemove->empty()) { llvm::sys::fs::remove(FilesToRemove->back()); FilesToRemove->pop_back(); } llvm::sys::RunSignalHandlers(); LeaveCriticalSection(&CriticalSection); } void llvm::sys::RunInterruptHandlers() { // The interrupt handler may be called from an interrupt, but it may also be // called manually (such as the case of report_fatal_error with no registered // error handler). We must ensure that the critical section is properly // initialized. InitializeThreading(); Cleanup(); } /// Find the Windows Registry Key for a given location. /// /// \returns a valid HKEY if the location exists, else NULL. static HKEY FindWERKey(const llvm::Twine &RegistryLocation) { HKEY Key; if (ERROR_SUCCESS != ::RegOpenKeyExA(HKEY_LOCAL_MACHINE, RegistryLocation.str().c_str(), 0, KEY_QUERY_VALUE | KEY_READ, &Key)) return NULL; return Key; } /// Populate ResultDirectory with the value for "DumpFolder" for a given /// Windows Registry key. /// /// \returns true if a valid value for DumpFolder exists, false otherwise. static bool GetDumpFolder(HKEY Key, llvm::SmallVectorImpl &ResultDirectory) { using llvm::sys::windows::UTF16ToUTF8; if (!Key) return false; DWORD BufferLengthBytes = 0; if (ERROR_SUCCESS != ::RegGetValueW(Key, 0, L"DumpFolder", REG_EXPAND_SZ, NULL, NULL, &BufferLengthBytes)) return false; SmallVector Buffer(BufferLengthBytes); if (ERROR_SUCCESS != ::RegGetValueW(Key, 0, L"DumpFolder", REG_EXPAND_SZ, NULL, Buffer.data(), &BufferLengthBytes)) return false; DWORD ExpandBufferSize = ::ExpandEnvironmentStringsW(Buffer.data(), NULL, 0); if (!ExpandBufferSize) return false; SmallVector ExpandBuffer(ExpandBufferSize); if (ExpandBufferSize != ::ExpandEnvironmentStringsW(Buffer.data(), ExpandBuffer.data(), ExpandBufferSize)) return false; if (UTF16ToUTF8(ExpandBuffer.data(), ExpandBufferSize - 1, ResultDirectory)) return false; return true; } /// Populate ResultType with a valid MINIDUMP_TYPE based on the value of /// "DumpType" for a given Windows Registry key. /// /// According to /// https://msdn.microsoft.com/en-us/library/windows/desktop/bb787181(v=vs.85).aspx /// valid values for DumpType are: /// * 0: Custom dump /// * 1: Mini dump /// * 2: Full dump /// If "Custom dump" is specified then the "CustomDumpFlags" field is read /// containing a bitwise combination of MINIDUMP_TYPE values. /// /// \returns true if a valid value for ResultType can be set, false otherwise. static bool GetDumpType(HKEY Key, MINIDUMP_TYPE &ResultType) { if (!Key) return false; DWORD DumpType; DWORD TypeSize = sizeof(DumpType); if (ERROR_SUCCESS != ::RegGetValueW(Key, NULL, L"DumpType", RRF_RT_REG_DWORD, NULL, &DumpType, &TypeSize)) return false; switch (DumpType) { case 0: { DWORD Flags = 0; if (ERROR_SUCCESS != ::RegGetValueW(Key, NULL, L"CustomDumpFlags", RRF_RT_REG_DWORD, NULL, &Flags, &TypeSize)) return false; ResultType = static_cast(Flags); break; } case 1: ResultType = MiniDumpNormal; break; case 2: ResultType = MiniDumpWithFullMemory; break; default: return false; } return true; } /// Write a Windows dump file containing process information that can be /// used for post-mortem debugging. /// /// \returns zero error code if a mini dump created, actual error code /// otherwise. static std::error_code WINAPI WriteWindowsDumpFile(PMINIDUMP_EXCEPTION_INFORMATION ExceptionInfo) { using namespace llvm; using namespace llvm::sys; std::string MainExecutableName = fs::getMainExecutable(nullptr, nullptr); StringRef ProgramName; if (MainExecutableName.empty()) { // If we can't get the executable filename, // things are in worse shape than we realize // and we should just bail out. return mapWindowsError(::GetLastError()); } ProgramName = path::filename(MainExecutableName.c_str()); // The Windows Registry location as specified at // https://msdn.microsoft.com/en-us/library/windows/desktop/bb787181%28v=vs.85%29.aspx // "Collecting User-Mode Dumps" that may optionally be set to collect crash // dumps in a specified location. StringRef LocalDumpsRegistryLocation = "SOFTWARE\\Microsoft\\Windows\\Windows Error Reporting\\LocalDumps"; // The key pointing to the Registry location that may contain global crash // dump settings. This will be NULL if the location can not be found. ScopedRegHandle DefaultLocalDumpsKey(FindWERKey(LocalDumpsRegistryLocation)); // The key pointing to the Registry location that may contain // application-specific crash dump settings. This will be NULL if the // location can not be found. ScopedRegHandle AppSpecificKey( FindWERKey(Twine(LocalDumpsRegistryLocation) + "\\" + ProgramName)); // Look to see if a dump type is specified in the registry; first with the // app-specific key and failing that with the global key. If none are found // default to a normal dump (GetDumpType will return false either if the key // is NULL or if there is no valid DumpType value at its location). MINIDUMP_TYPE DumpType; if (!GetDumpType(AppSpecificKey, DumpType)) if (!GetDumpType(DefaultLocalDumpsKey, DumpType)) DumpType = MiniDumpNormal; // Look to see if a dump location is specified in the registry; first with the // app-specific key and failing that with the global key. If none are found // we'll just create the dump file in the default temporary file location // (GetDumpFolder will return false either if the key is NULL or if there is // no valid DumpFolder value at its location). bool ExplicitDumpDirectorySet = true; SmallString DumpDirectory; if (!GetDumpFolder(AppSpecificKey, DumpDirectory)) if (!GetDumpFolder(DefaultLocalDumpsKey, DumpDirectory)) ExplicitDumpDirectorySet = false; int FD; SmallString DumpPath; if (ExplicitDumpDirectorySet) { if (std::error_code EC = fs::create_directories(DumpDirectory)) return EC; if (std::error_code EC = fs::createUniqueFile( Twine(DumpDirectory) + "\\" + ProgramName + ".%%%%%%.dmp", FD, DumpPath)) return EC; } else if (std::error_code EC = fs::createTemporaryFile(ProgramName, "dmp", FD, DumpPath)) return EC; // Our support functions return a file descriptor but Windows wants a handle. ScopedCommonHandle FileHandle(reinterpret_cast(_get_osfhandle(FD))); if (!fMiniDumpWriteDump(::GetCurrentProcess(), ::GetCurrentProcessId(), FileHandle, DumpType, ExceptionInfo, NULL, NULL)) return mapWindowsError(::GetLastError()); llvm::errs() << "Wrote crash dump file \"" << DumpPath << "\"\n"; return std::error_code(); } void sys::CleanupOnSignal(uintptr_t Context) { LLVMUnhandledExceptionFilter((LPEXCEPTION_POINTERS)Context); } static LONG WINAPI LLVMUnhandledExceptionFilter(LPEXCEPTION_POINTERS ep) { Cleanup(); // We'll automatically write a Minidump file here to help diagnose // the nasty sorts of crashes that aren't 100% reproducible from a set of // inputs (or in the event that the user is unable or unwilling to provide a // reproducible case). if (!llvm::sys::Process::AreCoreFilesPrevented()) { MINIDUMP_EXCEPTION_INFORMATION ExceptionInfo; ExceptionInfo.ThreadId = ::GetCurrentThreadId(); ExceptionInfo.ExceptionPointers = ep; ExceptionInfo.ClientPointers = FALSE; if (std::error_code EC = WriteWindowsDumpFile(&ExceptionInfo)) llvm::errs() << "Could not write crash dump file: " << EC.message() << "\n"; } // Stack unwinding appears to modify the context. Copy it to preserve the // caller's context. CONTEXT ContextCopy; if (ep) memcpy(&ContextCopy, ep->ContextRecord, sizeof(ContextCopy)); LocalPrintStackTrace(llvm::errs(), ep ? &ContextCopy : nullptr); return EXCEPTION_EXECUTE_HANDLER; } static BOOL WINAPI LLVMConsoleCtrlHandler(DWORD dwCtrlType) { // We are running in our very own thread, courtesy of Windows. EnterCriticalSection(&CriticalSection); Cleanup(); // If an interrupt function has been set, go and run one it; otherwise, // the process dies. void (*IF)() = InterruptFunction; InterruptFunction = 0; // Don't run it on another CTRL-C. if (IF) { // Note: if the interrupt function throws an exception, there is nothing // to catch it in this thread so it will kill the process. IF(); // Run it now. LeaveCriticalSection(&CriticalSection); return TRUE; // Don't kill the process. } // Allow normal processing to take place; i.e., the process dies. LeaveCriticalSection(&CriticalSection); return FALSE; } #if __MINGW32__ // We turned these warnings off for this file so that MinGW-g++ doesn't // complain about the ll format specifiers used. Now we are turning the // warnings back on. If MinGW starts to support diagnostic stacks, we can // replace this with a pop. #pragma GCC diagnostic warning "-Wformat" #pragma GCC diagnostic warning "-Wformat-extra-args" #endif diff --git a/contrib/llvm-project/llvm/lib/Support/Windows/ThreadLocal.inc b/contrib/llvm-project/llvm/lib/Support/Windows/ThreadLocal.inc index 1e0ed955e9ab..696e5c843ead 100644 --- a/contrib/llvm-project/llvm/lib/Support/Windows/ThreadLocal.inc +++ b/contrib/llvm-project/llvm/lib/Support/Windows/ThreadLocal.inc @@ -1,51 +1,51 @@ //= llvm/Support/Win32/ThreadLocal.inc - Win32 Thread Local Data -*- 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 implements the Win32 specific (non-pthread) ThreadLocal class. // //===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===// //=== WARNING: Implementation here must contain only generic Win32 code that //=== is guaranteed to work on *all* Win32 variants. //===----------------------------------------------------------------------===// -#include "WindowsSupport.h" +#include "llvm/Support/Windows/WindowsSupport.h" #include "llvm/Support/ThreadLocal.h" namespace llvm { sys::ThreadLocalImpl::ThreadLocalImpl() : data() { static_assert(sizeof(DWORD) <= sizeof(data), "size too big"); DWORD* tls = reinterpret_cast(&data); *tls = TlsAlloc(); assert(*tls != TLS_OUT_OF_INDEXES); } sys::ThreadLocalImpl::~ThreadLocalImpl() { DWORD* tls = reinterpret_cast(&data); TlsFree(*tls); } void *sys::ThreadLocalImpl::getInstance() { DWORD* tls = reinterpret_cast(&data); return TlsGetValue(*tls); } void sys::ThreadLocalImpl::setInstance(const void* d){ DWORD* tls = reinterpret_cast(&data); int errorcode = TlsSetValue(*tls, const_cast(d)); assert(errorcode != 0); (void)errorcode; } void sys::ThreadLocalImpl::removeInstance() { setInstance(0); } } diff --git a/contrib/llvm-project/llvm/lib/Support/Windows/Threading.inc b/contrib/llvm-project/llvm/lib/Support/Windows/Threading.inc index 9456efa686ff..efa4bc6cf735 100644 --- a/contrib/llvm-project/llvm/lib/Support/Windows/Threading.inc +++ b/contrib/llvm-project/llvm/lib/Support/Windows/Threading.inc @@ -1,124 +1,124 @@ //===- Windows/Threading.inc - Win32 Threading Implementation - -*- 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 the Win32 specific implementation of Threading functions. // //===----------------------------------------------------------------------===// #include "llvm/ADT/SmallString.h" #include "llvm/ADT/Twine.h" -#include "WindowsSupport.h" +#include "llvm/Support/Windows/WindowsSupport.h" #include // Windows will at times define MemoryFence. #ifdef MemoryFence #undef MemoryFence #endif static unsigned __stdcall threadFuncSync(void *Arg) { SyncThreadInfo *TI = static_cast(Arg); TI->UserFn(TI->UserData); return 0; } static unsigned __stdcall threadFuncAsync(void *Arg) { std::unique_ptr Info(static_cast(Arg)); (*Info)(); return 0; } static void llvm_execute_on_thread_impl(unsigned (__stdcall *ThreadFunc)(void *), void *Arg, llvm::Optional StackSizeInBytes, JoiningPolicy JP) { HANDLE hThread = (HANDLE)::_beginthreadex( NULL, StackSizeInBytes.getValueOr(0), ThreadFunc, Arg, 0, NULL); if (!hThread) { ReportLastErrorFatal("_beginthreadex failed"); } if (JP == JoiningPolicy::Join) { if (::WaitForSingleObject(hThread, INFINITE) == WAIT_FAILED) { ReportLastErrorFatal("WaitForSingleObject failed"); } } if (::CloseHandle(hThread) == FALSE) { ReportLastErrorFatal("CloseHandle failed"); } } uint64_t llvm::get_threadid() { return uint64_t(::GetCurrentThreadId()); } uint32_t llvm::get_max_thread_name_length() { return 0; } #if defined(_MSC_VER) static void SetThreadName(DWORD Id, LPCSTR Name) { constexpr DWORD MS_VC_EXCEPTION = 0x406D1388; #pragma pack(push, 8) struct THREADNAME_INFO { DWORD dwType; // Must be 0x1000. LPCSTR szName; // Pointer to thread name DWORD dwThreadId; // Thread ID (-1 == current thread) DWORD dwFlags; // Reserved. Do not use. }; #pragma pack(pop) THREADNAME_INFO info; info.dwType = 0x1000; info.szName = Name; info.dwThreadId = Id; info.dwFlags = 0; __try { ::RaiseException(MS_VC_EXCEPTION, 0, sizeof(info) / sizeof(ULONG_PTR), (ULONG_PTR *)&info); } __except (EXCEPTION_EXECUTE_HANDLER) { } } #endif void llvm::set_thread_name(const Twine &Name) { #if defined(_MSC_VER) // Make sure the input is null terminated. SmallString<64> Storage; StringRef NameStr = Name.toNullTerminatedStringRef(Storage); SetThreadName(::GetCurrentThreadId(), NameStr.data()); #endif } void llvm::get_thread_name(SmallVectorImpl &Name) { // "Name" is not an inherent property of a thread on Windows. In fact, when // you "set" the name, you are only firing a one-time message to a debugger // which it interprets as a program setting its threads' name. We may be // able to get fancy by creating a TLS entry when someone calls // set_thread_name so that subsequent calls to get_thread_name return this // value. Name.clear(); } SetThreadPriorityResult llvm::set_thread_priority(ThreadPriority Priority) { // https://docs.microsoft.com/en-us/windows/desktop/api/processthreadsapi/nf-processthreadsapi-setthreadpriority // Begin background processing mode. The system lowers the resource scheduling // priorities of the thread so that it can perform background work without // significantly affecting activity in the foreground. // End background processing mode. The system restores the resource scheduling // priorities of the thread as they were before the thread entered background // processing mode. return SetThreadPriority(GetCurrentThread(), Priority == ThreadPriority::Background ? THREAD_MODE_BACKGROUND_BEGIN : THREAD_MODE_BACKGROUND_END) ? SetThreadPriorityResult::SUCCESS : SetThreadPriorityResult::FAILURE; } diff --git a/contrib/llvm-project/llvm/lib/Support/raw_ostream.cpp b/contrib/llvm-project/llvm/lib/Support/raw_ostream.cpp index 4bb315f824af..13b0203ac953 100644 --- a/contrib/llvm-project/llvm/lib/Support/raw_ostream.cpp +++ b/contrib/llvm-project/llvm/lib/Support/raw_ostream.cpp @@ -1,946 +1,946 @@ //===--- raw_ostream.cpp - Implement the raw_ostream classes --------------===// // // 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 implements support for bulk buffered stream output. // //===----------------------------------------------------------------------===// #include "llvm/Support/raw_ostream.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Config/config.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Format.h" #include "llvm/Support/FormatVariadic.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/NativeFormatting.h" #include "llvm/Support/Process.h" #include "llvm/Support/Program.h" #include #include #include #include #include #include #include // may provide O_BINARY. #if defined(HAVE_FCNTL_H) # include #endif #if defined(HAVE_UNISTD_H) # include #endif #if defined(__CYGWIN__) #include #endif #if defined(_MSC_VER) #include #ifndef STDIN_FILENO # define STDIN_FILENO 0 #endif #ifndef STDOUT_FILENO # define STDOUT_FILENO 1 #endif #ifndef STDERR_FILENO # define STDERR_FILENO 2 #endif #endif #ifdef _WIN32 #include "llvm/Support/ConvertUTF.h" -#include "Windows/WindowsSupport.h" +#include "llvm/Support/Windows/WindowsSupport.h" #endif using namespace llvm; const raw_ostream::Colors raw_ostream::BLACK; const raw_ostream::Colors raw_ostream::RED; const raw_ostream::Colors raw_ostream::GREEN; const raw_ostream::Colors raw_ostream::YELLOW; const raw_ostream::Colors raw_ostream::BLUE; const raw_ostream::Colors raw_ostream::MAGENTA; const raw_ostream::Colors raw_ostream::CYAN; const raw_ostream::Colors raw_ostream::WHITE; const raw_ostream::Colors raw_ostream::SAVEDCOLOR; const raw_ostream::Colors raw_ostream::RESET; raw_ostream::~raw_ostream() { // raw_ostream's subclasses should take care to flush the buffer // in their destructors. assert(OutBufCur == OutBufStart && "raw_ostream destructor called with non-empty buffer!"); if (BufferMode == BufferKind::InternalBuffer) delete [] OutBufStart; } size_t raw_ostream::preferred_buffer_size() const { // BUFSIZ is intended to be a reasonable default. return BUFSIZ; } void raw_ostream::SetBuffered() { // Ask the subclass to determine an appropriate buffer size. if (size_t Size = preferred_buffer_size()) SetBufferSize(Size); else // It may return 0, meaning this stream should be unbuffered. SetUnbuffered(); } void raw_ostream::SetBufferAndMode(char *BufferStart, size_t Size, BufferKind Mode) { assert(((Mode == BufferKind::Unbuffered && !BufferStart && Size == 0) || (Mode != BufferKind::Unbuffered && BufferStart && Size != 0)) && "stream must be unbuffered or have at least one byte"); // Make sure the current buffer is free of content (we can't flush here; the // child buffer management logic will be in write_impl). assert(GetNumBytesInBuffer() == 0 && "Current buffer is non-empty!"); if (BufferMode == BufferKind::InternalBuffer) delete [] OutBufStart; OutBufStart = BufferStart; OutBufEnd = OutBufStart+Size; OutBufCur = OutBufStart; BufferMode = Mode; assert(OutBufStart <= OutBufEnd && "Invalid size!"); } raw_ostream &raw_ostream::operator<<(unsigned long N) { write_integer(*this, static_cast(N), 0, IntegerStyle::Integer); return *this; } raw_ostream &raw_ostream::operator<<(long N) { write_integer(*this, static_cast(N), 0, IntegerStyle::Integer); return *this; } raw_ostream &raw_ostream::operator<<(unsigned long long N) { write_integer(*this, static_cast(N), 0, IntegerStyle::Integer); return *this; } raw_ostream &raw_ostream::operator<<(long long N) { write_integer(*this, static_cast(N), 0, IntegerStyle::Integer); return *this; } raw_ostream &raw_ostream::write_hex(unsigned long long N) { llvm::write_hex(*this, N, HexPrintStyle::Lower); return *this; } raw_ostream &raw_ostream::operator<<(Colors C) { if (C == Colors::RESET) resetColor(); else changeColor(C); return *this; } raw_ostream &raw_ostream::write_uuid(const uuid_t UUID) { for (int Idx = 0; Idx < 16; ++Idx) { *this << format("%02" PRIX32, UUID[Idx]); if (Idx == 3 || Idx == 5 || Idx == 7 || Idx == 9) *this << "-"; } return *this; } raw_ostream &raw_ostream::write_escaped(StringRef Str, bool UseHexEscapes) { for (unsigned char c : Str) { switch (c) { case '\\': *this << '\\' << '\\'; break; case '\t': *this << '\\' << 't'; break; case '\n': *this << '\\' << 'n'; break; case '"': *this << '\\' << '"'; break; default: if (isPrint(c)) { *this << c; break; } // Write out the escaped representation. if (UseHexEscapes) { *this << '\\' << 'x'; *this << hexdigit((c >> 4 & 0xF)); *this << hexdigit((c >> 0) & 0xF); } else { // Always use a full 3-character octal escape. *this << '\\'; *this << char('0' + ((c >> 6) & 7)); *this << char('0' + ((c >> 3) & 7)); *this << char('0' + ((c >> 0) & 7)); } } } return *this; } raw_ostream &raw_ostream::operator<<(const void *P) { llvm::write_hex(*this, (uintptr_t)P, HexPrintStyle::PrefixLower); return *this; } raw_ostream &raw_ostream::operator<<(double N) { llvm::write_double(*this, N, FloatStyle::Exponent); return *this; } void raw_ostream::flush_nonempty() { assert(OutBufCur > OutBufStart && "Invalid call to flush_nonempty."); size_t Length = OutBufCur - OutBufStart; OutBufCur = OutBufStart; write_impl(OutBufStart, Length); } raw_ostream &raw_ostream::write(unsigned char C) { // Group exceptional cases into a single branch. if (LLVM_UNLIKELY(OutBufCur >= OutBufEnd)) { if (LLVM_UNLIKELY(!OutBufStart)) { if (BufferMode == BufferKind::Unbuffered) { write_impl(reinterpret_cast(&C), 1); return *this; } // Set up a buffer and start over. SetBuffered(); return write(C); } flush_nonempty(); } *OutBufCur++ = C; return *this; } raw_ostream &raw_ostream::write(const char *Ptr, size_t Size) { // Group exceptional cases into a single branch. if (LLVM_UNLIKELY(size_t(OutBufEnd - OutBufCur) < Size)) { if (LLVM_UNLIKELY(!OutBufStart)) { if (BufferMode == BufferKind::Unbuffered) { write_impl(Ptr, Size); return *this; } // Set up a buffer and start over. SetBuffered(); return write(Ptr, Size); } size_t NumBytes = OutBufEnd - OutBufCur; // If the buffer is empty at this point we have a string that is larger // than the buffer. Directly write the chunk that is a multiple of the // preferred buffer size and put the remainder in the buffer. if (LLVM_UNLIKELY(OutBufCur == OutBufStart)) { assert(NumBytes != 0 && "undefined behavior"); size_t BytesToWrite = Size - (Size % NumBytes); write_impl(Ptr, BytesToWrite); size_t BytesRemaining = Size - BytesToWrite; if (BytesRemaining > size_t(OutBufEnd - OutBufCur)) { // Too much left over to copy into our buffer. return write(Ptr + BytesToWrite, BytesRemaining); } copy_to_buffer(Ptr + BytesToWrite, BytesRemaining); return *this; } // We don't have enough space in the buffer to fit the string in. Insert as // much as possible, flush and start over with the remainder. copy_to_buffer(Ptr, NumBytes); flush_nonempty(); return write(Ptr + NumBytes, Size - NumBytes); } copy_to_buffer(Ptr, Size); return *this; } void raw_ostream::copy_to_buffer(const char *Ptr, size_t Size) { assert(Size <= size_t(OutBufEnd - OutBufCur) && "Buffer overrun!"); // Handle short strings specially, memcpy isn't very good at very short // strings. switch (Size) { case 4: OutBufCur[3] = Ptr[3]; LLVM_FALLTHROUGH; case 3: OutBufCur[2] = Ptr[2]; LLVM_FALLTHROUGH; case 2: OutBufCur[1] = Ptr[1]; LLVM_FALLTHROUGH; case 1: OutBufCur[0] = Ptr[0]; LLVM_FALLTHROUGH; case 0: break; default: memcpy(OutBufCur, Ptr, Size); break; } OutBufCur += Size; } // Formatted output. raw_ostream &raw_ostream::operator<<(const format_object_base &Fmt) { // If we have more than a few bytes left in our output buffer, try // formatting directly onto its end. size_t NextBufferSize = 127; size_t BufferBytesLeft = OutBufEnd - OutBufCur; if (BufferBytesLeft > 3) { size_t BytesUsed = Fmt.print(OutBufCur, BufferBytesLeft); // Common case is that we have plenty of space. if (BytesUsed <= BufferBytesLeft) { OutBufCur += BytesUsed; return *this; } // Otherwise, we overflowed and the return value tells us the size to try // again with. NextBufferSize = BytesUsed; } // If we got here, we didn't have enough space in the output buffer for the // string. Try printing into a SmallVector that is resized to have enough // space. Iterate until we win. SmallVector V; while (true) { V.resize(NextBufferSize); // Try formatting into the SmallVector. size_t BytesUsed = Fmt.print(V.data(), NextBufferSize); // If BytesUsed fit into the vector, we win. if (BytesUsed <= NextBufferSize) return write(V.data(), BytesUsed); // Otherwise, try again with a new size. assert(BytesUsed > NextBufferSize && "Didn't grow buffer!?"); NextBufferSize = BytesUsed; } } raw_ostream &raw_ostream::operator<<(const formatv_object_base &Obj) { SmallString<128> S; Obj.format(*this); return *this; } raw_ostream &raw_ostream::operator<<(const FormattedString &FS) { if (FS.Str.size() >= FS.Width || FS.Justify == FormattedString::JustifyNone) { this->operator<<(FS.Str); return *this; } const size_t Difference = FS.Width - FS.Str.size(); switch (FS.Justify) { case FormattedString::JustifyLeft: this->operator<<(FS.Str); this->indent(Difference); break; case FormattedString::JustifyRight: this->indent(Difference); this->operator<<(FS.Str); break; case FormattedString::JustifyCenter: { int PadAmount = Difference / 2; this->indent(PadAmount); this->operator<<(FS.Str); this->indent(Difference - PadAmount); break; } default: llvm_unreachable("Bad Justification"); } return *this; } raw_ostream &raw_ostream::operator<<(const FormattedNumber &FN) { if (FN.Hex) { HexPrintStyle Style; if (FN.Upper && FN.HexPrefix) Style = HexPrintStyle::PrefixUpper; else if (FN.Upper && !FN.HexPrefix) Style = HexPrintStyle::Upper; else if (!FN.Upper && FN.HexPrefix) Style = HexPrintStyle::PrefixLower; else Style = HexPrintStyle::Lower; llvm::write_hex(*this, FN.HexValue, Style, FN.Width); } else { llvm::SmallString<16> Buffer; llvm::raw_svector_ostream Stream(Buffer); llvm::write_integer(Stream, FN.DecValue, 0, IntegerStyle::Integer); if (Buffer.size() < FN.Width) indent(FN.Width - Buffer.size()); (*this) << Buffer; } return *this; } raw_ostream &raw_ostream::operator<<(const FormattedBytes &FB) { if (FB.Bytes.empty()) return *this; size_t LineIndex = 0; auto Bytes = FB.Bytes; const size_t Size = Bytes.size(); HexPrintStyle HPS = FB.Upper ? HexPrintStyle::Upper : HexPrintStyle::Lower; uint64_t OffsetWidth = 0; if (FB.FirstByteOffset.hasValue()) { // Figure out how many nibbles are needed to print the largest offset // represented by this data set, so that we can align the offset field // to the right width. size_t Lines = Size / FB.NumPerLine; uint64_t MaxOffset = *FB.FirstByteOffset + Lines * FB.NumPerLine; unsigned Power = 0; if (MaxOffset > 0) Power = llvm::Log2_64_Ceil(MaxOffset); OffsetWidth = std::max(4, llvm::alignTo(Power, 4) / 4); } // The width of a block of data including all spaces for group separators. unsigned NumByteGroups = alignTo(FB.NumPerLine, FB.ByteGroupSize) / FB.ByteGroupSize; unsigned BlockCharWidth = FB.NumPerLine * 2 + NumByteGroups - 1; while (!Bytes.empty()) { indent(FB.IndentLevel); if (FB.FirstByteOffset.hasValue()) { uint64_t Offset = FB.FirstByteOffset.getValue(); llvm::write_hex(*this, Offset + LineIndex, HPS, OffsetWidth); *this << ": "; } auto Line = Bytes.take_front(FB.NumPerLine); size_t CharsPrinted = 0; // Print the hex bytes for this line in groups for (size_t I = 0; I < Line.size(); ++I, CharsPrinted += 2) { if (I && (I % FB.ByteGroupSize) == 0) { ++CharsPrinted; *this << " "; } llvm::write_hex(*this, Line[I], HPS, 2); } if (FB.ASCII) { // Print any spaces needed for any bytes that we didn't print on this // line so that the ASCII bytes are correctly aligned. assert(BlockCharWidth >= CharsPrinted); indent(BlockCharWidth - CharsPrinted + 2); *this << "|"; // Print the ASCII char values for each byte on this line for (uint8_t Byte : Line) { if (isPrint(Byte)) *this << static_cast(Byte); else *this << '.'; } *this << '|'; } Bytes = Bytes.drop_front(Line.size()); LineIndex += Line.size(); if (LineIndex < Size) *this << '\n'; } return *this; } template static raw_ostream &write_padding(raw_ostream &OS, unsigned NumChars) { static const char Chars[] = {C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C}; // Usually the indentation is small, handle it with a fastpath. if (NumChars < array_lengthof(Chars)) return OS.write(Chars, NumChars); while (NumChars) { unsigned NumToWrite = std::min(NumChars, (unsigned)array_lengthof(Chars)-1); OS.write(Chars, NumToWrite); NumChars -= NumToWrite; } return OS; } /// indent - Insert 'NumSpaces' spaces. raw_ostream &raw_ostream::indent(unsigned NumSpaces) { return write_padding<' '>(*this, NumSpaces); } /// write_zeros - Insert 'NumZeros' nulls. raw_ostream &raw_ostream::write_zeros(unsigned NumZeros) { return write_padding<'\0'>(*this, NumZeros); } void raw_ostream::anchor() {} //===----------------------------------------------------------------------===// // Formatted Output //===----------------------------------------------------------------------===// // Out of line virtual method. void format_object_base::home() { } //===----------------------------------------------------------------------===// // raw_fd_ostream //===----------------------------------------------------------------------===// static int getFD(StringRef Filename, std::error_code &EC, sys::fs::CreationDisposition Disp, sys::fs::FileAccess Access, sys::fs::OpenFlags Flags) { assert((Access & sys::fs::FA_Write) && "Cannot make a raw_ostream from a read-only descriptor!"); // Handle "-" as stdout. Note that when we do this, we consider ourself // the owner of stdout and may set the "binary" flag globally based on Flags. if (Filename == "-") { EC = std::error_code(); // If user requested binary then put stdout into binary mode if // possible. if (!(Flags & sys::fs::OF_Text)) sys::ChangeStdoutToBinary(); return STDOUT_FILENO; } int FD; if (Access & sys::fs::FA_Read) EC = sys::fs::openFileForReadWrite(Filename, FD, Disp, Flags); else EC = sys::fs::openFileForWrite(Filename, FD, Disp, Flags); if (EC) return -1; return FD; } raw_fd_ostream::raw_fd_ostream(StringRef Filename, std::error_code &EC) : raw_fd_ostream(Filename, EC, sys::fs::CD_CreateAlways, sys::fs::FA_Write, sys::fs::OF_None) {} raw_fd_ostream::raw_fd_ostream(StringRef Filename, std::error_code &EC, sys::fs::CreationDisposition Disp) : raw_fd_ostream(Filename, EC, Disp, sys::fs::FA_Write, sys::fs::OF_None) {} raw_fd_ostream::raw_fd_ostream(StringRef Filename, std::error_code &EC, sys::fs::FileAccess Access) : raw_fd_ostream(Filename, EC, sys::fs::CD_CreateAlways, Access, sys::fs::OF_None) {} raw_fd_ostream::raw_fd_ostream(StringRef Filename, std::error_code &EC, sys::fs::OpenFlags Flags) : raw_fd_ostream(Filename, EC, sys::fs::CD_CreateAlways, sys::fs::FA_Write, Flags) {} raw_fd_ostream::raw_fd_ostream(StringRef Filename, std::error_code &EC, sys::fs::CreationDisposition Disp, sys::fs::FileAccess Access, sys::fs::OpenFlags Flags) : raw_fd_ostream(getFD(Filename, EC, Disp, Access, Flags), true) {} /// FD is the file descriptor that this writes to. If ShouldClose is true, this /// closes the file when the stream is destroyed. raw_fd_ostream::raw_fd_ostream(int fd, bool shouldClose, bool unbuffered) : raw_pwrite_stream(unbuffered), FD(fd), ShouldClose(shouldClose) { if (FD < 0 ) { ShouldClose = false; return; } // Do not attempt to close stdout or stderr. We used to try to maintain the // property that tools that support writing file to stdout should not also // write informational output to stdout, but in practice we were never able to // maintain this invariant. Many features have been added to LLVM and clang // (-fdump-record-layouts, optimization remarks, etc) that print to stdout, so // users must simply be aware that mixed output and remarks is a possibility. if (FD <= STDERR_FILENO) ShouldClose = false; #ifdef _WIN32 // Check if this is a console device. This is not equivalent to isatty. IsWindowsConsole = ::GetFileType((HANDLE)::_get_osfhandle(fd)) == FILE_TYPE_CHAR; #endif // Get the starting position. off_t loc = ::lseek(FD, 0, SEEK_CUR); #ifdef _WIN32 // MSVCRT's _lseek(SEEK_CUR) doesn't return -1 for pipes. sys::fs::file_status Status; std::error_code EC = status(FD, Status); SupportsSeeking = !EC && Status.type() == sys::fs::file_type::regular_file; #else SupportsSeeking = loc != (off_t)-1; #endif if (!SupportsSeeking) pos = 0; else pos = static_cast(loc); } raw_fd_ostream::~raw_fd_ostream() { if (FD >= 0) { flush(); if (ShouldClose) { if (auto EC = sys::Process::SafelyCloseFileDescriptor(FD)) error_detected(EC); } } #ifdef __MINGW32__ // On mingw, global dtors should not call exit(). // report_fatal_error() invokes exit(). We know report_fatal_error() // might not write messages to stderr when any errors were detected // on FD == 2. if (FD == 2) return; #endif // If there are any pending errors, report them now. Clients wishing // to avoid report_fatal_error calls should check for errors with // has_error() and clear the error flag with clear_error() before // destructing raw_ostream objects which may have errors. if (has_error()) report_fatal_error("IO failure on output stream: " + error().message(), /*gen_crash_diag=*/false); } #if defined(_WIN32) // The most reliable way to print unicode in a Windows console is with // WriteConsoleW. To use that, first transcode from UTF-8 to UTF-16. This // assumes that LLVM programs always print valid UTF-8 to the console. The data // might not be UTF-8 for two major reasons: // 1. The program is printing binary (-filetype=obj -o -), in which case it // would have been gibberish anyway. // 2. The program is printing text in a semi-ascii compatible codepage like // shift-jis or cp1252. // // Most LLVM programs don't produce non-ascii text unless they are quoting // user source input. A well-behaved LLVM program should either validate that // the input is UTF-8 or transcode from the local codepage to UTF-8 before // quoting it. If they don't, this may mess up the encoding, but this is still // probably the best compromise we can make. static bool write_console_impl(int FD, StringRef Data) { SmallVector WideText; // Fall back to ::write if it wasn't valid UTF-8. if (auto EC = sys::windows::UTF8ToUTF16(Data, WideText)) return false; // On Windows 7 and earlier, WriteConsoleW has a low maximum amount of data // that can be written to the console at a time. size_t MaxWriteSize = WideText.size(); if (!RunningWindows8OrGreater()) MaxWriteSize = 32767; size_t WCharsWritten = 0; do { size_t WCharsToWrite = std::min(MaxWriteSize, WideText.size() - WCharsWritten); DWORD ActuallyWritten; bool Success = ::WriteConsoleW((HANDLE)::_get_osfhandle(FD), &WideText[WCharsWritten], WCharsToWrite, &ActuallyWritten, /*Reserved=*/nullptr); // The most likely reason for WriteConsoleW to fail is that FD no longer // points to a console. Fall back to ::write. If this isn't the first loop // iteration, something is truly wrong. if (!Success) return false; WCharsWritten += ActuallyWritten; } while (WCharsWritten != WideText.size()); return true; } #endif void raw_fd_ostream::write_impl(const char *Ptr, size_t Size) { assert(FD >= 0 && "File already closed."); pos += Size; #if defined(_WIN32) // If this is a Windows console device, try re-encoding from UTF-8 to UTF-16 // and using WriteConsoleW. If that fails, fall back to plain write(). if (IsWindowsConsole) if (write_console_impl(FD, StringRef(Ptr, Size))) return; #endif // The maximum write size is limited to INT32_MAX. A write // greater than SSIZE_MAX is implementation-defined in POSIX, // and Windows _write requires 32 bit input. size_t MaxWriteSize = INT32_MAX; #if defined(__linux__) // It is observed that Linux returns EINVAL for a very large write (>2G). // Make it a reasonably small value. MaxWriteSize = 1024 * 1024 * 1024; #endif do { size_t ChunkSize = std::min(Size, MaxWriteSize); ssize_t ret = ::write(FD, Ptr, ChunkSize); if (ret < 0) { // If it's a recoverable error, swallow it and retry the write. // // Ideally we wouldn't ever see EAGAIN or EWOULDBLOCK here, since // raw_ostream isn't designed to do non-blocking I/O. However, some // programs, such as old versions of bjam, have mistakenly used // O_NONBLOCK. For compatibility, emulate blocking semantics by // spinning until the write succeeds. If you don't want spinning, // don't use O_NONBLOCK file descriptors with raw_ostream. if (errno == EINTR || errno == EAGAIN #ifdef EWOULDBLOCK || errno == EWOULDBLOCK #endif ) continue; // Otherwise it's a non-recoverable error. Note it and quit. error_detected(std::error_code(errno, std::generic_category())); break; } // The write may have written some or all of the data. Update the // size and buffer pointer to reflect the remainder that needs // to be written. If there are no bytes left, we're done. Ptr += ret; Size -= ret; } while (Size > 0); } void raw_fd_ostream::close() { assert(ShouldClose); ShouldClose = false; flush(); if (auto EC = sys::Process::SafelyCloseFileDescriptor(FD)) error_detected(EC); FD = -1; } uint64_t raw_fd_ostream::seek(uint64_t off) { assert(SupportsSeeking && "Stream does not support seeking!"); flush(); #ifdef _WIN32 pos = ::_lseeki64(FD, off, SEEK_SET); #elif defined(HAVE_LSEEK64) pos = ::lseek64(FD, off, SEEK_SET); #else pos = ::lseek(FD, off, SEEK_SET); #endif if (pos == (uint64_t)-1) error_detected(std::error_code(errno, std::generic_category())); return pos; } void raw_fd_ostream::pwrite_impl(const char *Ptr, size_t Size, uint64_t Offset) { uint64_t Pos = tell(); seek(Offset); write(Ptr, Size); seek(Pos); } size_t raw_fd_ostream::preferred_buffer_size() const { #if defined(_WIN32) // Disable buffering for console devices. Console output is re-encoded from // UTF-8 to UTF-16 on Windows, and buffering it would require us to split the // buffer on a valid UTF-8 codepoint boundary. Terminal buffering is disabled // below on most other OSs, so do the same thing on Windows and avoid that // complexity. if (IsWindowsConsole) return 0; return raw_ostream::preferred_buffer_size(); #elif !defined(__minix) // Minix has no st_blksize. assert(FD >= 0 && "File not yet open!"); struct stat statbuf; if (fstat(FD, &statbuf) != 0) return 0; // If this is a terminal, don't use buffering. Line buffering // would be a more traditional thing to do, but it's not worth // the complexity. if (S_ISCHR(statbuf.st_mode) && isatty(FD)) return 0; // Return the preferred block size. return statbuf.st_blksize; #else return raw_ostream::preferred_buffer_size(); #endif } raw_ostream &raw_fd_ostream::changeColor(enum Colors colors, bool bold, bool bg) { if (!ColorEnabled) return *this; if (sys::Process::ColorNeedsFlush()) flush(); const char *colorcode = (colors == SAVEDCOLOR) ? sys::Process::OutputBold(bg) : sys::Process::OutputColor(static_cast(colors), bold, bg); if (colorcode) { size_t len = strlen(colorcode); write(colorcode, len); // don't account colors towards output characters pos -= len; } return *this; } raw_ostream &raw_fd_ostream::resetColor() { if (!ColorEnabled) return *this; if (sys::Process::ColorNeedsFlush()) flush(); const char *colorcode = sys::Process::ResetColor(); if (colorcode) { size_t len = strlen(colorcode); write(colorcode, len); // don't account colors towards output characters pos -= len; } return *this; } raw_ostream &raw_fd_ostream::reverseColor() { if (!ColorEnabled) return *this; if (sys::Process::ColorNeedsFlush()) flush(); const char *colorcode = sys::Process::OutputReverse(); if (colorcode) { size_t len = strlen(colorcode); write(colorcode, len); // don't account colors towards output characters pos -= len; } return *this; } bool raw_fd_ostream::is_displayed() const { return sys::Process::FileDescriptorIsDisplayed(FD); } bool raw_fd_ostream::has_colors() const { return sys::Process::FileDescriptorHasColors(FD); } void raw_fd_ostream::anchor() {} //===----------------------------------------------------------------------===// // outs(), errs(), nulls() //===----------------------------------------------------------------------===// /// outs() - This returns a reference to a raw_ostream for standard output. /// Use it like: outs() << "foo" << "bar"; raw_ostream &llvm::outs() { // Set buffer settings to model stdout behavior. std::error_code EC; static raw_fd_ostream S("-", EC, sys::fs::OF_None); assert(!EC); return S; } /// errs() - This returns a reference to a raw_ostream for standard error. /// Use it like: errs() << "foo" << "bar"; raw_ostream &llvm::errs() { // Set standard error to be unbuffered by default. static raw_fd_ostream S(STDERR_FILENO, false, true); return S; } /// nulls() - This returns a reference to a raw_ostream which discards output. raw_ostream &llvm::nulls() { static raw_null_ostream S; return S; } //===----------------------------------------------------------------------===// // raw_string_ostream //===----------------------------------------------------------------------===// raw_string_ostream::~raw_string_ostream() { flush(); } void raw_string_ostream::write_impl(const char *Ptr, size_t Size) { OS.append(Ptr, Size); } //===----------------------------------------------------------------------===// // raw_svector_ostream //===----------------------------------------------------------------------===// uint64_t raw_svector_ostream::current_pos() const { return OS.size(); } void raw_svector_ostream::write_impl(const char *Ptr, size_t Size) { OS.append(Ptr, Ptr + Size); } void raw_svector_ostream::pwrite_impl(const char *Ptr, size_t Size, uint64_t Offset) { memcpy(OS.data() + Offset, Ptr, Size); } //===----------------------------------------------------------------------===// // raw_null_ostream //===----------------------------------------------------------------------===// raw_null_ostream::~raw_null_ostream() { #ifndef NDEBUG // ~raw_ostream asserts that the buffer is empty. This isn't necessary // with raw_null_ostream, but it's better to have raw_null_ostream follow // the rules than to change the rules just for raw_null_ostream. flush(); #endif } void raw_null_ostream::write_impl(const char *Ptr, size_t Size) { } uint64_t raw_null_ostream::current_pos() const { return 0; } void raw_null_ostream::pwrite_impl(const char *Ptr, size_t Size, uint64_t Offset) {} void raw_pwrite_stream::anchor() {} void buffer_ostream::anchor() {} diff --git a/contrib/llvm-project/llvm/lib/Transforms/InstCombine/InstCombinePHI.cpp b/contrib/llvm-project/llvm/lib/Transforms/InstCombine/InstCombinePHI.cpp index 74e015a4f1d4..6c2aead5a754 100644 --- a/contrib/llvm-project/llvm/lib/Transforms/InstCombine/InstCombinePHI.cpp +++ b/contrib/llvm-project/llvm/lib/Transforms/InstCombine/InstCombinePHI.cpp @@ -1,1268 +1,1278 @@ //===- InstCombinePHI.cpp -------------------------------------------------===// // // 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 visitPHINode function. // //===----------------------------------------------------------------------===// #include "InstCombineInternal.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/Analysis/InstructionSimplify.h" #include "llvm/Analysis/ValueTracking.h" #include "llvm/IR/PatternMatch.h" #include "llvm/Support/CommandLine.h" #include "llvm/Transforms/Utils/Local.h" using namespace llvm; using namespace llvm::PatternMatch; #define DEBUG_TYPE "instcombine" static cl::opt MaxNumPhis("instcombine-max-num-phis", cl::init(512), cl::desc("Maximum number phis to handle in intptr/ptrint folding")); /// The PHI arguments will be folded into a single operation with a PHI node /// as input. The debug location of the single operation will be the merged /// locations of the original PHI node arguments. void InstCombiner::PHIArgMergedDebugLoc(Instruction *Inst, PHINode &PN) { auto *FirstInst = cast(PN.getIncomingValue(0)); Inst->setDebugLoc(FirstInst->getDebugLoc()); // We do not expect a CallInst here, otherwise, N-way merging of DebugLoc // will be inefficient. assert(!isa(Inst)); for (unsigned i = 1; i != PN.getNumIncomingValues(); ++i) { auto *I = cast(PN.getIncomingValue(i)); Inst->applyMergedLocation(Inst->getDebugLoc(), I->getDebugLoc()); } } // Replace Integer typed PHI PN if the PHI's value is used as a pointer value. // If there is an existing pointer typed PHI that produces the same value as PN, // replace PN and the IntToPtr operation with it. Otherwise, synthesize a new // PHI node: // // Case-1: // bb1: // int_init = PtrToInt(ptr_init) // br label %bb2 // bb2: // int_val = PHI([int_init, %bb1], [int_val_inc, %bb2] // ptr_val = PHI([ptr_init, %bb1], [ptr_val_inc, %bb2] // ptr_val2 = IntToPtr(int_val) // ... // use(ptr_val2) // ptr_val_inc = ... // inc_val_inc = PtrToInt(ptr_val_inc) // // ==> // bb1: // br label %bb2 // bb2: // ptr_val = PHI([ptr_init, %bb1], [ptr_val_inc, %bb2] // ... // use(ptr_val) // ptr_val_inc = ... // // Case-2: // bb1: // int_ptr = BitCast(ptr_ptr) // int_init = Load(int_ptr) // br label %bb2 // bb2: // int_val = PHI([int_init, %bb1], [int_val_inc, %bb2] // ptr_val2 = IntToPtr(int_val) // ... // use(ptr_val2) // ptr_val_inc = ... // inc_val_inc = PtrToInt(ptr_val_inc) // ==> // bb1: // ptr_init = Load(ptr_ptr) // br label %bb2 // bb2: // ptr_val = PHI([ptr_init, %bb1], [ptr_val_inc, %bb2] // ... // use(ptr_val) // ptr_val_inc = ... // ... // Instruction *InstCombiner::FoldIntegerTypedPHI(PHINode &PN) { if (!PN.getType()->isIntegerTy()) return nullptr; if (!PN.hasOneUse()) return nullptr; auto *IntToPtr = dyn_cast(PN.user_back()); if (!IntToPtr) return nullptr; // Check if the pointer is actually used as pointer: auto HasPointerUse = [](Instruction *IIP) { for (User *U : IIP->users()) { Value *Ptr = nullptr; if (LoadInst *LoadI = dyn_cast(U)) { Ptr = LoadI->getPointerOperand(); } else if (StoreInst *SI = dyn_cast(U)) { Ptr = SI->getPointerOperand(); } else if (GetElementPtrInst *GI = dyn_cast(U)) { Ptr = GI->getPointerOperand(); } if (Ptr && Ptr == IIP) return true; } return false; }; if (!HasPointerUse(IntToPtr)) return nullptr; if (DL.getPointerSizeInBits(IntToPtr->getAddressSpace()) != DL.getTypeSizeInBits(IntToPtr->getOperand(0)->getType())) return nullptr; SmallVector AvailablePtrVals; for (unsigned i = 0; i != PN.getNumIncomingValues(); ++i) { Value *Arg = PN.getIncomingValue(i); // First look backward: if (auto *PI = dyn_cast(Arg)) { AvailablePtrVals.emplace_back(PI->getOperand(0)); continue; } // Next look forward: Value *ArgIntToPtr = nullptr; for (User *U : Arg->users()) { if (isa(U) && U->getType() == IntToPtr->getType() && (DT.dominates(cast(U), PN.getIncomingBlock(i)) || cast(U)->getParent() == PN.getIncomingBlock(i))) { ArgIntToPtr = U; break; } } if (ArgIntToPtr) { AvailablePtrVals.emplace_back(ArgIntToPtr); continue; } // If Arg is defined by a PHI, allow it. This will also create // more opportunities iteratively. if (isa(Arg)) { AvailablePtrVals.emplace_back(Arg); continue; } // For a single use integer load: auto *LoadI = dyn_cast(Arg); if (!LoadI) return nullptr; if (!LoadI->hasOneUse()) return nullptr; // Push the integer typed Load instruction into the available // value set, and fix it up later when the pointer typed PHI // is synthesized. AvailablePtrVals.emplace_back(LoadI); } // Now search for a matching PHI auto *BB = PN.getParent(); assert(AvailablePtrVals.size() == PN.getNumIncomingValues() && "Not enough available ptr typed incoming values"); PHINode *MatchingPtrPHI = nullptr; unsigned NumPhis = 0; for (auto II = BB->begin(); II != BB->end(); II++, NumPhis++) { // FIXME: consider handling this in AggressiveInstCombine PHINode *PtrPHI = dyn_cast(II); if (!PtrPHI) break; if (NumPhis > MaxNumPhis) return nullptr; if (PtrPHI == &PN || PtrPHI->getType() != IntToPtr->getType()) continue; MatchingPtrPHI = PtrPHI; for (unsigned i = 0; i != PtrPHI->getNumIncomingValues(); ++i) { if (AvailablePtrVals[i] != PtrPHI->getIncomingValueForBlock(PN.getIncomingBlock(i))) { MatchingPtrPHI = nullptr; break; } } if (MatchingPtrPHI) break; } if (MatchingPtrPHI) { assert(MatchingPtrPHI->getType() == IntToPtr->getType() && "Phi's Type does not match with IntToPtr"); // The PtrToCast + IntToPtr will be simplified later return CastInst::CreateBitOrPointerCast(MatchingPtrPHI, IntToPtr->getOperand(0)->getType()); } // If it requires a conversion for every PHI operand, do not do it. if (all_of(AvailablePtrVals, [&](Value *V) { return (V->getType() != IntToPtr->getType()) || isa(V); })) return nullptr; // If any of the operand that requires casting is a terminator - // instruction, do not do it. + // instruction, do not do it. Similarly, do not do the transform if the value + // is PHI in a block with no insertion point, for example, a catchswitch + // block, since we will not be able to insert a cast after the PHI. if (any_of(AvailablePtrVals, [&](Value *V) { if (V->getType() == IntToPtr->getType()) return false; - auto *Inst = dyn_cast(V); - return Inst && Inst->isTerminator(); + if (!Inst) + return false; + if (Inst->isTerminator()) + return true; + auto *BB = Inst->getParent(); + if (isa(Inst) && BB->getFirstInsertionPt() == BB->end()) + return true; + return false; })) return nullptr; PHINode *NewPtrPHI = PHINode::Create( IntToPtr->getType(), PN.getNumIncomingValues(), PN.getName() + ".ptr"); InsertNewInstBefore(NewPtrPHI, PN); SmallDenseMap Casts; for (unsigned i = 0; i != PN.getNumIncomingValues(); ++i) { auto *IncomingBB = PN.getIncomingBlock(i); auto *IncomingVal = AvailablePtrVals[i]; if (IncomingVal->getType() == IntToPtr->getType()) { NewPtrPHI->addIncoming(IncomingVal, IncomingBB); continue; } #ifndef NDEBUG LoadInst *LoadI = dyn_cast(IncomingVal); assert((isa(IncomingVal) || IncomingVal->getType()->isPointerTy() || (LoadI && LoadI->hasOneUse())) && "Can not replace LoadInst with multiple uses"); #endif // Need to insert a BitCast. // For an integer Load instruction with a single use, the load + IntToPtr // cast will be simplified into a pointer load: // %v = load i64, i64* %a.ip, align 8 // %v.cast = inttoptr i64 %v to float ** // ==> // %v.ptrp = bitcast i64 * %a.ip to float ** // %v.cast = load float *, float ** %v.ptrp, align 8 Instruction *&CI = Casts[IncomingVal]; if (!CI) { CI = CastInst::CreateBitOrPointerCast(IncomingVal, IntToPtr->getType(), IncomingVal->getName() + ".ptr"); if (auto *IncomingI = dyn_cast(IncomingVal)) { BasicBlock::iterator InsertPos(IncomingI); InsertPos++; + BasicBlock *BB = IncomingI->getParent(); if (isa(IncomingI)) - InsertPos = IncomingI->getParent()->getFirstInsertionPt(); + InsertPos = BB->getFirstInsertionPt(); + assert(InsertPos != BB->end() && "should have checked above"); InsertNewInstBefore(CI, *InsertPos); } else { auto *InsertBB = &IncomingBB->getParent()->getEntryBlock(); InsertNewInstBefore(CI, *InsertBB->getFirstInsertionPt()); } } NewPtrPHI->addIncoming(CI, IncomingBB); } // The PtrToCast + IntToPtr will be simplified later return CastInst::CreateBitOrPointerCast(NewPtrPHI, IntToPtr->getOperand(0)->getType()); } /// If we have something like phi [add (a,b), add(a,c)] and if a/b/c and the /// adds all have a single use, turn this into a phi and a single binop. Instruction *InstCombiner::FoldPHIArgBinOpIntoPHI(PHINode &PN) { Instruction *FirstInst = cast(PN.getIncomingValue(0)); assert(isa(FirstInst) || isa(FirstInst)); unsigned Opc = FirstInst->getOpcode(); Value *LHSVal = FirstInst->getOperand(0); Value *RHSVal = FirstInst->getOperand(1); Type *LHSType = LHSVal->getType(); Type *RHSType = RHSVal->getType(); // Scan to see if all operands are the same opcode, and all have one use. for (unsigned i = 1; i != PN.getNumIncomingValues(); ++i) { Instruction *I = dyn_cast(PN.getIncomingValue(i)); if (!I || I->getOpcode() != Opc || !I->hasOneUse() || // Verify type of the LHS matches so we don't fold cmp's of different // types. I->getOperand(0)->getType() != LHSType || I->getOperand(1)->getType() != RHSType) return nullptr; // If they are CmpInst instructions, check their predicates if (CmpInst *CI = dyn_cast(I)) if (CI->getPredicate() != cast(FirstInst)->getPredicate()) return nullptr; // Keep track of which operand needs a phi node. if (I->getOperand(0) != LHSVal) LHSVal = nullptr; if (I->getOperand(1) != RHSVal) RHSVal = nullptr; } // If both LHS and RHS would need a PHI, don't do this transformation, // because it would increase the number of PHIs entering the block, // which leads to higher register pressure. This is especially // bad when the PHIs are in the header of a loop. if (!LHSVal && !RHSVal) return nullptr; // Otherwise, this is safe to transform! Value *InLHS = FirstInst->getOperand(0); Value *InRHS = FirstInst->getOperand(1); PHINode *NewLHS = nullptr, *NewRHS = nullptr; if (!LHSVal) { NewLHS = PHINode::Create(LHSType, PN.getNumIncomingValues(), FirstInst->getOperand(0)->getName() + ".pn"); NewLHS->addIncoming(InLHS, PN.getIncomingBlock(0)); InsertNewInstBefore(NewLHS, PN); LHSVal = NewLHS; } if (!RHSVal) { NewRHS = PHINode::Create(RHSType, PN.getNumIncomingValues(), FirstInst->getOperand(1)->getName() + ".pn"); NewRHS->addIncoming(InRHS, PN.getIncomingBlock(0)); InsertNewInstBefore(NewRHS, PN); RHSVal = NewRHS; } // Add all operands to the new PHIs. if (NewLHS || NewRHS) { for (unsigned i = 1, e = PN.getNumIncomingValues(); i != e; ++i) { Instruction *InInst = cast(PN.getIncomingValue(i)); if (NewLHS) { Value *NewInLHS = InInst->getOperand(0); NewLHS->addIncoming(NewInLHS, PN.getIncomingBlock(i)); } if (NewRHS) { Value *NewInRHS = InInst->getOperand(1); NewRHS->addIncoming(NewInRHS, PN.getIncomingBlock(i)); } } } if (CmpInst *CIOp = dyn_cast(FirstInst)) { CmpInst *NewCI = CmpInst::Create(CIOp->getOpcode(), CIOp->getPredicate(), LHSVal, RHSVal); PHIArgMergedDebugLoc(NewCI, PN); return NewCI; } BinaryOperator *BinOp = cast(FirstInst); BinaryOperator *NewBinOp = BinaryOperator::Create(BinOp->getOpcode(), LHSVal, RHSVal); NewBinOp->copyIRFlags(PN.getIncomingValue(0)); for (unsigned i = 1, e = PN.getNumIncomingValues(); i != e; ++i) NewBinOp->andIRFlags(PN.getIncomingValue(i)); PHIArgMergedDebugLoc(NewBinOp, PN); return NewBinOp; } Instruction *InstCombiner::FoldPHIArgGEPIntoPHI(PHINode &PN) { GetElementPtrInst *FirstInst =cast(PN.getIncomingValue(0)); SmallVector FixedOperands(FirstInst->op_begin(), FirstInst->op_end()); // This is true if all GEP bases are allocas and if all indices into them are // constants. bool AllBasePointersAreAllocas = true; // We don't want to replace this phi if the replacement would require // more than one phi, which leads to higher register pressure. This is // especially bad when the PHIs are in the header of a loop. bool NeededPhi = false; bool AllInBounds = true; // Scan to see if all operands are the same opcode, and all have one use. for (unsigned i = 1; i != PN.getNumIncomingValues(); ++i) { GetElementPtrInst *GEP= dyn_cast(PN.getIncomingValue(i)); if (!GEP || !GEP->hasOneUse() || GEP->getType() != FirstInst->getType() || GEP->getNumOperands() != FirstInst->getNumOperands()) return nullptr; AllInBounds &= GEP->isInBounds(); // Keep track of whether or not all GEPs are of alloca pointers. if (AllBasePointersAreAllocas && (!isa(GEP->getOperand(0)) || !GEP->hasAllConstantIndices())) AllBasePointersAreAllocas = false; // Compare the operand lists. for (unsigned op = 0, e = FirstInst->getNumOperands(); op != e; ++op) { if (FirstInst->getOperand(op) == GEP->getOperand(op)) continue; // Don't merge two GEPs when two operands differ (introducing phi nodes) // if one of the PHIs has a constant for the index. The index may be // substantially cheaper to compute for the constants, so making it a // variable index could pessimize the path. This also handles the case // for struct indices, which must always be constant. if (isa(FirstInst->getOperand(op)) || isa(GEP->getOperand(op))) return nullptr; if (FirstInst->getOperand(op)->getType() !=GEP->getOperand(op)->getType()) return nullptr; // If we already needed a PHI for an earlier operand, and another operand // also requires a PHI, we'd be introducing more PHIs than we're // eliminating, which increases register pressure on entry to the PHI's // block. if (NeededPhi) return nullptr; FixedOperands[op] = nullptr; // Needs a PHI. NeededPhi = true; } } // If all of the base pointers of the PHI'd GEPs are from allocas, don't // bother doing this transformation. At best, this will just save a bit of // offset calculation, but all the predecessors will have to materialize the // stack address into a register anyway. We'd actually rather *clone* the // load up into the predecessors so that we have a load of a gep of an alloca, // which can usually all be folded into the load. if (AllBasePointersAreAllocas) return nullptr; // Otherwise, this is safe to transform. Insert PHI nodes for each operand // that is variable. SmallVector OperandPhis(FixedOperands.size()); bool HasAnyPHIs = false; for (unsigned i = 0, e = FixedOperands.size(); i != e; ++i) { if (FixedOperands[i]) continue; // operand doesn't need a phi. Value *FirstOp = FirstInst->getOperand(i); PHINode *NewPN = PHINode::Create(FirstOp->getType(), e, FirstOp->getName()+".pn"); InsertNewInstBefore(NewPN, PN); NewPN->addIncoming(FirstOp, PN.getIncomingBlock(0)); OperandPhis[i] = NewPN; FixedOperands[i] = NewPN; HasAnyPHIs = true; } // Add all operands to the new PHIs. if (HasAnyPHIs) { for (unsigned i = 1, e = PN.getNumIncomingValues(); i != e; ++i) { GetElementPtrInst *InGEP =cast(PN.getIncomingValue(i)); BasicBlock *InBB = PN.getIncomingBlock(i); for (unsigned op = 0, e = OperandPhis.size(); op != e; ++op) if (PHINode *OpPhi = OperandPhis[op]) OpPhi->addIncoming(InGEP->getOperand(op), InBB); } } Value *Base = FixedOperands[0]; GetElementPtrInst *NewGEP = GetElementPtrInst::Create(FirstInst->getSourceElementType(), Base, makeArrayRef(FixedOperands).slice(1)); if (AllInBounds) NewGEP->setIsInBounds(); PHIArgMergedDebugLoc(NewGEP, PN); return NewGEP; } /// Return true if we know that it is safe to sink the load out of the block /// that defines it. This means that it must be obvious the value of the load is /// not changed from the point of the load to the end of the block it is in. /// /// Finally, it is safe, but not profitable, to sink a load targeting a /// non-address-taken alloca. Doing so will cause us to not promote the alloca /// to a register. static bool isSafeAndProfitableToSinkLoad(LoadInst *L) { BasicBlock::iterator BBI = L->getIterator(), E = L->getParent()->end(); for (++BBI; BBI != E; ++BBI) if (BBI->mayWriteToMemory()) return false; // Check for non-address taken alloca. If not address-taken already, it isn't // profitable to do this xform. if (AllocaInst *AI = dyn_cast(L->getOperand(0))) { bool isAddressTaken = false; for (User *U : AI->users()) { if (isa(U)) continue; if (StoreInst *SI = dyn_cast(U)) { // If storing TO the alloca, then the address isn't taken. if (SI->getOperand(1) == AI) continue; } isAddressTaken = true; break; } if (!isAddressTaken && AI->isStaticAlloca()) return false; } // If this load is a load from a GEP with a constant offset from an alloca, // then we don't want to sink it. In its present form, it will be // load [constant stack offset]. Sinking it will cause us to have to // materialize the stack addresses in each predecessor in a register only to // do a shared load from register in the successor. if (GetElementPtrInst *GEP = dyn_cast(L->getOperand(0))) if (AllocaInst *AI = dyn_cast(GEP->getOperand(0))) if (AI->isStaticAlloca() && GEP->hasAllConstantIndices()) return false; return true; } Instruction *InstCombiner::FoldPHIArgLoadIntoPHI(PHINode &PN) { LoadInst *FirstLI = cast(PN.getIncomingValue(0)); // FIXME: This is overconservative; this transform is allowed in some cases // for atomic operations. if (FirstLI->isAtomic()) return nullptr; // When processing loads, we need to propagate two bits of information to the // sunk load: whether it is volatile, and what its alignment is. We currently // don't sink loads when some have their alignment specified and some don't. // visitLoadInst will propagate an alignment onto the load when TD is around, // and if TD isn't around, we can't handle the mixed case. bool isVolatile = FirstLI->isVolatile(); MaybeAlign LoadAlignment(FirstLI->getAlignment()); unsigned LoadAddrSpace = FirstLI->getPointerAddressSpace(); // We can't sink the load if the loaded value could be modified between the // load and the PHI. if (FirstLI->getParent() != PN.getIncomingBlock(0) || !isSafeAndProfitableToSinkLoad(FirstLI)) return nullptr; // If the PHI is of volatile loads and the load block has multiple // successors, sinking it would remove a load of the volatile value from // the path through the other successor. if (isVolatile && FirstLI->getParent()->getTerminator()->getNumSuccessors() != 1) return nullptr; // Check to see if all arguments are the same operation. for (unsigned i = 1, e = PN.getNumIncomingValues(); i != e; ++i) { LoadInst *LI = dyn_cast(PN.getIncomingValue(i)); if (!LI || !LI->hasOneUse()) return nullptr; // We can't sink the load if the loaded value could be modified between // the load and the PHI. if (LI->isVolatile() != isVolatile || LI->getParent() != PN.getIncomingBlock(i) || LI->getPointerAddressSpace() != LoadAddrSpace || !isSafeAndProfitableToSinkLoad(LI)) return nullptr; // If some of the loads have an alignment specified but not all of them, // we can't do the transformation. if ((LoadAlignment.hasValue()) != (LI->getAlignment() != 0)) return nullptr; LoadAlignment = std::min(LoadAlignment, MaybeAlign(LI->getAlignment())); // If the PHI is of volatile loads and the load block has multiple // successors, sinking it would remove a load of the volatile value from // the path through the other successor. if (isVolatile && LI->getParent()->getTerminator()->getNumSuccessors() != 1) return nullptr; } // Okay, they are all the same operation. Create a new PHI node of the // correct type, and PHI together all of the LHS's of the instructions. PHINode *NewPN = PHINode::Create(FirstLI->getOperand(0)->getType(), PN.getNumIncomingValues(), PN.getName()+".in"); Value *InVal = FirstLI->getOperand(0); NewPN->addIncoming(InVal, PN.getIncomingBlock(0)); LoadInst *NewLI = new LoadInst(FirstLI->getType(), NewPN, "", isVolatile, LoadAlignment); unsigned KnownIDs[] = { LLVMContext::MD_tbaa, LLVMContext::MD_range, LLVMContext::MD_invariant_load, LLVMContext::MD_alias_scope, LLVMContext::MD_noalias, LLVMContext::MD_nonnull, LLVMContext::MD_align, LLVMContext::MD_dereferenceable, LLVMContext::MD_dereferenceable_or_null, LLVMContext::MD_access_group, }; for (unsigned ID : KnownIDs) NewLI->setMetadata(ID, FirstLI->getMetadata(ID)); // Add all operands to the new PHI and combine TBAA metadata. for (unsigned i = 1, e = PN.getNumIncomingValues(); i != e; ++i) { LoadInst *LI = cast(PN.getIncomingValue(i)); combineMetadata(NewLI, LI, KnownIDs, true); Value *NewInVal = LI->getOperand(0); if (NewInVal != InVal) InVal = nullptr; NewPN->addIncoming(NewInVal, PN.getIncomingBlock(i)); } if (InVal) { // The new PHI unions all of the same values together. This is really // common, so we handle it intelligently here for compile-time speed. NewLI->setOperand(0, InVal); delete NewPN; } else { InsertNewInstBefore(NewPN, PN); } // If this was a volatile load that we are merging, make sure to loop through // and mark all the input loads as non-volatile. If we don't do this, we will // insert a new volatile load and the old ones will not be deletable. if (isVolatile) for (Value *IncValue : PN.incoming_values()) cast(IncValue)->setVolatile(false); PHIArgMergedDebugLoc(NewLI, PN); return NewLI; } /// TODO: This function could handle other cast types, but then it might /// require special-casing a cast from the 'i1' type. See the comment in /// FoldPHIArgOpIntoPHI() about pessimizing illegal integer types. Instruction *InstCombiner::FoldPHIArgZextsIntoPHI(PHINode &Phi) { // We cannot create a new instruction after the PHI if the terminator is an // EHPad because there is no valid insertion point. if (Instruction *TI = Phi.getParent()->getTerminator()) if (TI->isEHPad()) return nullptr; // Early exit for the common case of a phi with two operands. These are // handled elsewhere. See the comment below where we check the count of zexts // and constants for more details. unsigned NumIncomingValues = Phi.getNumIncomingValues(); if (NumIncomingValues < 3) return nullptr; // Find the narrower type specified by the first zext. Type *NarrowType = nullptr; for (Value *V : Phi.incoming_values()) { if (auto *Zext = dyn_cast(V)) { NarrowType = Zext->getSrcTy(); break; } } if (!NarrowType) return nullptr; // Walk the phi operands checking that we only have zexts or constants that // we can shrink for free. Store the new operands for the new phi. SmallVector NewIncoming; unsigned NumZexts = 0; unsigned NumConsts = 0; for (Value *V : Phi.incoming_values()) { if (auto *Zext = dyn_cast(V)) { // All zexts must be identical and have one use. if (Zext->getSrcTy() != NarrowType || !Zext->hasOneUse()) return nullptr; NewIncoming.push_back(Zext->getOperand(0)); NumZexts++; } else if (auto *C = dyn_cast(V)) { // Make sure that constants can fit in the new type. Constant *Trunc = ConstantExpr::getTrunc(C, NarrowType); if (ConstantExpr::getZExt(Trunc, C->getType()) != C) return nullptr; NewIncoming.push_back(Trunc); NumConsts++; } else { // If it's not a cast or a constant, bail out. return nullptr; } } // The more common cases of a phi with no constant operands or just one // variable operand are handled by FoldPHIArgOpIntoPHI() and foldOpIntoPhi() // respectively. foldOpIntoPhi() wants to do the opposite transform that is // performed here. It tries to replicate a cast in the phi operand's basic // block to expose other folding opportunities. Thus, InstCombine will // infinite loop without this check. if (NumConsts == 0 || NumZexts < 2) return nullptr; // All incoming values are zexts or constants that are safe to truncate. // Create a new phi node of the narrow type, phi together all of the new // operands, and zext the result back to the original type. PHINode *NewPhi = PHINode::Create(NarrowType, NumIncomingValues, Phi.getName() + ".shrunk"); for (unsigned i = 0; i != NumIncomingValues; ++i) NewPhi->addIncoming(NewIncoming[i], Phi.getIncomingBlock(i)); InsertNewInstBefore(NewPhi, Phi); return CastInst::CreateZExtOrBitCast(NewPhi, Phi.getType()); } /// If all operands to a PHI node are the same "unary" operator and they all are /// only used by the PHI, PHI together their inputs, and do the operation once, /// to the result of the PHI. Instruction *InstCombiner::FoldPHIArgOpIntoPHI(PHINode &PN) { // We cannot create a new instruction after the PHI if the terminator is an // EHPad because there is no valid insertion point. if (Instruction *TI = PN.getParent()->getTerminator()) if (TI->isEHPad()) return nullptr; Instruction *FirstInst = cast(PN.getIncomingValue(0)); if (isa(FirstInst)) return FoldPHIArgGEPIntoPHI(PN); if (isa(FirstInst)) return FoldPHIArgLoadIntoPHI(PN); // Scan the instruction, looking for input operations that can be folded away. // If all input operands to the phi are the same instruction (e.g. a cast from // the same type or "+42") we can pull the operation through the PHI, reducing // code size and simplifying code. Constant *ConstantOp = nullptr; Type *CastSrcTy = nullptr; if (isa(FirstInst)) { CastSrcTy = FirstInst->getOperand(0)->getType(); // Be careful about transforming integer PHIs. We don't want to pessimize // the code by turning an i32 into an i1293. if (PN.getType()->isIntegerTy() && CastSrcTy->isIntegerTy()) { if (!shouldChangeType(PN.getType(), CastSrcTy)) return nullptr; } } else if (isa(FirstInst) || isa(FirstInst)) { // Can fold binop, compare or shift here if the RHS is a constant, // otherwise call FoldPHIArgBinOpIntoPHI. ConstantOp = dyn_cast(FirstInst->getOperand(1)); if (!ConstantOp) return FoldPHIArgBinOpIntoPHI(PN); } else { return nullptr; // Cannot fold this operation. } // Check to see if all arguments are the same operation. for (unsigned i = 1, e = PN.getNumIncomingValues(); i != e; ++i) { Instruction *I = dyn_cast(PN.getIncomingValue(i)); if (!I || !I->hasOneUse() || !I->isSameOperationAs(FirstInst)) return nullptr; if (CastSrcTy) { if (I->getOperand(0)->getType() != CastSrcTy) return nullptr; // Cast operation must match. } else if (I->getOperand(1) != ConstantOp) { return nullptr; } } // Okay, they are all the same operation. Create a new PHI node of the // correct type, and PHI together all of the LHS's of the instructions. PHINode *NewPN = PHINode::Create(FirstInst->getOperand(0)->getType(), PN.getNumIncomingValues(), PN.getName()+".in"); Value *InVal = FirstInst->getOperand(0); NewPN->addIncoming(InVal, PN.getIncomingBlock(0)); // Add all operands to the new PHI. for (unsigned i = 1, e = PN.getNumIncomingValues(); i != e; ++i) { Value *NewInVal = cast(PN.getIncomingValue(i))->getOperand(0); if (NewInVal != InVal) InVal = nullptr; NewPN->addIncoming(NewInVal, PN.getIncomingBlock(i)); } Value *PhiVal; if (InVal) { // The new PHI unions all of the same values together. This is really // common, so we handle it intelligently here for compile-time speed. PhiVal = InVal; delete NewPN; } else { InsertNewInstBefore(NewPN, PN); PhiVal = NewPN; } // Insert and return the new operation. if (CastInst *FirstCI = dyn_cast(FirstInst)) { CastInst *NewCI = CastInst::Create(FirstCI->getOpcode(), PhiVal, PN.getType()); PHIArgMergedDebugLoc(NewCI, PN); return NewCI; } if (BinaryOperator *BinOp = dyn_cast(FirstInst)) { BinOp = BinaryOperator::Create(BinOp->getOpcode(), PhiVal, ConstantOp); BinOp->copyIRFlags(PN.getIncomingValue(0)); for (unsigned i = 1, e = PN.getNumIncomingValues(); i != e; ++i) BinOp->andIRFlags(PN.getIncomingValue(i)); PHIArgMergedDebugLoc(BinOp, PN); return BinOp; } CmpInst *CIOp = cast(FirstInst); CmpInst *NewCI = CmpInst::Create(CIOp->getOpcode(), CIOp->getPredicate(), PhiVal, ConstantOp); PHIArgMergedDebugLoc(NewCI, PN); return NewCI; } /// Return true if this PHI node is only used by a PHI node cycle that is dead. static bool DeadPHICycle(PHINode *PN, SmallPtrSetImpl &PotentiallyDeadPHIs) { if (PN->use_empty()) return true; if (!PN->hasOneUse()) return false; // Remember this node, and if we find the cycle, return. if (!PotentiallyDeadPHIs.insert(PN).second) return true; // Don't scan crazily complex things. if (PotentiallyDeadPHIs.size() == 16) return false; if (PHINode *PU = dyn_cast(PN->user_back())) return DeadPHICycle(PU, PotentiallyDeadPHIs); return false; } /// Return true if this phi node is always equal to NonPhiInVal. /// This happens with mutually cyclic phi nodes like: /// z = some value; x = phi (y, z); y = phi (x, z) static bool PHIsEqualValue(PHINode *PN, Value *NonPhiInVal, SmallPtrSetImpl &ValueEqualPHIs) { // See if we already saw this PHI node. if (!ValueEqualPHIs.insert(PN).second) return true; // Don't scan crazily complex things. if (ValueEqualPHIs.size() == 16) return false; // Scan the operands to see if they are either phi nodes or are equal to // the value. for (Value *Op : PN->incoming_values()) { if (PHINode *OpPN = dyn_cast(Op)) { if (!PHIsEqualValue(OpPN, NonPhiInVal, ValueEqualPHIs)) return false; } else if (Op != NonPhiInVal) return false; } return true; } /// Return an existing non-zero constant if this phi node has one, otherwise /// return constant 1. static ConstantInt *GetAnyNonZeroConstInt(PHINode &PN) { assert(isa(PN.getType()) && "Expect only integer type phi"); for (Value *V : PN.operands()) if (auto *ConstVA = dyn_cast(V)) if (!ConstVA->isZero()) return ConstVA; return ConstantInt::get(cast(PN.getType()), 1); } namespace { struct PHIUsageRecord { unsigned PHIId; // The ID # of the PHI (something determinstic to sort on) unsigned Shift; // The amount shifted. Instruction *Inst; // The trunc instruction. PHIUsageRecord(unsigned pn, unsigned Sh, Instruction *User) : PHIId(pn), Shift(Sh), Inst(User) {} bool operator<(const PHIUsageRecord &RHS) const { if (PHIId < RHS.PHIId) return true; if (PHIId > RHS.PHIId) return false; if (Shift < RHS.Shift) return true; if (Shift > RHS.Shift) return false; return Inst->getType()->getPrimitiveSizeInBits() < RHS.Inst->getType()->getPrimitiveSizeInBits(); } }; struct LoweredPHIRecord { PHINode *PN; // The PHI that was lowered. unsigned Shift; // The amount shifted. unsigned Width; // The width extracted. LoweredPHIRecord(PHINode *pn, unsigned Sh, Type *Ty) : PN(pn), Shift(Sh), Width(Ty->getPrimitiveSizeInBits()) {} // Ctor form used by DenseMap. LoweredPHIRecord(PHINode *pn, unsigned Sh) : PN(pn), Shift(Sh), Width(0) {} }; } namespace llvm { template<> struct DenseMapInfo { static inline LoweredPHIRecord getEmptyKey() { return LoweredPHIRecord(nullptr, 0); } static inline LoweredPHIRecord getTombstoneKey() { return LoweredPHIRecord(nullptr, 1); } static unsigned getHashValue(const LoweredPHIRecord &Val) { return DenseMapInfo::getHashValue(Val.PN) ^ (Val.Shift>>3) ^ (Val.Width>>3); } static bool isEqual(const LoweredPHIRecord &LHS, const LoweredPHIRecord &RHS) { return LHS.PN == RHS.PN && LHS.Shift == RHS.Shift && LHS.Width == RHS.Width; } }; } /// This is an integer PHI and we know that it has an illegal type: see if it is /// only used by trunc or trunc(lshr) operations. If so, we split the PHI into /// the various pieces being extracted. This sort of thing is introduced when /// SROA promotes an aggregate to large integer values. /// /// TODO: The user of the trunc may be an bitcast to float/double/vector or an /// inttoptr. We should produce new PHIs in the right type. /// Instruction *InstCombiner::SliceUpIllegalIntegerPHI(PHINode &FirstPhi) { // PHIUsers - Keep track of all of the truncated values extracted from a set // of PHIs, along with their offset. These are the things we want to rewrite. SmallVector PHIUsers; // PHIs are often mutually cyclic, so we keep track of a whole set of PHI // nodes which are extracted from. PHIsToSlice is a set we use to avoid // revisiting PHIs, PHIsInspected is a ordered list of PHIs that we need to // check the uses of (to ensure they are all extracts). SmallVector PHIsToSlice; SmallPtrSet PHIsInspected; PHIsToSlice.push_back(&FirstPhi); PHIsInspected.insert(&FirstPhi); for (unsigned PHIId = 0; PHIId != PHIsToSlice.size(); ++PHIId) { PHINode *PN = PHIsToSlice[PHIId]; // Scan the input list of the PHI. If any input is an invoke, and if the // input is defined in the predecessor, then we won't be split the critical // edge which is required to insert a truncate. Because of this, we have to // bail out. for (unsigned i = 0, e = PN->getNumIncomingValues(); i != e; ++i) { InvokeInst *II = dyn_cast(PN->getIncomingValue(i)); if (!II) continue; if (II->getParent() != PN->getIncomingBlock(i)) continue; // If we have a phi, and if it's directly in the predecessor, then we have // a critical edge where we need to put the truncate. Since we can't // split the edge in instcombine, we have to bail out. return nullptr; } for (User *U : PN->users()) { Instruction *UserI = cast(U); // If the user is a PHI, inspect its uses recursively. if (PHINode *UserPN = dyn_cast(UserI)) { if (PHIsInspected.insert(UserPN).second) PHIsToSlice.push_back(UserPN); continue; } // Truncates are always ok. if (isa(UserI)) { PHIUsers.push_back(PHIUsageRecord(PHIId, 0, UserI)); continue; } // Otherwise it must be a lshr which can only be used by one trunc. if (UserI->getOpcode() != Instruction::LShr || !UserI->hasOneUse() || !isa(UserI->user_back()) || !isa(UserI->getOperand(1))) return nullptr; // Bail on out of range shifts. unsigned SizeInBits = UserI->getType()->getScalarSizeInBits(); if (cast(UserI->getOperand(1))->getValue().uge(SizeInBits)) return nullptr; unsigned Shift = cast(UserI->getOperand(1))->getZExtValue(); PHIUsers.push_back(PHIUsageRecord(PHIId, Shift, UserI->user_back())); } } // If we have no users, they must be all self uses, just nuke the PHI. if (PHIUsers.empty()) return replaceInstUsesWith(FirstPhi, UndefValue::get(FirstPhi.getType())); // If this phi node is transformable, create new PHIs for all the pieces // extracted out of it. First, sort the users by their offset and size. array_pod_sort(PHIUsers.begin(), PHIUsers.end()); LLVM_DEBUG(dbgs() << "SLICING UP PHI: " << FirstPhi << '\n'; for (unsigned i = 1, e = PHIsToSlice.size(); i != e; ++i) dbgs() << "AND USER PHI #" << i << ": " << *PHIsToSlice[i] << '\n';); // PredValues - This is a temporary used when rewriting PHI nodes. It is // hoisted out here to avoid construction/destruction thrashing. DenseMap PredValues; // ExtractedVals - Each new PHI we introduce is saved here so we don't // introduce redundant PHIs. DenseMap ExtractedVals; for (unsigned UserI = 0, UserE = PHIUsers.size(); UserI != UserE; ++UserI) { unsigned PHIId = PHIUsers[UserI].PHIId; PHINode *PN = PHIsToSlice[PHIId]; unsigned Offset = PHIUsers[UserI].Shift; Type *Ty = PHIUsers[UserI].Inst->getType(); PHINode *EltPHI; // If we've already lowered a user like this, reuse the previously lowered // value. if ((EltPHI = ExtractedVals[LoweredPHIRecord(PN, Offset, Ty)]) == nullptr) { // Otherwise, Create the new PHI node for this user. EltPHI = PHINode::Create(Ty, PN->getNumIncomingValues(), PN->getName()+".off"+Twine(Offset), PN); assert(EltPHI->getType() != PN->getType() && "Truncate didn't shrink phi?"); for (unsigned i = 0, e = PN->getNumIncomingValues(); i != e; ++i) { BasicBlock *Pred = PN->getIncomingBlock(i); Value *&PredVal = PredValues[Pred]; // If we already have a value for this predecessor, reuse it. if (PredVal) { EltPHI->addIncoming(PredVal, Pred); continue; } // Handle the PHI self-reuse case. Value *InVal = PN->getIncomingValue(i); if (InVal == PN) { PredVal = EltPHI; EltPHI->addIncoming(PredVal, Pred); continue; } if (PHINode *InPHI = dyn_cast(PN)) { // If the incoming value was a PHI, and if it was one of the PHIs we // already rewrote it, just use the lowered value. if (Value *Res = ExtractedVals[LoweredPHIRecord(InPHI, Offset, Ty)]) { PredVal = Res; EltPHI->addIncoming(PredVal, Pred); continue; } } // Otherwise, do an extract in the predecessor. Builder.SetInsertPoint(Pred->getTerminator()); Value *Res = InVal; if (Offset) Res = Builder.CreateLShr(Res, ConstantInt::get(InVal->getType(), Offset), "extract"); Res = Builder.CreateTrunc(Res, Ty, "extract.t"); PredVal = Res; EltPHI->addIncoming(Res, Pred); // If the incoming value was a PHI, and if it was one of the PHIs we are // rewriting, we will ultimately delete the code we inserted. This // means we need to revisit that PHI to make sure we extract out the // needed piece. if (PHINode *OldInVal = dyn_cast(PN->getIncomingValue(i))) if (PHIsInspected.count(OldInVal)) { unsigned RefPHIId = find(PHIsToSlice, OldInVal) - PHIsToSlice.begin(); PHIUsers.push_back(PHIUsageRecord(RefPHIId, Offset, cast(Res))); ++UserE; } } PredValues.clear(); LLVM_DEBUG(dbgs() << " Made element PHI for offset " << Offset << ": " << *EltPHI << '\n'); ExtractedVals[LoweredPHIRecord(PN, Offset, Ty)] = EltPHI; } // Replace the use of this piece with the PHI node. replaceInstUsesWith(*PHIUsers[UserI].Inst, EltPHI); } // Replace all the remaining uses of the PHI nodes (self uses and the lshrs) // with undefs. Value *Undef = UndefValue::get(FirstPhi.getType()); for (unsigned i = 1, e = PHIsToSlice.size(); i != e; ++i) replaceInstUsesWith(*PHIsToSlice[i], Undef); return replaceInstUsesWith(FirstPhi, Undef); } // PHINode simplification // Instruction *InstCombiner::visitPHINode(PHINode &PN) { if (Value *V = SimplifyInstruction(&PN, SQ.getWithInstruction(&PN))) return replaceInstUsesWith(PN, V); if (Instruction *Result = FoldPHIArgZextsIntoPHI(PN)) return Result; // If all PHI operands are the same operation, pull them through the PHI, // reducing code size. if (isa(PN.getIncomingValue(0)) && isa(PN.getIncomingValue(1)) && cast(PN.getIncomingValue(0))->getOpcode() == cast(PN.getIncomingValue(1))->getOpcode() && // FIXME: The hasOneUse check will fail for PHIs that use the value more // than themselves more than once. PN.getIncomingValue(0)->hasOneUse()) if (Instruction *Result = FoldPHIArgOpIntoPHI(PN)) return Result; // If this is a trivial cycle in the PHI node graph, remove it. Basically, if // this PHI only has a single use (a PHI), and if that PHI only has one use (a // PHI)... break the cycle. if (PN.hasOneUse()) { if (Instruction *Result = FoldIntegerTypedPHI(PN)) return Result; Instruction *PHIUser = cast(PN.user_back()); if (PHINode *PU = dyn_cast(PHIUser)) { SmallPtrSet PotentiallyDeadPHIs; PotentiallyDeadPHIs.insert(&PN); if (DeadPHICycle(PU, PotentiallyDeadPHIs)) return replaceInstUsesWith(PN, UndefValue::get(PN.getType())); } // If this phi has a single use, and if that use just computes a value for // the next iteration of a loop, delete the phi. This occurs with unused // induction variables, e.g. "for (int j = 0; ; ++j);". Detecting this // common case here is good because the only other things that catch this // are induction variable analysis (sometimes) and ADCE, which is only run // late. if (PHIUser->hasOneUse() && (isa(PHIUser) || isa(PHIUser)) && PHIUser->user_back() == &PN) { return replaceInstUsesWith(PN, UndefValue::get(PN.getType())); } // When a PHI is used only to be compared with zero, it is safe to replace // an incoming value proved as known nonzero with any non-zero constant. // For example, in the code below, the incoming value %v can be replaced // with any non-zero constant based on the fact that the PHI is only used to // be compared with zero and %v is a known non-zero value: // %v = select %cond, 1, 2 // %p = phi [%v, BB] ... // icmp eq, %p, 0 auto *CmpInst = dyn_cast(PHIUser); // FIXME: To be simple, handle only integer type for now. if (CmpInst && isa(PN.getType()) && CmpInst->isEquality() && match(CmpInst->getOperand(1), m_Zero())) { ConstantInt *NonZeroConst = nullptr; for (unsigned i = 0, e = PN.getNumIncomingValues(); i != e; ++i) { Instruction *CtxI = PN.getIncomingBlock(i)->getTerminator(); Value *VA = PN.getIncomingValue(i); if (isKnownNonZero(VA, DL, 0, &AC, CtxI, &DT)) { if (!NonZeroConst) NonZeroConst = GetAnyNonZeroConstInt(PN); PN.setIncomingValue(i, NonZeroConst); } } } } // We sometimes end up with phi cycles that non-obviously end up being the // same value, for example: // z = some value; x = phi (y, z); y = phi (x, z) // where the phi nodes don't necessarily need to be in the same block. Do a // quick check to see if the PHI node only contains a single non-phi value, if // so, scan to see if the phi cycle is actually equal to that value. { unsigned InValNo = 0, NumIncomingVals = PN.getNumIncomingValues(); // Scan for the first non-phi operand. while (InValNo != NumIncomingVals && isa(PN.getIncomingValue(InValNo))) ++InValNo; if (InValNo != NumIncomingVals) { Value *NonPhiInVal = PN.getIncomingValue(InValNo); // Scan the rest of the operands to see if there are any conflicts, if so // there is no need to recursively scan other phis. for (++InValNo; InValNo != NumIncomingVals; ++InValNo) { Value *OpVal = PN.getIncomingValue(InValNo); if (OpVal != NonPhiInVal && !isa(OpVal)) break; } // If we scanned over all operands, then we have one unique value plus // phi values. Scan PHI nodes to see if they all merge in each other or // the value. if (InValNo == NumIncomingVals) { SmallPtrSet ValueEqualPHIs; if (PHIsEqualValue(&PN, NonPhiInVal, ValueEqualPHIs)) return replaceInstUsesWith(PN, NonPhiInVal); } } } // If there are multiple PHIs, sort their operands so that they all list // the blocks in the same order. This will help identical PHIs be eliminated // by other passes. Other passes shouldn't depend on this for correctness // however. PHINode *FirstPN = cast(PN.getParent()->begin()); if (&PN != FirstPN) for (unsigned i = 0, e = FirstPN->getNumIncomingValues(); i != e; ++i) { BasicBlock *BBA = PN.getIncomingBlock(i); BasicBlock *BBB = FirstPN->getIncomingBlock(i); if (BBA != BBB) { Value *VA = PN.getIncomingValue(i); unsigned j = PN.getBasicBlockIndex(BBB); Value *VB = PN.getIncomingValue(j); PN.setIncomingBlock(i, BBB); PN.setIncomingValue(i, VB); PN.setIncomingBlock(j, BBA); PN.setIncomingValue(j, VA); // NOTE: Instcombine normally would want us to "return &PN" if we // modified any of the operands of an instruction. However, since we // aren't adding or removing uses (just rearranging them) we don't do // this in this case. } } // If this is an integer PHI and we know that it has an illegal type, see if // it is only used by trunc or trunc(lshr) operations. If so, we split the // PHI into the various pieces being extracted. This sort of thing is // introduced when SROA promotes an aggregate to a single large integer type. if (PN.getType()->isIntegerTy() && !DL.isLegalInteger(PN.getType()->getPrimitiveSizeInBits())) if (Instruction *Res = SliceUpIllegalIntegerPHI(PN)) return Res; return nullptr; } diff --git a/contrib/llvm-project/llvm/lib/Transforms/Scalar/SROA.cpp b/contrib/llvm-project/llvm/lib/Transforms/Scalar/SROA.cpp index 89916e43fce2..1bdd806f15ac 100644 --- a/contrib/llvm-project/llvm/lib/Transforms/Scalar/SROA.cpp +++ b/contrib/llvm-project/llvm/lib/Transforms/Scalar/SROA.cpp @@ -1,4656 +1,4660 @@ //===- SROA.cpp - Scalar Replacement Of Aggregates ------------------------===// // // 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 /// This transformation implements the well known scalar replacement of /// aggregates transformation. It tries to identify promotable elements of an /// aggregate alloca, and promote them to registers. It will also try to /// convert uses of an element (or set of elements) of an alloca into a vector /// or bitfield-style integer scalar if appropriate. /// /// It works to do this with minimal slicing of the alloca so that regions /// which are merely transferred in and out of external memory remain unchanged /// and are not decomposed to scalar code. /// /// Because this also performs alloca promotion, it can be thought of as also /// serving the purpose of SSA formation. The algorithm iterates on the /// function until all opportunities for promotion have been realized. /// //===----------------------------------------------------------------------===// #include "llvm/Transforms/Scalar/SROA.h" #include "llvm/ADT/APInt.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/PointerIntPair.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SetVector.h" #include "llvm/ADT/SmallBitVector.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/Statistic.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Twine.h" #include "llvm/ADT/iterator.h" #include "llvm/ADT/iterator_range.h" #include "llvm/Analysis/AssumptionCache.h" #include "llvm/Analysis/GlobalsModRef.h" #include "llvm/Analysis/Loads.h" #include "llvm/Analysis/PtrUseVisitor.h" #include "llvm/Config/llvm-config.h" #include "llvm/IR/BasicBlock.h" #include "llvm/IR/Constant.h" #include "llvm/IR/ConstantFolder.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DIBuilder.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/DebugInfoMetadata.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/Dominators.h" #include "llvm/IR/Function.h" #include "llvm/IR/GetElementPtrTypeIterator.h" #include "llvm/IR/GlobalAlias.h" #include "llvm/IR/IRBuilder.h" #include "llvm/IR/InstVisitor.h" #include "llvm/IR/InstrTypes.h" #include "llvm/IR/Instruction.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/IntrinsicInst.h" #include "llvm/IR/Intrinsics.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Metadata.h" #include "llvm/IR/Module.h" #include "llvm/IR/Operator.h" #include "llvm/IR/PassManager.h" #include "llvm/IR/Type.h" #include "llvm/IR/Use.h" #include "llvm/IR/User.h" #include "llvm/IR/Value.h" #include "llvm/InitializePasses.h" #include "llvm/Pass.h" #include "llvm/Support/Casting.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Transforms/Scalar.h" #include "llvm/Transforms/Utils/Local.h" #include "llvm/Transforms/Utils/PromoteMemToReg.h" #include #include #include #include #include #include #include #include #include #include #include #ifndef NDEBUG // We only use this for a debug check. #include #endif using namespace llvm; using namespace llvm::sroa; #define DEBUG_TYPE "sroa" STATISTIC(NumAllocasAnalyzed, "Number of allocas analyzed for replacement"); STATISTIC(NumAllocaPartitions, "Number of alloca partitions formed"); STATISTIC(MaxPartitionsPerAlloca, "Maximum number of partitions per alloca"); STATISTIC(NumAllocaPartitionUses, "Number of alloca partition uses rewritten"); STATISTIC(MaxUsesPerAllocaPartition, "Maximum number of uses of a partition"); STATISTIC(NumNewAllocas, "Number of new, smaller allocas introduced"); STATISTIC(NumPromoted, "Number of allocas promoted to SSA values"); STATISTIC(NumLoadsSpeculated, "Number of loads speculated to allow promotion"); STATISTIC(NumDeleted, "Number of instructions deleted"); STATISTIC(NumVectorized, "Number of vectorized aggregates"); /// Hidden option to enable randomly shuffling the slices to help uncover /// instability in their order. static cl::opt SROARandomShuffleSlices("sroa-random-shuffle-slices", cl::init(false), cl::Hidden); /// Hidden option to experiment with completely strict handling of inbounds /// GEPs. static cl::opt SROAStrictInbounds("sroa-strict-inbounds", cl::init(false), cl::Hidden); namespace { /// A custom IRBuilder inserter which prefixes all names, but only in /// Assert builds. class IRBuilderPrefixedInserter : public IRBuilderDefaultInserter { std::string Prefix; const Twine getNameWithPrefix(const Twine &Name) const { return Name.isTriviallyEmpty() ? Name : Prefix + Name; } public: void SetNamePrefix(const Twine &P) { Prefix = P.str(); } protected: void InsertHelper(Instruction *I, const Twine &Name, BasicBlock *BB, BasicBlock::iterator InsertPt) const { IRBuilderDefaultInserter::InsertHelper(I, getNameWithPrefix(Name), BB, InsertPt); } }; /// Provide a type for IRBuilder that drops names in release builds. using IRBuilderTy = IRBuilder; /// A used slice of an alloca. /// /// This structure represents a slice of an alloca used by some instruction. It /// stores both the begin and end offsets of this use, a pointer to the use /// itself, and a flag indicating whether we can classify the use as splittable /// or not when forming partitions of the alloca. class Slice { /// The beginning offset of the range. uint64_t BeginOffset = 0; /// The ending offset, not included in the range. uint64_t EndOffset = 0; /// Storage for both the use of this slice and whether it can be /// split. PointerIntPair UseAndIsSplittable; public: Slice() = default; Slice(uint64_t BeginOffset, uint64_t EndOffset, Use *U, bool IsSplittable) : BeginOffset(BeginOffset), EndOffset(EndOffset), UseAndIsSplittable(U, IsSplittable) {} uint64_t beginOffset() const { return BeginOffset; } uint64_t endOffset() const { return EndOffset; } bool isSplittable() const { return UseAndIsSplittable.getInt(); } void makeUnsplittable() { UseAndIsSplittable.setInt(false); } Use *getUse() const { return UseAndIsSplittable.getPointer(); } bool isDead() const { return getUse() == nullptr; } void kill() { UseAndIsSplittable.setPointer(nullptr); } /// Support for ordering ranges. /// /// This provides an ordering over ranges such that start offsets are /// always increasing, and within equal start offsets, the end offsets are /// decreasing. Thus the spanning range comes first in a cluster with the /// same start position. bool operator<(const Slice &RHS) const { if (beginOffset() < RHS.beginOffset()) return true; if (beginOffset() > RHS.beginOffset()) return false; if (isSplittable() != RHS.isSplittable()) return !isSplittable(); if (endOffset() > RHS.endOffset()) return true; return false; } /// Support comparison with a single offset to allow binary searches. friend LLVM_ATTRIBUTE_UNUSED bool operator<(const Slice &LHS, uint64_t RHSOffset) { return LHS.beginOffset() < RHSOffset; } friend LLVM_ATTRIBUTE_UNUSED bool operator<(uint64_t LHSOffset, const Slice &RHS) { return LHSOffset < RHS.beginOffset(); } bool operator==(const Slice &RHS) const { return isSplittable() == RHS.isSplittable() && beginOffset() == RHS.beginOffset() && endOffset() == RHS.endOffset(); } bool operator!=(const Slice &RHS) const { return !operator==(RHS); } }; } // end anonymous namespace /// Representation of the alloca slices. /// /// This class represents the slices of an alloca which are formed by its /// various uses. If a pointer escapes, we can't fully build a representation /// for the slices used and we reflect that in this structure. The uses are /// stored, sorted by increasing beginning offset and with unsplittable slices /// starting at a particular offset before splittable slices. class llvm::sroa::AllocaSlices { public: /// Construct the slices of a particular alloca. AllocaSlices(const DataLayout &DL, AllocaInst &AI); /// Test whether a pointer to the allocation escapes our analysis. /// /// If this is true, the slices are never fully built and should be /// ignored. bool isEscaped() const { return PointerEscapingInstr; } /// Support for iterating over the slices. /// @{ using iterator = SmallVectorImpl::iterator; using range = iterator_range; iterator begin() { return Slices.begin(); } iterator end() { return Slices.end(); } using const_iterator = SmallVectorImpl::const_iterator; using const_range = iterator_range; const_iterator begin() const { return Slices.begin(); } const_iterator end() const { return Slices.end(); } /// @} /// Erase a range of slices. void erase(iterator Start, iterator Stop) { Slices.erase(Start, Stop); } /// Insert new slices for this alloca. /// /// This moves the slices into the alloca's slices collection, and re-sorts /// everything so that the usual ordering properties of the alloca's slices /// hold. void insert(ArrayRef NewSlices) { int OldSize = Slices.size(); Slices.append(NewSlices.begin(), NewSlices.end()); auto SliceI = Slices.begin() + OldSize; llvm::sort(SliceI, Slices.end()); std::inplace_merge(Slices.begin(), SliceI, Slices.end()); } // Forward declare the iterator and range accessor for walking the // partitions. class partition_iterator; iterator_range partitions(); /// Access the dead users for this alloca. ArrayRef getDeadUsers() const { return DeadUsers; } /// Access the dead operands referring to this alloca. /// /// These are operands which have cannot actually be used to refer to the /// alloca as they are outside its range and the user doesn't correct for /// that. These mostly consist of PHI node inputs and the like which we just /// need to replace with undef. ArrayRef getDeadOperands() const { return DeadOperands; } #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) void print(raw_ostream &OS, const_iterator I, StringRef Indent = " ") const; void printSlice(raw_ostream &OS, const_iterator I, StringRef Indent = " ") const; void printUse(raw_ostream &OS, const_iterator I, StringRef Indent = " ") const; void print(raw_ostream &OS) const; void dump(const_iterator I) const; void dump() const; #endif private: template class BuilderBase; class SliceBuilder; friend class AllocaSlices::SliceBuilder; #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) /// Handle to alloca instruction to simplify method interfaces. AllocaInst &AI; #endif /// The instruction responsible for this alloca not having a known set /// of slices. /// /// When an instruction (potentially) escapes the pointer to the alloca, we /// store a pointer to that here and abort trying to form slices of the /// alloca. This will be null if the alloca slices are analyzed successfully. Instruction *PointerEscapingInstr; /// The slices of the alloca. /// /// We store a vector of the slices formed by uses of the alloca here. This /// vector is sorted by increasing begin offset, and then the unsplittable /// slices before the splittable ones. See the Slice inner class for more /// details. SmallVector Slices; /// Instructions which will become dead if we rewrite the alloca. /// /// Note that these are not separated by slice. This is because we expect an /// alloca to be completely rewritten or not rewritten at all. If rewritten, /// all these instructions can simply be removed and replaced with undef as /// they come from outside of the allocated space. SmallVector DeadUsers; /// Operands which will become dead if we rewrite the alloca. /// /// These are operands that in their particular use can be replaced with /// undef when we rewrite the alloca. These show up in out-of-bounds inputs /// to PHI nodes and the like. They aren't entirely dead (there might be /// a GEP back into the bounds using it elsewhere) and nor is the PHI, but we /// want to swap this particular input for undef to simplify the use lists of /// the alloca. SmallVector DeadOperands; }; /// A partition of the slices. /// /// An ephemeral representation for a range of slices which can be viewed as /// a partition of the alloca. This range represents a span of the alloca's /// memory which cannot be split, and provides access to all of the slices /// overlapping some part of the partition. /// /// Objects of this type are produced by traversing the alloca's slices, but /// are only ephemeral and not persistent. class llvm::sroa::Partition { private: friend class AllocaSlices; friend class AllocaSlices::partition_iterator; using iterator = AllocaSlices::iterator; /// The beginning and ending offsets of the alloca for this /// partition. uint64_t BeginOffset = 0, EndOffset = 0; /// The start and end iterators of this partition. iterator SI, SJ; /// A collection of split slice tails overlapping the partition. SmallVector SplitTails; /// Raw constructor builds an empty partition starting and ending at /// the given iterator. Partition(iterator SI) : SI(SI), SJ(SI) {} public: /// The start offset of this partition. /// /// All of the contained slices start at or after this offset. uint64_t beginOffset() const { return BeginOffset; } /// The end offset of this partition. /// /// All of the contained slices end at or before this offset. uint64_t endOffset() const { return EndOffset; } /// The size of the partition. /// /// Note that this can never be zero. uint64_t size() const { assert(BeginOffset < EndOffset && "Partitions must span some bytes!"); return EndOffset - BeginOffset; } /// Test whether this partition contains no slices, and merely spans /// a region occupied by split slices. bool empty() const { return SI == SJ; } /// \name Iterate slices that start within the partition. /// These may be splittable or unsplittable. They have a begin offset >= the /// partition begin offset. /// @{ // FIXME: We should probably define a "concat_iterator" helper and use that // to stitch together pointee_iterators over the split tails and the // contiguous iterators of the partition. That would give a much nicer // interface here. We could then additionally expose filtered iterators for // split, unsplit, and unsplittable splices based on the usage patterns. iterator begin() const { return SI; } iterator end() const { return SJ; } /// @} /// Get the sequence of split slice tails. /// /// These tails are of slices which start before this partition but are /// split and overlap into the partition. We accumulate these while forming /// partitions. ArrayRef splitSliceTails() const { return SplitTails; } }; /// An iterator over partitions of the alloca's slices. /// /// This iterator implements the core algorithm for partitioning the alloca's /// slices. It is a forward iterator as we don't support backtracking for /// efficiency reasons, and re-use a single storage area to maintain the /// current set of split slices. /// /// It is templated on the slice iterator type to use so that it can operate /// with either const or non-const slice iterators. class AllocaSlices::partition_iterator : public iterator_facade_base { friend class AllocaSlices; /// Most of the state for walking the partitions is held in a class /// with a nice interface for examining them. Partition P; /// We need to keep the end of the slices to know when to stop. AllocaSlices::iterator SE; /// We also need to keep track of the maximum split end offset seen. /// FIXME: Do we really? uint64_t MaxSplitSliceEndOffset = 0; /// Sets the partition to be empty at given iterator, and sets the /// end iterator. partition_iterator(AllocaSlices::iterator SI, AllocaSlices::iterator SE) : P(SI), SE(SE) { // If not already at the end, advance our state to form the initial // partition. if (SI != SE) advance(); } /// Advance the iterator to the next partition. /// /// Requires that the iterator not be at the end of the slices. void advance() { assert((P.SI != SE || !P.SplitTails.empty()) && "Cannot advance past the end of the slices!"); // Clear out any split uses which have ended. if (!P.SplitTails.empty()) { if (P.EndOffset >= MaxSplitSliceEndOffset) { // If we've finished all splits, this is easy. P.SplitTails.clear(); MaxSplitSliceEndOffset = 0; } else { // Remove the uses which have ended in the prior partition. This // cannot change the max split slice end because we just checked that // the prior partition ended prior to that max. P.SplitTails.erase(llvm::remove_if(P.SplitTails, [&](Slice *S) { return S->endOffset() <= P.EndOffset; }), P.SplitTails.end()); assert(llvm::any_of(P.SplitTails, [&](Slice *S) { return S->endOffset() == MaxSplitSliceEndOffset; }) && "Could not find the current max split slice offset!"); assert(llvm::all_of(P.SplitTails, [&](Slice *S) { return S->endOffset() <= MaxSplitSliceEndOffset; }) && "Max split slice end offset is not actually the max!"); } } // If P.SI is already at the end, then we've cleared the split tail and // now have an end iterator. if (P.SI == SE) { assert(P.SplitTails.empty() && "Failed to clear the split slices!"); return; } // If we had a non-empty partition previously, set up the state for // subsequent partitions. if (P.SI != P.SJ) { // Accumulate all the splittable slices which started in the old // partition into the split list. for (Slice &S : P) if (S.isSplittable() && S.endOffset() > P.EndOffset) { P.SplitTails.push_back(&S); MaxSplitSliceEndOffset = std::max(S.endOffset(), MaxSplitSliceEndOffset); } // Start from the end of the previous partition. P.SI = P.SJ; // If P.SI is now at the end, we at most have a tail of split slices. if (P.SI == SE) { P.BeginOffset = P.EndOffset; P.EndOffset = MaxSplitSliceEndOffset; return; } // If the we have split slices and the next slice is after a gap and is // not splittable immediately form an empty partition for the split // slices up until the next slice begins. if (!P.SplitTails.empty() && P.SI->beginOffset() != P.EndOffset && !P.SI->isSplittable()) { P.BeginOffset = P.EndOffset; P.EndOffset = P.SI->beginOffset(); return; } } // OK, we need to consume new slices. Set the end offset based on the // current slice, and step SJ past it. The beginning offset of the // partition is the beginning offset of the next slice unless we have // pre-existing split slices that are continuing, in which case we begin // at the prior end offset. P.BeginOffset = P.SplitTails.empty() ? P.SI->beginOffset() : P.EndOffset; P.EndOffset = P.SI->endOffset(); ++P.SJ; // There are two strategies to form a partition based on whether the // partition starts with an unsplittable slice or a splittable slice. if (!P.SI->isSplittable()) { // When we're forming an unsplittable region, it must always start at // the first slice and will extend through its end. assert(P.BeginOffset == P.SI->beginOffset()); // Form a partition including all of the overlapping slices with this // unsplittable slice. while (P.SJ != SE && P.SJ->beginOffset() < P.EndOffset) { if (!P.SJ->isSplittable()) P.EndOffset = std::max(P.EndOffset, P.SJ->endOffset()); ++P.SJ; } // We have a partition across a set of overlapping unsplittable // partitions. return; } // If we're starting with a splittable slice, then we need to form // a synthetic partition spanning it and any other overlapping splittable // splices. assert(P.SI->isSplittable() && "Forming a splittable partition!"); // Collect all of the overlapping splittable slices. while (P.SJ != SE && P.SJ->beginOffset() < P.EndOffset && P.SJ->isSplittable()) { P.EndOffset = std::max(P.EndOffset, P.SJ->endOffset()); ++P.SJ; } // Back upiP.EndOffset if we ended the span early when encountering an // unsplittable slice. This synthesizes the early end offset of // a partition spanning only splittable slices. if (P.SJ != SE && P.SJ->beginOffset() < P.EndOffset) { assert(!P.SJ->isSplittable()); P.EndOffset = P.SJ->beginOffset(); } } public: bool operator==(const partition_iterator &RHS) const { assert(SE == RHS.SE && "End iterators don't match between compared partition iterators!"); // The observed positions of partitions is marked by the P.SI iterator and // the emptiness of the split slices. The latter is only relevant when // P.SI == SE, as the end iterator will additionally have an empty split // slices list, but the prior may have the same P.SI and a tail of split // slices. if (P.SI == RHS.P.SI && P.SplitTails.empty() == RHS.P.SplitTails.empty()) { assert(P.SJ == RHS.P.SJ && "Same set of slices formed two different sized partitions!"); assert(P.SplitTails.size() == RHS.P.SplitTails.size() && "Same slice position with differently sized non-empty split " "slice tails!"); return true; } return false; } partition_iterator &operator++() { advance(); return *this; } Partition &operator*() { return P; } }; /// A forward range over the partitions of the alloca's slices. /// /// This accesses an iterator range over the partitions of the alloca's /// slices. It computes these partitions on the fly based on the overlapping /// offsets of the slices and the ability to split them. It will visit "empty" /// partitions to cover regions of the alloca only accessed via split /// slices. iterator_range AllocaSlices::partitions() { return make_range(partition_iterator(begin(), end()), partition_iterator(end(), end())); } static Value *foldSelectInst(SelectInst &SI) { // If the condition being selected on is a constant or the same value is // being selected between, fold the select. Yes this does (rarely) happen // early on. if (ConstantInt *CI = dyn_cast(SI.getCondition())) return SI.getOperand(1 + CI->isZero()); if (SI.getOperand(1) == SI.getOperand(2)) return SI.getOperand(1); return nullptr; } /// A helper that folds a PHI node or a select. static Value *foldPHINodeOrSelectInst(Instruction &I) { if (PHINode *PN = dyn_cast(&I)) { // If PN merges together the same value, return that value. return PN->hasConstantValue(); } return foldSelectInst(cast(I)); } /// Builder for the alloca slices. /// /// This class builds a set of alloca slices by recursively visiting the uses /// of an alloca and making a slice for each load and store at each offset. class AllocaSlices::SliceBuilder : public PtrUseVisitor { friend class PtrUseVisitor; friend class InstVisitor; using Base = PtrUseVisitor; const uint64_t AllocSize; AllocaSlices &AS; SmallDenseMap MemTransferSliceMap; SmallDenseMap PHIOrSelectSizes; /// Set to de-duplicate dead instructions found in the use walk. SmallPtrSet VisitedDeadInsts; public: SliceBuilder(const DataLayout &DL, AllocaInst &AI, AllocaSlices &AS) : PtrUseVisitor(DL), AllocSize(DL.getTypeAllocSize(AI.getAllocatedType())), AS(AS) {} private: void markAsDead(Instruction &I) { if (VisitedDeadInsts.insert(&I).second) AS.DeadUsers.push_back(&I); } void insertUse(Instruction &I, const APInt &Offset, uint64_t Size, bool IsSplittable = false) { // Completely skip uses which have a zero size or start either before or // past the end of the allocation. if (Size == 0 || Offset.uge(AllocSize)) { LLVM_DEBUG(dbgs() << "WARNING: Ignoring " << Size << " byte use @" << Offset << " which has zero size or starts outside of the " << AllocSize << " byte alloca:\n" << " alloca: " << AS.AI << "\n" << " use: " << I << "\n"); return markAsDead(I); } uint64_t BeginOffset = Offset.getZExtValue(); uint64_t EndOffset = BeginOffset + Size; // Clamp the end offset to the end of the allocation. Note that this is // formulated to handle even the case where "BeginOffset + Size" overflows. // This may appear superficially to be something we could ignore entirely, // but that is not so! There may be widened loads or PHI-node uses where // some instructions are dead but not others. We can't completely ignore // them, and so have to record at least the information here. assert(AllocSize >= BeginOffset); // Established above. if (Size > AllocSize - BeginOffset) { LLVM_DEBUG(dbgs() << "WARNING: Clamping a " << Size << " byte use @" << Offset << " to remain within the " << AllocSize << " byte alloca:\n" << " alloca: " << AS.AI << "\n" << " use: " << I << "\n"); EndOffset = AllocSize; } AS.Slices.push_back(Slice(BeginOffset, EndOffset, U, IsSplittable)); } void visitBitCastInst(BitCastInst &BC) { if (BC.use_empty()) return markAsDead(BC); return Base::visitBitCastInst(BC); } void visitAddrSpaceCastInst(AddrSpaceCastInst &ASC) { if (ASC.use_empty()) return markAsDead(ASC); return Base::visitAddrSpaceCastInst(ASC); } void visitGetElementPtrInst(GetElementPtrInst &GEPI) { if (GEPI.use_empty()) return markAsDead(GEPI); if (SROAStrictInbounds && GEPI.isInBounds()) { // FIXME: This is a manually un-factored variant of the basic code inside // of GEPs with checking of the inbounds invariant specified in the // langref in a very strict sense. If we ever want to enable // SROAStrictInbounds, this code should be factored cleanly into // PtrUseVisitor, but it is easier to experiment with SROAStrictInbounds // by writing out the code here where we have the underlying allocation // size readily available. APInt GEPOffset = Offset; const DataLayout &DL = GEPI.getModule()->getDataLayout(); for (gep_type_iterator GTI = gep_type_begin(GEPI), GTE = gep_type_end(GEPI); GTI != GTE; ++GTI) { ConstantInt *OpC = dyn_cast(GTI.getOperand()); if (!OpC) break; // Handle a struct index, which adds its field offset to the pointer. if (StructType *STy = GTI.getStructTypeOrNull()) { unsigned ElementIdx = OpC->getZExtValue(); const StructLayout *SL = DL.getStructLayout(STy); GEPOffset += APInt(Offset.getBitWidth(), SL->getElementOffset(ElementIdx)); } else { // For array or vector indices, scale the index by the size of the // type. APInt Index = OpC->getValue().sextOrTrunc(Offset.getBitWidth()); GEPOffset += Index * APInt(Offset.getBitWidth(), DL.getTypeAllocSize(GTI.getIndexedType())); } // If this index has computed an intermediate pointer which is not // inbounds, then the result of the GEP is a poison value and we can // delete it and all uses. if (GEPOffset.ugt(AllocSize)) return markAsDead(GEPI); } } return Base::visitGetElementPtrInst(GEPI); } void handleLoadOrStore(Type *Ty, Instruction &I, const APInt &Offset, uint64_t Size, bool IsVolatile) { // We allow splitting of non-volatile loads and stores where the type is an // integer type. These may be used to implement 'memcpy' or other "transfer // of bits" patterns. bool IsSplittable = Ty->isIntegerTy() && !IsVolatile; insertUse(I, Offset, Size, IsSplittable); } void visitLoadInst(LoadInst &LI) { assert((!LI.isSimple() || LI.getType()->isSingleValueType()) && "All simple FCA loads should have been pre-split"); if (!IsOffsetKnown) return PI.setAborted(&LI); if (LI.isVolatile() && LI.getPointerAddressSpace() != DL.getAllocaAddrSpace()) return PI.setAborted(&LI); uint64_t Size = DL.getTypeStoreSize(LI.getType()); return handleLoadOrStore(LI.getType(), LI, Offset, Size, LI.isVolatile()); } void visitStoreInst(StoreInst &SI) { Value *ValOp = SI.getValueOperand(); if (ValOp == *U) return PI.setEscapedAndAborted(&SI); if (!IsOffsetKnown) return PI.setAborted(&SI); if (SI.isVolatile() && SI.getPointerAddressSpace() != DL.getAllocaAddrSpace()) return PI.setAborted(&SI); uint64_t Size = DL.getTypeStoreSize(ValOp->getType()); // If this memory access can be shown to *statically* extend outside the // bounds of the allocation, it's behavior is undefined, so simply // ignore it. Note that this is more strict than the generic clamping // behavior of insertUse. We also try to handle cases which might run the // risk of overflow. // FIXME: We should instead consider the pointer to have escaped if this // function is being instrumented for addressing bugs or race conditions. if (Size > AllocSize || Offset.ugt(AllocSize - Size)) { LLVM_DEBUG(dbgs() << "WARNING: Ignoring " << Size << " byte store @" << Offset << " which extends past the end of the " << AllocSize << " byte alloca:\n" << " alloca: " << AS.AI << "\n" << " use: " << SI << "\n"); return markAsDead(SI); } assert((!SI.isSimple() || ValOp->getType()->isSingleValueType()) && "All simple FCA stores should have been pre-split"); handleLoadOrStore(ValOp->getType(), SI, Offset, Size, SI.isVolatile()); } void visitMemSetInst(MemSetInst &II) { assert(II.getRawDest() == *U && "Pointer use is not the destination?"); ConstantInt *Length = dyn_cast(II.getLength()); if ((Length && Length->getValue() == 0) || (IsOffsetKnown && Offset.uge(AllocSize))) // Zero-length mem transfer intrinsics can be ignored entirely. return markAsDead(II); if (!IsOffsetKnown) return PI.setAborted(&II); // Don't replace this with a store with a different address space. TODO: // Use a store with the casted new alloca? if (II.isVolatile() && II.getDestAddressSpace() != DL.getAllocaAddrSpace()) return PI.setAborted(&II); insertUse(II, Offset, Length ? Length->getLimitedValue() : AllocSize - Offset.getLimitedValue(), (bool)Length); } void visitMemTransferInst(MemTransferInst &II) { ConstantInt *Length = dyn_cast(II.getLength()); if (Length && Length->getValue() == 0) // Zero-length mem transfer intrinsics can be ignored entirely. return markAsDead(II); // Because we can visit these intrinsics twice, also check to see if the // first time marked this instruction as dead. If so, skip it. if (VisitedDeadInsts.count(&II)) return; if (!IsOffsetKnown) return PI.setAborted(&II); // Don't replace this with a load/store with a different address space. // TODO: Use a store with the casted new alloca? if (II.isVolatile() && (II.getDestAddressSpace() != DL.getAllocaAddrSpace() || II.getSourceAddressSpace() != DL.getAllocaAddrSpace())) return PI.setAborted(&II); // This side of the transfer is completely out-of-bounds, and so we can // nuke the entire transfer. However, we also need to nuke the other side // if already added to our partitions. // FIXME: Yet another place we really should bypass this when // instrumenting for ASan. if (Offset.uge(AllocSize)) { SmallDenseMap::iterator MTPI = MemTransferSliceMap.find(&II); if (MTPI != MemTransferSliceMap.end()) AS.Slices[MTPI->second].kill(); return markAsDead(II); } uint64_t RawOffset = Offset.getLimitedValue(); uint64_t Size = Length ? Length->getLimitedValue() : AllocSize - RawOffset; // Check for the special case where the same exact value is used for both // source and dest. if (*U == II.getRawDest() && *U == II.getRawSource()) { // For non-volatile transfers this is a no-op. if (!II.isVolatile()) return markAsDead(II); return insertUse(II, Offset, Size, /*IsSplittable=*/false); } // If we have seen both source and destination for a mem transfer, then // they both point to the same alloca. bool Inserted; SmallDenseMap::iterator MTPI; std::tie(MTPI, Inserted) = MemTransferSliceMap.insert(std::make_pair(&II, AS.Slices.size())); unsigned PrevIdx = MTPI->second; if (!Inserted) { Slice &PrevP = AS.Slices[PrevIdx]; // Check if the begin offsets match and this is a non-volatile transfer. // In that case, we can completely elide the transfer. if (!II.isVolatile() && PrevP.beginOffset() == RawOffset) { PrevP.kill(); return markAsDead(II); } // Otherwise we have an offset transfer within the same alloca. We can't // split those. PrevP.makeUnsplittable(); } // Insert the use now that we've fixed up the splittable nature. insertUse(II, Offset, Size, /*IsSplittable=*/Inserted && Length); // Check that we ended up with a valid index in the map. assert(AS.Slices[PrevIdx].getUse()->getUser() == &II && "Map index doesn't point back to a slice with this user."); } // Disable SRoA for any intrinsics except for lifetime invariants. // FIXME: What about debug intrinsics? This matches old behavior, but // doesn't make sense. void visitIntrinsicInst(IntrinsicInst &II) { if (!IsOffsetKnown) return PI.setAborted(&II); if (II.isLifetimeStartOrEnd()) { ConstantInt *Length = cast(II.getArgOperand(0)); uint64_t Size = std::min(AllocSize - Offset.getLimitedValue(), Length->getLimitedValue()); insertUse(II, Offset, Size, true); return; } Base::visitIntrinsicInst(II); } Instruction *hasUnsafePHIOrSelectUse(Instruction *Root, uint64_t &Size) { // We consider any PHI or select that results in a direct load or store of // the same offset to be a viable use for slicing purposes. These uses // are considered unsplittable and the size is the maximum loaded or stored // size. SmallPtrSet Visited; SmallVector, 4> Uses; Visited.insert(Root); Uses.push_back(std::make_pair(cast(*U), Root)); const DataLayout &DL = Root->getModule()->getDataLayout(); // If there are no loads or stores, the access is dead. We mark that as // a size zero access. Size = 0; do { Instruction *I, *UsedI; std::tie(UsedI, I) = Uses.pop_back_val(); if (LoadInst *LI = dyn_cast(I)) { Size = std::max(Size, DL.getTypeStoreSize(LI->getType()).getFixedSize()); continue; } if (StoreInst *SI = dyn_cast(I)) { Value *Op = SI->getOperand(0); if (Op == UsedI) return SI; Size = std::max(Size, DL.getTypeStoreSize(Op->getType()).getFixedSize()); continue; } if (GetElementPtrInst *GEP = dyn_cast(I)) { if (!GEP->hasAllZeroIndices()) return GEP; } else if (!isa(I) && !isa(I) && !isa(I) && !isa(I)) { return I; } for (User *U : I->users()) if (Visited.insert(cast(U)).second) Uses.push_back(std::make_pair(I, cast(U))); } while (!Uses.empty()); return nullptr; } void visitPHINodeOrSelectInst(Instruction &I) { assert(isa(I) || isa(I)); if (I.use_empty()) return markAsDead(I); // TODO: We could use SimplifyInstruction here to fold PHINodes and // SelectInsts. However, doing so requires to change the current // dead-operand-tracking mechanism. For instance, suppose neither loading // from %U nor %other traps. Then "load (select undef, %U, %other)" does not // trap either. However, if we simply replace %U with undef using the // current dead-operand-tracking mechanism, "load (select undef, undef, // %other)" may trap because the select may return the first operand // "undef". if (Value *Result = foldPHINodeOrSelectInst(I)) { if (Result == *U) // If the result of the constant fold will be the pointer, recurse // through the PHI/select as if we had RAUW'ed it. enqueueUsers(I); else // Otherwise the operand to the PHI/select is dead, and we can replace // it with undef. AS.DeadOperands.push_back(U); return; } if (!IsOffsetKnown) return PI.setAborted(&I); // See if we already have computed info on this node. uint64_t &Size = PHIOrSelectSizes[&I]; if (!Size) { // This is a new PHI/Select, check for an unsafe use of it. if (Instruction *UnsafeI = hasUnsafePHIOrSelectUse(&I, Size)) return PI.setAborted(UnsafeI); } // For PHI and select operands outside the alloca, we can't nuke the entire // phi or select -- the other side might still be relevant, so we special // case them here and use a separate structure to track the operands // themselves which should be replaced with undef. // FIXME: This should instead be escaped in the event we're instrumenting // for address sanitization. if (Offset.uge(AllocSize)) { AS.DeadOperands.push_back(U); return; } insertUse(I, Offset, Size); } void visitPHINode(PHINode &PN) { visitPHINodeOrSelectInst(PN); } void visitSelectInst(SelectInst &SI) { visitPHINodeOrSelectInst(SI); } /// Disable SROA entirely if there are unhandled users of the alloca. void visitInstruction(Instruction &I) { PI.setAborted(&I); } }; AllocaSlices::AllocaSlices(const DataLayout &DL, AllocaInst &AI) : #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) AI(AI), #endif PointerEscapingInstr(nullptr) { SliceBuilder PB(DL, AI, *this); SliceBuilder::PtrInfo PtrI = PB.visitPtr(AI); if (PtrI.isEscaped() || PtrI.isAborted()) { // FIXME: We should sink the escape vs. abort info into the caller nicely, // possibly by just storing the PtrInfo in the AllocaSlices. PointerEscapingInstr = PtrI.getEscapingInst() ? PtrI.getEscapingInst() : PtrI.getAbortingInst(); assert(PointerEscapingInstr && "Did not track a bad instruction"); return; } Slices.erase( llvm::remove_if(Slices, [](const Slice &S) { return S.isDead(); }), Slices.end()); #ifndef NDEBUG if (SROARandomShuffleSlices) { std::mt19937 MT(static_cast( std::chrono::system_clock::now().time_since_epoch().count())); std::shuffle(Slices.begin(), Slices.end(), MT); } #endif // Sort the uses. This arranges for the offsets to be in ascending order, // and the sizes to be in descending order. llvm::sort(Slices); } #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) void AllocaSlices::print(raw_ostream &OS, const_iterator I, StringRef Indent) const { printSlice(OS, I, Indent); OS << "\n"; printUse(OS, I, Indent); } void AllocaSlices::printSlice(raw_ostream &OS, const_iterator I, StringRef Indent) const { OS << Indent << "[" << I->beginOffset() << "," << I->endOffset() << ")" << " slice #" << (I - begin()) << (I->isSplittable() ? " (splittable)" : ""); } void AllocaSlices::printUse(raw_ostream &OS, const_iterator I, StringRef Indent) const { OS << Indent << " used by: " << *I->getUse()->getUser() << "\n"; } void AllocaSlices::print(raw_ostream &OS) const { if (PointerEscapingInstr) { OS << "Can't analyze slices for alloca: " << AI << "\n" << " A pointer to this alloca escaped by:\n" << " " << *PointerEscapingInstr << "\n"; return; } OS << "Slices of alloca: " << AI << "\n"; for (const_iterator I = begin(), E = end(); I != E; ++I) print(OS, I); } LLVM_DUMP_METHOD void AllocaSlices::dump(const_iterator I) const { print(dbgs(), I); } LLVM_DUMP_METHOD void AllocaSlices::dump() const { print(dbgs()); } #endif // !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) /// Walk the range of a partitioning looking for a common type to cover this /// sequence of slices. static Type *findCommonType(AllocaSlices::const_iterator B, AllocaSlices::const_iterator E, uint64_t EndOffset) { Type *Ty = nullptr; bool TyIsCommon = true; IntegerType *ITy = nullptr; // Note that we need to look at *every* alloca slice's Use to ensure we // always get consistent results regardless of the order of slices. for (AllocaSlices::const_iterator I = B; I != E; ++I) { Use *U = I->getUse(); if (isa(*U->getUser())) continue; if (I->beginOffset() != B->beginOffset() || I->endOffset() != EndOffset) continue; Type *UserTy = nullptr; if (LoadInst *LI = dyn_cast(U->getUser())) { UserTy = LI->getType(); } else if (StoreInst *SI = dyn_cast(U->getUser())) { UserTy = SI->getValueOperand()->getType(); } if (IntegerType *UserITy = dyn_cast_or_null(UserTy)) { // If the type is larger than the partition, skip it. We only encounter // this for split integer operations where we want to use the type of the // entity causing the split. Also skip if the type is not a byte width // multiple. if (UserITy->getBitWidth() % 8 != 0 || UserITy->getBitWidth() / 8 > (EndOffset - B->beginOffset())) continue; // Track the largest bitwidth integer type used in this way in case there // is no common type. if (!ITy || ITy->getBitWidth() < UserITy->getBitWidth()) ITy = UserITy; } // To avoid depending on the order of slices, Ty and TyIsCommon must not // depend on types skipped above. if (!UserTy || (Ty && Ty != UserTy)) TyIsCommon = false; // Give up on anything but an iN type. else Ty = UserTy; } return TyIsCommon ? Ty : ITy; } /// PHI instructions that use an alloca and are subsequently loaded can be /// rewritten to load both input pointers in the pred blocks and then PHI the /// results, allowing the load of the alloca to be promoted. /// From this: /// %P2 = phi [i32* %Alloca, i32* %Other] /// %V = load i32* %P2 /// to: /// %V1 = load i32* %Alloca -> will be mem2reg'd /// ... /// %V2 = load i32* %Other /// ... /// %V = phi [i32 %V1, i32 %V2] /// /// We can do this to a select if its only uses are loads and if the operands /// to the select can be loaded unconditionally. /// /// FIXME: This should be hoisted into a generic utility, likely in /// Transforms/Util/Local.h static bool isSafePHIToSpeculate(PHINode &PN) { const DataLayout &DL = PN.getModule()->getDataLayout(); // For now, we can only do this promotion if the load is in the same block // as the PHI, and if there are no stores between the phi and load. // TODO: Allow recursive phi users. // TODO: Allow stores. BasicBlock *BB = PN.getParent(); MaybeAlign MaxAlign; uint64_t APWidth = DL.getIndexTypeSizeInBits(PN.getType()); APInt MaxSize(APWidth, 0); bool HaveLoad = false; for (User *U : PN.users()) { LoadInst *LI = dyn_cast(U); if (!LI || !LI->isSimple()) return false; // For now we only allow loads in the same block as the PHI. This is // a common case that happens when instcombine merges two loads through // a PHI. if (LI->getParent() != BB) return false; // Ensure that there are no instructions between the PHI and the load that // could store. for (BasicBlock::iterator BBI(PN); &*BBI != LI; ++BBI) if (BBI->mayWriteToMemory()) return false; uint64_t Size = DL.getTypeStoreSize(LI->getType()); MaxAlign = std::max(MaxAlign, MaybeAlign(LI->getAlignment())); MaxSize = MaxSize.ult(Size) ? APInt(APWidth, Size) : MaxSize; HaveLoad = true; } if (!HaveLoad) return false; // We can only transform this if it is safe to push the loads into the // predecessor blocks. The only thing to watch out for is that we can't put // a possibly trapping load in the predecessor if it is a critical edge. for (unsigned Idx = 0, Num = PN.getNumIncomingValues(); Idx != Num; ++Idx) { Instruction *TI = PN.getIncomingBlock(Idx)->getTerminator(); Value *InVal = PN.getIncomingValue(Idx); // If the value is produced by the terminator of the predecessor (an // invoke) or it has side-effects, there is no valid place to put a load // in the predecessor. if (TI == InVal || TI->mayHaveSideEffects()) return false; // If the predecessor has a single successor, then the edge isn't // critical. if (TI->getNumSuccessors() == 1) continue; // If this pointer is always safe to load, or if we can prove that there // is already a load in the block, then we can move the load to the pred // block. if (isSafeToLoadUnconditionally(InVal, MaxAlign, MaxSize, DL, TI)) continue; return false; } return true; } static void speculatePHINodeLoads(PHINode &PN) { LLVM_DEBUG(dbgs() << " original: " << PN << "\n"); LoadInst *SomeLoad = cast(PN.user_back()); Type *LoadTy = SomeLoad->getType(); IRBuilderTy PHIBuilder(&PN); PHINode *NewPN = PHIBuilder.CreatePHI(LoadTy, PN.getNumIncomingValues(), PN.getName() + ".sroa.speculated"); // Get the AA tags and alignment to use from one of the loads. It does not // matter which one we get and if any differ. AAMDNodes AATags; SomeLoad->getAAMetadata(AATags); const MaybeAlign Align = MaybeAlign(SomeLoad->getAlignment()); // Rewrite all loads of the PN to use the new PHI. while (!PN.use_empty()) { LoadInst *LI = cast(PN.user_back()); LI->replaceAllUsesWith(NewPN); LI->eraseFromParent(); } // Inject loads into all of the pred blocks. DenseMap InjectedLoads; for (unsigned Idx = 0, Num = PN.getNumIncomingValues(); Idx != Num; ++Idx) { BasicBlock *Pred = PN.getIncomingBlock(Idx); Value *InVal = PN.getIncomingValue(Idx); // A PHI node is allowed to have multiple (duplicated) entries for the same // basic block, as long as the value is the same. So if we already injected // a load in the predecessor, then we should reuse the same load for all // duplicated entries. if (Value* V = InjectedLoads.lookup(Pred)) { NewPN->addIncoming(V, Pred); continue; } Instruction *TI = Pred->getTerminator(); IRBuilderTy PredBuilder(TI); LoadInst *Load = PredBuilder.CreateLoad( LoadTy, InVal, (PN.getName() + ".sroa.speculate.load." + Pred->getName())); ++NumLoadsSpeculated; Load->setAlignment(Align); if (AATags) Load->setAAMetadata(AATags); NewPN->addIncoming(Load, Pred); InjectedLoads[Pred] = Load; } LLVM_DEBUG(dbgs() << " speculated to: " << *NewPN << "\n"); PN.eraseFromParent(); } /// Select instructions that use an alloca and are subsequently loaded can be /// rewritten to load both input pointers and then select between the result, /// allowing the load of the alloca to be promoted. /// From this: /// %P2 = select i1 %cond, i32* %Alloca, i32* %Other /// %V = load i32* %P2 /// to: /// %V1 = load i32* %Alloca -> will be mem2reg'd /// %V2 = load i32* %Other /// %V = select i1 %cond, i32 %V1, i32 %V2 /// /// We can do this to a select if its only uses are loads and if the operand /// to the select can be loaded unconditionally. static bool isSafeSelectToSpeculate(SelectInst &SI) { Value *TValue = SI.getTrueValue(); Value *FValue = SI.getFalseValue(); const DataLayout &DL = SI.getModule()->getDataLayout(); for (User *U : SI.users()) { LoadInst *LI = dyn_cast(U); if (!LI || !LI->isSimple()) return false; // Both operands to the select need to be dereferenceable, either // absolutely (e.g. allocas) or at this point because we can see other // accesses to it. if (!isSafeToLoadUnconditionally(TValue, LI->getType(), MaybeAlign(LI->getAlignment()), DL, LI)) return false; if (!isSafeToLoadUnconditionally(FValue, LI->getType(), MaybeAlign(LI->getAlignment()), DL, LI)) return false; } return true; } static void speculateSelectInstLoads(SelectInst &SI) { LLVM_DEBUG(dbgs() << " original: " << SI << "\n"); IRBuilderTy IRB(&SI); Value *TV = SI.getTrueValue(); Value *FV = SI.getFalseValue(); // Replace the loads of the select with a select of two loads. while (!SI.use_empty()) { LoadInst *LI = cast(SI.user_back()); assert(LI->isSimple() && "We only speculate simple loads"); IRB.SetInsertPoint(LI); LoadInst *TL = IRB.CreateLoad(LI->getType(), TV, LI->getName() + ".sroa.speculate.load.true"); LoadInst *FL = IRB.CreateLoad(LI->getType(), FV, LI->getName() + ".sroa.speculate.load.false"); NumLoadsSpeculated += 2; // Transfer alignment and AA info if present. TL->setAlignment(MaybeAlign(LI->getAlignment())); FL->setAlignment(MaybeAlign(LI->getAlignment())); AAMDNodes Tags; LI->getAAMetadata(Tags); if (Tags) { TL->setAAMetadata(Tags); FL->setAAMetadata(Tags); } Value *V = IRB.CreateSelect(SI.getCondition(), TL, FL, LI->getName() + ".sroa.speculated"); LLVM_DEBUG(dbgs() << " speculated to: " << *V << "\n"); LI->replaceAllUsesWith(V); LI->eraseFromParent(); } SI.eraseFromParent(); } /// Build a GEP out of a base pointer and indices. /// /// This will return the BasePtr if that is valid, or build a new GEP /// instruction using the IRBuilder if GEP-ing is needed. static Value *buildGEP(IRBuilderTy &IRB, Value *BasePtr, SmallVectorImpl &Indices, Twine NamePrefix) { if (Indices.empty()) return BasePtr; // A single zero index is a no-op, so check for this and avoid building a GEP // in that case. if (Indices.size() == 1 && cast(Indices.back())->isZero()) return BasePtr; return IRB.CreateInBoundsGEP(BasePtr->getType()->getPointerElementType(), BasePtr, Indices, NamePrefix + "sroa_idx"); } /// Get a natural GEP off of the BasePtr walking through Ty toward /// TargetTy without changing the offset of the pointer. /// /// This routine assumes we've already established a properly offset GEP with /// Indices, and arrived at the Ty type. The goal is to continue to GEP with /// zero-indices down through type layers until we find one the same as /// TargetTy. If we can't find one with the same type, we at least try to use /// one with the same size. If none of that works, we just produce the GEP as /// indicated by Indices to have the correct offset. static Value *getNaturalGEPWithType(IRBuilderTy &IRB, const DataLayout &DL, Value *BasePtr, Type *Ty, Type *TargetTy, SmallVectorImpl &Indices, Twine NamePrefix) { if (Ty == TargetTy) return buildGEP(IRB, BasePtr, Indices, NamePrefix); // Offset size to use for the indices. unsigned OffsetSize = DL.getIndexTypeSizeInBits(BasePtr->getType()); // See if we can descend into a struct and locate a field with the correct // type. unsigned NumLayers = 0; Type *ElementTy = Ty; do { if (ElementTy->isPointerTy()) break; if (ArrayType *ArrayTy = dyn_cast(ElementTy)) { ElementTy = ArrayTy->getElementType(); Indices.push_back(IRB.getIntN(OffsetSize, 0)); } else if (VectorType *VectorTy = dyn_cast(ElementTy)) { ElementTy = VectorTy->getElementType(); Indices.push_back(IRB.getInt32(0)); } else if (StructType *STy = dyn_cast(ElementTy)) { if (STy->element_begin() == STy->element_end()) break; // Nothing left to descend into. ElementTy = *STy->element_begin(); Indices.push_back(IRB.getInt32(0)); } else { break; } ++NumLayers; } while (ElementTy != TargetTy); if (ElementTy != TargetTy) Indices.erase(Indices.end() - NumLayers, Indices.end()); return buildGEP(IRB, BasePtr, Indices, NamePrefix); } /// Recursively compute indices for a natural GEP. /// /// This is the recursive step for getNaturalGEPWithOffset that walks down the /// element types adding appropriate indices for the GEP. static Value *getNaturalGEPRecursively(IRBuilderTy &IRB, const DataLayout &DL, Value *Ptr, Type *Ty, APInt &Offset, Type *TargetTy, SmallVectorImpl &Indices, Twine NamePrefix) { if (Offset == 0) return getNaturalGEPWithType(IRB, DL, Ptr, Ty, TargetTy, Indices, NamePrefix); // We can't recurse through pointer types. if (Ty->isPointerTy()) return nullptr; // We try to analyze GEPs over vectors here, but note that these GEPs are // extremely poorly defined currently. The long-term goal is to remove GEPing // over a vector from the IR completely. if (VectorType *VecTy = dyn_cast(Ty)) { unsigned ElementSizeInBits = DL.getTypeSizeInBits(VecTy->getScalarType()); if (ElementSizeInBits % 8 != 0) { // GEPs over non-multiple of 8 size vector elements are invalid. return nullptr; } APInt ElementSize(Offset.getBitWidth(), ElementSizeInBits / 8); APInt NumSkippedElements = Offset.sdiv(ElementSize); if (NumSkippedElements.ugt(VecTy->getNumElements())) return nullptr; Offset -= NumSkippedElements * ElementSize; Indices.push_back(IRB.getInt(NumSkippedElements)); return getNaturalGEPRecursively(IRB, DL, Ptr, VecTy->getElementType(), Offset, TargetTy, Indices, NamePrefix); } if (ArrayType *ArrTy = dyn_cast(Ty)) { Type *ElementTy = ArrTy->getElementType(); APInt ElementSize(Offset.getBitWidth(), DL.getTypeAllocSize(ElementTy)); APInt NumSkippedElements = Offset.sdiv(ElementSize); if (NumSkippedElements.ugt(ArrTy->getNumElements())) return nullptr; Offset -= NumSkippedElements * ElementSize; Indices.push_back(IRB.getInt(NumSkippedElements)); return getNaturalGEPRecursively(IRB, DL, Ptr, ElementTy, Offset, TargetTy, Indices, NamePrefix); } StructType *STy = dyn_cast(Ty); if (!STy) return nullptr; const StructLayout *SL = DL.getStructLayout(STy); uint64_t StructOffset = Offset.getZExtValue(); if (StructOffset >= SL->getSizeInBytes()) return nullptr; unsigned Index = SL->getElementContainingOffset(StructOffset); Offset -= APInt(Offset.getBitWidth(), SL->getElementOffset(Index)); Type *ElementTy = STy->getElementType(Index); if (Offset.uge(DL.getTypeAllocSize(ElementTy))) return nullptr; // The offset points into alignment padding. Indices.push_back(IRB.getInt32(Index)); return getNaturalGEPRecursively(IRB, DL, Ptr, ElementTy, Offset, TargetTy, Indices, NamePrefix); } /// Get a natural GEP from a base pointer to a particular offset and /// resulting in a particular type. /// /// The goal is to produce a "natural" looking GEP that works with the existing /// composite types to arrive at the appropriate offset and element type for /// a pointer. TargetTy is the element type the returned GEP should point-to if /// possible. We recurse by decreasing Offset, adding the appropriate index to /// Indices, and setting Ty to the result subtype. /// /// If no natural GEP can be constructed, this function returns null. static Value *getNaturalGEPWithOffset(IRBuilderTy &IRB, const DataLayout &DL, Value *Ptr, APInt Offset, Type *TargetTy, SmallVectorImpl &Indices, Twine NamePrefix) { PointerType *Ty = cast(Ptr->getType()); // Don't consider any GEPs through an i8* as natural unless the TargetTy is // an i8. if (Ty == IRB.getInt8PtrTy(Ty->getAddressSpace()) && TargetTy->isIntegerTy(8)) return nullptr; Type *ElementTy = Ty->getElementType(); if (!ElementTy->isSized()) return nullptr; // We can't GEP through an unsized element. APInt ElementSize(Offset.getBitWidth(), DL.getTypeAllocSize(ElementTy)); if (ElementSize == 0) return nullptr; // Zero-length arrays can't help us build a natural GEP. APInt NumSkippedElements = Offset.sdiv(ElementSize); Offset -= NumSkippedElements * ElementSize; Indices.push_back(IRB.getInt(NumSkippedElements)); return getNaturalGEPRecursively(IRB, DL, Ptr, ElementTy, Offset, TargetTy, Indices, NamePrefix); } /// Compute an adjusted pointer from Ptr by Offset bytes where the /// resulting pointer has PointerTy. /// /// This tries very hard to compute a "natural" GEP which arrives at the offset /// and produces the pointer type desired. Where it cannot, it will try to use /// the natural GEP to arrive at the offset and bitcast to the type. Where that /// fails, it will try to use an existing i8* and GEP to the byte offset and /// bitcast to the type. /// /// The strategy for finding the more natural GEPs is to peel off layers of the /// pointer, walking back through bit casts and GEPs, searching for a base /// pointer from which we can compute a natural GEP with the desired /// properties. The algorithm tries to fold as many constant indices into /// a single GEP as possible, thus making each GEP more independent of the /// surrounding code. static Value *getAdjustedPtr(IRBuilderTy &IRB, const DataLayout &DL, Value *Ptr, APInt Offset, Type *PointerTy, Twine NamePrefix) { // Even though we don't look through PHI nodes, we could be called on an // instruction in an unreachable block, which may be on a cycle. SmallPtrSet Visited; Visited.insert(Ptr); SmallVector Indices; // We may end up computing an offset pointer that has the wrong type. If we // never are able to compute one directly that has the correct type, we'll // fall back to it, so keep it and the base it was computed from around here. Value *OffsetPtr = nullptr; Value *OffsetBasePtr; // Remember any i8 pointer we come across to re-use if we need to do a raw // byte offset. Value *Int8Ptr = nullptr; APInt Int8PtrOffset(Offset.getBitWidth(), 0); PointerType *TargetPtrTy = cast(PointerTy); Type *TargetTy = TargetPtrTy->getElementType(); // As `addrspacecast` is , `Ptr` (the storage pointer) may have different // address space from the expected `PointerTy` (the pointer to be used). // Adjust the pointer type based the original storage pointer. auto AS = cast(Ptr->getType())->getAddressSpace(); PointerTy = TargetTy->getPointerTo(AS); do { // First fold any existing GEPs into the offset. while (GEPOperator *GEP = dyn_cast(Ptr)) { APInt GEPOffset(Offset.getBitWidth(), 0); if (!GEP->accumulateConstantOffset(DL, GEPOffset)) break; Offset += GEPOffset; Ptr = GEP->getPointerOperand(); if (!Visited.insert(Ptr).second) break; } // See if we can perform a natural GEP here. Indices.clear(); if (Value *P = getNaturalGEPWithOffset(IRB, DL, Ptr, Offset, TargetTy, Indices, NamePrefix)) { // If we have a new natural pointer at the offset, clear out any old // offset pointer we computed. Unless it is the base pointer or // a non-instruction, we built a GEP we don't need. Zap it. if (OffsetPtr && OffsetPtr != OffsetBasePtr) if (Instruction *I = dyn_cast(OffsetPtr)) { assert(I->use_empty() && "Built a GEP with uses some how!"); I->eraseFromParent(); } OffsetPtr = P; OffsetBasePtr = Ptr; // If we also found a pointer of the right type, we're done. if (P->getType() == PointerTy) break; } // Stash this pointer if we've found an i8*. if (Ptr->getType()->isIntegerTy(8)) { Int8Ptr = Ptr; Int8PtrOffset = Offset; } // Peel off a layer of the pointer and update the offset appropriately. if (Operator::getOpcode(Ptr) == Instruction::BitCast) { Ptr = cast(Ptr)->getOperand(0); } else if (GlobalAlias *GA = dyn_cast(Ptr)) { if (GA->isInterposable()) break; Ptr = GA->getAliasee(); } else { break; } assert(Ptr->getType()->isPointerTy() && "Unexpected operand type!"); } while (Visited.insert(Ptr).second); if (!OffsetPtr) { if (!Int8Ptr) { Int8Ptr = IRB.CreateBitCast( Ptr, IRB.getInt8PtrTy(PointerTy->getPointerAddressSpace()), NamePrefix + "sroa_raw_cast"); Int8PtrOffset = Offset; } OffsetPtr = Int8PtrOffset == 0 ? Int8Ptr : IRB.CreateInBoundsGEP(IRB.getInt8Ty(), Int8Ptr, IRB.getInt(Int8PtrOffset), NamePrefix + "sroa_raw_idx"); } Ptr = OffsetPtr; // On the off chance we were targeting i8*, guard the bitcast here. if (cast(Ptr->getType()) != TargetPtrTy) { Ptr = IRB.CreatePointerBitCastOrAddrSpaceCast(Ptr, TargetPtrTy, NamePrefix + "sroa_cast"); } return Ptr; } /// Compute the adjusted alignment for a load or store from an offset. static Align getAdjustedAlignment(Instruction *I, uint64_t Offset, const DataLayout &DL) { MaybeAlign Alignment; Type *Ty; if (auto *LI = dyn_cast(I)) { Alignment = MaybeAlign(LI->getAlignment()); Ty = LI->getType(); } else if (auto *SI = dyn_cast(I)) { Alignment = MaybeAlign(SI->getAlignment()); Ty = SI->getValueOperand()->getType(); } else { llvm_unreachable("Only loads and stores are allowed!"); } return commonAlignment(DL.getValueOrABITypeAlignment(Alignment, Ty), Offset); } /// Test whether we can convert a value from the old to the new type. /// /// This predicate should be used to guard calls to convertValue in order to /// ensure that we only try to convert viable values. The strategy is that we /// will peel off single element struct and array wrappings to get to an /// underlying value, and convert that value. static bool canConvertValue(const DataLayout &DL, Type *OldTy, Type *NewTy) { if (OldTy == NewTy) return true; // For integer types, we can't handle any bit-width differences. This would // break both vector conversions with extension and introduce endianness // issues when in conjunction with loads and stores. if (isa(OldTy) && isa(NewTy)) { assert(cast(OldTy)->getBitWidth() != cast(NewTy)->getBitWidth() && "We can't have the same bitwidth for different int types"); return false; } if (DL.getTypeSizeInBits(NewTy) != DL.getTypeSizeInBits(OldTy)) return false; if (!NewTy->isSingleValueType() || !OldTy->isSingleValueType()) return false; // We can convert pointers to integers and vice-versa. Same for vectors // of pointers and integers. OldTy = OldTy->getScalarType(); NewTy = NewTy->getScalarType(); if (NewTy->isPointerTy() || OldTy->isPointerTy()) { if (NewTy->isPointerTy() && OldTy->isPointerTy()) { return cast(NewTy)->getPointerAddressSpace() == cast(OldTy)->getPointerAddressSpace(); } // We can convert integers to integral pointers, but not to non-integral // pointers. if (OldTy->isIntegerTy()) return !DL.isNonIntegralPointerType(NewTy); // We can convert integral pointers to integers, but non-integral pointers // need to remain pointers. if (!DL.isNonIntegralPointerType(OldTy)) return NewTy->isIntegerTy(); return false; } return true; } /// Generic routine to convert an SSA value to a value of a different /// type. /// /// This will try various different casting techniques, such as bitcasts, /// inttoptr, and ptrtoint casts. Use the \c canConvertValue predicate to test /// two types for viability with this routine. static Value *convertValue(const DataLayout &DL, IRBuilderTy &IRB, Value *V, Type *NewTy) { Type *OldTy = V->getType(); assert(canConvertValue(DL, OldTy, NewTy) && "Value not convertable to type"); if (OldTy == NewTy) return V; assert(!(isa(OldTy) && isa(NewTy)) && "Integer types must be the exact same to convert."); // See if we need inttoptr for this type pair. A cast involving both scalars // and vectors requires and additional bitcast. if (OldTy->isIntOrIntVectorTy() && NewTy->isPtrOrPtrVectorTy()) { // Expand <2 x i32> to i8* --> <2 x i32> to i64 to i8* if (OldTy->isVectorTy() && !NewTy->isVectorTy()) return IRB.CreateIntToPtr(IRB.CreateBitCast(V, DL.getIntPtrType(NewTy)), NewTy); // Expand i128 to <2 x i8*> --> i128 to <2 x i64> to <2 x i8*> if (!OldTy->isVectorTy() && NewTy->isVectorTy()) return IRB.CreateIntToPtr(IRB.CreateBitCast(V, DL.getIntPtrType(NewTy)), NewTy); return IRB.CreateIntToPtr(V, NewTy); } // See if we need ptrtoint for this type pair. A cast involving both scalars // and vectors requires and additional bitcast. if (OldTy->isPtrOrPtrVectorTy() && NewTy->isIntOrIntVectorTy()) { // Expand <2 x i8*> to i128 --> <2 x i8*> to <2 x i64> to i128 if (OldTy->isVectorTy() && !NewTy->isVectorTy()) return IRB.CreateBitCast(IRB.CreatePtrToInt(V, DL.getIntPtrType(OldTy)), NewTy); // Expand i8* to <2 x i32> --> i8* to i64 to <2 x i32> if (!OldTy->isVectorTy() && NewTy->isVectorTy()) return IRB.CreateBitCast(IRB.CreatePtrToInt(V, DL.getIntPtrType(OldTy)), NewTy); return IRB.CreatePtrToInt(V, NewTy); } return IRB.CreateBitCast(V, NewTy); } /// Test whether the given slice use can be promoted to a vector. /// /// This function is called to test each entry in a partition which is slated /// for a single slice. static bool isVectorPromotionViableForSlice(Partition &P, const Slice &S, VectorType *Ty, uint64_t ElementSize, const DataLayout &DL) { // First validate the slice offsets. uint64_t BeginOffset = std::max(S.beginOffset(), P.beginOffset()) - P.beginOffset(); uint64_t BeginIndex = BeginOffset / ElementSize; if (BeginIndex * ElementSize != BeginOffset || BeginIndex >= Ty->getNumElements()) return false; uint64_t EndOffset = std::min(S.endOffset(), P.endOffset()) - P.beginOffset(); uint64_t EndIndex = EndOffset / ElementSize; if (EndIndex * ElementSize != EndOffset || EndIndex > Ty->getNumElements()) return false; assert(EndIndex > BeginIndex && "Empty vector!"); uint64_t NumElements = EndIndex - BeginIndex; Type *SliceTy = (NumElements == 1) ? Ty->getElementType() : VectorType::get(Ty->getElementType(), NumElements); Type *SplitIntTy = Type::getIntNTy(Ty->getContext(), NumElements * ElementSize * 8); Use *U = S.getUse(); if (MemIntrinsic *MI = dyn_cast(U->getUser())) { if (MI->isVolatile()) return false; if (!S.isSplittable()) return false; // Skip any unsplittable intrinsics. } else if (IntrinsicInst *II = dyn_cast(U->getUser())) { if (!II->isLifetimeStartOrEnd()) return false; } else if (U->get()->getType()->getPointerElementType()->isStructTy()) { // Disable vector promotion when there are loads or stores of an FCA. return false; } else if (LoadInst *LI = dyn_cast(U->getUser())) { if (LI->isVolatile()) return false; Type *LTy = LI->getType(); if (P.beginOffset() > S.beginOffset() || P.endOffset() < S.endOffset()) { assert(LTy->isIntegerTy()); LTy = SplitIntTy; } if (!canConvertValue(DL, SliceTy, LTy)) return false; } else if (StoreInst *SI = dyn_cast(U->getUser())) { if (SI->isVolatile()) return false; Type *STy = SI->getValueOperand()->getType(); if (P.beginOffset() > S.beginOffset() || P.endOffset() < S.endOffset()) { assert(STy->isIntegerTy()); STy = SplitIntTy; } if (!canConvertValue(DL, STy, SliceTy)) return false; } else { return false; } return true; } /// Test whether the given alloca partitioning and range of slices can be /// promoted to a vector. /// /// This is a quick test to check whether we can rewrite a particular alloca /// partition (and its newly formed alloca) into a vector alloca with only /// whole-vector loads and stores such that it could be promoted to a vector /// SSA value. We only can ensure this for a limited set of operations, and we /// don't want to do the rewrites unless we are confident that the result will /// be promotable, so we have an early test here. static VectorType *isVectorPromotionViable(Partition &P, const DataLayout &DL) { // Collect the candidate types for vector-based promotion. Also track whether // we have different element types. SmallVector CandidateTys; Type *CommonEltTy = nullptr; bool HaveCommonEltTy = true; auto CheckCandidateType = [&](Type *Ty) { if (auto *VTy = dyn_cast(Ty)) { // Return if bitcast to vectors is different for total size in bits. if (!CandidateTys.empty()) { VectorType *V = CandidateTys[0]; if (DL.getTypeSizeInBits(VTy) != DL.getTypeSizeInBits(V)) { CandidateTys.clear(); return; } } CandidateTys.push_back(VTy); if (!CommonEltTy) CommonEltTy = VTy->getElementType(); else if (CommonEltTy != VTy->getElementType()) HaveCommonEltTy = false; } }; // Consider any loads or stores that are the exact size of the slice. for (const Slice &S : P) if (S.beginOffset() == P.beginOffset() && S.endOffset() == P.endOffset()) { if (auto *LI = dyn_cast(S.getUse()->getUser())) CheckCandidateType(LI->getType()); else if (auto *SI = dyn_cast(S.getUse()->getUser())) CheckCandidateType(SI->getValueOperand()->getType()); } // If we didn't find a vector type, nothing to do here. if (CandidateTys.empty()) return nullptr; // Remove non-integer vector types if we had multiple common element types. // FIXME: It'd be nice to replace them with integer vector types, but we can't // do that until all the backends are known to produce good code for all // integer vector types. if (!HaveCommonEltTy) { CandidateTys.erase( llvm::remove_if(CandidateTys, [](VectorType *VTy) { return !VTy->getElementType()->isIntegerTy(); }), CandidateTys.end()); // If there were no integer vector types, give up. if (CandidateTys.empty()) return nullptr; // Rank the remaining candidate vector types. This is easy because we know // they're all integer vectors. We sort by ascending number of elements. auto RankVectorTypes = [&DL](VectorType *RHSTy, VectorType *LHSTy) { (void)DL; assert(DL.getTypeSizeInBits(RHSTy) == DL.getTypeSizeInBits(LHSTy) && "Cannot have vector types of different sizes!"); assert(RHSTy->getElementType()->isIntegerTy() && "All non-integer types eliminated!"); assert(LHSTy->getElementType()->isIntegerTy() && "All non-integer types eliminated!"); return RHSTy->getNumElements() < LHSTy->getNumElements(); }; llvm::sort(CandidateTys, RankVectorTypes); CandidateTys.erase( std::unique(CandidateTys.begin(), CandidateTys.end(), RankVectorTypes), CandidateTys.end()); } else { // The only way to have the same element type in every vector type is to // have the same vector type. Check that and remove all but one. #ifndef NDEBUG for (VectorType *VTy : CandidateTys) { assert(VTy->getElementType() == CommonEltTy && "Unaccounted for element type!"); assert(VTy == CandidateTys[0] && "Different vector types with the same element type!"); } #endif CandidateTys.resize(1); } // Try each vector type, and return the one which works. auto CheckVectorTypeForPromotion = [&](VectorType *VTy) { uint64_t ElementSize = DL.getTypeSizeInBits(VTy->getElementType()); // While the definition of LLVM vectors is bitpacked, we don't support sizes // that aren't byte sized. if (ElementSize % 8) return false; assert((DL.getTypeSizeInBits(VTy) % 8) == 0 && "vector size not a multiple of element size?"); ElementSize /= 8; for (const Slice &S : P) if (!isVectorPromotionViableForSlice(P, S, VTy, ElementSize, DL)) return false; for (const Slice *S : P.splitSliceTails()) if (!isVectorPromotionViableForSlice(P, *S, VTy, ElementSize, DL)) return false; return true; }; for (VectorType *VTy : CandidateTys) if (CheckVectorTypeForPromotion(VTy)) return VTy; return nullptr; } /// Test whether a slice of an alloca is valid for integer widening. /// /// This implements the necessary checking for the \c isIntegerWideningViable /// test below on a single slice of the alloca. static bool isIntegerWideningViableForSlice(const Slice &S, uint64_t AllocBeginOffset, Type *AllocaTy, const DataLayout &DL, bool &WholeAllocaOp) { uint64_t Size = DL.getTypeStoreSize(AllocaTy); uint64_t RelBegin = S.beginOffset() - AllocBeginOffset; uint64_t RelEnd = S.endOffset() - AllocBeginOffset; // We can't reasonably handle cases where the load or store extends past // the end of the alloca's type and into its padding. if (RelEnd > Size) return false; Use *U = S.getUse(); if (LoadInst *LI = dyn_cast(U->getUser())) { if (LI->isVolatile()) return false; // We can't handle loads that extend past the allocated memory. if (DL.getTypeStoreSize(LI->getType()) > Size) return false; // So far, AllocaSliceRewriter does not support widening split slice tails // in rewriteIntegerLoad. if (S.beginOffset() < AllocBeginOffset) return false; // Note that we don't count vector loads or stores as whole-alloca // operations which enable integer widening because we would prefer to use // vector widening instead. if (!isa(LI->getType()) && RelBegin == 0 && RelEnd == Size) WholeAllocaOp = true; if (IntegerType *ITy = dyn_cast(LI->getType())) { if (ITy->getBitWidth() < DL.getTypeStoreSizeInBits(ITy)) return false; } else if (RelBegin != 0 || RelEnd != Size || !canConvertValue(DL, AllocaTy, LI->getType())) { // Non-integer loads need to be convertible from the alloca type so that // they are promotable. return false; } } else if (StoreInst *SI = dyn_cast(U->getUser())) { Type *ValueTy = SI->getValueOperand()->getType(); if (SI->isVolatile()) return false; // We can't handle stores that extend past the allocated memory. if (DL.getTypeStoreSize(ValueTy) > Size) return false; // So far, AllocaSliceRewriter does not support widening split slice tails // in rewriteIntegerStore. if (S.beginOffset() < AllocBeginOffset) return false; // Note that we don't count vector loads or stores as whole-alloca // operations which enable integer widening because we would prefer to use // vector widening instead. if (!isa(ValueTy) && RelBegin == 0 && RelEnd == Size) WholeAllocaOp = true; if (IntegerType *ITy = dyn_cast(ValueTy)) { if (ITy->getBitWidth() < DL.getTypeStoreSizeInBits(ITy)) return false; } else if (RelBegin != 0 || RelEnd != Size || !canConvertValue(DL, ValueTy, AllocaTy)) { // Non-integer stores need to be convertible to the alloca type so that // they are promotable. return false; } } else if (MemIntrinsic *MI = dyn_cast(U->getUser())) { if (MI->isVolatile() || !isa(MI->getLength())) return false; if (!S.isSplittable()) return false; // Skip any unsplittable intrinsics. } else if (IntrinsicInst *II = dyn_cast(U->getUser())) { if (!II->isLifetimeStartOrEnd()) return false; } else { return false; } return true; } /// Test whether the given alloca partition's integer operations can be /// widened to promotable ones. /// /// This is a quick test to check whether we can rewrite the integer loads and /// stores to a particular alloca into wider loads and stores and be able to /// promote the resulting alloca. static bool isIntegerWideningViable(Partition &P, Type *AllocaTy, const DataLayout &DL) { uint64_t SizeInBits = DL.getTypeSizeInBits(AllocaTy); // Don't create integer types larger than the maximum bitwidth. if (SizeInBits > IntegerType::MAX_INT_BITS) return false; // Don't try to handle allocas with bit-padding. if (SizeInBits != DL.getTypeStoreSizeInBits(AllocaTy)) return false; // We need to ensure that an integer type with the appropriate bitwidth can // be converted to the alloca type, whatever that is. We don't want to force // the alloca itself to have an integer type if there is a more suitable one. Type *IntTy = Type::getIntNTy(AllocaTy->getContext(), SizeInBits); if (!canConvertValue(DL, AllocaTy, IntTy) || !canConvertValue(DL, IntTy, AllocaTy)) return false; // While examining uses, we ensure that the alloca has a covering load or // store. We don't want to widen the integer operations only to fail to // promote due to some other unsplittable entry (which we may make splittable // later). However, if there are only splittable uses, go ahead and assume // that we cover the alloca. // FIXME: We shouldn't consider split slices that happen to start in the // partition here... bool WholeAllocaOp = P.begin() != P.end() ? false : DL.isLegalInteger(SizeInBits); for (const Slice &S : P) if (!isIntegerWideningViableForSlice(S, P.beginOffset(), AllocaTy, DL, WholeAllocaOp)) return false; for (const Slice *S : P.splitSliceTails()) if (!isIntegerWideningViableForSlice(*S, P.beginOffset(), AllocaTy, DL, WholeAllocaOp)) return false; return WholeAllocaOp; } static Value *extractInteger(const DataLayout &DL, IRBuilderTy &IRB, Value *V, IntegerType *Ty, uint64_t Offset, const Twine &Name) { LLVM_DEBUG(dbgs() << " start: " << *V << "\n"); IntegerType *IntTy = cast(V->getType()); assert(DL.getTypeStoreSize(Ty) + Offset <= DL.getTypeStoreSize(IntTy) && "Element extends past full value"); uint64_t ShAmt = 8 * Offset; if (DL.isBigEndian()) ShAmt = 8 * (DL.getTypeStoreSize(IntTy) - DL.getTypeStoreSize(Ty) - Offset); if (ShAmt) { V = IRB.CreateLShr(V, ShAmt, Name + ".shift"); LLVM_DEBUG(dbgs() << " shifted: " << *V << "\n"); } assert(Ty->getBitWidth() <= IntTy->getBitWidth() && "Cannot extract to a larger integer!"); if (Ty != IntTy) { V = IRB.CreateTrunc(V, Ty, Name + ".trunc"); LLVM_DEBUG(dbgs() << " trunced: " << *V << "\n"); } return V; } static Value *insertInteger(const DataLayout &DL, IRBuilderTy &IRB, Value *Old, Value *V, uint64_t Offset, const Twine &Name) { IntegerType *IntTy = cast(Old->getType()); IntegerType *Ty = cast(V->getType()); assert(Ty->getBitWidth() <= IntTy->getBitWidth() && "Cannot insert a larger integer!"); LLVM_DEBUG(dbgs() << " start: " << *V << "\n"); if (Ty != IntTy) { V = IRB.CreateZExt(V, IntTy, Name + ".ext"); LLVM_DEBUG(dbgs() << " extended: " << *V << "\n"); } assert(DL.getTypeStoreSize(Ty) + Offset <= DL.getTypeStoreSize(IntTy) && "Element store outside of alloca store"); uint64_t ShAmt = 8 * Offset; if (DL.isBigEndian()) ShAmt = 8 * (DL.getTypeStoreSize(IntTy) - DL.getTypeStoreSize(Ty) - Offset); if (ShAmt) { V = IRB.CreateShl(V, ShAmt, Name + ".shift"); LLVM_DEBUG(dbgs() << " shifted: " << *V << "\n"); } if (ShAmt || Ty->getBitWidth() < IntTy->getBitWidth()) { APInt Mask = ~Ty->getMask().zext(IntTy->getBitWidth()).shl(ShAmt); Old = IRB.CreateAnd(Old, Mask, Name + ".mask"); LLVM_DEBUG(dbgs() << " masked: " << *Old << "\n"); V = IRB.CreateOr(Old, V, Name + ".insert"); LLVM_DEBUG(dbgs() << " inserted: " << *V << "\n"); } return V; } static Value *extractVector(IRBuilderTy &IRB, Value *V, unsigned BeginIndex, unsigned EndIndex, const Twine &Name) { VectorType *VecTy = cast(V->getType()); unsigned NumElements = EndIndex - BeginIndex; assert(NumElements <= VecTy->getNumElements() && "Too many elements!"); if (NumElements == VecTy->getNumElements()) return V; if (NumElements == 1) { V = IRB.CreateExtractElement(V, IRB.getInt32(BeginIndex), Name + ".extract"); LLVM_DEBUG(dbgs() << " extract: " << *V << "\n"); return V; } SmallVector Mask; Mask.reserve(NumElements); for (unsigned i = BeginIndex; i != EndIndex; ++i) Mask.push_back(IRB.getInt32(i)); V = IRB.CreateShuffleVector(V, UndefValue::get(V->getType()), ConstantVector::get(Mask), Name + ".extract"); LLVM_DEBUG(dbgs() << " shuffle: " << *V << "\n"); return V; } static Value *insertVector(IRBuilderTy &IRB, Value *Old, Value *V, unsigned BeginIndex, const Twine &Name) { VectorType *VecTy = cast(Old->getType()); assert(VecTy && "Can only insert a vector into a vector"); VectorType *Ty = dyn_cast(V->getType()); if (!Ty) { // Single element to insert. V = IRB.CreateInsertElement(Old, V, IRB.getInt32(BeginIndex), Name + ".insert"); LLVM_DEBUG(dbgs() << " insert: " << *V << "\n"); return V; } assert(Ty->getNumElements() <= VecTy->getNumElements() && "Too many elements!"); if (Ty->getNumElements() == VecTy->getNumElements()) { assert(V->getType() == VecTy && "Vector type mismatch"); return V; } unsigned EndIndex = BeginIndex + Ty->getNumElements(); // When inserting a smaller vector into the larger to store, we first // use a shuffle vector to widen it with undef elements, and then // a second shuffle vector to select between the loaded vector and the // incoming vector. SmallVector Mask; Mask.reserve(VecTy->getNumElements()); for (unsigned i = 0; i != VecTy->getNumElements(); ++i) if (i >= BeginIndex && i < EndIndex) Mask.push_back(IRB.getInt32(i - BeginIndex)); else Mask.push_back(UndefValue::get(IRB.getInt32Ty())); V = IRB.CreateShuffleVector(V, UndefValue::get(V->getType()), ConstantVector::get(Mask), Name + ".expand"); LLVM_DEBUG(dbgs() << " shuffle: " << *V << "\n"); Mask.clear(); for (unsigned i = 0; i != VecTy->getNumElements(); ++i) Mask.push_back(IRB.getInt1(i >= BeginIndex && i < EndIndex)); V = IRB.CreateSelect(ConstantVector::get(Mask), V, Old, Name + "blend"); LLVM_DEBUG(dbgs() << " blend: " << *V << "\n"); return V; } /// Visitor to rewrite instructions using p particular slice of an alloca /// to use a new alloca. /// /// Also implements the rewriting to vector-based accesses when the partition /// passes the isVectorPromotionViable predicate. Most of the rewriting logic /// lives here. class llvm::sroa::AllocaSliceRewriter : public InstVisitor { // Befriend the base class so it can delegate to private visit methods. friend class InstVisitor; using Base = InstVisitor; const DataLayout &DL; AllocaSlices &AS; SROA &Pass; AllocaInst &OldAI, &NewAI; const uint64_t NewAllocaBeginOffset, NewAllocaEndOffset; Type *NewAllocaTy; // This is a convenience and flag variable that will be null unless the new // alloca's integer operations should be widened to this integer type due to // passing isIntegerWideningViable above. If it is non-null, the desired // integer type will be stored here for easy access during rewriting. IntegerType *IntTy; // If we are rewriting an alloca partition which can be written as pure // vector operations, we stash extra information here. When VecTy is // non-null, we have some strict guarantees about the rewritten alloca: // - The new alloca is exactly the size of the vector type here. // - The accesses all either map to the entire vector or to a single // element. // - The set of accessing instructions is only one of those handled above // in isVectorPromotionViable. Generally these are the same access kinds // which are promotable via mem2reg. VectorType *VecTy; Type *ElementTy; uint64_t ElementSize; // The original offset of the slice currently being rewritten relative to // the original alloca. uint64_t BeginOffset = 0; uint64_t EndOffset = 0; // The new offsets of the slice currently being rewritten relative to the // original alloca. uint64_t NewBeginOffset = 0, NewEndOffset = 0; uint64_t SliceSize = 0; bool IsSplittable = false; bool IsSplit = false; Use *OldUse = nullptr; Instruction *OldPtr = nullptr; // Track post-rewrite users which are PHI nodes and Selects. SmallSetVector &PHIUsers; SmallSetVector &SelectUsers; // Utility IR builder, whose name prefix is setup for each visited use, and // the insertion point is set to point to the user. IRBuilderTy IRB; public: AllocaSliceRewriter(const DataLayout &DL, AllocaSlices &AS, SROA &Pass, AllocaInst &OldAI, AllocaInst &NewAI, uint64_t NewAllocaBeginOffset, uint64_t NewAllocaEndOffset, bool IsIntegerPromotable, VectorType *PromotableVecTy, SmallSetVector &PHIUsers, SmallSetVector &SelectUsers) : DL(DL), AS(AS), Pass(Pass), OldAI(OldAI), NewAI(NewAI), NewAllocaBeginOffset(NewAllocaBeginOffset), NewAllocaEndOffset(NewAllocaEndOffset), NewAllocaTy(NewAI.getAllocatedType()), IntTy(IsIntegerPromotable ? Type::getIntNTy( NewAI.getContext(), DL.getTypeSizeInBits(NewAI.getAllocatedType())) : nullptr), VecTy(PromotableVecTy), ElementTy(VecTy ? VecTy->getElementType() : nullptr), ElementSize(VecTy ? DL.getTypeSizeInBits(ElementTy) / 8 : 0), PHIUsers(PHIUsers), SelectUsers(SelectUsers), IRB(NewAI.getContext(), ConstantFolder()) { if (VecTy) { assert((DL.getTypeSizeInBits(ElementTy) % 8) == 0 && "Only multiple-of-8 sized vector elements are viable"); ++NumVectorized; } assert((!IntTy && !VecTy) || (IntTy && !VecTy) || (!IntTy && VecTy)); } bool visit(AllocaSlices::const_iterator I) { bool CanSROA = true; BeginOffset = I->beginOffset(); EndOffset = I->endOffset(); IsSplittable = I->isSplittable(); IsSplit = BeginOffset < NewAllocaBeginOffset || EndOffset > NewAllocaEndOffset; LLVM_DEBUG(dbgs() << " rewriting " << (IsSplit ? "split " : "")); LLVM_DEBUG(AS.printSlice(dbgs(), I, "")); LLVM_DEBUG(dbgs() << "\n"); // Compute the intersecting offset range. assert(BeginOffset < NewAllocaEndOffset); assert(EndOffset > NewAllocaBeginOffset); NewBeginOffset = std::max(BeginOffset, NewAllocaBeginOffset); NewEndOffset = std::min(EndOffset, NewAllocaEndOffset); SliceSize = NewEndOffset - NewBeginOffset; OldUse = I->getUse(); OldPtr = cast(OldUse->get()); Instruction *OldUserI = cast(OldUse->getUser()); IRB.SetInsertPoint(OldUserI); IRB.SetCurrentDebugLocation(OldUserI->getDebugLoc()); IRB.SetNamePrefix(Twine(NewAI.getName()) + "." + Twine(BeginOffset) + "."); CanSROA &= visit(cast(OldUse->getUser())); if (VecTy || IntTy) assert(CanSROA); return CanSROA; } private: // Make sure the other visit overloads are visible. using Base::visit; // Every instruction which can end up as a user must have a rewrite rule. bool visitInstruction(Instruction &I) { LLVM_DEBUG(dbgs() << " !!!! Cannot rewrite: " << I << "\n"); llvm_unreachable("No rewrite rule for this instruction!"); } Value *getNewAllocaSlicePtr(IRBuilderTy &IRB, Type *PointerTy) { // Note that the offset computation can use BeginOffset or NewBeginOffset // interchangeably for unsplit slices. assert(IsSplit || BeginOffset == NewBeginOffset); uint64_t Offset = NewBeginOffset - NewAllocaBeginOffset; #ifndef NDEBUG StringRef OldName = OldPtr->getName(); // Skip through the last '.sroa.' component of the name. size_t LastSROAPrefix = OldName.rfind(".sroa."); if (LastSROAPrefix != StringRef::npos) { OldName = OldName.substr(LastSROAPrefix + strlen(".sroa.")); // Look for an SROA slice index. size_t IndexEnd = OldName.find_first_not_of("0123456789"); if (IndexEnd != StringRef::npos && OldName[IndexEnd] == '.') { // Strip the index and look for the offset. OldName = OldName.substr(IndexEnd + 1); size_t OffsetEnd = OldName.find_first_not_of("0123456789"); if (OffsetEnd != StringRef::npos && OldName[OffsetEnd] == '.') // Strip the offset. OldName = OldName.substr(OffsetEnd + 1); } } // Strip any SROA suffixes as well. OldName = OldName.substr(0, OldName.find(".sroa_")); #endif return getAdjustedPtr(IRB, DL, &NewAI, APInt(DL.getIndexTypeSizeInBits(PointerTy), Offset), PointerTy, #ifndef NDEBUG Twine(OldName) + "." #else Twine() #endif ); } /// Compute suitable alignment to access this slice of the *new* /// alloca. /// /// You can optionally pass a type to this routine and if that type's ABI /// alignment is itself suitable, this will return zero. MaybeAlign getSliceAlign(Type *Ty = nullptr) { const MaybeAlign NewAIAlign = DL.getValueOrABITypeAlignment( MaybeAlign(NewAI.getAlignment()), NewAI.getAllocatedType()); const MaybeAlign Align = commonAlignment(NewAIAlign, NewBeginOffset - NewAllocaBeginOffset); return (Ty && Align && Align->value() == DL.getABITypeAlignment(Ty)) ? None : Align; } unsigned getIndex(uint64_t Offset) { assert(VecTy && "Can only call getIndex when rewriting a vector"); uint64_t RelOffset = Offset - NewAllocaBeginOffset; assert(RelOffset / ElementSize < UINT32_MAX && "Index out of bounds"); uint32_t Index = RelOffset / ElementSize; assert(Index * ElementSize == RelOffset); return Index; } void deleteIfTriviallyDead(Value *V) { Instruction *I = cast(V); if (isInstructionTriviallyDead(I)) Pass.DeadInsts.insert(I); } Value *rewriteVectorizedLoadInst() { unsigned BeginIndex = getIndex(NewBeginOffset); unsigned EndIndex = getIndex(NewEndOffset); assert(EndIndex > BeginIndex && "Empty vector!"); Value *V = IRB.CreateAlignedLoad(NewAI.getAllocatedType(), &NewAI, NewAI.getAlignment(), "load"); return extractVector(IRB, V, BeginIndex, EndIndex, "vec"); } Value *rewriteIntegerLoad(LoadInst &LI) { assert(IntTy && "We cannot insert an integer to the alloca"); assert(!LI.isVolatile()); Value *V = IRB.CreateAlignedLoad(NewAI.getAllocatedType(), &NewAI, NewAI.getAlignment(), "load"); V = convertValue(DL, IRB, V, IntTy); assert(NewBeginOffset >= NewAllocaBeginOffset && "Out of bounds offset"); uint64_t Offset = NewBeginOffset - NewAllocaBeginOffset; if (Offset > 0 || NewEndOffset < NewAllocaEndOffset) { IntegerType *ExtractTy = Type::getIntNTy(LI.getContext(), SliceSize * 8); V = extractInteger(DL, IRB, V, ExtractTy, Offset, "extract"); } // It is possible that the extracted type is not the load type. This // happens if there is a load past the end of the alloca, and as // a consequence the slice is narrower but still a candidate for integer // lowering. To handle this case, we just zero extend the extracted // integer. assert(cast(LI.getType())->getBitWidth() >= SliceSize * 8 && "Can only handle an extract for an overly wide load"); if (cast(LI.getType())->getBitWidth() > SliceSize * 8) V = IRB.CreateZExt(V, LI.getType()); return V; } bool visitLoadInst(LoadInst &LI) { LLVM_DEBUG(dbgs() << " original: " << LI << "\n"); Value *OldOp = LI.getOperand(0); assert(OldOp == OldPtr); AAMDNodes AATags; LI.getAAMetadata(AATags); unsigned AS = LI.getPointerAddressSpace(); Type *TargetTy = IsSplit ? Type::getIntNTy(LI.getContext(), SliceSize * 8) : LI.getType(); const bool IsLoadPastEnd = DL.getTypeStoreSize(TargetTy) > SliceSize; bool IsPtrAdjusted = false; Value *V; if (VecTy) { V = rewriteVectorizedLoadInst(); } else if (IntTy && LI.getType()->isIntegerTy()) { V = rewriteIntegerLoad(LI); } else if (NewBeginOffset == NewAllocaBeginOffset && NewEndOffset == NewAllocaEndOffset && (canConvertValue(DL, NewAllocaTy, TargetTy) || (IsLoadPastEnd && NewAllocaTy->isIntegerTy() && TargetTy->isIntegerTy()))) { LoadInst *NewLI = IRB.CreateAlignedLoad(NewAI.getAllocatedType(), &NewAI, NewAI.getAlignment(), LI.isVolatile(), LI.getName()); if (AATags) NewLI->setAAMetadata(AATags); if (LI.isVolatile()) NewLI->setAtomic(LI.getOrdering(), LI.getSyncScopeID()); + if (NewLI->isAtomic()) + NewLI->setAlignment(LI.getAlign()); // Any !nonnull metadata or !range metadata on the old load is also valid // on the new load. This is even true in some cases even when the loads // are different types, for example by mapping !nonnull metadata to // !range metadata by modeling the null pointer constant converted to the // integer type. // FIXME: Add support for range metadata here. Currently the utilities // for this don't propagate range metadata in trivial cases from one // integer load to another, don't handle non-addrspace-0 null pointers // correctly, and don't have any support for mapping ranges as the // integer type becomes winder or narrower. if (MDNode *N = LI.getMetadata(LLVMContext::MD_nonnull)) copyNonnullMetadata(LI, N, *NewLI); // Try to preserve nonnull metadata V = NewLI; // If this is an integer load past the end of the slice (which means the // bytes outside the slice are undef or this load is dead) just forcibly // fix the integer size with correct handling of endianness. if (auto *AITy = dyn_cast(NewAllocaTy)) if (auto *TITy = dyn_cast(TargetTy)) if (AITy->getBitWidth() < TITy->getBitWidth()) { V = IRB.CreateZExt(V, TITy, "load.ext"); if (DL.isBigEndian()) V = IRB.CreateShl(V, TITy->getBitWidth() - AITy->getBitWidth(), "endian_shift"); } } else { Type *LTy = TargetTy->getPointerTo(AS); LoadInst *NewLI = IRB.CreateAlignedLoad( TargetTy, getNewAllocaSlicePtr(IRB, LTy), getSliceAlign(TargetTy), LI.isVolatile(), LI.getName()); if (AATags) NewLI->setAAMetadata(AATags); if (LI.isVolatile()) NewLI->setAtomic(LI.getOrdering(), LI.getSyncScopeID()); V = NewLI; IsPtrAdjusted = true; } V = convertValue(DL, IRB, V, TargetTy); if (IsSplit) { assert(!LI.isVolatile()); assert(LI.getType()->isIntegerTy() && "Only integer type loads and stores are split"); assert(SliceSize < DL.getTypeStoreSize(LI.getType()) && "Split load isn't smaller than original load"); assert(DL.typeSizeEqualsStoreSize(LI.getType()) && "Non-byte-multiple bit width"); // Move the insertion point just past the load so that we can refer to it. IRB.SetInsertPoint(&*std::next(BasicBlock::iterator(&LI))); // Create a placeholder value with the same type as LI to use as the // basis for the new value. This allows us to replace the uses of LI with // the computed value, and then replace the placeholder with LI, leaving // LI only used for this computation. Value *Placeholder = new LoadInst( LI.getType(), UndefValue::get(LI.getType()->getPointerTo(AS))); V = insertInteger(DL, IRB, Placeholder, V, NewBeginOffset - BeginOffset, "insert"); LI.replaceAllUsesWith(V); Placeholder->replaceAllUsesWith(&LI); Placeholder->deleteValue(); } else { LI.replaceAllUsesWith(V); } Pass.DeadInsts.insert(&LI); deleteIfTriviallyDead(OldOp); LLVM_DEBUG(dbgs() << " to: " << *V << "\n"); return !LI.isVolatile() && !IsPtrAdjusted; } bool rewriteVectorizedStoreInst(Value *V, StoreInst &SI, Value *OldOp, AAMDNodes AATags) { if (V->getType() != VecTy) { unsigned BeginIndex = getIndex(NewBeginOffset); unsigned EndIndex = getIndex(NewEndOffset); assert(EndIndex > BeginIndex && "Empty vector!"); unsigned NumElements = EndIndex - BeginIndex; assert(NumElements <= VecTy->getNumElements() && "Too many elements!"); Type *SliceTy = (NumElements == 1) ? ElementTy : VectorType::get(ElementTy, NumElements); if (V->getType() != SliceTy) V = convertValue(DL, IRB, V, SliceTy); // Mix in the existing elements. Value *Old = IRB.CreateAlignedLoad(NewAI.getAllocatedType(), &NewAI, NewAI.getAlignment(), "load"); V = insertVector(IRB, Old, V, BeginIndex, "vec"); } StoreInst *Store = IRB.CreateAlignedStore(V, &NewAI, NewAI.getAlignment()); if (AATags) Store->setAAMetadata(AATags); Pass.DeadInsts.insert(&SI); LLVM_DEBUG(dbgs() << " to: " << *Store << "\n"); return true; } bool rewriteIntegerStore(Value *V, StoreInst &SI, AAMDNodes AATags) { assert(IntTy && "We cannot extract an integer from the alloca"); assert(!SI.isVolatile()); if (DL.getTypeSizeInBits(V->getType()) != IntTy->getBitWidth()) { Value *Old = IRB.CreateAlignedLoad(NewAI.getAllocatedType(), &NewAI, NewAI.getAlignment(), "oldload"); Old = convertValue(DL, IRB, Old, IntTy); assert(BeginOffset >= NewAllocaBeginOffset && "Out of bounds offset"); uint64_t Offset = BeginOffset - NewAllocaBeginOffset; V = insertInteger(DL, IRB, Old, SI.getValueOperand(), Offset, "insert"); } V = convertValue(DL, IRB, V, NewAllocaTy); StoreInst *Store = IRB.CreateAlignedStore(V, &NewAI, NewAI.getAlignment()); Store->copyMetadata(SI, {LLVMContext::MD_mem_parallel_loop_access, LLVMContext::MD_access_group}); if (AATags) Store->setAAMetadata(AATags); Pass.DeadInsts.insert(&SI); LLVM_DEBUG(dbgs() << " to: " << *Store << "\n"); return true; } bool visitStoreInst(StoreInst &SI) { LLVM_DEBUG(dbgs() << " original: " << SI << "\n"); Value *OldOp = SI.getOperand(1); assert(OldOp == OldPtr); AAMDNodes AATags; SI.getAAMetadata(AATags); Value *V = SI.getValueOperand(); // Strip all inbounds GEPs and pointer casts to try to dig out any root // alloca that should be re-examined after promoting this alloca. if (V->getType()->isPointerTy()) if (AllocaInst *AI = dyn_cast(V->stripInBoundsOffsets())) Pass.PostPromotionWorklist.insert(AI); if (SliceSize < DL.getTypeStoreSize(V->getType())) { assert(!SI.isVolatile()); assert(V->getType()->isIntegerTy() && "Only integer type loads and stores are split"); assert(DL.typeSizeEqualsStoreSize(V->getType()) && "Non-byte-multiple bit width"); IntegerType *NarrowTy = Type::getIntNTy(SI.getContext(), SliceSize * 8); V = extractInteger(DL, IRB, V, NarrowTy, NewBeginOffset - BeginOffset, "extract"); } if (VecTy) return rewriteVectorizedStoreInst(V, SI, OldOp, AATags); if (IntTy && V->getType()->isIntegerTy()) return rewriteIntegerStore(V, SI, AATags); const bool IsStorePastEnd = DL.getTypeStoreSize(V->getType()) > SliceSize; StoreInst *NewSI; if (NewBeginOffset == NewAllocaBeginOffset && NewEndOffset == NewAllocaEndOffset && (canConvertValue(DL, V->getType(), NewAllocaTy) || (IsStorePastEnd && NewAllocaTy->isIntegerTy() && V->getType()->isIntegerTy()))) { // If this is an integer store past the end of slice (and thus the bytes // past that point are irrelevant or this is unreachable), truncate the // value prior to storing. if (auto *VITy = dyn_cast(V->getType())) if (auto *AITy = dyn_cast(NewAllocaTy)) if (VITy->getBitWidth() > AITy->getBitWidth()) { if (DL.isBigEndian()) V = IRB.CreateLShr(V, VITy->getBitWidth() - AITy->getBitWidth(), "endian_shift"); V = IRB.CreateTrunc(V, AITy, "load.trunc"); } V = convertValue(DL, IRB, V, NewAllocaTy); NewSI = IRB.CreateAlignedStore(V, &NewAI, NewAI.getAlignment(), SI.isVolatile()); } else { unsigned AS = SI.getPointerAddressSpace(); Value *NewPtr = getNewAllocaSlicePtr(IRB, V->getType()->getPointerTo(AS)); NewSI = IRB.CreateAlignedStore(V, NewPtr, getSliceAlign(V->getType()), SI.isVolatile()); } NewSI->copyMetadata(SI, {LLVMContext::MD_mem_parallel_loop_access, LLVMContext::MD_access_group}); if (AATags) NewSI->setAAMetadata(AATags); if (SI.isVolatile()) NewSI->setAtomic(SI.getOrdering(), SI.getSyncScopeID()); + if (NewSI->isAtomic()) + NewSI->setAlignment(SI.getAlign()); Pass.DeadInsts.insert(&SI); deleteIfTriviallyDead(OldOp); LLVM_DEBUG(dbgs() << " to: " << *NewSI << "\n"); return NewSI->getPointerOperand() == &NewAI && !SI.isVolatile(); } /// Compute an integer value from splatting an i8 across the given /// number of bytes. /// /// Note that this routine assumes an i8 is a byte. If that isn't true, don't /// call this routine. /// FIXME: Heed the advice above. /// /// \param V The i8 value to splat. /// \param Size The number of bytes in the output (assuming i8 is one byte) Value *getIntegerSplat(Value *V, unsigned Size) { assert(Size > 0 && "Expected a positive number of bytes."); IntegerType *VTy = cast(V->getType()); assert(VTy->getBitWidth() == 8 && "Expected an i8 value for the byte"); if (Size == 1) return V; Type *SplatIntTy = Type::getIntNTy(VTy->getContext(), Size * 8); V = IRB.CreateMul( IRB.CreateZExt(V, SplatIntTy, "zext"), ConstantExpr::getUDiv( Constant::getAllOnesValue(SplatIntTy), ConstantExpr::getZExt(Constant::getAllOnesValue(V->getType()), SplatIntTy)), "isplat"); return V; } /// Compute a vector splat for a given element value. Value *getVectorSplat(Value *V, unsigned NumElements) { V = IRB.CreateVectorSplat(NumElements, V, "vsplat"); LLVM_DEBUG(dbgs() << " splat: " << *V << "\n"); return V; } bool visitMemSetInst(MemSetInst &II) { LLVM_DEBUG(dbgs() << " original: " << II << "\n"); assert(II.getRawDest() == OldPtr); AAMDNodes AATags; II.getAAMetadata(AATags); // If the memset has a variable size, it cannot be split, just adjust the // pointer to the new alloca. if (!isa(II.getLength())) { assert(!IsSplit); assert(NewBeginOffset == BeginOffset); II.setDest(getNewAllocaSlicePtr(IRB, OldPtr->getType())); II.setDestAlignment(getSliceAlign()); deleteIfTriviallyDead(OldPtr); return false; } // Record this instruction for deletion. Pass.DeadInsts.insert(&II); Type *AllocaTy = NewAI.getAllocatedType(); Type *ScalarTy = AllocaTy->getScalarType(); const bool CanContinue = [&]() { if (VecTy || IntTy) return true; if (BeginOffset > NewAllocaBeginOffset || EndOffset < NewAllocaEndOffset) return false; auto *C = cast(II.getLength()); if (C->getBitWidth() > 64) return false; const auto Len = C->getZExtValue(); auto *Int8Ty = IntegerType::getInt8Ty(NewAI.getContext()); auto *SrcTy = VectorType::get(Int8Ty, Len); return canConvertValue(DL, SrcTy, AllocaTy) && DL.isLegalInteger(DL.getTypeSizeInBits(ScalarTy)); }(); // If this doesn't map cleanly onto the alloca type, and that type isn't // a single value type, just emit a memset. if (!CanContinue) { Type *SizeTy = II.getLength()->getType(); Constant *Size = ConstantInt::get(SizeTy, NewEndOffset - NewBeginOffset); CallInst *New = IRB.CreateMemSet( getNewAllocaSlicePtr(IRB, OldPtr->getType()), II.getValue(), Size, MaybeAlign(getSliceAlign()), II.isVolatile()); if (AATags) New->setAAMetadata(AATags); LLVM_DEBUG(dbgs() << " to: " << *New << "\n"); return false; } // If we can represent this as a simple value, we have to build the actual // value to store, which requires expanding the byte present in memset to // a sensible representation for the alloca type. This is essentially // splatting the byte to a sufficiently wide integer, splatting it across // any desired vector width, and bitcasting to the final type. Value *V; if (VecTy) { // If this is a memset of a vectorized alloca, insert it. assert(ElementTy == ScalarTy); unsigned BeginIndex = getIndex(NewBeginOffset); unsigned EndIndex = getIndex(NewEndOffset); assert(EndIndex > BeginIndex && "Empty vector!"); unsigned NumElements = EndIndex - BeginIndex; assert(NumElements <= VecTy->getNumElements() && "Too many elements!"); Value *Splat = getIntegerSplat(II.getValue(), DL.getTypeSizeInBits(ElementTy) / 8); Splat = convertValue(DL, IRB, Splat, ElementTy); if (NumElements > 1) Splat = getVectorSplat(Splat, NumElements); Value *Old = IRB.CreateAlignedLoad(NewAI.getAllocatedType(), &NewAI, NewAI.getAlignment(), "oldload"); V = insertVector(IRB, Old, Splat, BeginIndex, "vec"); } else if (IntTy) { // If this is a memset on an alloca where we can widen stores, insert the // set integer. assert(!II.isVolatile()); uint64_t Size = NewEndOffset - NewBeginOffset; V = getIntegerSplat(II.getValue(), Size); if (IntTy && (BeginOffset != NewAllocaBeginOffset || EndOffset != NewAllocaBeginOffset)) { Value *Old = IRB.CreateAlignedLoad(NewAI.getAllocatedType(), &NewAI, NewAI.getAlignment(), "oldload"); Old = convertValue(DL, IRB, Old, IntTy); uint64_t Offset = NewBeginOffset - NewAllocaBeginOffset; V = insertInteger(DL, IRB, Old, V, Offset, "insert"); } else { assert(V->getType() == IntTy && "Wrong type for an alloca wide integer!"); } V = convertValue(DL, IRB, V, AllocaTy); } else { // Established these invariants above. assert(NewBeginOffset == NewAllocaBeginOffset); assert(NewEndOffset == NewAllocaEndOffset); V = getIntegerSplat(II.getValue(), DL.getTypeSizeInBits(ScalarTy) / 8); if (VectorType *AllocaVecTy = dyn_cast(AllocaTy)) V = getVectorSplat(V, AllocaVecTy->getNumElements()); V = convertValue(DL, IRB, V, AllocaTy); } StoreInst *New = IRB.CreateAlignedStore(V, &NewAI, NewAI.getAlignment(), II.isVolatile()); if (AATags) New->setAAMetadata(AATags); LLVM_DEBUG(dbgs() << " to: " << *New << "\n"); return !II.isVolatile(); } bool visitMemTransferInst(MemTransferInst &II) { // Rewriting of memory transfer instructions can be a bit tricky. We break // them into two categories: split intrinsics and unsplit intrinsics. LLVM_DEBUG(dbgs() << " original: " << II << "\n"); AAMDNodes AATags; II.getAAMetadata(AATags); bool IsDest = &II.getRawDestUse() == OldUse; assert((IsDest && II.getRawDest() == OldPtr) || (!IsDest && II.getRawSource() == OldPtr)); MaybeAlign SliceAlign = getSliceAlign(); // For unsplit intrinsics, we simply modify the source and destination // pointers in place. This isn't just an optimization, it is a matter of // correctness. With unsplit intrinsics we may be dealing with transfers // within a single alloca before SROA ran, or with transfers that have // a variable length. We may also be dealing with memmove instead of // memcpy, and so simply updating the pointers is the necessary for us to // update both source and dest of a single call. if (!IsSplittable) { Value *AdjustedPtr = getNewAllocaSlicePtr(IRB, OldPtr->getType()); if (IsDest) { II.setDest(AdjustedPtr); II.setDestAlignment(SliceAlign); } else { II.setSource(AdjustedPtr); II.setSourceAlignment(SliceAlign); } LLVM_DEBUG(dbgs() << " to: " << II << "\n"); deleteIfTriviallyDead(OldPtr); return false; } // For split transfer intrinsics we have an incredibly useful assurance: // the source and destination do not reside within the same alloca, and at // least one of them does not escape. This means that we can replace // memmove with memcpy, and we don't need to worry about all manner of // downsides to splitting and transforming the operations. // If this doesn't map cleanly onto the alloca type, and that type isn't // a single value type, just emit a memcpy. bool EmitMemCpy = !VecTy && !IntTy && (BeginOffset > NewAllocaBeginOffset || EndOffset < NewAllocaEndOffset || SliceSize != DL.getTypeStoreSize(NewAI.getAllocatedType()) || !NewAI.getAllocatedType()->isSingleValueType()); // If we're just going to emit a memcpy, the alloca hasn't changed, and the // size hasn't been shrunk based on analysis of the viable range, this is // a no-op. if (EmitMemCpy && &OldAI == &NewAI) { // Ensure the start lines up. assert(NewBeginOffset == BeginOffset); // Rewrite the size as needed. if (NewEndOffset != EndOffset) II.setLength(ConstantInt::get(II.getLength()->getType(), NewEndOffset - NewBeginOffset)); return false; } // Record this instruction for deletion. Pass.DeadInsts.insert(&II); // Strip all inbounds GEPs and pointer casts to try to dig out any root // alloca that should be re-examined after rewriting this instruction. Value *OtherPtr = IsDest ? II.getRawSource() : II.getRawDest(); if (AllocaInst *AI = dyn_cast(OtherPtr->stripInBoundsOffsets())) { assert(AI != &OldAI && AI != &NewAI && "Splittable transfers cannot reach the same alloca on both ends."); Pass.Worklist.insert(AI); } Type *OtherPtrTy = OtherPtr->getType(); unsigned OtherAS = OtherPtrTy->getPointerAddressSpace(); // Compute the relative offset for the other pointer within the transfer. unsigned OffsetWidth = DL.getIndexSizeInBits(OtherAS); APInt OtherOffset(OffsetWidth, NewBeginOffset - BeginOffset); Align OtherAlign = assumeAligned(IsDest ? II.getSourceAlignment() : II.getDestAlignment()); OtherAlign = commonAlignment(OtherAlign, OtherOffset.zextOrTrunc(64).getZExtValue()); if (EmitMemCpy) { // Compute the other pointer, folding as much as possible to produce // a single, simple GEP in most cases. OtherPtr = getAdjustedPtr(IRB, DL, OtherPtr, OtherOffset, OtherPtrTy, OtherPtr->getName() + "."); Value *OurPtr = getNewAllocaSlicePtr(IRB, OldPtr->getType()); Type *SizeTy = II.getLength()->getType(); Constant *Size = ConstantInt::get(SizeTy, NewEndOffset - NewBeginOffset); Value *DestPtr, *SrcPtr; MaybeAlign DestAlign, SrcAlign; // Note: IsDest is true iff we're copying into the new alloca slice if (IsDest) { DestPtr = OurPtr; DestAlign = SliceAlign; SrcPtr = OtherPtr; SrcAlign = OtherAlign; } else { DestPtr = OtherPtr; DestAlign = OtherAlign; SrcPtr = OurPtr; SrcAlign = SliceAlign; } CallInst *New = IRB.CreateMemCpy(DestPtr, DestAlign, SrcPtr, SrcAlign, Size, II.isVolatile()); if (AATags) New->setAAMetadata(AATags); LLVM_DEBUG(dbgs() << " to: " << *New << "\n"); return false; } bool IsWholeAlloca = NewBeginOffset == NewAllocaBeginOffset && NewEndOffset == NewAllocaEndOffset; uint64_t Size = NewEndOffset - NewBeginOffset; unsigned BeginIndex = VecTy ? getIndex(NewBeginOffset) : 0; unsigned EndIndex = VecTy ? getIndex(NewEndOffset) : 0; unsigned NumElements = EndIndex - BeginIndex; IntegerType *SubIntTy = IntTy ? Type::getIntNTy(IntTy->getContext(), Size * 8) : nullptr; // Reset the other pointer type to match the register type we're going to // use, but using the address space of the original other pointer. Type *OtherTy; if (VecTy && !IsWholeAlloca) { if (NumElements == 1) OtherTy = VecTy->getElementType(); else OtherTy = VectorType::get(VecTy->getElementType(), NumElements); } else if (IntTy && !IsWholeAlloca) { OtherTy = SubIntTy; } else { OtherTy = NewAllocaTy; } OtherPtrTy = OtherTy->getPointerTo(OtherAS); Value *SrcPtr = getAdjustedPtr(IRB, DL, OtherPtr, OtherOffset, OtherPtrTy, OtherPtr->getName() + "."); MaybeAlign SrcAlign = OtherAlign; Value *DstPtr = &NewAI; MaybeAlign DstAlign = SliceAlign; if (!IsDest) { std::swap(SrcPtr, DstPtr); std::swap(SrcAlign, DstAlign); } Value *Src; if (VecTy && !IsWholeAlloca && !IsDest) { Src = IRB.CreateAlignedLoad(NewAI.getAllocatedType(), &NewAI, NewAI.getAlignment(), "load"); Src = extractVector(IRB, Src, BeginIndex, EndIndex, "vec"); } else if (IntTy && !IsWholeAlloca && !IsDest) { Src = IRB.CreateAlignedLoad(NewAI.getAllocatedType(), &NewAI, NewAI.getAlignment(), "load"); Src = convertValue(DL, IRB, Src, IntTy); uint64_t Offset = NewBeginOffset - NewAllocaBeginOffset; Src = extractInteger(DL, IRB, Src, SubIntTy, Offset, "extract"); } else { LoadInst *Load = IRB.CreateAlignedLoad(OtherTy, SrcPtr, SrcAlign, II.isVolatile(), "copyload"); if (AATags) Load->setAAMetadata(AATags); Src = Load; } if (VecTy && !IsWholeAlloca && IsDest) { Value *Old = IRB.CreateAlignedLoad(NewAI.getAllocatedType(), &NewAI, NewAI.getAlignment(), "oldload"); Src = insertVector(IRB, Old, Src, BeginIndex, "vec"); } else if (IntTy && !IsWholeAlloca && IsDest) { Value *Old = IRB.CreateAlignedLoad(NewAI.getAllocatedType(), &NewAI, NewAI.getAlignment(), "oldload"); Old = convertValue(DL, IRB, Old, IntTy); uint64_t Offset = NewBeginOffset - NewAllocaBeginOffset; Src = insertInteger(DL, IRB, Old, Src, Offset, "insert"); Src = convertValue(DL, IRB, Src, NewAllocaTy); } StoreInst *Store = cast( IRB.CreateAlignedStore(Src, DstPtr, DstAlign, II.isVolatile())); if (AATags) Store->setAAMetadata(AATags); LLVM_DEBUG(dbgs() << " to: " << *Store << "\n"); return !II.isVolatile(); } bool visitIntrinsicInst(IntrinsicInst &II) { assert(II.isLifetimeStartOrEnd()); LLVM_DEBUG(dbgs() << " original: " << II << "\n"); assert(II.getArgOperand(1) == OldPtr); // Record this instruction for deletion. Pass.DeadInsts.insert(&II); // Lifetime intrinsics are only promotable if they cover the whole alloca. // Therefore, we drop lifetime intrinsics which don't cover the whole // alloca. // (In theory, intrinsics which partially cover an alloca could be // promoted, but PromoteMemToReg doesn't handle that case.) // FIXME: Check whether the alloca is promotable before dropping the // lifetime intrinsics? if (NewBeginOffset != NewAllocaBeginOffset || NewEndOffset != NewAllocaEndOffset) return true; ConstantInt *Size = ConstantInt::get(cast(II.getArgOperand(0)->getType()), NewEndOffset - NewBeginOffset); // Lifetime intrinsics always expect an i8* so directly get such a pointer // for the new alloca slice. Type *PointerTy = IRB.getInt8PtrTy(OldPtr->getType()->getPointerAddressSpace()); Value *Ptr = getNewAllocaSlicePtr(IRB, PointerTy); Value *New; if (II.getIntrinsicID() == Intrinsic::lifetime_start) New = IRB.CreateLifetimeStart(Ptr, Size); else New = IRB.CreateLifetimeEnd(Ptr, Size); (void)New; LLVM_DEBUG(dbgs() << " to: " << *New << "\n"); return true; } void fixLoadStoreAlign(Instruction &Root) { // This algorithm implements the same visitor loop as // hasUnsafePHIOrSelectUse, and fixes the alignment of each load // or store found. SmallPtrSet Visited; SmallVector Uses; Visited.insert(&Root); Uses.push_back(&Root); do { Instruction *I = Uses.pop_back_val(); if (LoadInst *LI = dyn_cast(I)) { MaybeAlign LoadAlign = DL.getValueOrABITypeAlignment( MaybeAlign(LI->getAlignment()), LI->getType()); LI->setAlignment(std::min(LoadAlign, getSliceAlign())); continue; } if (StoreInst *SI = dyn_cast(I)) { Value *Op = SI->getOperand(0); MaybeAlign StoreAlign = DL.getValueOrABITypeAlignment( MaybeAlign(SI->getAlignment()), Op->getType()); SI->setAlignment(std::min(StoreAlign, getSliceAlign())); continue; } assert(isa(I) || isa(I) || isa(I) || isa(I) || isa(I)); for (User *U : I->users()) if (Visited.insert(cast(U)).second) Uses.push_back(cast(U)); } while (!Uses.empty()); } bool visitPHINode(PHINode &PN) { LLVM_DEBUG(dbgs() << " original: " << PN << "\n"); assert(BeginOffset >= NewAllocaBeginOffset && "PHIs are unsplittable"); assert(EndOffset <= NewAllocaEndOffset && "PHIs are unsplittable"); // We would like to compute a new pointer in only one place, but have it be // as local as possible to the PHI. To do that, we re-use the location of // the old pointer, which necessarily must be in the right position to // dominate the PHI. IRBuilderTy PtrBuilder(IRB); if (isa(OldPtr)) PtrBuilder.SetInsertPoint(&*OldPtr->getParent()->getFirstInsertionPt()); else PtrBuilder.SetInsertPoint(OldPtr); PtrBuilder.SetCurrentDebugLocation(OldPtr->getDebugLoc()); Value *NewPtr = getNewAllocaSlicePtr(PtrBuilder, OldPtr->getType()); // Replace the operands which were using the old pointer. std::replace(PN.op_begin(), PN.op_end(), cast(OldPtr), NewPtr); LLVM_DEBUG(dbgs() << " to: " << PN << "\n"); deleteIfTriviallyDead(OldPtr); // Fix the alignment of any loads or stores using this PHI node. fixLoadStoreAlign(PN); // PHIs can't be promoted on their own, but often can be speculated. We // check the speculation outside of the rewriter so that we see the // fully-rewritten alloca. PHIUsers.insert(&PN); return true; } bool visitSelectInst(SelectInst &SI) { LLVM_DEBUG(dbgs() << " original: " << SI << "\n"); assert((SI.getTrueValue() == OldPtr || SI.getFalseValue() == OldPtr) && "Pointer isn't an operand!"); assert(BeginOffset >= NewAllocaBeginOffset && "Selects are unsplittable"); assert(EndOffset <= NewAllocaEndOffset && "Selects are unsplittable"); Value *NewPtr = getNewAllocaSlicePtr(IRB, OldPtr->getType()); // Replace the operands which were using the old pointer. if (SI.getOperand(1) == OldPtr) SI.setOperand(1, NewPtr); if (SI.getOperand(2) == OldPtr) SI.setOperand(2, NewPtr); LLVM_DEBUG(dbgs() << " to: " << SI << "\n"); deleteIfTriviallyDead(OldPtr); // Fix the alignment of any loads or stores using this select. fixLoadStoreAlign(SI); // Selects can't be promoted on their own, but often can be speculated. We // check the speculation outside of the rewriter so that we see the // fully-rewritten alloca. SelectUsers.insert(&SI); return true; } }; namespace { /// Visitor to rewrite aggregate loads and stores as scalar. /// /// This pass aggressively rewrites all aggregate loads and stores on /// a particular pointer (or any pointer derived from it which we can identify) /// with scalar loads and stores. class AggLoadStoreRewriter : public InstVisitor { // Befriend the base class so it can delegate to private visit methods. friend class InstVisitor; /// Queue of pointer uses to analyze and potentially rewrite. SmallVector Queue; /// Set to prevent us from cycling with phi nodes and loops. SmallPtrSet Visited; /// The current pointer use being rewritten. This is used to dig up the used /// value (as opposed to the user). Use *U = nullptr; /// Used to calculate offsets, and hence alignment, of subobjects. const DataLayout &DL; public: AggLoadStoreRewriter(const DataLayout &DL) : DL(DL) {} /// Rewrite loads and stores through a pointer and all pointers derived from /// it. bool rewrite(Instruction &I) { LLVM_DEBUG(dbgs() << " Rewriting FCA loads and stores...\n"); enqueueUsers(I); bool Changed = false; while (!Queue.empty()) { U = Queue.pop_back_val(); Changed |= visit(cast(U->getUser())); } return Changed; } private: /// Enqueue all the users of the given instruction for further processing. /// This uses a set to de-duplicate users. void enqueueUsers(Instruction &I) { for (Use &U : I.uses()) if (Visited.insert(U.getUser()).second) Queue.push_back(&U); } // Conservative default is to not rewrite anything. bool visitInstruction(Instruction &I) { return false; } /// Generic recursive split emission class. template class OpSplitter { protected: /// The builder used to form new instructions. IRBuilderTy IRB; /// The indices which to be used with insert- or extractvalue to select the /// appropriate value within the aggregate. SmallVector Indices; /// The indices to a GEP instruction which will move Ptr to the correct slot /// within the aggregate. SmallVector GEPIndices; /// The base pointer of the original op, used as a base for GEPing the /// split operations. Value *Ptr; /// The base pointee type being GEPed into. Type *BaseTy; /// Known alignment of the base pointer. Align BaseAlign; /// To calculate offset of each component so we can correctly deduce /// alignments. const DataLayout &DL; /// Initialize the splitter with an insertion point, Ptr and start with a /// single zero GEP index. OpSplitter(Instruction *InsertionPoint, Value *Ptr, Type *BaseTy, Align BaseAlign, const DataLayout &DL) : IRB(InsertionPoint), GEPIndices(1, IRB.getInt32(0)), Ptr(Ptr), BaseTy(BaseTy), BaseAlign(BaseAlign), DL(DL) {} public: /// Generic recursive split emission routine. /// /// This method recursively splits an aggregate op (load or store) into /// scalar or vector ops. It splits recursively until it hits a single value /// and emits that single value operation via the template argument. /// /// The logic of this routine relies on GEPs and insertvalue and /// extractvalue all operating with the same fundamental index list, merely /// formatted differently (GEPs need actual values). /// /// \param Ty The type being split recursively into smaller ops. /// \param Agg The aggregate value being built up or stored, depending on /// whether this is splitting a load or a store respectively. void emitSplitOps(Type *Ty, Value *&Agg, const Twine &Name) { if (Ty->isSingleValueType()) { unsigned Offset = DL.getIndexedOffsetInType(BaseTy, GEPIndices); return static_cast(this)->emitFunc( Ty, Agg, commonAlignment(BaseAlign, Offset), Name); } if (ArrayType *ATy = dyn_cast(Ty)) { unsigned OldSize = Indices.size(); (void)OldSize; for (unsigned Idx = 0, Size = ATy->getNumElements(); Idx != Size; ++Idx) { assert(Indices.size() == OldSize && "Did not return to the old size"); Indices.push_back(Idx); GEPIndices.push_back(IRB.getInt32(Idx)); emitSplitOps(ATy->getElementType(), Agg, Name + "." + Twine(Idx)); GEPIndices.pop_back(); Indices.pop_back(); } return; } if (StructType *STy = dyn_cast(Ty)) { unsigned OldSize = Indices.size(); (void)OldSize; for (unsigned Idx = 0, Size = STy->getNumElements(); Idx != Size; ++Idx) { assert(Indices.size() == OldSize && "Did not return to the old size"); Indices.push_back(Idx); GEPIndices.push_back(IRB.getInt32(Idx)); emitSplitOps(STy->getElementType(Idx), Agg, Name + "." + Twine(Idx)); GEPIndices.pop_back(); Indices.pop_back(); } return; } llvm_unreachable("Only arrays and structs are aggregate loadable types"); } }; struct LoadOpSplitter : public OpSplitter { AAMDNodes AATags; LoadOpSplitter(Instruction *InsertionPoint, Value *Ptr, Type *BaseTy, AAMDNodes AATags, Align BaseAlign, const DataLayout &DL) : OpSplitter(InsertionPoint, Ptr, BaseTy, BaseAlign, DL), AATags(AATags) {} /// Emit a leaf load of a single value. This is called at the leaves of the /// recursive emission to actually load values. void emitFunc(Type *Ty, Value *&Agg, Align Alignment, const Twine &Name) { assert(Ty->isSingleValueType()); // Load the single value and insert it using the indices. Value *GEP = IRB.CreateInBoundsGEP(BaseTy, Ptr, GEPIndices, Name + ".gep"); LoadInst *Load = IRB.CreateAlignedLoad(Ty, GEP, Alignment.value(), Name + ".load"); if (AATags) Load->setAAMetadata(AATags); Agg = IRB.CreateInsertValue(Agg, Load, Indices, Name + ".insert"); LLVM_DEBUG(dbgs() << " to: " << *Load << "\n"); } }; bool visitLoadInst(LoadInst &LI) { assert(LI.getPointerOperand() == *U); if (!LI.isSimple() || LI.getType()->isSingleValueType()) return false; // We have an aggregate being loaded, split it apart. LLVM_DEBUG(dbgs() << " original: " << LI << "\n"); AAMDNodes AATags; LI.getAAMetadata(AATags); LoadOpSplitter Splitter(&LI, *U, LI.getType(), AATags, getAdjustedAlignment(&LI, 0, DL), DL); Value *V = UndefValue::get(LI.getType()); Splitter.emitSplitOps(LI.getType(), V, LI.getName() + ".fca"); LI.replaceAllUsesWith(V); LI.eraseFromParent(); return true; } struct StoreOpSplitter : public OpSplitter { StoreOpSplitter(Instruction *InsertionPoint, Value *Ptr, Type *BaseTy, AAMDNodes AATags, Align BaseAlign, const DataLayout &DL) : OpSplitter(InsertionPoint, Ptr, BaseTy, BaseAlign, DL), AATags(AATags) {} AAMDNodes AATags; /// Emit a leaf store of a single value. This is called at the leaves of the /// recursive emission to actually produce stores. void emitFunc(Type *Ty, Value *&Agg, Align Alignment, const Twine &Name) { assert(Ty->isSingleValueType()); // Extract the single value and store it using the indices. // // The gep and extractvalue values are factored out of the CreateStore // call to make the output independent of the argument evaluation order. Value *ExtractValue = IRB.CreateExtractValue(Agg, Indices, Name + ".extract"); Value *InBoundsGEP = IRB.CreateInBoundsGEP(BaseTy, Ptr, GEPIndices, Name + ".gep"); StoreInst *Store = IRB.CreateAlignedStore(ExtractValue, InBoundsGEP, Alignment.value()); if (AATags) Store->setAAMetadata(AATags); LLVM_DEBUG(dbgs() << " to: " << *Store << "\n"); } }; bool visitStoreInst(StoreInst &SI) { if (!SI.isSimple() || SI.getPointerOperand() != *U) return false; Value *V = SI.getValueOperand(); if (V->getType()->isSingleValueType()) return false; // We have an aggregate being stored, split it apart. LLVM_DEBUG(dbgs() << " original: " << SI << "\n"); AAMDNodes AATags; SI.getAAMetadata(AATags); StoreOpSplitter Splitter(&SI, *U, V->getType(), AATags, getAdjustedAlignment(&SI, 0, DL), DL); Splitter.emitSplitOps(V->getType(), V, V->getName() + ".fca"); SI.eraseFromParent(); return true; } bool visitBitCastInst(BitCastInst &BC) { enqueueUsers(BC); return false; } bool visitAddrSpaceCastInst(AddrSpaceCastInst &ASC) { enqueueUsers(ASC); return false; } bool visitGetElementPtrInst(GetElementPtrInst &GEPI) { enqueueUsers(GEPI); return false; } bool visitPHINode(PHINode &PN) { enqueueUsers(PN); return false; } bool visitSelectInst(SelectInst &SI) { enqueueUsers(SI); return false; } }; } // end anonymous namespace /// Strip aggregate type wrapping. /// /// This removes no-op aggregate types wrapping an underlying type. It will /// strip as many layers of types as it can without changing either the type /// size or the allocated size. static Type *stripAggregateTypeWrapping(const DataLayout &DL, Type *Ty) { if (Ty->isSingleValueType()) return Ty; uint64_t AllocSize = DL.getTypeAllocSize(Ty); uint64_t TypeSize = DL.getTypeSizeInBits(Ty); Type *InnerTy; if (ArrayType *ArrTy = dyn_cast(Ty)) { InnerTy = ArrTy->getElementType(); } else if (StructType *STy = dyn_cast(Ty)) { const StructLayout *SL = DL.getStructLayout(STy); unsigned Index = SL->getElementContainingOffset(0); InnerTy = STy->getElementType(Index); } else { return Ty; } if (AllocSize > DL.getTypeAllocSize(InnerTy) || TypeSize > DL.getTypeSizeInBits(InnerTy)) return Ty; return stripAggregateTypeWrapping(DL, InnerTy); } /// Try to find a partition of the aggregate type passed in for a given /// offset and size. /// /// This recurses through the aggregate type and tries to compute a subtype /// based on the offset and size. When the offset and size span a sub-section /// of an array, it will even compute a new array type for that sub-section, /// and the same for structs. /// /// Note that this routine is very strict and tries to find a partition of the /// type which produces the *exact* right offset and size. It is not forgiving /// when the size or offset cause either end of type-based partition to be off. /// Also, this is a best-effort routine. It is reasonable to give up and not /// return a type if necessary. static Type *getTypePartition(const DataLayout &DL, Type *Ty, uint64_t Offset, uint64_t Size) { if (Offset == 0 && DL.getTypeAllocSize(Ty) == Size) return stripAggregateTypeWrapping(DL, Ty); if (Offset > DL.getTypeAllocSize(Ty) || (DL.getTypeAllocSize(Ty) - Offset) < Size) return nullptr; if (SequentialType *SeqTy = dyn_cast(Ty)) { Type *ElementTy = SeqTy->getElementType(); uint64_t ElementSize = DL.getTypeAllocSize(ElementTy); uint64_t NumSkippedElements = Offset / ElementSize; if (NumSkippedElements >= SeqTy->getNumElements()) return nullptr; Offset -= NumSkippedElements * ElementSize; // First check if we need to recurse. if (Offset > 0 || Size < ElementSize) { // Bail if the partition ends in a different array element. if ((Offset + Size) > ElementSize) return nullptr; // Recurse through the element type trying to peel off offset bytes. return getTypePartition(DL, ElementTy, Offset, Size); } assert(Offset == 0); if (Size == ElementSize) return stripAggregateTypeWrapping(DL, ElementTy); assert(Size > ElementSize); uint64_t NumElements = Size / ElementSize; if (NumElements * ElementSize != Size) return nullptr; return ArrayType::get(ElementTy, NumElements); } StructType *STy = dyn_cast(Ty); if (!STy) return nullptr; const StructLayout *SL = DL.getStructLayout(STy); if (Offset >= SL->getSizeInBytes()) return nullptr; uint64_t EndOffset = Offset + Size; if (EndOffset > SL->getSizeInBytes()) return nullptr; unsigned Index = SL->getElementContainingOffset(Offset); Offset -= SL->getElementOffset(Index); Type *ElementTy = STy->getElementType(Index); uint64_t ElementSize = DL.getTypeAllocSize(ElementTy); if (Offset >= ElementSize) return nullptr; // The offset points into alignment padding. // See if any partition must be contained by the element. if (Offset > 0 || Size < ElementSize) { if ((Offset + Size) > ElementSize) return nullptr; return getTypePartition(DL, ElementTy, Offset, Size); } assert(Offset == 0); if (Size == ElementSize) return stripAggregateTypeWrapping(DL, ElementTy); StructType::element_iterator EI = STy->element_begin() + Index, EE = STy->element_end(); if (EndOffset < SL->getSizeInBytes()) { unsigned EndIndex = SL->getElementContainingOffset(EndOffset); if (Index == EndIndex) return nullptr; // Within a single element and its padding. // Don't try to form "natural" types if the elements don't line up with the // expected size. // FIXME: We could potentially recurse down through the last element in the // sub-struct to find a natural end point. if (SL->getElementOffset(EndIndex) != EndOffset) return nullptr; assert(Index < EndIndex); EE = STy->element_begin() + EndIndex; } // Try to build up a sub-structure. StructType *SubTy = StructType::get(STy->getContext(), makeArrayRef(EI, EE), STy->isPacked()); const StructLayout *SubSL = DL.getStructLayout(SubTy); if (Size != SubSL->getSizeInBytes()) return nullptr; // The sub-struct doesn't have quite the size needed. return SubTy; } /// Pre-split loads and stores to simplify rewriting. /// /// We want to break up the splittable load+store pairs as much as /// possible. This is important to do as a preprocessing step, as once we /// start rewriting the accesses to partitions of the alloca we lose the /// necessary information to correctly split apart paired loads and stores /// which both point into this alloca. The case to consider is something like /// the following: /// /// %a = alloca [12 x i8] /// %gep1 = getelementptr [12 x i8]* %a, i32 0, i32 0 /// %gep2 = getelementptr [12 x i8]* %a, i32 0, i32 4 /// %gep3 = getelementptr [12 x i8]* %a, i32 0, i32 8 /// %iptr1 = bitcast i8* %gep1 to i64* /// %iptr2 = bitcast i8* %gep2 to i64* /// %fptr1 = bitcast i8* %gep1 to float* /// %fptr2 = bitcast i8* %gep2 to float* /// %fptr3 = bitcast i8* %gep3 to float* /// store float 0.0, float* %fptr1 /// store float 1.0, float* %fptr2 /// %v = load i64* %iptr1 /// store i64 %v, i64* %iptr2 /// %f1 = load float* %fptr2 /// %f2 = load float* %fptr3 /// /// Here we want to form 3 partitions of the alloca, each 4 bytes large, and /// promote everything so we recover the 2 SSA values that should have been /// there all along. /// /// \returns true if any changes are made. bool SROA::presplitLoadsAndStores(AllocaInst &AI, AllocaSlices &AS) { LLVM_DEBUG(dbgs() << "Pre-splitting loads and stores\n"); // Track the loads and stores which are candidates for pre-splitting here, in // the order they first appear during the partition scan. These give stable // iteration order and a basis for tracking which loads and stores we // actually split. SmallVector Loads; SmallVector Stores; // We need to accumulate the splits required of each load or store where we // can find them via a direct lookup. This is important to cross-check loads // and stores against each other. We also track the slice so that we can kill // all the slices that end up split. struct SplitOffsets { Slice *S; std::vector Splits; }; SmallDenseMap SplitOffsetsMap; // Track loads out of this alloca which cannot, for any reason, be pre-split. // This is important as we also cannot pre-split stores of those loads! // FIXME: This is all pretty gross. It means that we can be more aggressive // in pre-splitting when the load feeding the store happens to come from // a separate alloca. Put another way, the effectiveness of SROA would be // decreased by a frontend which just concatenated all of its local allocas // into one big flat alloca. But defeating such patterns is exactly the job // SROA is tasked with! Sadly, to not have this discrepancy we would have // change store pre-splitting to actually force pre-splitting of the load // that feeds it *and all stores*. That makes pre-splitting much harder, but // maybe it would make it more principled? SmallPtrSet UnsplittableLoads; LLVM_DEBUG(dbgs() << " Searching for candidate loads and stores\n"); for (auto &P : AS.partitions()) { for (Slice &S : P) { Instruction *I = cast(S.getUse()->getUser()); if (!S.isSplittable() || S.endOffset() <= P.endOffset()) { // If this is a load we have to track that it can't participate in any // pre-splitting. If this is a store of a load we have to track that // that load also can't participate in any pre-splitting. if (auto *LI = dyn_cast(I)) UnsplittableLoads.insert(LI); else if (auto *SI = dyn_cast(I)) if (auto *LI = dyn_cast(SI->getValueOperand())) UnsplittableLoads.insert(LI); continue; } assert(P.endOffset() > S.beginOffset() && "Empty or backwards partition!"); // Determine if this is a pre-splittable slice. if (auto *LI = dyn_cast(I)) { assert(!LI->isVolatile() && "Cannot split volatile loads!"); // The load must be used exclusively to store into other pointers for // us to be able to arbitrarily pre-split it. The stores must also be // simple to avoid changing semantics. auto IsLoadSimplyStored = [](LoadInst *LI) { for (User *LU : LI->users()) { auto *SI = dyn_cast(LU); if (!SI || !SI->isSimple()) return false; } return true; }; if (!IsLoadSimplyStored(LI)) { UnsplittableLoads.insert(LI); continue; } Loads.push_back(LI); } else if (auto *SI = dyn_cast(I)) { if (S.getUse() != &SI->getOperandUse(SI->getPointerOperandIndex())) // Skip stores *of* pointers. FIXME: This shouldn't even be possible! continue; auto *StoredLoad = dyn_cast(SI->getValueOperand()); if (!StoredLoad || !StoredLoad->isSimple()) continue; assert(!SI->isVolatile() && "Cannot split volatile stores!"); Stores.push_back(SI); } else { // Other uses cannot be pre-split. continue; } // Record the initial split. LLVM_DEBUG(dbgs() << " Candidate: " << *I << "\n"); auto &Offsets = SplitOffsetsMap[I]; assert(Offsets.Splits.empty() && "Should not have splits the first time we see an instruction!"); Offsets.S = &S; Offsets.Splits.push_back(P.endOffset() - S.beginOffset()); } // Now scan the already split slices, and add a split for any of them which // we're going to pre-split. for (Slice *S : P.splitSliceTails()) { auto SplitOffsetsMapI = SplitOffsetsMap.find(cast(S->getUse()->getUser())); if (SplitOffsetsMapI == SplitOffsetsMap.end()) continue; auto &Offsets = SplitOffsetsMapI->second; assert(Offsets.S == S && "Found a mismatched slice!"); assert(!Offsets.Splits.empty() && "Cannot have an empty set of splits on the second partition!"); assert(Offsets.Splits.back() == P.beginOffset() - Offsets.S->beginOffset() && "Previous split does not end where this one begins!"); // Record each split. The last partition's end isn't needed as the size // of the slice dictates that. if (S->endOffset() > P.endOffset()) Offsets.Splits.push_back(P.endOffset() - Offsets.S->beginOffset()); } } // We may have split loads where some of their stores are split stores. For // such loads and stores, we can only pre-split them if their splits exactly // match relative to their starting offset. We have to verify this prior to // any rewriting. Stores.erase( llvm::remove_if(Stores, [&UnsplittableLoads, &SplitOffsetsMap](StoreInst *SI) { // Lookup the load we are storing in our map of split // offsets. auto *LI = cast(SI->getValueOperand()); // If it was completely unsplittable, then we're done, // and this store can't be pre-split. if (UnsplittableLoads.count(LI)) return true; auto LoadOffsetsI = SplitOffsetsMap.find(LI); if (LoadOffsetsI == SplitOffsetsMap.end()) return false; // Unrelated loads are definitely safe. auto &LoadOffsets = LoadOffsetsI->second; // Now lookup the store's offsets. auto &StoreOffsets = SplitOffsetsMap[SI]; // If the relative offsets of each split in the load and // store match exactly, then we can split them and we // don't need to remove them here. if (LoadOffsets.Splits == StoreOffsets.Splits) return false; LLVM_DEBUG( dbgs() << " Mismatched splits for load and store:\n" << " " << *LI << "\n" << " " << *SI << "\n"); // We've found a store and load that we need to split // with mismatched relative splits. Just give up on them // and remove both instructions from our list of // candidates. UnsplittableLoads.insert(LI); return true; }), Stores.end()); // Now we have to go *back* through all the stores, because a later store may // have caused an earlier store's load to become unsplittable and if it is // unsplittable for the later store, then we can't rely on it being split in // the earlier store either. Stores.erase(llvm::remove_if(Stores, [&UnsplittableLoads](StoreInst *SI) { auto *LI = cast(SI->getValueOperand()); return UnsplittableLoads.count(LI); }), Stores.end()); // Once we've established all the loads that can't be split for some reason, // filter any that made it into our list out. Loads.erase(llvm::remove_if(Loads, [&UnsplittableLoads](LoadInst *LI) { return UnsplittableLoads.count(LI); }), Loads.end()); // If no loads or stores are left, there is no pre-splitting to be done for // this alloca. if (Loads.empty() && Stores.empty()) return false; // From here on, we can't fail and will be building new accesses, so rig up // an IR builder. IRBuilderTy IRB(&AI); // Collect the new slices which we will merge into the alloca slices. SmallVector NewSlices; // Track any allocas we end up splitting loads and stores for so we iterate // on them. SmallPtrSet ResplitPromotableAllocas; // At this point, we have collected all of the loads and stores we can // pre-split, and the specific splits needed for them. We actually do the // splitting in a specific order in order to handle when one of the loads in // the value operand to one of the stores. // // First, we rewrite all of the split loads, and just accumulate each split // load in a parallel structure. We also build the slices for them and append // them to the alloca slices. SmallDenseMap, 1> SplitLoadsMap; std::vector SplitLoads; const DataLayout &DL = AI.getModule()->getDataLayout(); for (LoadInst *LI : Loads) { SplitLoads.clear(); IntegerType *Ty = cast(LI->getType()); uint64_t LoadSize = Ty->getBitWidth() / 8; assert(LoadSize > 0 && "Cannot have a zero-sized integer load!"); auto &Offsets = SplitOffsetsMap[LI]; assert(LoadSize == Offsets.S->endOffset() - Offsets.S->beginOffset() && "Slice size should always match load size exactly!"); uint64_t BaseOffset = Offsets.S->beginOffset(); assert(BaseOffset + LoadSize > BaseOffset && "Cannot represent alloca access size using 64-bit integers!"); Instruction *BasePtr = cast(LI->getPointerOperand()); IRB.SetInsertPoint(LI); LLVM_DEBUG(dbgs() << " Splitting load: " << *LI << "\n"); uint64_t PartOffset = 0, PartSize = Offsets.Splits.front(); int Idx = 0, Size = Offsets.Splits.size(); for (;;) { auto *PartTy = Type::getIntNTy(Ty->getContext(), PartSize * 8); auto AS = LI->getPointerAddressSpace(); auto *PartPtrTy = PartTy->getPointerTo(AS); LoadInst *PLoad = IRB.CreateAlignedLoad( PartTy, getAdjustedPtr(IRB, DL, BasePtr, APInt(DL.getIndexSizeInBits(AS), PartOffset), PartPtrTy, BasePtr->getName() + "."), getAdjustedAlignment(LI, PartOffset, DL).value(), /*IsVolatile*/ false, LI->getName()); PLoad->copyMetadata(*LI, {LLVMContext::MD_mem_parallel_loop_access, LLVMContext::MD_access_group}); // Append this load onto the list of split loads so we can find it later // to rewrite the stores. SplitLoads.push_back(PLoad); // Now build a new slice for the alloca. NewSlices.push_back( Slice(BaseOffset + PartOffset, BaseOffset + PartOffset + PartSize, &PLoad->getOperandUse(PLoad->getPointerOperandIndex()), /*IsSplittable*/ false)); LLVM_DEBUG(dbgs() << " new slice [" << NewSlices.back().beginOffset() << ", " << NewSlices.back().endOffset() << "): " << *PLoad << "\n"); // See if we've handled all the splits. if (Idx >= Size) break; // Setup the next partition. PartOffset = Offsets.Splits[Idx]; ++Idx; PartSize = (Idx < Size ? Offsets.Splits[Idx] : LoadSize) - PartOffset; } // Now that we have the split loads, do the slow walk over all uses of the // load and rewrite them as split stores, or save the split loads to use // below if the store is going to be split there anyways. bool DeferredStores = false; for (User *LU : LI->users()) { StoreInst *SI = cast(LU); if (!Stores.empty() && SplitOffsetsMap.count(SI)) { DeferredStores = true; LLVM_DEBUG(dbgs() << " Deferred splitting of store: " << *SI << "\n"); continue; } Value *StoreBasePtr = SI->getPointerOperand(); IRB.SetInsertPoint(SI); LLVM_DEBUG(dbgs() << " Splitting store of load: " << *SI << "\n"); for (int Idx = 0, Size = SplitLoads.size(); Idx < Size; ++Idx) { LoadInst *PLoad = SplitLoads[Idx]; uint64_t PartOffset = Idx == 0 ? 0 : Offsets.Splits[Idx - 1]; auto *PartPtrTy = PLoad->getType()->getPointerTo(SI->getPointerAddressSpace()); auto AS = SI->getPointerAddressSpace(); StoreInst *PStore = IRB.CreateAlignedStore( PLoad, getAdjustedPtr(IRB, DL, StoreBasePtr, APInt(DL.getIndexSizeInBits(AS), PartOffset), PartPtrTy, StoreBasePtr->getName() + "."), getAdjustedAlignment(SI, PartOffset, DL).value(), /*IsVolatile*/ false); PStore->copyMetadata(*LI, {LLVMContext::MD_mem_parallel_loop_access, LLVMContext::MD_access_group}); LLVM_DEBUG(dbgs() << " +" << PartOffset << ":" << *PStore << "\n"); } // We want to immediately iterate on any allocas impacted by splitting // this store, and we have to track any promotable alloca (indicated by // a direct store) as needing to be resplit because it is no longer // promotable. if (AllocaInst *OtherAI = dyn_cast(StoreBasePtr)) { ResplitPromotableAllocas.insert(OtherAI); Worklist.insert(OtherAI); } else if (AllocaInst *OtherAI = dyn_cast( StoreBasePtr->stripInBoundsOffsets())) { Worklist.insert(OtherAI); } // Mark the original store as dead. DeadInsts.insert(SI); } // Save the split loads if there are deferred stores among the users. if (DeferredStores) SplitLoadsMap.insert(std::make_pair(LI, std::move(SplitLoads))); // Mark the original load as dead and kill the original slice. DeadInsts.insert(LI); Offsets.S->kill(); } // Second, we rewrite all of the split stores. At this point, we know that // all loads from this alloca have been split already. For stores of such // loads, we can simply look up the pre-existing split loads. For stores of // other loads, we split those loads first and then write split stores of // them. for (StoreInst *SI : Stores) { auto *LI = cast(SI->getValueOperand()); IntegerType *Ty = cast(LI->getType()); uint64_t StoreSize = Ty->getBitWidth() / 8; assert(StoreSize > 0 && "Cannot have a zero-sized integer store!"); auto &Offsets = SplitOffsetsMap[SI]; assert(StoreSize == Offsets.S->endOffset() - Offsets.S->beginOffset() && "Slice size should always match load size exactly!"); uint64_t BaseOffset = Offsets.S->beginOffset(); assert(BaseOffset + StoreSize > BaseOffset && "Cannot represent alloca access size using 64-bit integers!"); Value *LoadBasePtr = LI->getPointerOperand(); Instruction *StoreBasePtr = cast(SI->getPointerOperand()); LLVM_DEBUG(dbgs() << " Splitting store: " << *SI << "\n"); // Check whether we have an already split load. auto SplitLoadsMapI = SplitLoadsMap.find(LI); std::vector *SplitLoads = nullptr; if (SplitLoadsMapI != SplitLoadsMap.end()) { SplitLoads = &SplitLoadsMapI->second; assert(SplitLoads->size() == Offsets.Splits.size() + 1 && "Too few split loads for the number of splits in the store!"); } else { LLVM_DEBUG(dbgs() << " of load: " << *LI << "\n"); } uint64_t PartOffset = 0, PartSize = Offsets.Splits.front(); int Idx = 0, Size = Offsets.Splits.size(); for (;;) { auto *PartTy = Type::getIntNTy(Ty->getContext(), PartSize * 8); auto *LoadPartPtrTy = PartTy->getPointerTo(LI->getPointerAddressSpace()); auto *StorePartPtrTy = PartTy->getPointerTo(SI->getPointerAddressSpace()); // Either lookup a split load or create one. LoadInst *PLoad; if (SplitLoads) { PLoad = (*SplitLoads)[Idx]; } else { IRB.SetInsertPoint(LI); auto AS = LI->getPointerAddressSpace(); PLoad = IRB.CreateAlignedLoad( PartTy, getAdjustedPtr(IRB, DL, LoadBasePtr, APInt(DL.getIndexSizeInBits(AS), PartOffset), LoadPartPtrTy, LoadBasePtr->getName() + "."), getAdjustedAlignment(LI, PartOffset, DL).value(), /*IsVolatile*/ false, LI->getName()); } // And store this partition. IRB.SetInsertPoint(SI); auto AS = SI->getPointerAddressSpace(); StoreInst *PStore = IRB.CreateAlignedStore( PLoad, getAdjustedPtr(IRB, DL, StoreBasePtr, APInt(DL.getIndexSizeInBits(AS), PartOffset), StorePartPtrTy, StoreBasePtr->getName() + "."), getAdjustedAlignment(SI, PartOffset, DL).value(), /*IsVolatile*/ false); // Now build a new slice for the alloca. NewSlices.push_back( Slice(BaseOffset + PartOffset, BaseOffset + PartOffset + PartSize, &PStore->getOperandUse(PStore->getPointerOperandIndex()), /*IsSplittable*/ false)); LLVM_DEBUG(dbgs() << " new slice [" << NewSlices.back().beginOffset() << ", " << NewSlices.back().endOffset() << "): " << *PStore << "\n"); if (!SplitLoads) { LLVM_DEBUG(dbgs() << " of split load: " << *PLoad << "\n"); } // See if we've finished all the splits. if (Idx >= Size) break; // Setup the next partition. PartOffset = Offsets.Splits[Idx]; ++Idx; PartSize = (Idx < Size ? Offsets.Splits[Idx] : StoreSize) - PartOffset; } // We want to immediately iterate on any allocas impacted by splitting // this load, which is only relevant if it isn't a load of this alloca and // thus we didn't already split the loads above. We also have to keep track // of any promotable allocas we split loads on as they can no longer be // promoted. if (!SplitLoads) { if (AllocaInst *OtherAI = dyn_cast(LoadBasePtr)) { assert(OtherAI != &AI && "We can't re-split our own alloca!"); ResplitPromotableAllocas.insert(OtherAI); Worklist.insert(OtherAI); } else if (AllocaInst *OtherAI = dyn_cast( LoadBasePtr->stripInBoundsOffsets())) { assert(OtherAI != &AI && "We can't re-split our own alloca!"); Worklist.insert(OtherAI); } } // Mark the original store as dead now that we've split it up and kill its // slice. Note that we leave the original load in place unless this store // was its only use. It may in turn be split up if it is an alloca load // for some other alloca, but it may be a normal load. This may introduce // redundant loads, but where those can be merged the rest of the optimizer // should handle the merging, and this uncovers SSA splits which is more // important. In practice, the original loads will almost always be fully // split and removed eventually, and the splits will be merged by any // trivial CSE, including instcombine. if (LI->hasOneUse()) { assert(*LI->user_begin() == SI && "Single use isn't this store!"); DeadInsts.insert(LI); } DeadInsts.insert(SI); Offsets.S->kill(); } // Remove the killed slices that have ben pre-split. AS.erase(llvm::remove_if(AS, [](const Slice &S) { return S.isDead(); }), AS.end()); // Insert our new slices. This will sort and merge them into the sorted // sequence. AS.insert(NewSlices); LLVM_DEBUG(dbgs() << " Pre-split slices:\n"); #ifndef NDEBUG for (auto I = AS.begin(), E = AS.end(); I != E; ++I) LLVM_DEBUG(AS.print(dbgs(), I, " ")); #endif // Finally, don't try to promote any allocas that new require re-splitting. // They have already been added to the worklist above. PromotableAllocas.erase( llvm::remove_if( PromotableAllocas, [&](AllocaInst *AI) { return ResplitPromotableAllocas.count(AI); }), PromotableAllocas.end()); return true; } /// Rewrite an alloca partition's users. /// /// This routine drives both of the rewriting goals of the SROA pass. It tries /// to rewrite uses of an alloca partition to be conducive for SSA value /// promotion. If the partition needs a new, more refined alloca, this will /// build that new alloca, preserving as much type information as possible, and /// rewrite the uses of the old alloca to point at the new one and have the /// appropriate new offsets. It also evaluates how successful the rewrite was /// at enabling promotion and if it was successful queues the alloca to be /// promoted. AllocaInst *SROA::rewritePartition(AllocaInst &AI, AllocaSlices &AS, Partition &P) { // Try to compute a friendly type for this partition of the alloca. This // won't always succeed, in which case we fall back to a legal integer type // or an i8 array of an appropriate size. Type *SliceTy = nullptr; const DataLayout &DL = AI.getModule()->getDataLayout(); if (Type *CommonUseTy = findCommonType(P.begin(), P.end(), P.endOffset())) if (DL.getTypeAllocSize(CommonUseTy) >= P.size()) SliceTy = CommonUseTy; if (!SliceTy) if (Type *TypePartitionTy = getTypePartition(DL, AI.getAllocatedType(), P.beginOffset(), P.size())) SliceTy = TypePartitionTy; if ((!SliceTy || (SliceTy->isArrayTy() && SliceTy->getArrayElementType()->isIntegerTy())) && DL.isLegalInteger(P.size() * 8)) SliceTy = Type::getIntNTy(*C, P.size() * 8); if (!SliceTy) SliceTy = ArrayType::get(Type::getInt8Ty(*C), P.size()); assert(DL.getTypeAllocSize(SliceTy) >= P.size()); bool IsIntegerPromotable = isIntegerWideningViable(P, SliceTy, DL); VectorType *VecTy = IsIntegerPromotable ? nullptr : isVectorPromotionViable(P, DL); if (VecTy) SliceTy = VecTy; // Check for the case where we're going to rewrite to a new alloca of the // exact same type as the original, and with the same access offsets. In that // case, re-use the existing alloca, but still run through the rewriter to // perform phi and select speculation. // P.beginOffset() can be non-zero even with the same type in a case with // out-of-bounds access (e.g. @PR35657 function in SROA/basictest.ll). AllocaInst *NewAI; if (SliceTy == AI.getAllocatedType() && P.beginOffset() == 0) { NewAI = &AI; // FIXME: We should be able to bail at this point with "nothing changed". // FIXME: We might want to defer PHI speculation until after here. // FIXME: return nullptr; } else { // If alignment is unspecified we fallback on the one required by the ABI // for this type. We also make sure the alignment is compatible with // P.beginOffset(). const Align Alignment = commonAlignment( DL.getValueOrABITypeAlignment(MaybeAlign(AI.getAlignment()), AI.getAllocatedType()), P.beginOffset()); // If we will get at least this much alignment from the type alone, leave // the alloca's alignment unconstrained. const bool IsUnconstrained = Alignment <= DL.getABITypeAlignment(SliceTy); NewAI = new AllocaInst( SliceTy, AI.getType()->getAddressSpace(), nullptr, IsUnconstrained ? MaybeAlign() : Alignment, AI.getName() + ".sroa." + Twine(P.begin() - AS.begin()), &AI); // Copy the old AI debug location over to the new one. NewAI->setDebugLoc(AI.getDebugLoc()); ++NumNewAllocas; } LLVM_DEBUG(dbgs() << "Rewriting alloca partition " << "[" << P.beginOffset() << "," << P.endOffset() << ") to: " << *NewAI << "\n"); // Track the high watermark on the worklist as it is only relevant for // promoted allocas. We will reset it to this point if the alloca is not in // fact scheduled for promotion. unsigned PPWOldSize = PostPromotionWorklist.size(); unsigned NumUses = 0; SmallSetVector PHIUsers; SmallSetVector SelectUsers; AllocaSliceRewriter Rewriter(DL, AS, *this, AI, *NewAI, P.beginOffset(), P.endOffset(), IsIntegerPromotable, VecTy, PHIUsers, SelectUsers); bool Promotable = true; for (Slice *S : P.splitSliceTails()) { Promotable &= Rewriter.visit(S); ++NumUses; } for (Slice &S : P) { Promotable &= Rewriter.visit(&S); ++NumUses; } NumAllocaPartitionUses += NumUses; MaxUsesPerAllocaPartition.updateMax(NumUses); // Now that we've processed all the slices in the new partition, check if any // PHIs or Selects would block promotion. for (PHINode *PHI : PHIUsers) if (!isSafePHIToSpeculate(*PHI)) { Promotable = false; PHIUsers.clear(); SelectUsers.clear(); break; } for (SelectInst *Sel : SelectUsers) if (!isSafeSelectToSpeculate(*Sel)) { Promotable = false; PHIUsers.clear(); SelectUsers.clear(); break; } if (Promotable) { if (PHIUsers.empty() && SelectUsers.empty()) { // Promote the alloca. PromotableAllocas.push_back(NewAI); } else { // If we have either PHIs or Selects to speculate, add them to those // worklists and re-queue the new alloca so that we promote in on the // next iteration. for (PHINode *PHIUser : PHIUsers) SpeculatablePHIs.insert(PHIUser); for (SelectInst *SelectUser : SelectUsers) SpeculatableSelects.insert(SelectUser); Worklist.insert(NewAI); } } else { // Drop any post-promotion work items if promotion didn't happen. while (PostPromotionWorklist.size() > PPWOldSize) PostPromotionWorklist.pop_back(); // We couldn't promote and we didn't create a new partition, nothing // happened. if (NewAI == &AI) return nullptr; // If we can't promote the alloca, iterate on it to check for new // refinements exposed by splitting the current alloca. Don't iterate on an // alloca which didn't actually change and didn't get promoted. Worklist.insert(NewAI); } return NewAI; } /// Walks the slices of an alloca and form partitions based on them, /// rewriting each of their uses. bool SROA::splitAlloca(AllocaInst &AI, AllocaSlices &AS) { if (AS.begin() == AS.end()) return false; unsigned NumPartitions = 0; bool Changed = false; const DataLayout &DL = AI.getModule()->getDataLayout(); // First try to pre-split loads and stores. Changed |= presplitLoadsAndStores(AI, AS); // Now that we have identified any pre-splitting opportunities, // mark loads and stores unsplittable except for the following case. // We leave a slice splittable if all other slices are disjoint or fully // included in the slice, such as whole-alloca loads and stores. // If we fail to split these during pre-splitting, we want to force them // to be rewritten into a partition. bool IsSorted = true; uint64_t AllocaSize = DL.getTypeAllocSize(AI.getAllocatedType()); const uint64_t MaxBitVectorSize = 1024; if (AllocaSize <= MaxBitVectorSize) { // If a byte boundary is included in any load or store, a slice starting or // ending at the boundary is not splittable. SmallBitVector SplittableOffset(AllocaSize + 1, true); for (Slice &S : AS) for (unsigned O = S.beginOffset() + 1; O < S.endOffset() && O < AllocaSize; O++) SplittableOffset.reset(O); for (Slice &S : AS) { if (!S.isSplittable()) continue; if ((S.beginOffset() > AllocaSize || SplittableOffset[S.beginOffset()]) && (S.endOffset() > AllocaSize || SplittableOffset[S.endOffset()])) continue; if (isa(S.getUse()->getUser()) || isa(S.getUse()->getUser())) { S.makeUnsplittable(); IsSorted = false; } } } else { // We only allow whole-alloca splittable loads and stores // for a large alloca to avoid creating too large BitVector. for (Slice &S : AS) { if (!S.isSplittable()) continue; if (S.beginOffset() == 0 && S.endOffset() >= AllocaSize) continue; if (isa(S.getUse()->getUser()) || isa(S.getUse()->getUser())) { S.makeUnsplittable(); IsSorted = false; } } } if (!IsSorted) llvm::sort(AS); /// Describes the allocas introduced by rewritePartition in order to migrate /// the debug info. struct Fragment { AllocaInst *Alloca; uint64_t Offset; uint64_t Size; Fragment(AllocaInst *AI, uint64_t O, uint64_t S) : Alloca(AI), Offset(O), Size(S) {} }; SmallVector Fragments; // Rewrite each partition. for (auto &P : AS.partitions()) { if (AllocaInst *NewAI = rewritePartition(AI, AS, P)) { Changed = true; if (NewAI != &AI) { uint64_t SizeOfByte = 8; uint64_t AllocaSize = DL.getTypeSizeInBits(NewAI->getAllocatedType()); // Don't include any padding. uint64_t Size = std::min(AllocaSize, P.size() * SizeOfByte); Fragments.push_back(Fragment(NewAI, P.beginOffset() * SizeOfByte, Size)); } } ++NumPartitions; } NumAllocaPartitions += NumPartitions; MaxPartitionsPerAlloca.updateMax(NumPartitions); // Migrate debug information from the old alloca to the new alloca(s) // and the individual partitions. TinyPtrVector DbgDeclares = FindDbgAddrUses(&AI); if (!DbgDeclares.empty()) { auto *Var = DbgDeclares.front()->getVariable(); auto *Expr = DbgDeclares.front()->getExpression(); auto VarSize = Var->getSizeInBits(); DIBuilder DIB(*AI.getModule(), /*AllowUnresolved*/ false); uint64_t AllocaSize = DL.getTypeSizeInBits(AI.getAllocatedType()); for (auto Fragment : Fragments) { // Create a fragment expression describing the new partition or reuse AI's // expression if there is only one partition. auto *FragmentExpr = Expr; if (Fragment.Size < AllocaSize || Expr->isFragment()) { // If this alloca is already a scalar replacement of a larger aggregate, // Fragment.Offset describes the offset inside the scalar. auto ExprFragment = Expr->getFragmentInfo(); uint64_t Offset = ExprFragment ? ExprFragment->OffsetInBits : 0; uint64_t Start = Offset + Fragment.Offset; uint64_t Size = Fragment.Size; if (ExprFragment) { uint64_t AbsEnd = ExprFragment->OffsetInBits + ExprFragment->SizeInBits; if (Start >= AbsEnd) // No need to describe a SROAed padding. continue; Size = std::min(Size, AbsEnd - Start); } // The new, smaller fragment is stenciled out from the old fragment. if (auto OrigFragment = FragmentExpr->getFragmentInfo()) { assert(Start >= OrigFragment->OffsetInBits && "new fragment is outside of original fragment"); Start -= OrigFragment->OffsetInBits; } // The alloca may be larger than the variable. if (VarSize) { if (Size > *VarSize) Size = *VarSize; if (Size == 0 || Start + Size > *VarSize) continue; } // Avoid creating a fragment expression that covers the entire variable. if (!VarSize || *VarSize != Size) { if (auto E = DIExpression::createFragmentExpression(Expr, Start, Size)) FragmentExpr = *E; else continue; } } // Remove any existing intrinsics describing the same alloca. for (DbgVariableIntrinsic *OldDII : FindDbgAddrUses(Fragment.Alloca)) OldDII->eraseFromParent(); DIB.insertDeclare(Fragment.Alloca, Var, FragmentExpr, DbgDeclares.front()->getDebugLoc(), &AI); } } return Changed; } /// Clobber a use with undef, deleting the used value if it becomes dead. void SROA::clobberUse(Use &U) { Value *OldV = U; // Replace the use with an undef value. U = UndefValue::get(OldV->getType()); // Check for this making an instruction dead. We have to garbage collect // all the dead instructions to ensure the uses of any alloca end up being // minimal. if (Instruction *OldI = dyn_cast(OldV)) if (isInstructionTriviallyDead(OldI)) { DeadInsts.insert(OldI); } } /// Analyze an alloca for SROA. /// /// This analyzes the alloca to ensure we can reason about it, builds /// the slices of the alloca, and then hands it off to be split and /// rewritten as needed. bool SROA::runOnAlloca(AllocaInst &AI) { LLVM_DEBUG(dbgs() << "SROA alloca: " << AI << "\n"); ++NumAllocasAnalyzed; // Special case dead allocas, as they're trivial. if (AI.use_empty()) { AI.eraseFromParent(); return true; } const DataLayout &DL = AI.getModule()->getDataLayout(); // Skip alloca forms that this analysis can't handle. if (AI.isArrayAllocation() || !AI.getAllocatedType()->isSized() || DL.getTypeAllocSize(AI.getAllocatedType()) == 0) return false; bool Changed = false; // First, split any FCA loads and stores touching this alloca to promote // better splitting and promotion opportunities. AggLoadStoreRewriter AggRewriter(DL); Changed |= AggRewriter.rewrite(AI); // Build the slices using a recursive instruction-visiting builder. AllocaSlices AS(DL, AI); LLVM_DEBUG(AS.print(dbgs())); if (AS.isEscaped()) return Changed; // Delete all the dead users of this alloca before splitting and rewriting it. for (Instruction *DeadUser : AS.getDeadUsers()) { // Free up everything used by this instruction. for (Use &DeadOp : DeadUser->operands()) clobberUse(DeadOp); // Now replace the uses of this instruction. DeadUser->replaceAllUsesWith(UndefValue::get(DeadUser->getType())); // And mark it for deletion. DeadInsts.insert(DeadUser); Changed = true; } for (Use *DeadOp : AS.getDeadOperands()) { clobberUse(*DeadOp); Changed = true; } // No slices to split. Leave the dead alloca for a later pass to clean up. if (AS.begin() == AS.end()) return Changed; Changed |= splitAlloca(AI, AS); LLVM_DEBUG(dbgs() << " Speculating PHIs\n"); while (!SpeculatablePHIs.empty()) speculatePHINodeLoads(*SpeculatablePHIs.pop_back_val()); LLVM_DEBUG(dbgs() << " Speculating Selects\n"); while (!SpeculatableSelects.empty()) speculateSelectInstLoads(*SpeculatableSelects.pop_back_val()); return Changed; } /// Delete the dead instructions accumulated in this run. /// /// Recursively deletes the dead instructions we've accumulated. This is done /// at the very end to maximize locality of the recursive delete and to /// minimize the problems of invalidated instruction pointers as such pointers /// are used heavily in the intermediate stages of the algorithm. /// /// We also record the alloca instructions deleted here so that they aren't /// subsequently handed to mem2reg to promote. bool SROA::deleteDeadInstructions( SmallPtrSetImpl &DeletedAllocas) { bool Changed = false; while (!DeadInsts.empty()) { Instruction *I = DeadInsts.pop_back_val(); LLVM_DEBUG(dbgs() << "Deleting dead instruction: " << *I << "\n"); // If the instruction is an alloca, find the possible dbg.declare connected // to it, and remove it too. We must do this before calling RAUW or we will // not be able to find it. if (AllocaInst *AI = dyn_cast(I)) { DeletedAllocas.insert(AI); for (DbgVariableIntrinsic *OldDII : FindDbgAddrUses(AI)) OldDII->eraseFromParent(); } I->replaceAllUsesWith(UndefValue::get(I->getType())); for (Use &Operand : I->operands()) if (Instruction *U = dyn_cast(Operand)) { // Zero out the operand and see if it becomes trivially dead. Operand = nullptr; if (isInstructionTriviallyDead(U)) DeadInsts.insert(U); } ++NumDeleted; I->eraseFromParent(); Changed = true; } return Changed; } /// Promote the allocas, using the best available technique. /// /// This attempts to promote whatever allocas have been identified as viable in /// the PromotableAllocas list. If that list is empty, there is nothing to do. /// This function returns whether any promotion occurred. bool SROA::promoteAllocas(Function &F) { if (PromotableAllocas.empty()) return false; NumPromoted += PromotableAllocas.size(); LLVM_DEBUG(dbgs() << "Promoting allocas with mem2reg...\n"); PromoteMemToReg(PromotableAllocas, *DT, AC); PromotableAllocas.clear(); return true; } PreservedAnalyses SROA::runImpl(Function &F, DominatorTree &RunDT, AssumptionCache &RunAC) { LLVM_DEBUG(dbgs() << "SROA function: " << F.getName() << "\n"); C = &F.getContext(); DT = &RunDT; AC = &RunAC; BasicBlock &EntryBB = F.getEntryBlock(); for (BasicBlock::iterator I = EntryBB.begin(), E = std::prev(EntryBB.end()); I != E; ++I) { if (AllocaInst *AI = dyn_cast(I)) Worklist.insert(AI); } bool Changed = false; // A set of deleted alloca instruction pointers which should be removed from // the list of promotable allocas. SmallPtrSet DeletedAllocas; do { while (!Worklist.empty()) { Changed |= runOnAlloca(*Worklist.pop_back_val()); Changed |= deleteDeadInstructions(DeletedAllocas); // Remove the deleted allocas from various lists so that we don't try to // continue processing them. if (!DeletedAllocas.empty()) { auto IsInSet = [&](AllocaInst *AI) { return DeletedAllocas.count(AI); }; Worklist.remove_if(IsInSet); PostPromotionWorklist.remove_if(IsInSet); PromotableAllocas.erase(llvm::remove_if(PromotableAllocas, IsInSet), PromotableAllocas.end()); DeletedAllocas.clear(); } } Changed |= promoteAllocas(F); Worklist = PostPromotionWorklist; PostPromotionWorklist.clear(); } while (!Worklist.empty()); if (!Changed) return PreservedAnalyses::all(); PreservedAnalyses PA; PA.preserveSet(); PA.preserve(); return PA; } PreservedAnalyses SROA::run(Function &F, FunctionAnalysisManager &AM) { return runImpl(F, AM.getResult(F), AM.getResult(F)); } /// A legacy pass for the legacy pass manager that wraps the \c SROA pass. /// /// This is in the llvm namespace purely to allow it to be a friend of the \c /// SROA pass. class llvm::sroa::SROALegacyPass : public FunctionPass { /// The SROA implementation. SROA Impl; public: static char ID; SROALegacyPass() : FunctionPass(ID) { initializeSROALegacyPassPass(*PassRegistry::getPassRegistry()); } bool runOnFunction(Function &F) override { if (skipFunction(F)) return false; auto PA = Impl.runImpl( F, getAnalysis().getDomTree(), getAnalysis().getAssumptionCache(F)); return !PA.areAllPreserved(); } void getAnalysisUsage(AnalysisUsage &AU) const override { AU.addRequired(); AU.addRequired(); AU.addPreserved(); AU.setPreservesCFG(); } StringRef getPassName() const override { return "SROA"; } }; char SROALegacyPass::ID = 0; FunctionPass *llvm::createSROAPass() { return new SROALegacyPass(); } INITIALIZE_PASS_BEGIN(SROALegacyPass, "sroa", "Scalar Replacement Of Aggregates", false, false) INITIALIZE_PASS_DEPENDENCY(AssumptionCacheTracker) INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass) INITIALIZE_PASS_END(SROALegacyPass, "sroa", "Scalar Replacement Of Aggregates", false, false) diff --git a/contrib/llvm-project/llvm/tools/llvm-ar/llvm-ar.cpp b/contrib/llvm-project/llvm/tools/llvm-ar/llvm-ar.cpp index c339dfe1f33e..516cc2626b51 100644 --- a/contrib/llvm-project/llvm/tools/llvm-ar/llvm-ar.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-ar/llvm-ar.cpp @@ -1,1226 +1,1225 @@ //===-- llvm-ar.cpp - LLVM archive librarian utility ----------------------===// // // 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 // //===----------------------------------------------------------------------===// // // Builds up (relatively) standard unix archive files (.a) containing LLVM // bitcode or other files. // //===----------------------------------------------------------------------===// #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/Triple.h" #include "llvm/IR/LLVMContext.h" #include "llvm/Object/Archive.h" #include "llvm/Object/ArchiveWriter.h" #include "llvm/Object/MachO.h" #include "llvm/Object/ObjectFile.h" #include "llvm/Support/Chrono.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Errc.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Format.h" #include "llvm/Support/FormatVariadic.h" #include "llvm/Support/InitLLVM.h" #include "llvm/Support/LineIterator.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" #include "llvm/Support/Process.h" #include "llvm/Support/StringSaver.h" #include "llvm/Support/TargetSelect.h" #include "llvm/Support/ToolOutputFile.h" #include "llvm/Support/WithColor.h" #include "llvm/Support/raw_ostream.h" #include "llvm/ToolDrivers/llvm-dlltool/DlltoolDriver.h" #include "llvm/ToolDrivers/llvm-lib/LibDriver.h" #if !defined(_MSC_VER) && !defined(__MINGW32__) #include #else #include #endif #ifdef _WIN32 -#define WIN32_LEAN_AND_MEAN -#include +#include "llvm/Support/Windows/WindowsSupport.h" #endif using namespace llvm; // The name this program was invoked as. static StringRef ToolName; // The basename of this program. static StringRef Stem; const char RanlibHelp[] = R"(OVERVIEW: LLVM Ranlib (llvm-ranlib) This program generates an index to speed access to archives USAGE: llvm-ranlib OPTIONS: -h --help - Display available options -v --version - Display the version of this program -D - Use zero for timestamps and uids/gids (default) -U - Use actual timestamps and uids/gids )"; const char ArHelp[] = R"(OVERVIEW: LLVM Archiver USAGE: llvm-ar [options] [-][modifiers] [relpos] [count] [files] llvm-ar -M [ - ignored for compatibility -h --help - display this help and exit --version - print the version and exit @ - read options from OPERATIONS: d - delete [files] from the archive m - move [files] in the archive p - print [files] found in the archive q - quick append [files] to the archive r - replace or insert [files] into the archive s - act as ranlib t - display contents of archive x - extract [files] from the archive MODIFIERS: [a] - put [files] after [relpos] [b] - put [files] before [relpos] (same as [i]) [c] - do not warn if archive had to be created [D] - use zero for timestamps and uids/gids (default) [h] - display this help and exit [i] - put [files] before [relpos] (same as [b]) [l] - ignored for compatibility [L] - add archive's contents [N] - use instance [count] of name [o] - preserve original dates [O] - display member offsets [P] - use full names when matching (implied for thin archives) [s] - create an archive index (cf. ranlib) [S] - do not build a symbol table [T] - create a thin archive [u] - update only [files] newer than archive contents [U] - use actual timestamps and uids/gids [v] - be verbose about actions taken [V] - display the version and exit )"; void printHelpMessage() { if (Stem.contains_lower("ranlib")) outs() << RanlibHelp; else if (Stem.contains_lower("ar")) outs() << ArHelp; } static unsigned MRILineNumber; static bool ParsingMRIScript; // Show the error plus the usage message, and exit. LLVM_ATTRIBUTE_NORETURN static void badUsage(Twine Error) { WithColor::error(errs(), ToolName) << Error << "\n"; printHelpMessage(); exit(1); } // Show the error message and exit. LLVM_ATTRIBUTE_NORETURN static void fail(Twine Error) { if (ParsingMRIScript) { WithColor::error(errs(), ToolName) << "script line " << MRILineNumber << ": " << Error << "\n"; } else { WithColor::error(errs(), ToolName) << Error << "\n"; } exit(1); } static void failIfError(std::error_code EC, Twine Context = "") { if (!EC) return; std::string ContextStr = Context.str(); if (ContextStr.empty()) fail(EC.message()); fail(Context + ": " + EC.message()); } static void failIfError(Error E, Twine Context = "") { if (!E) return; handleAllErrors(std::move(E), [&](const llvm::ErrorInfoBase &EIB) { std::string ContextStr = Context.str(); if (ContextStr.empty()) fail(EIB.message()); fail(Context + ": " + EIB.message()); }); } static SmallVector PositionalArgs; static bool MRI; namespace { enum Format { Default, GNU, BSD, DARWIN, Unknown }; } static Format FormatType = Default; static std::string Options; // This enumeration delineates the kinds of operations on an archive // that are permitted. enum ArchiveOperation { Print, ///< Print the contents of the archive Delete, ///< Delete the specified members Move, ///< Move members to end or as given by {a,b,i} modifiers QuickAppend, ///< Quickly append to end of archive ReplaceOrInsert, ///< Replace or Insert members DisplayTable, ///< Display the table of contents Extract, ///< Extract files back to file system CreateSymTab ///< Create a symbol table in an existing archive }; // Modifiers to follow operation to vary behavior static bool AddAfter = false; ///< 'a' modifier static bool AddBefore = false; ///< 'b' modifier static bool Create = false; ///< 'c' modifier static bool OriginalDates = false; ///< 'o' modifier static bool DisplayMemberOffsets = false; ///< 'O' modifier static bool CompareFullPath = false; ///< 'P' modifier static bool OnlyUpdate = false; ///< 'u' modifier static bool Verbose = false; ///< 'v' modifier static bool Symtab = true; ///< 's' modifier static bool Deterministic = true; ///< 'D' and 'U' modifiers static bool Thin = false; ///< 'T' modifier static bool AddLibrary = false; ///< 'L' modifier // Relative Positional Argument (for insert/move). This variable holds // the name of the archive member to which the 'a', 'b' or 'i' modifier // refers. Only one of 'a', 'b' or 'i' can be specified so we only need // one variable. static std::string RelPos; // Count parameter for 'N' modifier. This variable specifies which file should // match for extract/delete operations when there are multiple matches. This is // 1-indexed. A value of 0 is invalid, and implies 'N' is not used. static int CountParam = 0; // This variable holds the name of the archive file as given on the // command line. static std::string ArchiveName; static std::vector> ArchiveBuffers; static std::vector> Archives; // This variable holds the list of member files to proecess, as given // on the command line. static std::vector Members; // Static buffer to hold StringRefs. static BumpPtrAllocator Alloc; // Extract the member filename from the command line for the [relpos] argument // associated with a, b, and i modifiers static void getRelPos() { if (PositionalArgs.empty()) fail("expected [relpos] for 'a', 'b', or 'i' modifier"); RelPos = PositionalArgs[0]; PositionalArgs.erase(PositionalArgs.begin()); } // Extract the parameter from the command line for the [count] argument // associated with the N modifier static void getCountParam() { if (PositionalArgs.empty()) badUsage("expected [count] for 'N' modifier"); auto CountParamArg = StringRef(PositionalArgs[0]); if (CountParamArg.getAsInteger(10, CountParam)) badUsage("value for [count] must be numeric, got: " + CountParamArg); if (CountParam < 1) badUsage("value for [count] must be positive, got: " + CountParamArg); PositionalArgs.erase(PositionalArgs.begin()); } // Get the archive file name from the command line static void getArchive() { if (PositionalArgs.empty()) badUsage("an archive name must be specified"); ArchiveName = PositionalArgs[0]; PositionalArgs.erase(PositionalArgs.begin()); } static object::Archive &readLibrary(const Twine &Library) { auto BufOrErr = MemoryBuffer::getFile(Library, -1, false); failIfError(BufOrErr.getError(), "could not open library " + Library); ArchiveBuffers.push_back(std::move(*BufOrErr)); auto LibOrErr = object::Archive::create(ArchiveBuffers.back()->getMemBufferRef()); failIfError(errorToErrorCode(LibOrErr.takeError()), "could not parse library"); Archives.push_back(std::move(*LibOrErr)); return *Archives.back(); } static void runMRIScript(); // Parse the command line options as presented and return the operation // specified. Process all modifiers and check to make sure that constraints on // modifier/operation pairs have not been violated. static ArchiveOperation parseCommandLine() { if (MRI) { if (!PositionalArgs.empty() || !Options.empty()) badUsage("cannot mix -M and other options"); runMRIScript(); } // Keep track of number of operations. We can only specify one // per execution. unsigned NumOperations = 0; // Keep track of the number of positional modifiers (a,b,i). Only // one can be specified. unsigned NumPositional = 0; // Keep track of which operation was requested ArchiveOperation Operation; bool MaybeJustCreateSymTab = false; for (unsigned i = 0; i < Options.size(); ++i) { switch (Options[i]) { case 'd': ++NumOperations; Operation = Delete; break; case 'm': ++NumOperations; Operation = Move; break; case 'p': ++NumOperations; Operation = Print; break; case 'q': ++NumOperations; Operation = QuickAppend; break; case 'r': ++NumOperations; Operation = ReplaceOrInsert; break; case 't': ++NumOperations; Operation = DisplayTable; break; case 'x': ++NumOperations; Operation = Extract; break; case 'c': Create = true; break; case 'l': /* accepted but unused */ break; case 'o': OriginalDates = true; break; case 'O': DisplayMemberOffsets = true; break; case 'P': CompareFullPath = true; break; case 's': Symtab = true; MaybeJustCreateSymTab = true; break; case 'S': Symtab = false; break; case 'u': OnlyUpdate = true; break; case 'v': Verbose = true; break; case 'a': getRelPos(); AddAfter = true; NumPositional++; break; case 'b': getRelPos(); AddBefore = true; NumPositional++; break; case 'i': getRelPos(); AddBefore = true; NumPositional++; break; case 'D': Deterministic = true; break; case 'U': Deterministic = false; break; case 'N': getCountParam(); break; case 'T': Thin = true; // Thin archives store path names, so P should be forced. CompareFullPath = true; break; case 'L': AddLibrary = true; break; case 'V': cl::PrintVersionMessage(); exit(0); case 'h': printHelpMessage(); exit(0); default: badUsage(std::string("unknown option ") + Options[i]); } } // At this point, the next thing on the command line must be // the archive name. getArchive(); // Everything on the command line at this point is a member. Members.assign(PositionalArgs.begin(), PositionalArgs.end()); if (NumOperations == 0 && MaybeJustCreateSymTab) { NumOperations = 1; Operation = CreateSymTab; if (!Members.empty()) badUsage("the 's' operation takes only an archive as argument"); } // Perform various checks on the operation/modifier specification // to make sure we are dealing with a legal request. if (NumOperations == 0) badUsage("you must specify at least one of the operations"); if (NumOperations > 1) badUsage("only one operation may be specified"); if (NumPositional > 1) badUsage("you may only specify one of 'a', 'b', and 'i' modifiers"); if (AddAfter || AddBefore) if (Operation != Move && Operation != ReplaceOrInsert) badUsage("the 'a', 'b' and 'i' modifiers can only be specified with " "the 'm' or 'r' operations"); if (CountParam) if (Operation != Extract && Operation != Delete) badUsage("the 'N' modifier can only be specified with the 'x' or 'd' " "operations"); if (OriginalDates && Operation != Extract) badUsage("the 'o' modifier is only applicable to the 'x' operation"); if (OnlyUpdate && Operation != ReplaceOrInsert) badUsage("the 'u' modifier is only applicable to the 'r' operation"); if (AddLibrary && Operation != QuickAppend) badUsage("the 'L' modifier is only applicable to the 'q' operation"); // Return the parsed operation to the caller return Operation; } // Implements the 'p' operation. This function traverses the archive // looking for members that match the path list. static void doPrint(StringRef Name, const object::Archive::Child &C) { if (Verbose) outs() << "Printing " << Name << "\n"; Expected DataOrErr = C.getBuffer(); failIfError(DataOrErr.takeError()); StringRef Data = *DataOrErr; outs().write(Data.data(), Data.size()); } // Utility function for printing out the file mode when the 't' operation is in // verbose mode. static void printMode(unsigned mode) { outs() << ((mode & 004) ? "r" : "-"); outs() << ((mode & 002) ? "w" : "-"); outs() << ((mode & 001) ? "x" : "-"); } // Implement the 't' operation. This function prints out just // the file names of each of the members. However, if verbose mode is requested // ('v' modifier) then the file type, permission mode, user, group, size, and // modification time are also printed. static void doDisplayTable(StringRef Name, const object::Archive::Child &C) { if (Verbose) { Expected ModeOrErr = C.getAccessMode(); failIfError(ModeOrErr.takeError()); sys::fs::perms Mode = ModeOrErr.get(); printMode((Mode >> 6) & 007); printMode((Mode >> 3) & 007); printMode(Mode & 007); Expected UIDOrErr = C.getUID(); failIfError(UIDOrErr.takeError()); outs() << ' ' << UIDOrErr.get(); Expected GIDOrErr = C.getGID(); failIfError(GIDOrErr.takeError()); outs() << '/' << GIDOrErr.get(); Expected Size = C.getSize(); failIfError(Size.takeError()); outs() << ' ' << format("%6llu", Size.get()); auto ModTimeOrErr = C.getLastModified(); failIfError(ModTimeOrErr.takeError()); // Note: formatv() only handles the default TimePoint<>, which is in // nanoseconds. // TODO: fix format_provider> to allow other units. sys::TimePoint<> ModTimeInNs = ModTimeOrErr.get(); outs() << ' ' << formatv("{0:%b %e %H:%M %Y}", ModTimeInNs); outs() << ' '; } if (C.getParent()->isThin()) { if (!sys::path::is_absolute(Name)) { StringRef ParentDir = sys::path::parent_path(ArchiveName); if (!ParentDir.empty()) outs() << sys::path::convert_to_slash(ParentDir) << '/'; } outs() << Name; } else { outs() << Name; if (DisplayMemberOffsets) outs() << " 0x" << utohexstr(C.getDataOffset(), true); } outs() << '\n'; } static std::string normalizePath(StringRef Path) { return CompareFullPath ? sys::path::convert_to_slash(Path) : std::string(sys::path::filename(Path)); } static bool comparePaths(StringRef Path1, StringRef Path2) { // When on Windows this function calls CompareStringOrdinal // as Windows file paths are case-insensitive. // CompareStringOrdinal compares two Unicode strings for // binary equivalence and allows for case insensitivity. #ifdef _WIN32 SmallVector WPath1, WPath2; failIfError(sys::path::widenPath(normalizePath(Path1), WPath1)); failIfError(sys::path::widenPath(normalizePath(Path2), WPath2)); return CompareStringOrdinal(WPath1.data(), WPath1.size(), WPath2.data(), WPath2.size(), true) == CSTR_EQUAL; #else return normalizePath(Path1) == normalizePath(Path2); #endif } // Implement the 'x' operation. This function extracts files back to the file // system. static void doExtract(StringRef Name, const object::Archive::Child &C) { // Retain the original mode. Expected ModeOrErr = C.getAccessMode(); failIfError(ModeOrErr.takeError()); sys::fs::perms Mode = ModeOrErr.get(); llvm::StringRef outputFilePath = sys::path::filename(Name); if (Verbose) outs() << "x - " << outputFilePath << '\n'; int FD; failIfError(sys::fs::openFileForWrite(outputFilePath, FD, sys::fs::CD_CreateAlways, sys::fs::OF_None, Mode), Name); { raw_fd_ostream file(FD, false); // Get the data and its length Expected BufOrErr = C.getBuffer(); failIfError(BufOrErr.takeError()); StringRef Data = BufOrErr.get(); // Write the data. file.write(Data.data(), Data.size()); } // If we're supposed to retain the original modification times, etc. do so // now. if (OriginalDates) { auto ModTimeOrErr = C.getLastModified(); failIfError(ModTimeOrErr.takeError()); failIfError( sys::fs::setLastAccessAndModificationTime(FD, ModTimeOrErr.get())); } if (close(FD)) fail("Could not close the file"); } static bool shouldCreateArchive(ArchiveOperation Op) { switch (Op) { case Print: case Delete: case Move: case DisplayTable: case Extract: case CreateSymTab: return false; case QuickAppend: case ReplaceOrInsert: return true; } llvm_unreachable("Missing entry in covered switch."); } static void performReadOperation(ArchiveOperation Operation, object::Archive *OldArchive) { if (Operation == Extract && OldArchive->isThin()) fail("extracting from a thin archive is not supported"); bool Filter = !Members.empty(); StringMap MemberCount; { Error Err = Error::success(); for (auto &C : OldArchive->children(Err)) { Expected NameOrErr = C.getName(); failIfError(NameOrErr.takeError()); StringRef Name = NameOrErr.get(); if (Filter) { auto I = find_if(Members, [Name](StringRef Path) { return comparePaths(Name, Path); }); if (I == Members.end()) continue; if (CountParam && ++MemberCount[Name] != CountParam) continue; Members.erase(I); } switch (Operation) { default: llvm_unreachable("Not a read operation"); case Print: doPrint(Name, C); break; case DisplayTable: doDisplayTable(Name, C); break; case Extract: doExtract(Name, C); break; } } failIfError(std::move(Err)); } if (Members.empty()) return; for (StringRef Name : Members) WithColor::error(errs(), ToolName) << "'" << Name << "' was not found\n"; exit(1); } static void addChildMember(std::vector &Members, const object::Archive::Child &M, bool FlattenArchive = false) { if (Thin && !M.getParent()->isThin()) fail("cannot convert a regular archive to a thin one"); Expected NMOrErr = NewArchiveMember::getOldMember(M, Deterministic); failIfError(NMOrErr.takeError()); // If the child member we're trying to add is thin, use the path relative to // the archive it's in, so the file resolves correctly. if (Thin && FlattenArchive) { StringSaver Saver(Alloc); Expected FileNameOrErr = M.getName(); failIfError(FileNameOrErr.takeError()); if (sys::path::is_absolute(*FileNameOrErr)) { NMOrErr->MemberName = Saver.save(sys::path::convert_to_slash(*FileNameOrErr)); } else { FileNameOrErr = M.getFullName(); failIfError(FileNameOrErr.takeError()); Expected PathOrErr = computeArchiveRelativePath(ArchiveName, *FileNameOrErr); NMOrErr->MemberName = Saver.save( PathOrErr ? *PathOrErr : sys::path::convert_to_slash(*FileNameOrErr)); } } if (FlattenArchive && identify_magic(NMOrErr->Buf->getBuffer()) == file_magic::archive) { Expected FileNameOrErr = M.getFullName(); failIfError(FileNameOrErr.takeError()); object::Archive &Lib = readLibrary(*FileNameOrErr); // When creating thin archives, only flatten if the member is also thin. if (!Thin || Lib.isThin()) { Error Err = Error::success(); // Only Thin archives are recursively flattened. for (auto &Child : Lib.children(Err)) addChildMember(Members, Child, /*FlattenArchive=*/Thin); failIfError(std::move(Err)); return; } } Members.push_back(std::move(*NMOrErr)); } static void addMember(std::vector &Members, StringRef FileName, bool FlattenArchive = false) { Expected NMOrErr = NewArchiveMember::getFile(FileName, Deterministic); failIfError(NMOrErr.takeError(), FileName); StringSaver Saver(Alloc); // For regular archives, use the basename of the object path for the member // name. For thin archives, use the full relative paths so the file resolves // correctly. if (!Thin) { NMOrErr->MemberName = sys::path::filename(NMOrErr->MemberName); } else { if (sys::path::is_absolute(FileName)) NMOrErr->MemberName = Saver.save(sys::path::convert_to_slash(FileName)); else { Expected PathOrErr = computeArchiveRelativePath(ArchiveName, FileName); NMOrErr->MemberName = Saver.save( PathOrErr ? *PathOrErr : sys::path::convert_to_slash(FileName)); } } if (FlattenArchive && identify_magic(NMOrErr->Buf->getBuffer()) == file_magic::archive) { object::Archive &Lib = readLibrary(FileName); // When creating thin archives, only flatten if the member is also thin. if (!Thin || Lib.isThin()) { Error Err = Error::success(); // Only Thin archives are recursively flattened. for (auto &Child : Lib.children(Err)) addChildMember(Members, Child, /*FlattenArchive=*/Thin); failIfError(std::move(Err)); return; } } Members.push_back(std::move(*NMOrErr)); } enum InsertAction { IA_AddOldMember, IA_AddNewMember, IA_Delete, IA_MoveOldMember, IA_MoveNewMember }; static InsertAction computeInsertAction(ArchiveOperation Operation, const object::Archive::Child &Member, StringRef Name, std::vector::iterator &Pos, StringMap &MemberCount) { if (Operation == QuickAppend || Members.empty()) return IA_AddOldMember; auto MI = find_if( Members, [Name](StringRef Path) { return comparePaths(Name, Path); }); if (MI == Members.end()) return IA_AddOldMember; Pos = MI; if (Operation == Delete) { if (CountParam && ++MemberCount[Name] != CountParam) return IA_AddOldMember; return IA_Delete; } if (Operation == Move) return IA_MoveOldMember; if (Operation == ReplaceOrInsert) { if (!OnlyUpdate) { if (RelPos.empty()) return IA_AddNewMember; return IA_MoveNewMember; } // We could try to optimize this to a fstat, but it is not a common // operation. sys::fs::file_status Status; failIfError(sys::fs::status(*MI, Status), *MI); auto ModTimeOrErr = Member.getLastModified(); failIfError(ModTimeOrErr.takeError()); if (Status.getLastModificationTime() < ModTimeOrErr.get()) { if (RelPos.empty()) return IA_AddOldMember; return IA_MoveOldMember; } if (RelPos.empty()) return IA_AddNewMember; return IA_MoveNewMember; } llvm_unreachable("No such operation"); } // We have to walk this twice and computing it is not trivial, so creating an // explicit std::vector is actually fairly efficient. static std::vector computeNewArchiveMembers(ArchiveOperation Operation, object::Archive *OldArchive) { std::vector Ret; std::vector Moved; int InsertPos = -1; if (OldArchive) { Error Err = Error::success(); StringMap MemberCount; for (auto &Child : OldArchive->children(Err)) { int Pos = Ret.size(); Expected NameOrErr = Child.getName(); failIfError(NameOrErr.takeError()); std::string Name = NameOrErr.get(); if (comparePaths(Name, RelPos)) { assert(AddAfter || AddBefore); if (AddBefore) InsertPos = Pos; else InsertPos = Pos + 1; } std::vector::iterator MemberI = Members.end(); InsertAction Action = computeInsertAction(Operation, Child, Name, MemberI, MemberCount); switch (Action) { case IA_AddOldMember: addChildMember(Ret, Child, /*FlattenArchive=*/Thin); break; case IA_AddNewMember: addMember(Ret, *MemberI); break; case IA_Delete: break; case IA_MoveOldMember: addChildMember(Moved, Child, /*FlattenArchive=*/Thin); break; case IA_MoveNewMember: addMember(Moved, *MemberI); break; } // When processing elements with the count param, we need to preserve the // full members list when iterating over all archive members. For // instance, "llvm-ar dN 2 archive.a member.o" should delete the second // file named member.o it sees; we are not done with member.o the first // time we see it in the archive. if (MemberI != Members.end() && !CountParam) Members.erase(MemberI); } failIfError(std::move(Err)); } if (Operation == Delete) return Ret; if (!RelPos.empty() && InsertPos == -1) fail("insertion point not found"); if (RelPos.empty()) InsertPos = Ret.size(); assert(unsigned(InsertPos) <= Ret.size()); int Pos = InsertPos; for (auto &M : Moved) { Ret.insert(Ret.begin() + Pos, std::move(M)); ++Pos; } if (AddLibrary) { assert(Operation == QuickAppend); for (auto &Member : Members) addMember(Ret, Member, /*FlattenArchive=*/true); return Ret; } std::vector NewMembers; for (auto &Member : Members) addMember(NewMembers, Member, /*FlattenArchive=*/Thin); Ret.reserve(Ret.size() + NewMembers.size()); std::move(NewMembers.begin(), NewMembers.end(), std::inserter(Ret, std::next(Ret.begin(), InsertPos))); return Ret; } static object::Archive::Kind getDefaultForHost() { return Triple(sys::getProcessTriple()).isOSDarwin() ? object::Archive::K_DARWIN : object::Archive::K_GNU; } static object::Archive::Kind getKindFromMember(const NewArchiveMember &Member) { Expected> OptionalObject = object::ObjectFile::createObjectFile(Member.Buf->getMemBufferRef()); if (OptionalObject) return isa(**OptionalObject) ? object::Archive::K_DARWIN : object::Archive::K_GNU; // squelch the error in case we had a non-object file consumeError(OptionalObject.takeError()); return getDefaultForHost(); } static void performWriteOperation(ArchiveOperation Operation, object::Archive *OldArchive, std::unique_ptr OldArchiveBuf, std::vector *NewMembersP) { std::vector NewMembers; if (!NewMembersP) NewMembers = computeNewArchiveMembers(Operation, OldArchive); object::Archive::Kind Kind; switch (FormatType) { case Default: if (Thin) Kind = object::Archive::K_GNU; else if (OldArchive) Kind = OldArchive->kind(); else if (NewMembersP) Kind = !NewMembersP->empty() ? getKindFromMember(NewMembersP->front()) : getDefaultForHost(); else Kind = !NewMembers.empty() ? getKindFromMember(NewMembers.front()) : getDefaultForHost(); break; case GNU: Kind = object::Archive::K_GNU; break; case BSD: if (Thin) fail("only the gnu format has a thin mode"); Kind = object::Archive::K_BSD; break; case DARWIN: if (Thin) fail("only the gnu format has a thin mode"); Kind = object::Archive::K_DARWIN; break; case Unknown: llvm_unreachable(""); } Error E = writeArchive(ArchiveName, NewMembersP ? *NewMembersP : NewMembers, Symtab, Kind, Deterministic, Thin, std::move(OldArchiveBuf)); failIfError(std::move(E), ArchiveName); } static void createSymbolTable(object::Archive *OldArchive) { // When an archive is created or modified, if the s option is given, the // resulting archive will have a current symbol table. If the S option // is given, it will have no symbol table. // In summary, we only need to update the symbol table if we have none. // This is actually very common because of broken build systems that think // they have to run ranlib. if (OldArchive->hasSymbolTable()) return; performWriteOperation(CreateSymTab, OldArchive, nullptr, nullptr); } static void performOperation(ArchiveOperation Operation, object::Archive *OldArchive, std::unique_ptr OldArchiveBuf, std::vector *NewMembers) { switch (Operation) { case Print: case DisplayTable: case Extract: performReadOperation(Operation, OldArchive); return; case Delete: case Move: case QuickAppend: case ReplaceOrInsert: performWriteOperation(Operation, OldArchive, std::move(OldArchiveBuf), NewMembers); return; case CreateSymTab: createSymbolTable(OldArchive); return; } llvm_unreachable("Unknown operation."); } static int performOperation(ArchiveOperation Operation, std::vector *NewMembers) { // Create or open the archive object. ErrorOr> Buf = MemoryBuffer::getFile(ArchiveName, -1, false); std::error_code EC = Buf.getError(); if (EC && EC != errc::no_such_file_or_directory) fail("error opening '" + ArchiveName + "': " + EC.message()); if (!EC) { Error Err = Error::success(); object::Archive Archive(Buf.get()->getMemBufferRef(), Err); failIfError(std::move(Err), "unable to load '" + ArchiveName + "'"); if (Archive.isThin()) CompareFullPath = true; performOperation(Operation, &Archive, std::move(Buf.get()), NewMembers); return 0; } assert(EC == errc::no_such_file_or_directory); if (!shouldCreateArchive(Operation)) { failIfError(EC, Twine("error loading '") + ArchiveName + "'"); } else { if (!Create) { // Produce a warning if we should and we're creating the archive WithColor::warning(errs(), ToolName) << "creating " << ArchiveName << "\n"; } } performOperation(Operation, nullptr, nullptr, NewMembers); return 0; } static void runMRIScript() { enum class MRICommand { AddLib, AddMod, Create, CreateThin, Delete, Save, End, Invalid }; ErrorOr> Buf = MemoryBuffer::getSTDIN(); failIfError(Buf.getError()); const MemoryBuffer &Ref = *Buf.get(); bool Saved = false; std::vector NewMembers; ParsingMRIScript = true; for (line_iterator I(Ref, /*SkipBlanks*/ false), E; I != E; ++I) { ++MRILineNumber; StringRef Line = *I; Line = Line.split(';').first; Line = Line.split('*').first; Line = Line.trim(); if (Line.empty()) continue; StringRef CommandStr, Rest; std::tie(CommandStr, Rest) = Line.split(' '); Rest = Rest.trim(); if (!Rest.empty() && Rest.front() == '"' && Rest.back() == '"') Rest = Rest.drop_front().drop_back(); auto Command = StringSwitch(CommandStr.lower()) .Case("addlib", MRICommand::AddLib) .Case("addmod", MRICommand::AddMod) .Case("create", MRICommand::Create) .Case("createthin", MRICommand::CreateThin) .Case("delete", MRICommand::Delete) .Case("save", MRICommand::Save) .Case("end", MRICommand::End) .Default(MRICommand::Invalid); switch (Command) { case MRICommand::AddLib: { object::Archive &Lib = readLibrary(Rest); { Error Err = Error::success(); for (auto &Member : Lib.children(Err)) addChildMember(NewMembers, Member, /*FlattenArchive=*/Thin); failIfError(std::move(Err)); } break; } case MRICommand::AddMod: addMember(NewMembers, Rest); break; case MRICommand::CreateThin: Thin = true; LLVM_FALLTHROUGH; case MRICommand::Create: Create = true; if (!ArchiveName.empty()) fail("editing multiple archives not supported"); if (Saved) fail("file already saved"); ArchiveName = Rest; break; case MRICommand::Delete: { llvm::erase_if(NewMembers, [=](NewArchiveMember &M) { return comparePaths(M.MemberName, Rest); }); break; } case MRICommand::Save: Saved = true; break; case MRICommand::End: break; case MRICommand::Invalid: fail("unknown command: " + CommandStr); } } ParsingMRIScript = false; // Nothing to do if not saved. if (Saved) performOperation(ReplaceOrInsert, &NewMembers); exit(0); } static bool handleGenericOption(StringRef arg) { if (arg == "-help" || arg == "--help" || arg == "-h") { printHelpMessage(); return true; } if (arg == "-version" || arg == "--version") { cl::PrintVersionMessage(); return true; } return false; } static int ar_main(int argc, char **argv) { SmallVector Argv(argv, argv + argc); StringSaver Saver(Alloc); cl::ExpandResponseFiles(Saver, cl::TokenizeGNUCommandLine, Argv); for (size_t i = 1; i < Argv.size(); ++i) { StringRef Arg = Argv[i]; const char *match = nullptr; auto MatchFlagWithArg = [&](const char *expected) { size_t len = strlen(expected); if (Arg == expected) { if (++i >= Argv.size()) fail(std::string(expected) + " requires an argument"); match = Argv[i]; return true; } if (Arg.startswith(expected) && Arg.size() > len && Arg[len] == '=') { match = Arg.data() + len + 1; return true; } return false; }; if (handleGenericOption(Argv[i])) return 0; if (Arg == "--") { for (; i < Argv.size(); ++i) PositionalArgs.push_back(Argv[i]); break; } if (Arg[0] == '-') { if (Arg.startswith("--")) Arg = Argv[i] + 2; else Arg = Argv[i] + 1; if (Arg == "M") { MRI = true; } else if (MatchFlagWithArg("format")) { FormatType = StringSwitch(match) .Case("default", Default) .Case("gnu", GNU) .Case("darwin", DARWIN) .Case("bsd", BSD) .Default(Unknown); if (FormatType == Unknown) fail(std::string("Invalid format ") + match); } else if (MatchFlagWithArg("plugin")) { // Ignored. } else { Options += Argv[i] + 1; } } else if (Options.empty()) { Options += Argv[i]; } else { PositionalArgs.push_back(Argv[i]); } } ArchiveOperation Operation = parseCommandLine(); return performOperation(Operation, nullptr); } static int ranlib_main(int argc, char **argv) { bool ArchiveSpecified = false; for (int i = 1; i < argc; ++i) { StringRef arg(argv[i]); if (handleGenericOption(arg)) { return 0; } else if (arg.consume_front("-")) { // Handle the -D/-U flag while (!arg.empty()) { if (arg.front() == 'D') { Deterministic = true; } else if (arg.front() == 'U') { Deterministic = false; } else if (arg.front() == 'h') { printHelpMessage(); return 0; } else if (arg.front() == 'v') { cl::PrintVersionMessage(); return 0; } else { // TODO: GNU ranlib also supports a -t flag fail("Invalid option: '-" + arg + "'"); } arg = arg.drop_front(1); } } else { if (ArchiveSpecified) fail("exactly one archive should be specified"); ArchiveSpecified = true; ArchiveName = arg.str(); } } if (!ArchiveSpecified) { badUsage("an archive name must be specified"); } return performOperation(CreateSymTab, nullptr); } int main(int argc, char **argv) { InitLLVM X(argc, argv); ToolName = argv[0]; llvm::InitializeAllTargetInfos(); llvm::InitializeAllTargetMCs(); llvm::InitializeAllAsmParsers(); Stem = sys::path::stem(ToolName); auto Is = [](StringRef Tool) { // We need to recognize the following filenames. // // Lib.exe -> lib (see D44808, MSBuild runs Lib.exe) // dlltool.exe -> dlltool // arm-pokymllib32-linux-gnueabi-llvm-ar-10 -> ar auto I = Stem.rfind_lower(Tool); return I != StringRef::npos && (I + Tool.size() == Stem.size() || !isAlnum(Stem[I + Tool.size()])); }; if (Is("dlltool")) return dlltoolDriverMain(makeArrayRef(argv, argc)); if (Is("ranlib")) return ranlib_main(argc, argv); if (Is("lib")) return libDriverMain(makeArrayRef(argv, argc)); if (Is("ar")) return ar_main(argc, argv); fail("not ranlib, ar, lib or dlltool"); } diff --git a/lib/clang/include/VCSVersion.inc b/lib/clang/include/VCSVersion.inc index 33b247760efb..d96651ad5cc2 100644 --- a/lib/clang/include/VCSVersion.inc +++ b/lib/clang/include/VCSVersion.inc @@ -1,14 +1,14 @@ // $FreeBSD$ -#define LLVM_REVISION "llvmorg-10.0.0-rc2-70-ge5cb70267e7" +#define LLVM_REVISION "llvmorg-10.0.0-rc3-1-gc290cb61fdc" #define LLVM_REPOSITORY "git@github.com:llvm/llvm-project.git" -#define CLANG_REVISION "llvmorg-10.0.0-rc2-70-ge5cb70267e7" +#define CLANG_REVISION "llvmorg-10.0.0-rc3-1-gc290cb61fdc" #define CLANG_REPOSITORY "git@github.com:llvm/llvm-project.git" // - -#define LLD_REVISION "llvmorg-10.0.0-rc2-70-ge5cb70267e7-1300007" +#define LLD_REVISION "llvmorg-10.0.0-rc3-1-gc290cb61fdc-1300007" #define LLD_REPOSITORY "FreeBSD" -#define LLDB_REVISION "llvmorg-10.0.0-rc2-70-ge5cb70267e7" +#define LLDB_REVISION "llvmorg-10.0.0-rc3-1-gc290cb61fdc" #define LLDB_REPOSITORY "git@github.com:llvm/llvm-project.git" diff --git a/lib/clang/include/llvm/Support/VCSRevision.h b/lib/clang/include/llvm/Support/VCSRevision.h index c0dae1121e56..43294f49b9af 100644 --- a/lib/clang/include/llvm/Support/VCSRevision.h +++ b/lib/clang/include/llvm/Support/VCSRevision.h @@ -1,3 +1,3 @@ /* $FreeBSD$ */ -#define LLVM_REVISION "llvmorg-10.0.0-rc2-70-ge5cb70267e7" +#define LLVM_REVISION "llvmorg-10.0.0-rc3-1-gc290cb61fdc" #define LLVM_REPOSITORY "git@github.com:llvm/llvm-project.git"