diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h index ecbbd73e19fb..05e78aa78236 100644 --- a/clang/include/clang/AST/Type.h +++ b/clang/include/clang/AST/Type.h @@ -1,6963 +1,6969 @@ //===- Type.h - C Language Family Type Representation -----------*- 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 // //===----------------------------------------------------------------------===// // /// \file /// C Language Family Type Representation /// /// This file defines the clang::Type interface and subclasses, used to /// represent types for languages in the C family. // //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_AST_TYPE_H #define LLVM_CLANG_AST_TYPE_H #include "clang/AST/NestedNameSpecifier.h" #include "clang/AST/TemplateName.h" #include "clang/Basic/AddressSpaces.h" #include "clang/Basic/AttrKinds.h" #include "clang/Basic/Diagnostic.h" #include "clang/Basic/ExceptionSpecificationType.h" #include "clang/Basic/LLVM.h" #include "clang/Basic/Linkage.h" #include "clang/Basic/PartialDiagnostic.h" #include "clang/Basic/SourceLocation.h" #include "clang/Basic/Specifiers.h" #include "clang/Basic/Visibility.h" #include "llvm/ADT/APInt.h" #include "llvm/ADT/APSInt.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/FoldingSet.h" #include "llvm/ADT/None.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/PointerIntPair.h" #include "llvm/ADT/PointerUnion.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Twine.h" #include "llvm/ADT/iterator_range.h" #include "llvm/Support/Casting.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/PointerLikeTypeTraits.h" #include "llvm/Support/type_traits.h" #include "llvm/Support/TrailingObjects.h" #include #include #include #include #include #include #include namespace clang { class ExtQuals; class QualType; class TagDecl; class Type; enum { TypeAlignmentInBits = 4, TypeAlignment = 1 << TypeAlignmentInBits }; } // namespace clang namespace llvm { template struct PointerLikeTypeTraits; template<> struct PointerLikeTypeTraits< ::clang::Type*> { static inline void *getAsVoidPointer(::clang::Type *P) { return P; } static inline ::clang::Type *getFromVoidPointer(void *P) { return static_cast< ::clang::Type*>(P); } enum { NumLowBitsAvailable = clang::TypeAlignmentInBits }; }; template<> struct PointerLikeTypeTraits< ::clang::ExtQuals*> { static inline void *getAsVoidPointer(::clang::ExtQuals *P) { return P; } static inline ::clang::ExtQuals *getFromVoidPointer(void *P) { return static_cast< ::clang::ExtQuals*>(P); } enum { NumLowBitsAvailable = clang::TypeAlignmentInBits }; }; } // namespace llvm namespace clang { class ASTContext; template class CanQual; class CXXRecordDecl; class DeclContext; class EnumDecl; class Expr; class ExtQualsTypeCommonBase; class FunctionDecl; class IdentifierInfo; class NamedDecl; class ObjCInterfaceDecl; class ObjCProtocolDecl; class ObjCTypeParamDecl; struct PrintingPolicy; class RecordDecl; class Stmt; class TagDecl; class TemplateArgument; class TemplateArgumentListInfo; class TemplateArgumentLoc; class TemplateTypeParmDecl; class TypedefNameDecl; class UnresolvedUsingTypenameDecl; using CanQualType = CanQual; // Provide forward declarations for all of the *Type classes. #define TYPE(Class, Base) class Class##Type; #include "clang/AST/TypeNodes.inc" /// The collection of all-type qualifiers we support. /// Clang supports five independent qualifiers: /// * C99: const, volatile, and restrict /// * MS: __unaligned /// * Embedded C (TR18037): address spaces /// * Objective C: the GC attributes (none, weak, or strong) class Qualifiers { public: enum TQ { // NOTE: These flags must be kept in sync with DeclSpec::TQ. Const = 0x1, Restrict = 0x2, Volatile = 0x4, CVRMask = Const | Volatile | Restrict }; enum GC { GCNone = 0, Weak, Strong }; enum ObjCLifetime { /// There is no lifetime qualification on this type. OCL_None, /// This object can be modified without requiring retains or /// releases. OCL_ExplicitNone, /// Assigning into this object requires the old value to be /// released and the new value to be retained. The timing of the /// release of the old value is inexact: it may be moved to /// immediately after the last known point where the value is /// live. OCL_Strong, /// Reading or writing from this object requires a barrier call. OCL_Weak, /// Assigning into this object requires a lifetime extension. OCL_Autoreleasing }; enum { /// The maximum supported address space number. /// 23 bits should be enough for anyone. MaxAddressSpace = 0x7fffffu, /// The width of the "fast" qualifier mask. FastWidth = 3, /// The fast qualifier mask. FastMask = (1 << FastWidth) - 1 }; /// Returns the common set of qualifiers while removing them from /// the given sets. static Qualifiers removeCommonQualifiers(Qualifiers &L, Qualifiers &R) { // If both are only CVR-qualified, bit operations are sufficient. if (!(L.Mask & ~CVRMask) && !(R.Mask & ~CVRMask)) { Qualifiers Q; Q.Mask = L.Mask & R.Mask; L.Mask &= ~Q.Mask; R.Mask &= ~Q.Mask; return Q; } Qualifiers Q; unsigned CommonCRV = L.getCVRQualifiers() & R.getCVRQualifiers(); Q.addCVRQualifiers(CommonCRV); L.removeCVRQualifiers(CommonCRV); R.removeCVRQualifiers(CommonCRV); if (L.getObjCGCAttr() == R.getObjCGCAttr()) { Q.setObjCGCAttr(L.getObjCGCAttr()); L.removeObjCGCAttr(); R.removeObjCGCAttr(); } if (L.getObjCLifetime() == R.getObjCLifetime()) { Q.setObjCLifetime(L.getObjCLifetime()); L.removeObjCLifetime(); R.removeObjCLifetime(); } if (L.getAddressSpace() == R.getAddressSpace()) { Q.setAddressSpace(L.getAddressSpace()); L.removeAddressSpace(); R.removeAddressSpace(); } return Q; } static Qualifiers fromFastMask(unsigned Mask) { Qualifiers Qs; Qs.addFastQualifiers(Mask); return Qs; } static Qualifiers fromCVRMask(unsigned CVR) { Qualifiers Qs; Qs.addCVRQualifiers(CVR); return Qs; } static Qualifiers fromCVRUMask(unsigned CVRU) { Qualifiers Qs; Qs.addCVRUQualifiers(CVRU); return Qs; } // Deserialize qualifiers from an opaque representation. static Qualifiers fromOpaqueValue(unsigned opaque) { Qualifiers Qs; Qs.Mask = opaque; return Qs; } // Serialize these qualifiers into an opaque representation. unsigned getAsOpaqueValue() const { return Mask; } bool hasConst() const { return Mask & Const; } bool hasOnlyConst() const { return Mask == Const; } void removeConst() { Mask &= ~Const; } void addConst() { Mask |= Const; } bool hasVolatile() const { return Mask & Volatile; } bool hasOnlyVolatile() const { return Mask == Volatile; } void removeVolatile() { Mask &= ~Volatile; } void addVolatile() { Mask |= Volatile; } bool hasRestrict() const { return Mask & Restrict; } bool hasOnlyRestrict() const { return Mask == Restrict; } void removeRestrict() { Mask &= ~Restrict; } void addRestrict() { Mask |= Restrict; } bool hasCVRQualifiers() const { return getCVRQualifiers(); } unsigned getCVRQualifiers() const { return Mask & CVRMask; } unsigned getCVRUQualifiers() const { return Mask & (CVRMask | UMask); } void setCVRQualifiers(unsigned mask) { assert(!(mask & ~CVRMask) && "bitmask contains non-CVR bits"); Mask = (Mask & ~CVRMask) | mask; } void removeCVRQualifiers(unsigned mask) { assert(!(mask & ~CVRMask) && "bitmask contains non-CVR bits"); Mask &= ~mask; } void removeCVRQualifiers() { removeCVRQualifiers(CVRMask); } void addCVRQualifiers(unsigned mask) { assert(!(mask & ~CVRMask) && "bitmask contains non-CVR bits"); Mask |= mask; } void addCVRUQualifiers(unsigned mask) { assert(!(mask & ~CVRMask & ~UMask) && "bitmask contains non-CVRU bits"); Mask |= mask; } bool hasUnaligned() const { return Mask & UMask; } void setUnaligned(bool flag) { Mask = (Mask & ~UMask) | (flag ? UMask : 0); } void removeUnaligned() { Mask &= ~UMask; } void addUnaligned() { Mask |= UMask; } bool hasObjCGCAttr() const { return Mask & GCAttrMask; } GC getObjCGCAttr() const { return GC((Mask & GCAttrMask) >> GCAttrShift); } void setObjCGCAttr(GC type) { Mask = (Mask & ~GCAttrMask) | (type << GCAttrShift); } void removeObjCGCAttr() { setObjCGCAttr(GCNone); } void addObjCGCAttr(GC type) { assert(type); setObjCGCAttr(type); } Qualifiers withoutObjCGCAttr() const { Qualifiers qs = *this; qs.removeObjCGCAttr(); return qs; } Qualifiers withoutObjCLifetime() const { Qualifiers qs = *this; qs.removeObjCLifetime(); return qs; } Qualifiers withoutAddressSpace() const { Qualifiers qs = *this; qs.removeAddressSpace(); return qs; } bool hasObjCLifetime() const { return Mask & LifetimeMask; } ObjCLifetime getObjCLifetime() const { return ObjCLifetime((Mask & LifetimeMask) >> LifetimeShift); } void setObjCLifetime(ObjCLifetime type) { Mask = (Mask & ~LifetimeMask) | (type << LifetimeShift); } void removeObjCLifetime() { setObjCLifetime(OCL_None); } void addObjCLifetime(ObjCLifetime type) { assert(type); assert(!hasObjCLifetime()); Mask |= (type << LifetimeShift); } /// True if the lifetime is neither None or ExplicitNone. bool hasNonTrivialObjCLifetime() const { ObjCLifetime lifetime = getObjCLifetime(); return (lifetime > OCL_ExplicitNone); } /// True if the lifetime is either strong or weak. bool hasStrongOrWeakObjCLifetime() const { ObjCLifetime lifetime = getObjCLifetime(); return (lifetime == OCL_Strong || lifetime == OCL_Weak); } bool hasAddressSpace() const { return Mask & AddressSpaceMask; } LangAS getAddressSpace() const { return static_cast(Mask >> AddressSpaceShift); } bool hasTargetSpecificAddressSpace() const { return isTargetAddressSpace(getAddressSpace()); } /// Get the address space attribute value to be printed by diagnostics. unsigned getAddressSpaceAttributePrintValue() const { auto Addr = getAddressSpace(); // This function is not supposed to be used with language specific // address spaces. If that happens, the diagnostic message should consider // printing the QualType instead of the address space value. assert(Addr == LangAS::Default || hasTargetSpecificAddressSpace()); if (Addr != LangAS::Default) return toTargetAddressSpace(Addr); // TODO: The diagnostic messages where Addr may be 0 should be fixed // since it cannot differentiate the situation where 0 denotes the default // address space or user specified __attribute__((address_space(0))). return 0; } void setAddressSpace(LangAS space) { assert((unsigned)space <= MaxAddressSpace); Mask = (Mask & ~AddressSpaceMask) | (((uint32_t) space) << AddressSpaceShift); } void removeAddressSpace() { setAddressSpace(LangAS::Default); } void addAddressSpace(LangAS space) { assert(space != LangAS::Default); setAddressSpace(space); } // Fast qualifiers are those that can be allocated directly // on a QualType object. bool hasFastQualifiers() const { return getFastQualifiers(); } unsigned getFastQualifiers() const { return Mask & FastMask; } void setFastQualifiers(unsigned mask) { assert(!(mask & ~FastMask) && "bitmask contains non-fast qualifier bits"); Mask = (Mask & ~FastMask) | mask; } void removeFastQualifiers(unsigned mask) { assert(!(mask & ~FastMask) && "bitmask contains non-fast qualifier bits"); Mask &= ~mask; } void removeFastQualifiers() { removeFastQualifiers(FastMask); } void addFastQualifiers(unsigned mask) { assert(!(mask & ~FastMask) && "bitmask contains non-fast qualifier bits"); Mask |= mask; } /// Return true if the set contains any qualifiers which require an ExtQuals /// node to be allocated. bool hasNonFastQualifiers() const { return Mask & ~FastMask; } Qualifiers getNonFastQualifiers() const { Qualifiers Quals = *this; Quals.setFastQualifiers(0); return Quals; } /// Return true if the set contains any qualifiers. bool hasQualifiers() const { return Mask; } bool empty() const { return !Mask; } /// Add the qualifiers from the given set to this set. void addQualifiers(Qualifiers Q) { // If the other set doesn't have any non-boolean qualifiers, just // bit-or it in. if (!(Q.Mask & ~CVRMask)) Mask |= Q.Mask; else { Mask |= (Q.Mask & CVRMask); if (Q.hasAddressSpace()) addAddressSpace(Q.getAddressSpace()); if (Q.hasObjCGCAttr()) addObjCGCAttr(Q.getObjCGCAttr()); if (Q.hasObjCLifetime()) addObjCLifetime(Q.getObjCLifetime()); } } /// Remove the qualifiers from the given set from this set. void removeQualifiers(Qualifiers Q) { // If the other set doesn't have any non-boolean qualifiers, just // bit-and the inverse in. if (!(Q.Mask & ~CVRMask)) Mask &= ~Q.Mask; else { Mask &= ~(Q.Mask & CVRMask); if (getObjCGCAttr() == Q.getObjCGCAttr()) removeObjCGCAttr(); if (getObjCLifetime() == Q.getObjCLifetime()) removeObjCLifetime(); if (getAddressSpace() == Q.getAddressSpace()) removeAddressSpace(); } } /// Add the qualifiers from the given set to this set, given that /// they don't conflict. void addConsistentQualifiers(Qualifiers qs) { assert(getAddressSpace() == qs.getAddressSpace() || !hasAddressSpace() || !qs.hasAddressSpace()); assert(getObjCGCAttr() == qs.getObjCGCAttr() || !hasObjCGCAttr() || !qs.hasObjCGCAttr()); assert(getObjCLifetime() == qs.getObjCLifetime() || !hasObjCLifetime() || !qs.hasObjCLifetime()); Mask |= qs.Mask; } /// Returns true if address space A is equal to or a superset of B. /// OpenCL v2.0 defines conversion rules (OpenCLC v2.0 s6.5.5) and notion of /// overlapping address spaces. /// CL1.1 or CL1.2: /// every address space is a superset of itself. /// CL2.0 adds: /// __generic is a superset of any address space except for __constant. static bool isAddressSpaceSupersetOf(LangAS A, LangAS B) { // Address spaces must match exactly. return A == B || // Otherwise in OpenCLC v2.0 s6.5.5: every address space except // for __constant can be used as __generic. (A == LangAS::opencl_generic && B != LangAS::opencl_constant); } /// Returns true if the address space in these qualifiers is equal to or /// a superset of the address space in the argument qualifiers. bool isAddressSpaceSupersetOf(Qualifiers other) const { return isAddressSpaceSupersetOf(getAddressSpace(), other.getAddressSpace()); } /// Determines if these qualifiers compatibly include another set. /// Generally this answers the question of whether an object with the other /// qualifiers can be safely used as an object with these qualifiers. bool compatiblyIncludes(Qualifiers other) const { return isAddressSpaceSupersetOf(other) && // ObjC GC qualifiers can match, be added, or be removed, but can't // be changed. (getObjCGCAttr() == other.getObjCGCAttr() || !hasObjCGCAttr() || !other.hasObjCGCAttr()) && // ObjC lifetime qualifiers must match exactly. getObjCLifetime() == other.getObjCLifetime() && // CVR qualifiers may subset. (((Mask & CVRMask) | (other.Mask & CVRMask)) == (Mask & CVRMask)) && // U qualifier may superset. (!other.hasUnaligned() || hasUnaligned()); } /// Determines if these qualifiers compatibly include another set of /// qualifiers from the narrow perspective of Objective-C ARC lifetime. /// /// One set of Objective-C lifetime qualifiers compatibly includes the other /// if the lifetime qualifiers match, or if both are non-__weak and the /// including set also contains the 'const' qualifier, or both are non-__weak /// and one is None (which can only happen in non-ARC modes). bool compatiblyIncludesObjCLifetime(Qualifiers other) const { if (getObjCLifetime() == other.getObjCLifetime()) return true; if (getObjCLifetime() == OCL_Weak || other.getObjCLifetime() == OCL_Weak) return false; if (getObjCLifetime() == OCL_None || other.getObjCLifetime() == OCL_None) return true; return hasConst(); } /// Determine whether this set of qualifiers is a strict superset of /// another set of qualifiers, not considering qualifier compatibility. bool isStrictSupersetOf(Qualifiers Other) const; bool operator==(Qualifiers Other) const { return Mask == Other.Mask; } bool operator!=(Qualifiers Other) const { return Mask != Other.Mask; } explicit operator bool() const { return hasQualifiers(); } Qualifiers &operator+=(Qualifiers R) { addQualifiers(R); return *this; } // Union two qualifier sets. If an enumerated qualifier appears // in both sets, use the one from the right. friend Qualifiers operator+(Qualifiers L, Qualifiers R) { L += R; return L; } Qualifiers &operator-=(Qualifiers R) { removeQualifiers(R); return *this; } /// Compute the difference between two qualifier sets. friend Qualifiers operator-(Qualifiers L, Qualifiers R) { L -= R; return L; } std::string getAsString() const; std::string getAsString(const PrintingPolicy &Policy) const; bool isEmptyWhenPrinted(const PrintingPolicy &Policy) const; void print(raw_ostream &OS, const PrintingPolicy &Policy, bool appendSpaceIfNonEmpty = false) const; void Profile(llvm::FoldingSetNodeID &ID) const { ID.AddInteger(Mask); } private: // bits: |0 1 2|3|4 .. 5|6 .. 8|9 ... 31| // |C R V|U|GCAttr|Lifetime|AddressSpace| uint32_t Mask = 0; static const uint32_t UMask = 0x8; static const uint32_t UShift = 3; static const uint32_t GCAttrMask = 0x30; static const uint32_t GCAttrShift = 4; static const uint32_t LifetimeMask = 0x1C0; static const uint32_t LifetimeShift = 6; static const uint32_t AddressSpaceMask = ~(CVRMask | UMask | GCAttrMask | LifetimeMask); static const uint32_t AddressSpaceShift = 9; }; /// A std::pair-like structure for storing a qualified type split /// into its local qualifiers and its locally-unqualified type. struct SplitQualType { /// The locally-unqualified type. const Type *Ty = nullptr; /// The local qualifiers. Qualifiers Quals; SplitQualType() = default; SplitQualType(const Type *ty, Qualifiers qs) : Ty(ty), Quals(qs) {} SplitQualType getSingleStepDesugaredType() const; // end of this file // Make std::tie work. std::pair asPair() const { return std::pair(Ty, Quals); } friend bool operator==(SplitQualType a, SplitQualType b) { return a.Ty == b.Ty && a.Quals == b.Quals; } friend bool operator!=(SplitQualType a, SplitQualType b) { return a.Ty != b.Ty || a.Quals != b.Quals; } }; /// The kind of type we are substituting Objective-C type arguments into. /// /// The kind of substitution affects the replacement of type parameters when /// no concrete type information is provided, e.g., when dealing with an /// unspecialized type. enum class ObjCSubstitutionContext { /// An ordinary type. Ordinary, /// The result type of a method or function. Result, /// The parameter type of a method or function. Parameter, /// The type of a property. Property, /// The superclass of a type. Superclass, }; /// A (possibly-)qualified type. /// /// For efficiency, we don't store CV-qualified types as nodes on their /// own: instead each reference to a type stores the qualifiers. This /// greatly reduces the number of nodes we need to allocate for types (for /// example we only need one for 'int', 'const int', 'volatile int', /// 'const volatile int', etc). /// /// As an added efficiency bonus, instead of making this a pair, we /// just store the two bits we care about in the low bits of the /// pointer. To handle the packing/unpacking, we make QualType be a /// simple wrapper class that acts like a smart pointer. A third bit /// indicates whether there are extended qualifiers present, in which /// case the pointer points to a special structure. class QualType { friend class QualifierCollector; // Thankfully, these are efficiently composable. llvm::PointerIntPair, Qualifiers::FastWidth> Value; const ExtQuals *getExtQualsUnsafe() const { return Value.getPointer().get(); } const Type *getTypePtrUnsafe() const { return Value.getPointer().get(); } const ExtQualsTypeCommonBase *getCommonPtr() const { assert(!isNull() && "Cannot retrieve a NULL type pointer"); auto CommonPtrVal = reinterpret_cast(Value.getOpaqueValue()); CommonPtrVal &= ~(uintptr_t)((1 << TypeAlignmentInBits) - 1); return reinterpret_cast(CommonPtrVal); } public: QualType() = default; QualType(const Type *Ptr, unsigned Quals) : Value(Ptr, Quals) {} QualType(const ExtQuals *Ptr, unsigned Quals) : Value(Ptr, Quals) {} unsigned getLocalFastQualifiers() const { return Value.getInt(); } void setLocalFastQualifiers(unsigned Quals) { Value.setInt(Quals); } /// Retrieves a pointer to the underlying (unqualified) type. /// /// This function requires that the type not be NULL. If the type might be /// NULL, use the (slightly less efficient) \c getTypePtrOrNull(). const Type *getTypePtr() const; const Type *getTypePtrOrNull() const; /// Retrieves a pointer to the name of the base type. const IdentifierInfo *getBaseTypeIdentifier() const; /// Divides a QualType into its unqualified type and a set of local /// qualifiers. SplitQualType split() const; void *getAsOpaquePtr() const { return Value.getOpaqueValue(); } static QualType getFromOpaquePtr(const void *Ptr) { QualType T; T.Value.setFromOpaqueValue(const_cast(Ptr)); return T; } const Type &operator*() const { return *getTypePtr(); } const Type *operator->() const { return getTypePtr(); } bool isCanonical() const; bool isCanonicalAsParam() const; /// Return true if this QualType doesn't point to a type yet. bool isNull() const { return Value.getPointer().isNull(); } /// Determine whether this particular QualType instance has the /// "const" qualifier set, without looking through typedefs that may have /// added "const" at a different level. bool isLocalConstQualified() const { return (getLocalFastQualifiers() & Qualifiers::Const); } /// Determine whether this type is const-qualified. bool isConstQualified() const; /// Determine whether this particular QualType instance has the /// "restrict" qualifier set, without looking through typedefs that may have /// added "restrict" at a different level. bool isLocalRestrictQualified() const { return (getLocalFastQualifiers() & Qualifiers::Restrict); } /// Determine whether this type is restrict-qualified. bool isRestrictQualified() const; /// Determine whether this particular QualType instance has the /// "volatile" qualifier set, without looking through typedefs that may have /// added "volatile" at a different level. bool isLocalVolatileQualified() const { return (getLocalFastQualifiers() & Qualifiers::Volatile); } /// Determine whether this type is volatile-qualified. bool isVolatileQualified() const; /// Determine whether this particular QualType instance has any /// qualifiers, without looking through any typedefs that might add /// qualifiers at a different level. bool hasLocalQualifiers() const { return getLocalFastQualifiers() || hasLocalNonFastQualifiers(); } /// Determine whether this type has any qualifiers. bool hasQualifiers() const; /// Determine whether this particular QualType instance has any /// "non-fast" qualifiers, e.g., those that are stored in an ExtQualType /// instance. bool hasLocalNonFastQualifiers() const { return Value.getPointer().is(); } /// Retrieve the set of qualifiers local to this particular QualType /// instance, not including any qualifiers acquired through typedefs or /// other sugar. Qualifiers getLocalQualifiers() const; /// Retrieve the set of qualifiers applied to this type. Qualifiers getQualifiers() const; /// Retrieve the set of CVR (const-volatile-restrict) qualifiers /// local to this particular QualType instance, not including any qualifiers /// acquired through typedefs or other sugar. unsigned getLocalCVRQualifiers() const { return getLocalFastQualifiers(); } /// Retrieve the set of CVR (const-volatile-restrict) qualifiers /// applied to this type. unsigned getCVRQualifiers() const; bool isConstant(const ASTContext& Ctx) const { return QualType::isConstant(*this, Ctx); } /// Determine whether this is a Plain Old Data (POD) type (C++ 3.9p10). bool isPODType(const ASTContext &Context) const; /// Return true if this is a POD type according to the rules of the C++98 /// standard, regardless of the current compilation's language. bool isCXX98PODType(const ASTContext &Context) const; /// Return true if this is a POD type according to the more relaxed rules /// of the C++11 standard, regardless of the current compilation's language. /// (C++0x [basic.types]p9). Note that, unlike /// CXXRecordDecl::isCXX11StandardLayout, this takes DRs into account. bool isCXX11PODType(const ASTContext &Context) const; /// Return true if this is a trivial type per (C++0x [basic.types]p9) bool isTrivialType(const ASTContext &Context) const; /// Return true if this is a trivially copyable type (C++0x [basic.types]p9) bool isTriviallyCopyableType(const ASTContext &Context) const; /// Returns true if it is a class and it might be dynamic. bool mayBeDynamicClass() const; /// Returns true if it is not a class or if the class might not be dynamic. bool mayBeNotDynamicClass() const; // Don't promise in the API that anything besides 'const' can be // easily added. /// Add the `const` type qualifier to this QualType. void addConst() { addFastQualifiers(Qualifiers::Const); } QualType withConst() const { return withFastQualifiers(Qualifiers::Const); } /// Add the `volatile` type qualifier to this QualType. void addVolatile() { addFastQualifiers(Qualifiers::Volatile); } QualType withVolatile() const { return withFastQualifiers(Qualifiers::Volatile); } /// Add the `restrict` qualifier to this QualType. void addRestrict() { addFastQualifiers(Qualifiers::Restrict); } QualType withRestrict() const { return withFastQualifiers(Qualifiers::Restrict); } QualType withCVRQualifiers(unsigned CVR) const { return withFastQualifiers(CVR); } void addFastQualifiers(unsigned TQs) { assert(!(TQs & ~Qualifiers::FastMask) && "non-fast qualifier bits set in mask!"); Value.setInt(Value.getInt() | TQs); } void removeLocalConst(); void removeLocalVolatile(); void removeLocalRestrict(); void removeLocalCVRQualifiers(unsigned Mask); void removeLocalFastQualifiers() { Value.setInt(0); } void removeLocalFastQualifiers(unsigned Mask) { assert(!(Mask & ~Qualifiers::FastMask) && "mask has non-fast qualifiers"); Value.setInt(Value.getInt() & ~Mask); } // Creates a type with the given qualifiers in addition to any // qualifiers already on this type. QualType withFastQualifiers(unsigned TQs) const { QualType T = *this; T.addFastQualifiers(TQs); return T; } // Creates a type with exactly the given fast qualifiers, removing // any existing fast qualifiers. QualType withExactLocalFastQualifiers(unsigned TQs) const { return withoutLocalFastQualifiers().withFastQualifiers(TQs); } // Removes fast qualifiers, but leaves any extended qualifiers in place. QualType withoutLocalFastQualifiers() const { QualType T = *this; T.removeLocalFastQualifiers(); return T; } QualType getCanonicalType() const; /// Return this type with all of the instance-specific qualifiers /// removed, but without removing any qualifiers that may have been applied /// through typedefs. QualType getLocalUnqualifiedType() const { return QualType(getTypePtr(), 0); } /// Retrieve the unqualified variant of the given type, /// removing as little sugar as possible. /// /// This routine looks through various kinds of sugar to find the /// least-desugared type that is unqualified. For example, given: /// /// \code /// typedef int Integer; /// typedef const Integer CInteger; /// typedef CInteger DifferenceType; /// \endcode /// /// Executing \c getUnqualifiedType() on the type \c DifferenceType will /// desugar until we hit the type \c Integer, which has no qualifiers on it. /// /// The resulting type might still be qualified if it's sugar for an array /// type. To strip qualifiers even from within a sugared array type, use /// ASTContext::getUnqualifiedArrayType. inline QualType getUnqualifiedType() const; /// Retrieve the unqualified variant of the given type, removing as little /// sugar as possible. /// /// Like getUnqualifiedType(), but also returns the set of /// qualifiers that were built up. /// /// The resulting type might still be qualified if it's sugar for an array /// type. To strip qualifiers even from within a sugared array type, use /// ASTContext::getUnqualifiedArrayType. inline SplitQualType getSplitUnqualifiedType() const; /// Determine whether this type is more qualified than the other /// given type, requiring exact equality for non-CVR qualifiers. bool isMoreQualifiedThan(QualType Other) const; /// Determine whether this type is at least as qualified as the other /// given type, requiring exact equality for non-CVR qualifiers. bool isAtLeastAsQualifiedAs(QualType Other) const; QualType getNonReferenceType() const; /// Determine the type of a (typically non-lvalue) expression with the /// specified result type. /// /// This routine should be used for expressions for which the return type is /// explicitly specified (e.g., in a cast or call) and isn't necessarily /// an lvalue. It removes a top-level reference (since there are no /// expressions of reference type) and deletes top-level cvr-qualifiers /// from non-class types (in C++) or all types (in C). QualType getNonLValueExprType(const ASTContext &Context) const; /// Return the specified type with any "sugar" removed from /// the type. This takes off typedefs, typeof's etc. If the outer level of /// the type is already concrete, it returns it unmodified. This is similar /// to getting the canonical type, but it doesn't remove *all* typedefs. For /// example, it returns "T*" as "T*", (not as "int*"), because the pointer is /// concrete. /// /// Qualifiers are left in place. QualType getDesugaredType(const ASTContext &Context) const { return getDesugaredType(*this, Context); } SplitQualType getSplitDesugaredType() const { return getSplitDesugaredType(*this); } /// Return the specified type with one level of "sugar" removed from /// the type. /// /// This routine takes off the first typedef, typeof, etc. If the outer level /// of the type is already concrete, it returns it unmodified. QualType getSingleStepDesugaredType(const ASTContext &Context) const { return getSingleStepDesugaredTypeImpl(*this, Context); } /// Returns the specified type after dropping any /// outer-level parentheses. QualType IgnoreParens() const { if (isa(*this)) return QualType::IgnoreParens(*this); return *this; } /// Indicate whether the specified types and qualifiers are identical. friend bool operator==(const QualType &LHS, const QualType &RHS) { return LHS.Value == RHS.Value; } friend bool operator!=(const QualType &LHS, const QualType &RHS) { return LHS.Value != RHS.Value; } friend bool operator<(const QualType &LHS, const QualType &RHS) { return LHS.Value < RHS.Value; } static std::string getAsString(SplitQualType split, const PrintingPolicy &Policy) { return getAsString(split.Ty, split.Quals, Policy); } static std::string getAsString(const Type *ty, Qualifiers qs, const PrintingPolicy &Policy); std::string getAsString() const; std::string getAsString(const PrintingPolicy &Policy) const; void print(raw_ostream &OS, const PrintingPolicy &Policy, const Twine &PlaceHolder = Twine(), unsigned Indentation = 0) const; static void print(SplitQualType split, raw_ostream &OS, const PrintingPolicy &policy, const Twine &PlaceHolder, unsigned Indentation = 0) { return print(split.Ty, split.Quals, OS, policy, PlaceHolder, Indentation); } static void print(const Type *ty, Qualifiers qs, raw_ostream &OS, const PrintingPolicy &policy, const Twine &PlaceHolder, unsigned Indentation = 0); void getAsStringInternal(std::string &Str, const PrintingPolicy &Policy) const; static void getAsStringInternal(SplitQualType split, std::string &out, const PrintingPolicy &policy) { return getAsStringInternal(split.Ty, split.Quals, out, policy); } static void getAsStringInternal(const Type *ty, Qualifiers qs, std::string &out, const PrintingPolicy &policy); class StreamedQualTypeHelper { const QualType &T; const PrintingPolicy &Policy; const Twine &PlaceHolder; unsigned Indentation; public: StreamedQualTypeHelper(const QualType &T, const PrintingPolicy &Policy, const Twine &PlaceHolder, unsigned Indentation) : T(T), Policy(Policy), PlaceHolder(PlaceHolder), Indentation(Indentation) {} friend raw_ostream &operator<<(raw_ostream &OS, const StreamedQualTypeHelper &SQT) { SQT.T.print(OS, SQT.Policy, SQT.PlaceHolder, SQT.Indentation); return OS; } }; StreamedQualTypeHelper stream(const PrintingPolicy &Policy, const Twine &PlaceHolder = Twine(), unsigned Indentation = 0) const { return StreamedQualTypeHelper(*this, Policy, PlaceHolder, Indentation); } void dump(const char *s) const; void dump() const; void dump(llvm::raw_ostream &OS) const; void Profile(llvm::FoldingSetNodeID &ID) const { ID.AddPointer(getAsOpaquePtr()); } /// Return the address space of this type. inline LangAS getAddressSpace() const; /// Returns gc attribute of this type. inline Qualifiers::GC getObjCGCAttr() const; /// true when Type is objc's weak. bool isObjCGCWeak() const { return getObjCGCAttr() == Qualifiers::Weak; } /// true when Type is objc's strong. bool isObjCGCStrong() const { return getObjCGCAttr() == Qualifiers::Strong; } /// Returns lifetime attribute of this type. Qualifiers::ObjCLifetime getObjCLifetime() const { return getQualifiers().getObjCLifetime(); } bool hasNonTrivialObjCLifetime() const { return getQualifiers().hasNonTrivialObjCLifetime(); } bool hasStrongOrWeakObjCLifetime() const { return getQualifiers().hasStrongOrWeakObjCLifetime(); } // true when Type is objc's weak and weak is enabled but ARC isn't. bool isNonWeakInMRRWithObjCWeak(const ASTContext &Context) const; enum PrimitiveDefaultInitializeKind { /// The type does not fall into any of the following categories. Note that /// this case is zero-valued so that values of this enum can be used as a /// boolean condition for non-triviality. PDIK_Trivial, /// The type is an Objective-C retainable pointer type that is qualified /// with the ARC __strong qualifier. PDIK_ARCStrong, /// The type is an Objective-C retainable pointer type that is qualified /// with the ARC __weak qualifier. PDIK_ARCWeak, /// The type is a struct containing a field whose type is not PCK_Trivial. PDIK_Struct }; /// Functions to query basic properties of non-trivial C struct types. /// Check if this is a non-trivial type that would cause a C struct /// transitively containing this type to be non-trivial to default initialize /// and return the kind. PrimitiveDefaultInitializeKind isNonTrivialToPrimitiveDefaultInitialize() const; enum PrimitiveCopyKind { /// The type does not fall into any of the following categories. Note that /// this case is zero-valued so that values of this enum can be used as a /// boolean condition for non-triviality. PCK_Trivial, /// The type would be trivial except that it is volatile-qualified. Types /// that fall into one of the other non-trivial cases may additionally be /// volatile-qualified. PCK_VolatileTrivial, /// The type is an Objective-C retainable pointer type that is qualified /// with the ARC __strong qualifier. PCK_ARCStrong, /// The type is an Objective-C retainable pointer type that is qualified /// with the ARC __weak qualifier. PCK_ARCWeak, /// The type is a struct containing a field whose type is neither /// PCK_Trivial nor PCK_VolatileTrivial. /// Note that a C++ struct type does not necessarily match this; C++ copying /// semantics are too complex to express here, in part because they depend /// on the exact constructor or assignment operator that is chosen by /// overload resolution to do the copy. PCK_Struct }; /// Check if this is a non-trivial type that would cause a C struct /// transitively containing this type to be non-trivial to copy and return the /// kind. PrimitiveCopyKind isNonTrivialToPrimitiveCopy() const; /// Check if this is a non-trivial type that would cause a C struct /// transitively containing this type to be non-trivial to destructively /// move and return the kind. Destructive move in this context is a C++-style /// move in which the source object is placed in a valid but unspecified state /// after it is moved, as opposed to a truly destructive move in which the /// source object is placed in an uninitialized state. PrimitiveCopyKind isNonTrivialToPrimitiveDestructiveMove() const; enum DestructionKind { DK_none, DK_cxx_destructor, DK_objc_strong_lifetime, DK_objc_weak_lifetime, DK_nontrivial_c_struct }; /// Returns a nonzero value if objects of this type require /// non-trivial work to clean up after. Non-zero because it's /// conceivable that qualifiers (objc_gc(weak)?) could make /// something require destruction. DestructionKind isDestructedType() const { return isDestructedTypeImpl(*this); } /// Check if this is or contains a C union that is non-trivial to /// default-initialize, which is a union that has a member that is non-trivial /// to default-initialize. If this returns true, /// isNonTrivialToPrimitiveDefaultInitialize returns PDIK_Struct. bool hasNonTrivialToPrimitiveDefaultInitializeCUnion() const; /// Check if this is or contains a C union that is non-trivial to destruct, /// which is a union that has a member that is non-trivial to destruct. If /// this returns true, isDestructedType returns DK_nontrivial_c_struct. bool hasNonTrivialToPrimitiveDestructCUnion() const; /// Check if this is or contains a C union that is non-trivial to copy, which /// is a union that has a member that is non-trivial to copy. If this returns /// true, isNonTrivialToPrimitiveCopy returns PCK_Struct. bool hasNonTrivialToPrimitiveCopyCUnion() const; /// Determine whether expressions of the given type are forbidden /// from being lvalues in C. /// /// The expression types that are forbidden to be lvalues are: /// - 'void', but not qualified void /// - function types /// /// The exact rule here is C99 6.3.2.1: /// An lvalue is an expression with an object type or an incomplete /// type other than void. bool isCForbiddenLValueType() const; /// Substitute type arguments for the Objective-C type parameters used in the /// subject type. /// /// \param ctx ASTContext in which the type exists. /// /// \param typeArgs The type arguments that will be substituted for the /// Objective-C type parameters in the subject type, which are generally /// computed via \c Type::getObjCSubstitutions. If empty, the type /// parameters will be replaced with their bounds or id/Class, as appropriate /// for the context. /// /// \param context The context in which the subject type was written. /// /// \returns the resulting type. QualType substObjCTypeArgs(ASTContext &ctx, ArrayRef typeArgs, ObjCSubstitutionContext context) const; /// Substitute type arguments from an object type for the Objective-C type /// parameters used in the subject type. /// /// This operation combines the computation of type arguments for /// substitution (\c Type::getObjCSubstitutions) with the actual process of /// substitution (\c QualType::substObjCTypeArgs) for the convenience of /// callers that need to perform a single substitution in isolation. /// /// \param objectType The type of the object whose member type we're /// substituting into. For example, this might be the receiver of a message /// or the base of a property access. /// /// \param dc The declaration context from which the subject type was /// retrieved, which indicates (for example) which type parameters should /// be substituted. /// /// \param context The context in which the subject type was written. /// /// \returns the subject type after replacing all of the Objective-C type /// parameters with their corresponding arguments. QualType substObjCMemberType(QualType objectType, const DeclContext *dc, ObjCSubstitutionContext context) const; /// Strip Objective-C "__kindof" types from the given type. QualType stripObjCKindOfType(const ASTContext &ctx) const; /// Remove all qualifiers including _Atomic. QualType getAtomicUnqualifiedType() const; private: // These methods are implemented in a separate translation unit; // "static"-ize them to avoid creating temporary QualTypes in the // caller. static bool isConstant(QualType T, const ASTContext& Ctx); static QualType getDesugaredType(QualType T, const ASTContext &Context); static SplitQualType getSplitDesugaredType(QualType T); static SplitQualType getSplitUnqualifiedTypeImpl(QualType type); static QualType getSingleStepDesugaredTypeImpl(QualType type, const ASTContext &C); static QualType IgnoreParens(QualType T); static DestructionKind isDestructedTypeImpl(QualType type); /// Check if \param RD is or contains a non-trivial C union. static bool hasNonTrivialToPrimitiveDefaultInitializeCUnion(const RecordDecl *RD); static bool hasNonTrivialToPrimitiveDestructCUnion(const RecordDecl *RD); static bool hasNonTrivialToPrimitiveCopyCUnion(const RecordDecl *RD); }; } // namespace clang namespace llvm { /// Implement simplify_type for QualType, so that we can dyn_cast from QualType /// to a specific Type class. template<> struct simplify_type< ::clang::QualType> { using SimpleType = const ::clang::Type *; static SimpleType getSimplifiedValue(::clang::QualType Val) { return Val.getTypePtr(); } }; // Teach SmallPtrSet that QualType is "basically a pointer". template<> struct PointerLikeTypeTraits { static inline void *getAsVoidPointer(clang::QualType P) { return P.getAsOpaquePtr(); } static inline clang::QualType getFromVoidPointer(void *P) { return clang::QualType::getFromOpaquePtr(P); } // Various qualifiers go in low bits. enum { NumLowBitsAvailable = 0 }; }; } // namespace llvm namespace clang { /// Base class that is common to both the \c ExtQuals and \c Type /// classes, which allows \c QualType to access the common fields between the /// two. class ExtQualsTypeCommonBase { friend class ExtQuals; friend class QualType; friend class Type; /// The "base" type of an extended qualifiers type (\c ExtQuals) or /// a self-referential pointer (for \c Type). /// /// This pointer allows an efficient mapping from a QualType to its /// underlying type pointer. const Type *const BaseType; /// The canonical type of this type. A QualType. QualType CanonicalType; ExtQualsTypeCommonBase(const Type *baseType, QualType canon) : BaseType(baseType), CanonicalType(canon) {} }; /// We can encode up to four bits in the low bits of a /// type pointer, but there are many more type qualifiers that we want /// to be able to apply to an arbitrary type. Therefore we have this /// struct, intended to be heap-allocated and used by QualType to /// store qualifiers. /// /// The current design tags the 'const', 'restrict', and 'volatile' qualifiers /// in three low bits on the QualType pointer; a fourth bit records whether /// the pointer is an ExtQuals node. The extended qualifiers (address spaces, /// Objective-C GC attributes) are much more rare. class ExtQuals : public ExtQualsTypeCommonBase, public llvm::FoldingSetNode { // NOTE: changing the fast qualifiers should be straightforward as // long as you don't make 'const' non-fast. // 1. Qualifiers: // a) Modify the bitmasks (Qualifiers::TQ and DeclSpec::TQ). // Fast qualifiers must occupy the low-order bits. // b) Update Qualifiers::FastWidth and FastMask. // 2. QualType: // a) Update is{Volatile,Restrict}Qualified(), defined inline. // b) Update remove{Volatile,Restrict}, defined near the end of // this header. // 3. ASTContext: // a) Update get{Volatile,Restrict}Type. /// The immutable set of qualifiers applied by this node. Always contains /// extended qualifiers. Qualifiers Quals; ExtQuals *this_() { return this; } public: ExtQuals(const Type *baseType, QualType canon, Qualifiers quals) : ExtQualsTypeCommonBase(baseType, canon.isNull() ? QualType(this_(), 0) : canon), Quals(quals) { assert(Quals.hasNonFastQualifiers() && "ExtQuals created with no fast qualifiers"); assert(!Quals.hasFastQualifiers() && "ExtQuals created with fast qualifiers"); } Qualifiers getQualifiers() const { return Quals; } bool hasObjCGCAttr() const { return Quals.hasObjCGCAttr(); } Qualifiers::GC getObjCGCAttr() const { return Quals.getObjCGCAttr(); } bool hasObjCLifetime() const { return Quals.hasObjCLifetime(); } Qualifiers::ObjCLifetime getObjCLifetime() const { return Quals.getObjCLifetime(); } bool hasAddressSpace() const { return Quals.hasAddressSpace(); } LangAS getAddressSpace() const { return Quals.getAddressSpace(); } const Type *getBaseType() const { return BaseType; } public: void Profile(llvm::FoldingSetNodeID &ID) const { Profile(ID, getBaseType(), Quals); } static void Profile(llvm::FoldingSetNodeID &ID, const Type *BaseType, Qualifiers Quals) { assert(!Quals.hasFastQualifiers() && "fast qualifiers in ExtQuals hash!"); ID.AddPointer(BaseType); Quals.Profile(ID); } }; /// The kind of C++11 ref-qualifier associated with a function type. /// This determines whether a member function's "this" object can be an /// lvalue, rvalue, or neither. enum RefQualifierKind { /// No ref-qualifier was provided. RQ_None = 0, /// An lvalue ref-qualifier was provided (\c &). RQ_LValue, /// An rvalue ref-qualifier was provided (\c &&). RQ_RValue }; /// Which keyword(s) were used to create an AutoType. enum class AutoTypeKeyword { /// auto Auto, /// decltype(auto) DecltypeAuto, /// __auto_type (GNU extension) GNUAutoType }; /// The base class of the type hierarchy. /// /// A central concept with types is that each type always has a canonical /// type. A canonical type is the type with any typedef names stripped out /// of it or the types it references. For example, consider: /// /// typedef int foo; /// typedef foo* bar; /// 'int *' 'foo *' 'bar' /// /// There will be a Type object created for 'int'. Since int is canonical, its /// CanonicalType pointer points to itself. There is also a Type for 'foo' (a /// TypedefType). Its CanonicalType pointer points to the 'int' Type. Next /// there is a PointerType that represents 'int*', which, like 'int', is /// canonical. Finally, there is a PointerType type for 'foo*' whose canonical /// type is 'int*', and there is a TypedefType for 'bar', whose canonical type /// is also 'int*'. /// /// Non-canonical types are useful for emitting diagnostics, without losing /// information about typedefs being used. Canonical types are useful for type /// comparisons (they allow by-pointer equality tests) and useful for reasoning /// about whether something has a particular form (e.g. is a function type), /// because they implicitly, recursively, strip all typedefs out of a type. /// /// Types, once created, are immutable. /// class alignas(8) Type : public ExtQualsTypeCommonBase { public: enum TypeClass { #define TYPE(Class, Base) Class, #define LAST_TYPE(Class) TypeLast = Class #define ABSTRACT_TYPE(Class, Base) #include "clang/AST/TypeNodes.inc" }; private: /// Bitfields required by the Type class. class TypeBitfields { friend class Type; template friend class TypePropertyCache; /// TypeClass bitfield - Enum that specifies what subclass this belongs to. unsigned TC : 8; /// Whether this type is a dependent type (C++ [temp.dep.type]). unsigned Dependent : 1; /// Whether this type somehow involves a template parameter, even /// if the resolution of the type does not depend on a template parameter. unsigned InstantiationDependent : 1; /// Whether this type is a variably-modified type (C99 6.7.5). unsigned VariablyModified : 1; /// Whether this type contains an unexpanded parameter pack /// (for C++11 variadic templates). unsigned ContainsUnexpandedParameterPack : 1; /// True if the cache (i.e. the bitfields here starting with /// 'Cache') is valid. mutable unsigned CacheValid : 1; /// Linkage of this type. mutable unsigned CachedLinkage : 3; /// Whether this type involves and local or unnamed types. mutable unsigned CachedLocalOrUnnamed : 1; /// Whether this type comes from an AST file. mutable unsigned FromAST : 1; bool isCacheValid() const { return CacheValid; } Linkage getLinkage() const { assert(isCacheValid() && "getting linkage from invalid cache"); return static_cast(CachedLinkage); } bool hasLocalOrUnnamedType() const { assert(isCacheValid() && "getting linkage from invalid cache"); return CachedLocalOrUnnamed; } }; enum { NumTypeBits = 18 }; protected: // These classes allow subclasses to somewhat cleanly pack bitfields // into Type. class ArrayTypeBitfields { friend class ArrayType; unsigned : NumTypeBits; /// CVR qualifiers from declarations like /// 'int X[static restrict 4]'. For function parameters only. unsigned IndexTypeQuals : 3; /// Storage class qualifiers from declarations like /// 'int X[static restrict 4]'. For function parameters only. /// Actually an ArrayType::ArraySizeModifier. unsigned SizeModifier : 3; }; class ConstantArrayTypeBitfields { friend class ConstantArrayType; unsigned : NumTypeBits + 3 + 3; /// Whether we have a stored size expression. unsigned HasStoredSizeExpr : 1; }; class BuiltinTypeBitfields { friend class BuiltinType; unsigned : NumTypeBits; /// The kind (BuiltinType::Kind) of builtin type this is. unsigned Kind : 8; }; /// FunctionTypeBitfields store various bits belonging to FunctionProtoType. /// Only common bits are stored here. Additional uncommon bits are stored /// in a trailing object after FunctionProtoType. class FunctionTypeBitfields { friend class FunctionProtoType; friend class FunctionType; unsigned : NumTypeBits; /// Extra information which affects how the function is called, like /// regparm and the calling convention. unsigned ExtInfo : 12; /// The ref-qualifier associated with a \c FunctionProtoType. /// /// This is a value of type \c RefQualifierKind. unsigned RefQualifier : 2; /// Used only by FunctionProtoType, put here to pack with the /// other bitfields. /// The qualifiers are part of FunctionProtoType because... /// /// C++ 8.3.5p4: The return type, the parameter type list and the /// cv-qualifier-seq, [...], are part of the function type. unsigned FastTypeQuals : Qualifiers::FastWidth; /// Whether this function has extended Qualifiers. unsigned HasExtQuals : 1; /// The number of parameters this function has, not counting '...'. /// According to [implimits] 8 bits should be enough here but this is /// somewhat easy to exceed with metaprogramming and so we would like to /// keep NumParams as wide as reasonably possible. unsigned NumParams : 16; /// The type of exception specification this function has. unsigned ExceptionSpecType : 4; /// Whether this function has extended parameter information. unsigned HasExtParameterInfos : 1; /// Whether the function is variadic. unsigned Variadic : 1; /// Whether this function has a trailing return type. unsigned HasTrailingReturn : 1; }; class ObjCObjectTypeBitfields { friend class ObjCObjectType; unsigned : NumTypeBits; /// The number of type arguments stored directly on this object type. unsigned NumTypeArgs : 7; /// The number of protocols stored directly on this object type. unsigned NumProtocols : 6; /// Whether this is a "kindof" type. unsigned IsKindOf : 1; }; class ReferenceTypeBitfields { friend class ReferenceType; unsigned : NumTypeBits; /// True if the type was originally spelled with an lvalue sigil. /// This is never true of rvalue references but can also be false /// on lvalue references because of C++0x [dcl.typedef]p9, /// as follows: /// /// typedef int &ref; // lvalue, spelled lvalue /// typedef int &&rvref; // rvalue /// ref &a; // lvalue, inner ref, spelled lvalue /// ref &&a; // lvalue, inner ref /// rvref &a; // lvalue, inner ref, spelled lvalue /// rvref &&a; // rvalue, inner ref unsigned SpelledAsLValue : 1; /// True if the inner type is a reference type. This only happens /// in non-canonical forms. unsigned InnerRef : 1; }; class TypeWithKeywordBitfields { friend class TypeWithKeyword; unsigned : NumTypeBits; /// An ElaboratedTypeKeyword. 8 bits for efficient access. unsigned Keyword : 8; }; enum { NumTypeWithKeywordBits = 8 }; class ElaboratedTypeBitfields { friend class ElaboratedType; unsigned : NumTypeBits; unsigned : NumTypeWithKeywordBits; /// Whether the ElaboratedType has a trailing OwnedTagDecl. unsigned HasOwnedTagDecl : 1; }; class VectorTypeBitfields { friend class VectorType; friend class DependentVectorType; unsigned : NumTypeBits; /// The kind of vector, either a generic vector type or some /// target-specific vector type such as for AltiVec or Neon. unsigned VecKind : 3; /// The number of elements in the vector. unsigned NumElements : 29 - NumTypeBits; enum { MaxNumElements = (1 << (29 - NumTypeBits)) - 1 }; }; class AttributedTypeBitfields { friend class AttributedType; unsigned : NumTypeBits; /// An AttributedType::Kind unsigned AttrKind : 32 - NumTypeBits; }; class AutoTypeBitfields { friend class AutoType; unsigned : NumTypeBits; /// Was this placeholder type spelled as 'auto', 'decltype(auto)', /// or '__auto_type'? AutoTypeKeyword value. unsigned Keyword : 2; }; class SubstTemplateTypeParmPackTypeBitfields { friend class SubstTemplateTypeParmPackType; unsigned : NumTypeBits; /// The number of template arguments in \c Arguments, which is /// expected to be able to hold at least 1024 according to [implimits]. /// However as this limit is somewhat easy to hit with template /// metaprogramming we'd prefer to keep it as large as possible. /// At the moment it has been left as a non-bitfield since this type /// safely fits in 64 bits as an unsigned, so there is no reason to /// introduce the performance impact of a bitfield. unsigned NumArgs; }; class TemplateSpecializationTypeBitfields { friend class TemplateSpecializationType; unsigned : NumTypeBits; /// Whether this template specialization type is a substituted type alias. unsigned TypeAlias : 1; /// The number of template arguments named in this class template /// specialization, which is expected to be able to hold at least 1024 /// according to [implimits]. However, as this limit is somewhat easy to /// hit with template metaprogramming we'd prefer to keep it as large /// as possible. At the moment it has been left as a non-bitfield since /// this type safely fits in 64 bits as an unsigned, so there is no reason /// to introduce the performance impact of a bitfield. unsigned NumArgs; }; class DependentTemplateSpecializationTypeBitfields { friend class DependentTemplateSpecializationType; unsigned : NumTypeBits; unsigned : NumTypeWithKeywordBits; /// The number of template arguments named in this class template /// specialization, which is expected to be able to hold at least 1024 /// according to [implimits]. However, as this limit is somewhat easy to /// hit with template metaprogramming we'd prefer to keep it as large /// as possible. At the moment it has been left as a non-bitfield since /// this type safely fits in 64 bits as an unsigned, so there is no reason /// to introduce the performance impact of a bitfield. unsigned NumArgs; }; class PackExpansionTypeBitfields { friend class PackExpansionType; unsigned : NumTypeBits; /// The number of expansions that this pack expansion will /// generate when substituted (+1), which is expected to be able to /// hold at least 1024 according to [implimits]. However, as this limit /// is somewhat easy to hit with template metaprogramming we'd prefer to /// keep it as large as possible. At the moment it has been left as a /// non-bitfield since this type safely fits in 64 bits as an unsigned, so /// there is no reason to introduce the performance impact of a bitfield. /// /// This field will only have a non-zero value when some of the parameter /// packs that occur within the pattern have been substituted but others /// have not. unsigned NumExpansions; }; union { TypeBitfields TypeBits; ArrayTypeBitfields ArrayTypeBits; ConstantArrayTypeBitfields ConstantArrayTypeBits; AttributedTypeBitfields AttributedTypeBits; AutoTypeBitfields AutoTypeBits; BuiltinTypeBitfields BuiltinTypeBits; FunctionTypeBitfields FunctionTypeBits; ObjCObjectTypeBitfields ObjCObjectTypeBits; ReferenceTypeBitfields ReferenceTypeBits; TypeWithKeywordBitfields TypeWithKeywordBits; ElaboratedTypeBitfields ElaboratedTypeBits; VectorTypeBitfields VectorTypeBits; SubstTemplateTypeParmPackTypeBitfields SubstTemplateTypeParmPackTypeBits; TemplateSpecializationTypeBitfields TemplateSpecializationTypeBits; DependentTemplateSpecializationTypeBitfields DependentTemplateSpecializationTypeBits; PackExpansionTypeBitfields PackExpansionTypeBits; static_assert(sizeof(TypeBitfields) <= 8, "TypeBitfields is larger than 8 bytes!"); static_assert(sizeof(ArrayTypeBitfields) <= 8, "ArrayTypeBitfields is larger than 8 bytes!"); static_assert(sizeof(AttributedTypeBitfields) <= 8, "AttributedTypeBitfields is larger than 8 bytes!"); static_assert(sizeof(AutoTypeBitfields) <= 8, "AutoTypeBitfields is larger than 8 bytes!"); static_assert(sizeof(BuiltinTypeBitfields) <= 8, "BuiltinTypeBitfields is larger than 8 bytes!"); static_assert(sizeof(FunctionTypeBitfields) <= 8, "FunctionTypeBitfields is larger than 8 bytes!"); static_assert(sizeof(ObjCObjectTypeBitfields) <= 8, "ObjCObjectTypeBitfields is larger than 8 bytes!"); static_assert(sizeof(ReferenceTypeBitfields) <= 8, "ReferenceTypeBitfields is larger than 8 bytes!"); static_assert(sizeof(TypeWithKeywordBitfields) <= 8, "TypeWithKeywordBitfields is larger than 8 bytes!"); static_assert(sizeof(ElaboratedTypeBitfields) <= 8, "ElaboratedTypeBitfields is larger than 8 bytes!"); static_assert(sizeof(VectorTypeBitfields) <= 8, "VectorTypeBitfields is larger than 8 bytes!"); static_assert(sizeof(SubstTemplateTypeParmPackTypeBitfields) <= 8, "SubstTemplateTypeParmPackTypeBitfields is larger" " than 8 bytes!"); static_assert(sizeof(TemplateSpecializationTypeBitfields) <= 8, "TemplateSpecializationTypeBitfields is larger" " than 8 bytes!"); static_assert(sizeof(DependentTemplateSpecializationTypeBitfields) <= 8, "DependentTemplateSpecializationTypeBitfields is larger" " than 8 bytes!"); static_assert(sizeof(PackExpansionTypeBitfields) <= 8, "PackExpansionTypeBitfields is larger than 8 bytes"); }; private: template friend class TypePropertyCache; /// Set whether this type comes from an AST file. void setFromAST(bool V = true) const { TypeBits.FromAST = V; } protected: friend class ASTContext; Type(TypeClass tc, QualType canon, bool Dependent, bool InstantiationDependent, bool VariablyModified, bool ContainsUnexpandedParameterPack) : ExtQualsTypeCommonBase(this, canon.isNull() ? QualType(this_(), 0) : canon) { TypeBits.TC = tc; TypeBits.Dependent = Dependent; TypeBits.InstantiationDependent = Dependent || InstantiationDependent; TypeBits.VariablyModified = VariablyModified; TypeBits.ContainsUnexpandedParameterPack = ContainsUnexpandedParameterPack; TypeBits.CacheValid = false; TypeBits.CachedLocalOrUnnamed = false; TypeBits.CachedLinkage = NoLinkage; TypeBits.FromAST = false; } // silence VC++ warning C4355: 'this' : used in base member initializer list Type *this_() { return this; } void setDependent(bool D = true) { TypeBits.Dependent = D; if (D) TypeBits.InstantiationDependent = true; } void setInstantiationDependent(bool D = true) { TypeBits.InstantiationDependent = D; } void setVariablyModified(bool VM = true) { TypeBits.VariablyModified = VM; } void setContainsUnexpandedParameterPack(bool PP = true) { TypeBits.ContainsUnexpandedParameterPack = PP; } public: friend class ASTReader; friend class ASTWriter; Type(const Type &) = delete; Type(Type &&) = delete; Type &operator=(const Type &) = delete; Type &operator=(Type &&) = delete; TypeClass getTypeClass() const { return static_cast(TypeBits.TC); } /// Whether this type comes from an AST file. bool isFromAST() const { return TypeBits.FromAST; } /// Whether this type is or contains an unexpanded parameter /// pack, used to support C++0x variadic templates. /// /// A type that contains a parameter pack shall be expanded by the /// ellipsis operator at some point. For example, the typedef in the /// following example contains an unexpanded parameter pack 'T': /// /// \code /// template /// struct X { /// typedef T* pointer_types; // ill-formed; T is a parameter pack. /// }; /// \endcode /// /// Note that this routine does not specify which bool containsUnexpandedParameterPack() const { return TypeBits.ContainsUnexpandedParameterPack; } /// Determines if this type would be canonical if it had no further /// qualification. bool isCanonicalUnqualified() const { return CanonicalType == QualType(this, 0); } /// Pull a single level of sugar off of this locally-unqualified type. /// Users should generally prefer SplitQualType::getSingleStepDesugaredType() /// or QualType::getSingleStepDesugaredType(const ASTContext&). QualType getLocallyUnqualifiedSingleStepDesugaredType() const; /// Types are partitioned into 3 broad categories (C99 6.2.5p1): /// object types, function types, and incomplete types. /// Return true if this is an incomplete type. /// A type that can describe objects, but which lacks information needed to /// determine its size (e.g. void, or a fwd declared struct). Clients of this /// routine will need to determine if the size is actually required. /// /// Def If non-null, and the type refers to some kind of declaration /// that can be completed (such as a C struct, C++ class, or Objective-C /// class), will be set to the declaration. bool isIncompleteType(NamedDecl **Def = nullptr) const; /// Return true if this is an incomplete or object /// type, in other words, not a function type. bool isIncompleteOrObjectType() const { return !isFunctionType(); } /// Determine whether this type is an object type. bool isObjectType() const { // C++ [basic.types]p8: // An object type is a (possibly cv-qualified) type that is not a // function type, not a reference type, and not a void type. return !isReferenceType() && !isFunctionType() && !isVoidType(); } /// Return true if this is a literal type /// (C++11 [basic.types]p10) bool isLiteralType(const ASTContext &Ctx) const; /// Test if this type is a standard-layout type. /// (C++0x [basic.type]p9) bool isStandardLayoutType() const; /// Helper methods to distinguish type categories. All type predicates /// operate on the canonical type, ignoring typedefs and qualifiers. /// Returns true if the type is a builtin type. bool isBuiltinType() const; /// Test for a particular builtin type. bool isSpecificBuiltinType(unsigned K) const; /// Test for a type which does not represent an actual type-system type but /// is instead used as a placeholder for various convenient purposes within /// Clang. All such types are BuiltinTypes. bool isPlaceholderType() const; const BuiltinType *getAsPlaceholderType() const; /// Test for a specific placeholder type. bool isSpecificPlaceholderType(unsigned K) const; /// Test for a placeholder type other than Overload; see /// BuiltinType::isNonOverloadPlaceholderType. bool isNonOverloadPlaceholderType() const; /// isIntegerType() does *not* include complex integers (a GCC extension). /// isComplexIntegerType() can be used to test for complex integers. bool isIntegerType() const; // C99 6.2.5p17 (int, char, bool, enum) bool isEnumeralType() const; /// Determine whether this type is a scoped enumeration type. bool isScopedEnumeralType() const; bool isBooleanType() const; bool isCharType() const; bool isWideCharType() const; bool isChar8Type() const; bool isChar16Type() const; bool isChar32Type() const; bool isAnyCharacterType() const; bool isIntegralType(const ASTContext &Ctx) const; /// Determine whether this type is an integral or enumeration type. bool isIntegralOrEnumerationType() const; /// Determine whether this type is an integral or unscoped enumeration type. bool isIntegralOrUnscopedEnumerationType() const; /// Floating point categories. bool isRealFloatingType() const; // C99 6.2.5p10 (float, double, long double) /// isComplexType() does *not* include complex integers (a GCC extension). /// isComplexIntegerType() can be used to test for complex integers. bool isComplexType() const; // C99 6.2.5p11 (complex) bool isAnyComplexType() const; // C99 6.2.5p11 (complex) + Complex Int. bool isFloatingType() const; // C99 6.2.5p11 (real floating + complex) bool isHalfType() const; // OpenCL 6.1.1.1, NEON (IEEE 754-2008 half) bool isFloat16Type() const; // C11 extension ISO/IEC TS 18661 bool isFloat128Type() const; bool isRealType() const; // C99 6.2.5p17 (real floating + integer) bool isArithmeticType() const; // C99 6.2.5p18 (integer + floating) bool isVoidType() const; // C99 6.2.5p19 bool isScalarType() const; // C99 6.2.5p21 (arithmetic + pointers) bool isAggregateType() const; bool isFundamentalType() const; bool isCompoundType() const; // Type Predicates: Check to see if this type is structurally the specified // type, ignoring typedefs and qualifiers. bool isFunctionType() const; bool isFunctionNoProtoType() const { return getAs(); } bool isFunctionProtoType() const { return getAs(); } bool isPointerType() const; bool isAnyPointerType() const; // Any C pointer or ObjC object pointer bool isBlockPointerType() const; bool isVoidPointerType() const; bool isReferenceType() const; bool isLValueReferenceType() const; bool isRValueReferenceType() const; bool isFunctionPointerType() const; bool isFunctionReferenceType() const; bool isMemberPointerType() const; bool isMemberFunctionPointerType() const; bool isMemberDataPointerType() const; bool isArrayType() const; bool isConstantArrayType() const; bool isIncompleteArrayType() const; bool isVariableArrayType() const; bool isDependentSizedArrayType() const; bool isRecordType() const; bool isClassType() const; bool isStructureType() const; bool isObjCBoxableRecordType() const; bool isInterfaceType() const; bool isStructureOrClassType() const; bool isUnionType() const; bool isComplexIntegerType() const; // GCC _Complex integer type. bool isVectorType() const; // GCC vector type. bool isExtVectorType() const; // Extended vector type. bool isDependentAddressSpaceType() const; // value-dependent address space qualifier bool isObjCObjectPointerType() const; // pointer to ObjC object bool isObjCRetainableType() const; // ObjC object or block pointer bool isObjCLifetimeType() const; // (array of)* retainable type bool isObjCIndirectLifetimeType() const; // (pointer to)* lifetime type bool isObjCNSObjectType() const; // __attribute__((NSObject)) bool isObjCIndependentClassType() const; // __attribute__((objc_independent_class)) // FIXME: change this to 'raw' interface type, so we can used 'interface' type // for the common case. bool isObjCObjectType() const; // NSString or typeof(*(id)0) bool isObjCQualifiedInterfaceType() const; // NSString bool isObjCQualifiedIdType() const; // id bool isObjCQualifiedClassType() const; // Class bool isObjCObjectOrInterfaceType() const; bool isObjCIdType() const; // id bool isDecltypeType() const; /// Was this type written with the special inert-in-ARC __unsafe_unretained /// qualifier? /// /// This approximates the answer to the following question: if this /// translation unit were compiled in ARC, would this type be qualified /// with __unsafe_unretained? bool isObjCInertUnsafeUnretainedType() const { return hasAttr(attr::ObjCInertUnsafeUnretained); } /// Whether the type is Objective-C 'id' or a __kindof type of an /// object type, e.g., __kindof NSView * or __kindof id /// . /// /// \param bound Will be set to the bound on non-id subtype types, /// which will be (possibly specialized) Objective-C class type, or /// null for 'id. bool isObjCIdOrObjectKindOfType(const ASTContext &ctx, const ObjCObjectType *&bound) const; bool isObjCClassType() const; // Class /// Whether the type is Objective-C 'Class' or a __kindof type of an /// Class type, e.g., __kindof Class . /// /// Unlike \c isObjCIdOrObjectKindOfType, there is no relevant bound /// here because Objective-C's type system cannot express "a class /// object for a subclass of NSFoo". bool isObjCClassOrClassKindOfType() const; bool isBlockCompatibleObjCPointerType(ASTContext &ctx) const; bool isObjCSelType() const; // Class bool isObjCBuiltinType() const; // 'id' or 'Class' bool isObjCARCBridgableType() const; bool isCARCBridgableType() const; bool isTemplateTypeParmType() const; // C++ template type parameter bool isNullPtrType() const; // C++11 std::nullptr_t bool isNothrowT() const; // C++ std::nothrow_t bool isAlignValT() const; // C++17 std::align_val_t bool isStdByteType() const; // C++17 std::byte bool isAtomicType() const; // C11 _Atomic() + bool isUndeducedAutoType() const; // C++11 auto or + // C++14 decltype(auto) #define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \ bool is##Id##Type() const; #include "clang/Basic/OpenCLImageTypes.def" bool isImageType() const; // Any OpenCL image type bool isSamplerT() const; // OpenCL sampler_t bool isEventT() const; // OpenCL event_t bool isClkEventT() const; // OpenCL clk_event_t bool isQueueT() const; // OpenCL queue_t bool isReserveIDT() const; // OpenCL reserve_id_t #define EXT_OPAQUE_TYPE(ExtType, Id, Ext) \ bool is##Id##Type() const; #include "clang/Basic/OpenCLExtensionTypes.def" // Type defined in cl_intel_device_side_avc_motion_estimation OpenCL extension bool isOCLIntelSubgroupAVCType() const; bool isOCLExtOpaqueType() const; // Any OpenCL extension type bool isPipeType() const; // OpenCL pipe type bool isOpenCLSpecificType() const; // Any OpenCL specific type /// Determines if this type, which must satisfy /// isObjCLifetimeType(), is implicitly __unsafe_unretained rather /// than implicitly __strong. bool isObjCARCImplicitlyUnretainedType() const; /// Return the implicit lifetime for this type, which must not be dependent. Qualifiers::ObjCLifetime getObjCARCImplicitLifetime() const; enum ScalarTypeKind { STK_CPointer, STK_BlockPointer, STK_ObjCObjectPointer, STK_MemberPointer, STK_Bool, STK_Integral, STK_Floating, STK_IntegralComplex, STK_FloatingComplex, STK_FixedPoint }; /// Given that this is a scalar type, classify it. ScalarTypeKind getScalarTypeKind() const; /// Whether this type is a dependent type, meaning that its definition /// somehow depends on a template parameter (C++ [temp.dep.type]). bool isDependentType() const { return TypeBits.Dependent; } /// Determine whether this type is an instantiation-dependent type, /// meaning that the type involves a template parameter (even if the /// definition does not actually depend on the type substituted for that /// template parameter). bool isInstantiationDependentType() const { return TypeBits.InstantiationDependent; } /// Determine whether this type is an undeduced type, meaning that /// it somehow involves a C++11 'auto' type or similar which has not yet been /// deduced. bool isUndeducedType() const; /// Whether this type is a variably-modified type (C99 6.7.5). bool isVariablyModifiedType() const { return TypeBits.VariablyModified; } /// Whether this type involves a variable-length array type /// with a definite size. bool hasSizedVLAType() const; /// Whether this type is or contains a local or unnamed type. bool hasUnnamedOrLocalType() const; bool isOverloadableType() const; /// Determine wither this type is a C++ elaborated-type-specifier. bool isElaboratedTypeSpecifier() const; bool canDecayToPointerType() const; /// Whether this type is represented natively as a pointer. This includes /// pointers, references, block pointers, and Objective-C interface, /// qualified id, and qualified interface types, as well as nullptr_t. bool hasPointerRepresentation() const; /// Whether this type can represent an objective pointer type for the /// purpose of GC'ability bool hasObjCPointerRepresentation() const; /// Determine whether this type has an integer representation /// of some sort, e.g., it is an integer type or a vector. bool hasIntegerRepresentation() const; /// Determine whether this type has an signed integer representation /// of some sort, e.g., it is an signed integer type or a vector. bool hasSignedIntegerRepresentation() const; /// Determine whether this type has an unsigned integer representation /// of some sort, e.g., it is an unsigned integer type or a vector. bool hasUnsignedIntegerRepresentation() const; /// Determine whether this type has a floating-point representation /// of some sort, e.g., it is a floating-point type or a vector thereof. bool hasFloatingRepresentation() const; // Type Checking Functions: Check to see if this type is structurally the // specified type, ignoring typedefs and qualifiers, and return a pointer to // the best type we can. const RecordType *getAsStructureType() const; /// NOTE: getAs*ArrayType are methods on ASTContext. const RecordType *getAsUnionType() const; const ComplexType *getAsComplexIntegerType() const; // GCC complex int type. const ObjCObjectType *getAsObjCInterfaceType() const; // The following is a convenience method that returns an ObjCObjectPointerType // for object declared using an interface. const ObjCObjectPointerType *getAsObjCInterfacePointerType() const; const ObjCObjectPointerType *getAsObjCQualifiedIdType() const; const ObjCObjectPointerType *getAsObjCQualifiedClassType() const; const ObjCObjectType *getAsObjCQualifiedInterfaceType() const; /// Retrieves the CXXRecordDecl that this type refers to, either /// because the type is a RecordType or because it is the injected-class-name /// type of a class template or class template partial specialization. CXXRecordDecl *getAsCXXRecordDecl() const; /// Retrieves the RecordDecl this type refers to. RecordDecl *getAsRecordDecl() const; /// Retrieves the TagDecl that this type refers to, either /// because the type is a TagType or because it is the injected-class-name /// type of a class template or class template partial specialization. TagDecl *getAsTagDecl() const; /// If this is a pointer or reference to a RecordType, return the /// CXXRecordDecl that the type refers to. /// /// If this is not a pointer or reference, or the type being pointed to does /// not refer to a CXXRecordDecl, returns NULL. const CXXRecordDecl *getPointeeCXXRecordDecl() const; /// Get the DeducedType whose type will be deduced for a variable with /// an initializer of this type. This looks through declarators like pointer /// types, but not through decltype or typedefs. DeducedType *getContainedDeducedType() const; /// Get the AutoType whose type will be deduced for a variable with /// an initializer of this type. This looks through declarators like pointer /// types, but not through decltype or typedefs. AutoType *getContainedAutoType() const { return dyn_cast_or_null(getContainedDeducedType()); } /// Determine whether this type was written with a leading 'auto' /// corresponding to a trailing return type (possibly for a nested /// function type within a pointer to function type or similar). bool hasAutoForTrailingReturnType() const; /// Member-template getAs'. Look through sugar for /// an instance of \. This scheme will eventually /// replace the specific getAsXXXX methods above. /// /// There are some specializations of this member template listed /// immediately following this class. template const T *getAs() const; /// Member-template getAsAdjusted. Look through specific kinds /// of sugar (parens, attributes, etc) for an instance of \. /// This is used when you need to walk over sugar nodes that represent some /// kind of type adjustment from a type that was written as a \ /// to another type that is still canonically a \. template const T *getAsAdjusted() const; /// A variant of getAs<> for array types which silently discards /// qualifiers from the outermost type. const ArrayType *getAsArrayTypeUnsafe() const; /// Member-template castAs. Look through sugar for /// the underlying instance of \. /// /// This method has the same relationship to getAs as cast has /// to dyn_cast; which is to say, the underlying type *must* /// have the intended type, and this method will never return null. template const T *castAs() const; /// A variant of castAs<> for array type which silently discards /// qualifiers from the outermost type. const ArrayType *castAsArrayTypeUnsafe() const; /// Determine whether this type had the specified attribute applied to it /// (looking through top-level type sugar). bool hasAttr(attr::Kind AK) const; /// Get the base element type of this type, potentially discarding type /// qualifiers. This should never be used when type qualifiers /// are meaningful. const Type *getBaseElementTypeUnsafe() const; /// If this is an array type, return the element type of the array, /// potentially with type qualifiers missing. /// This should never be used when type qualifiers are meaningful. const Type *getArrayElementTypeNoTypeQual() const; /// If this is a pointer type, return the pointee type. /// If this is an array type, return the array element type. /// This should never be used when type qualifiers are meaningful. const Type *getPointeeOrArrayElementType() const; /// If this is a pointer, ObjC object pointer, or block /// pointer, this returns the respective pointee. QualType getPointeeType() const; /// Return the specified type with any "sugar" removed from the type, /// removing any typedefs, typeofs, etc., as well as any qualifiers. const Type *getUnqualifiedDesugaredType() const; /// More type predicates useful for type checking/promotion bool isPromotableIntegerType() const; // C99 6.3.1.1p2 /// Return true if this is an integer type that is /// signed, according to C99 6.2.5p4 [char, signed char, short, int, long..], /// or an enum decl which has a signed representation. bool isSignedIntegerType() const; /// Return true if this is an integer type that is /// unsigned, according to C99 6.2.5p6 [which returns true for _Bool], /// or an enum decl which has an unsigned representation. bool isUnsignedIntegerType() const; /// Determines whether this is an integer type that is signed or an /// enumeration types whose underlying type is a signed integer type. bool isSignedIntegerOrEnumerationType() const; /// Determines whether this is an integer type that is unsigned or an /// enumeration types whose underlying type is a unsigned integer type. bool isUnsignedIntegerOrEnumerationType() const; /// Return true if this is a fixed point type according to /// ISO/IEC JTC1 SC22 WG14 N1169. bool isFixedPointType() const; /// Return true if this is a fixed point or integer type. bool isFixedPointOrIntegerType() const; /// Return true if this is a saturated fixed point type according to /// ISO/IEC JTC1 SC22 WG14 N1169. This type can be signed or unsigned. bool isSaturatedFixedPointType() const; /// Return true if this is a saturated fixed point type according to /// ISO/IEC JTC1 SC22 WG14 N1169. This type can be signed or unsigned. bool isUnsaturatedFixedPointType() const; /// Return true if this is a fixed point type that is signed according /// to ISO/IEC JTC1 SC22 WG14 N1169. This type can also be saturated. bool isSignedFixedPointType() const; /// Return true if this is a fixed point type that is unsigned according /// to ISO/IEC JTC1 SC22 WG14 N1169. This type can also be saturated. bool isUnsignedFixedPointType() const; /// Return true if this is not a variable sized type, /// according to the rules of C99 6.7.5p3. It is not legal to call this on /// incomplete types. bool isConstantSizeType() const; /// Returns true if this type can be represented by some /// set of type specifiers. bool isSpecifierType() const; /// Determine the linkage of this type. Linkage getLinkage() const; /// Determine the visibility of this type. Visibility getVisibility() const { return getLinkageAndVisibility().getVisibility(); } /// Return true if the visibility was explicitly set is the code. bool isVisibilityExplicit() const { return getLinkageAndVisibility().isVisibilityExplicit(); } /// Determine the linkage and visibility of this type. LinkageInfo getLinkageAndVisibility() const; /// True if the computed linkage is valid. Used for consistency /// checking. Should always return true. bool isLinkageValid() const; /// Determine the nullability of the given type. /// /// Note that nullability is only captured as sugar within the type /// system, not as part of the canonical type, so nullability will /// be lost by canonicalization and desugaring. Optional getNullability(const ASTContext &context) const; /// Determine whether the given type can have a nullability /// specifier applied to it, i.e., if it is any kind of pointer type. /// /// \param ResultIfUnknown The value to return if we don't yet know whether /// this type can have nullability because it is dependent. bool canHaveNullability(bool ResultIfUnknown = true) const; /// Retrieve the set of substitutions required when accessing a member /// of the Objective-C receiver type that is declared in the given context. /// /// \c *this is the type of the object we're operating on, e.g., the /// receiver for a message send or the base of a property access, and is /// expected to be of some object or object pointer type. /// /// \param dc The declaration context for which we are building up a /// substitution mapping, which should be an Objective-C class, extension, /// category, or method within. /// /// \returns an array of type arguments that can be substituted for /// the type parameters of the given declaration context in any type described /// within that context, or an empty optional to indicate that no /// substitution is required. Optional> getObjCSubstitutions(const DeclContext *dc) const; /// Determines if this is an ObjC interface type that may accept type /// parameters. bool acceptsObjCTypeParams() const; const char *getTypeClassName() const; QualType getCanonicalTypeInternal() const { return CanonicalType; } CanQualType getCanonicalTypeUnqualified() const; // in CanonicalType.h void dump() const; void dump(llvm::raw_ostream &OS) const; }; /// This will check for a TypedefType by removing any existing sugar /// until it reaches a TypedefType or a non-sugared type. template <> const TypedefType *Type::getAs() const; /// This will check for a TemplateSpecializationType by removing any /// existing sugar until it reaches a TemplateSpecializationType or a /// non-sugared type. template <> const TemplateSpecializationType *Type::getAs() const; /// This will check for an AttributedType by removing any existing sugar /// until it reaches an AttributedType or a non-sugared type. template <> const AttributedType *Type::getAs() const; // We can do canonical leaf types faster, because we don't have to // worry about preserving child type decoration. #define TYPE(Class, Base) #define LEAF_TYPE(Class) \ template <> inline const Class##Type *Type::getAs() const { \ return dyn_cast(CanonicalType); \ } \ template <> inline const Class##Type *Type::castAs() const { \ return cast(CanonicalType); \ } #include "clang/AST/TypeNodes.inc" /// This class is used for builtin types like 'int'. Builtin /// types are always canonical and have a literal name field. class BuiltinType : public Type { public: enum Kind { // OpenCL image types #define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) Id, #include "clang/Basic/OpenCLImageTypes.def" // OpenCL extension types #define EXT_OPAQUE_TYPE(ExtType, Id, Ext) Id, #include "clang/Basic/OpenCLExtensionTypes.def" // SVE Types #define SVE_TYPE(Name, Id, SingletonId) Id, #include "clang/Basic/AArch64SVEACLETypes.def" // All other builtin types #define BUILTIN_TYPE(Id, SingletonId) Id, #define LAST_BUILTIN_TYPE(Id) LastKind = Id #include "clang/AST/BuiltinTypes.def" }; private: friend class ASTContext; // ASTContext creates these. BuiltinType(Kind K) : Type(Builtin, QualType(), /*Dependent=*/(K == Dependent), /*InstantiationDependent=*/(K == Dependent), /*VariablyModified=*/false, /*Unexpanded parameter pack=*/false) { BuiltinTypeBits.Kind = K; } public: Kind getKind() const { return static_cast(BuiltinTypeBits.Kind); } StringRef getName(const PrintingPolicy &Policy) const; const char *getNameAsCString(const PrintingPolicy &Policy) const { // The StringRef is null-terminated. StringRef str = getName(Policy); assert(!str.empty() && str.data()[str.size()] == '\0'); return str.data(); } bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } bool isInteger() const { return getKind() >= Bool && getKind() <= Int128; } bool isSignedInteger() const { return getKind() >= Char_S && getKind() <= Int128; } bool isUnsignedInteger() const { return getKind() >= Bool && getKind() <= UInt128; } bool isFloatingPoint() const { return getKind() >= Half && getKind() <= Float128; } /// Determines whether the given kind corresponds to a placeholder type. static bool isPlaceholderTypeKind(Kind K) { return K >= Overload; } /// Determines whether this type is a placeholder type, i.e. a type /// which cannot appear in arbitrary positions in a fully-formed /// expression. bool isPlaceholderType() const { return isPlaceholderTypeKind(getKind()); } /// Determines whether this type is a placeholder type other than /// Overload. Most placeholder types require only syntactic /// information about their context in order to be resolved (e.g. /// whether it is a call expression), which means they can (and /// should) be resolved in an earlier "phase" of analysis. /// Overload expressions sometimes pick up further information /// from their context, like whether the context expects a /// specific function-pointer type, and so frequently need /// special treatment. bool isNonOverloadPlaceholderType() const { return getKind() > Overload; } static bool classof(const Type *T) { return T->getTypeClass() == Builtin; } }; /// Complex values, per C99 6.2.5p11. This supports the C99 complex /// types (_Complex float etc) as well as the GCC integer complex extensions. class ComplexType : public Type, public llvm::FoldingSetNode { friend class ASTContext; // ASTContext creates these. QualType ElementType; ComplexType(QualType Element, QualType CanonicalPtr) : Type(Complex, CanonicalPtr, Element->isDependentType(), Element->isInstantiationDependentType(), Element->isVariablyModifiedType(), Element->containsUnexpandedParameterPack()), ElementType(Element) {} public: QualType getElementType() const { return ElementType; } bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, getElementType()); } static void Profile(llvm::FoldingSetNodeID &ID, QualType Element) { ID.AddPointer(Element.getAsOpaquePtr()); } static bool classof(const Type *T) { return T->getTypeClass() == Complex; } }; /// Sugar for parentheses used when specifying types. class ParenType : public Type, public llvm::FoldingSetNode { friend class ASTContext; // ASTContext creates these. QualType Inner; ParenType(QualType InnerType, QualType CanonType) : Type(Paren, CanonType, InnerType->isDependentType(), InnerType->isInstantiationDependentType(), InnerType->isVariablyModifiedType(), InnerType->containsUnexpandedParameterPack()), Inner(InnerType) {} public: QualType getInnerType() const { return Inner; } bool isSugared() const { return true; } QualType desugar() const { return getInnerType(); } void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, getInnerType()); } static void Profile(llvm::FoldingSetNodeID &ID, QualType Inner) { Inner.Profile(ID); } static bool classof(const Type *T) { return T->getTypeClass() == Paren; } }; /// PointerType - C99 6.7.5.1 - Pointer Declarators. class PointerType : public Type, public llvm::FoldingSetNode { friend class ASTContext; // ASTContext creates these. QualType PointeeType; PointerType(QualType Pointee, QualType CanonicalPtr) : Type(Pointer, CanonicalPtr, Pointee->isDependentType(), Pointee->isInstantiationDependentType(), Pointee->isVariablyModifiedType(), Pointee->containsUnexpandedParameterPack()), PointeeType(Pointee) {} public: QualType getPointeeType() const { return PointeeType; } /// Returns true if address spaces of pointers overlap. /// OpenCL v2.0 defines conversion rules for pointers to different /// address spaces (OpenCLC v2.0 s6.5.5) and notion of overlapping /// address spaces. /// CL1.1 or CL1.2: /// address spaces overlap iff they are they same. /// CL2.0 adds: /// __generic overlaps with any address space except for __constant. bool isAddressSpaceOverlapping(const PointerType &other) const { Qualifiers thisQuals = PointeeType.getQualifiers(); Qualifiers otherQuals = other.getPointeeType().getQualifiers(); // Address spaces overlap if at least one of them is a superset of another return thisQuals.isAddressSpaceSupersetOf(otherQuals) || otherQuals.isAddressSpaceSupersetOf(thisQuals); } bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, getPointeeType()); } static void Profile(llvm::FoldingSetNodeID &ID, QualType Pointee) { ID.AddPointer(Pointee.getAsOpaquePtr()); } static bool classof(const Type *T) { return T->getTypeClass() == Pointer; } }; /// Represents a type which was implicitly adjusted by the semantic /// engine for arbitrary reasons. For example, array and function types can /// decay, and function types can have their calling conventions adjusted. class AdjustedType : public Type, public llvm::FoldingSetNode { QualType OriginalTy; QualType AdjustedTy; protected: friend class ASTContext; // ASTContext creates these. AdjustedType(TypeClass TC, QualType OriginalTy, QualType AdjustedTy, QualType CanonicalPtr) : Type(TC, CanonicalPtr, OriginalTy->isDependentType(), OriginalTy->isInstantiationDependentType(), OriginalTy->isVariablyModifiedType(), OriginalTy->containsUnexpandedParameterPack()), OriginalTy(OriginalTy), AdjustedTy(AdjustedTy) {} public: QualType getOriginalType() const { return OriginalTy; } QualType getAdjustedType() const { return AdjustedTy; } bool isSugared() const { return true; } QualType desugar() const { return AdjustedTy; } void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, OriginalTy, AdjustedTy); } static void Profile(llvm::FoldingSetNodeID &ID, QualType Orig, QualType New) { ID.AddPointer(Orig.getAsOpaquePtr()); ID.AddPointer(New.getAsOpaquePtr()); } static bool classof(const Type *T) { return T->getTypeClass() == Adjusted || T->getTypeClass() == Decayed; } }; /// Represents a pointer type decayed from an array or function type. class DecayedType : public AdjustedType { friend class ASTContext; // ASTContext creates these. inline DecayedType(QualType OriginalType, QualType Decayed, QualType Canonical); public: QualType getDecayedType() const { return getAdjustedType(); } inline QualType getPointeeType() const; static bool classof(const Type *T) { return T->getTypeClass() == Decayed; } }; /// Pointer to a block type. /// This type is to represent types syntactically represented as /// "void (^)(int)", etc. Pointee is required to always be a function type. class BlockPointerType : public Type, public llvm::FoldingSetNode { friend class ASTContext; // ASTContext creates these. // Block is some kind of pointer type QualType PointeeType; BlockPointerType(QualType Pointee, QualType CanonicalCls) : Type(BlockPointer, CanonicalCls, Pointee->isDependentType(), Pointee->isInstantiationDependentType(), Pointee->isVariablyModifiedType(), Pointee->containsUnexpandedParameterPack()), PointeeType(Pointee) {} public: // Get the pointee type. Pointee is required to always be a function type. QualType getPointeeType() const { return PointeeType; } bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, getPointeeType()); } static void Profile(llvm::FoldingSetNodeID &ID, QualType Pointee) { ID.AddPointer(Pointee.getAsOpaquePtr()); } static bool classof(const Type *T) { return T->getTypeClass() == BlockPointer; } }; /// Base for LValueReferenceType and RValueReferenceType class ReferenceType : public Type, public llvm::FoldingSetNode { QualType PointeeType; protected: ReferenceType(TypeClass tc, QualType Referencee, QualType CanonicalRef, bool SpelledAsLValue) : Type(tc, CanonicalRef, Referencee->isDependentType(), Referencee->isInstantiationDependentType(), Referencee->isVariablyModifiedType(), Referencee->containsUnexpandedParameterPack()), PointeeType(Referencee) { ReferenceTypeBits.SpelledAsLValue = SpelledAsLValue; ReferenceTypeBits.InnerRef = Referencee->isReferenceType(); } public: bool isSpelledAsLValue() const { return ReferenceTypeBits.SpelledAsLValue; } bool isInnerRef() const { return ReferenceTypeBits.InnerRef; } QualType getPointeeTypeAsWritten() const { return PointeeType; } QualType getPointeeType() const { // FIXME: this might strip inner qualifiers; okay? const ReferenceType *T = this; while (T->isInnerRef()) T = T->PointeeType->castAs(); return T->PointeeType; } void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, PointeeType, isSpelledAsLValue()); } static void Profile(llvm::FoldingSetNodeID &ID, QualType Referencee, bool SpelledAsLValue) { ID.AddPointer(Referencee.getAsOpaquePtr()); ID.AddBoolean(SpelledAsLValue); } static bool classof(const Type *T) { return T->getTypeClass() == LValueReference || T->getTypeClass() == RValueReference; } }; /// An lvalue reference type, per C++11 [dcl.ref]. class LValueReferenceType : public ReferenceType { friend class ASTContext; // ASTContext creates these LValueReferenceType(QualType Referencee, QualType CanonicalRef, bool SpelledAsLValue) : ReferenceType(LValueReference, Referencee, CanonicalRef, SpelledAsLValue) {} public: bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } static bool classof(const Type *T) { return T->getTypeClass() == LValueReference; } }; /// An rvalue reference type, per C++11 [dcl.ref]. class RValueReferenceType : public ReferenceType { friend class ASTContext; // ASTContext creates these RValueReferenceType(QualType Referencee, QualType CanonicalRef) : ReferenceType(RValueReference, Referencee, CanonicalRef, false) {} public: bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } static bool classof(const Type *T) { return T->getTypeClass() == RValueReference; } }; /// A pointer to member type per C++ 8.3.3 - Pointers to members. /// /// This includes both pointers to data members and pointer to member functions. class MemberPointerType : public Type, public llvm::FoldingSetNode { friend class ASTContext; // ASTContext creates these. QualType PointeeType; /// The class of which the pointee is a member. Must ultimately be a /// RecordType, but could be a typedef or a template parameter too. const Type *Class; MemberPointerType(QualType Pointee, const Type *Cls, QualType CanonicalPtr) : Type(MemberPointer, CanonicalPtr, Cls->isDependentType() || Pointee->isDependentType(), (Cls->isInstantiationDependentType() || Pointee->isInstantiationDependentType()), Pointee->isVariablyModifiedType(), (Cls->containsUnexpandedParameterPack() || Pointee->containsUnexpandedParameterPack())), PointeeType(Pointee), Class(Cls) {} public: QualType getPointeeType() const { return PointeeType; } /// Returns true if the member type (i.e. the pointee type) is a /// function type rather than a data-member type. bool isMemberFunctionPointer() const { return PointeeType->isFunctionProtoType(); } /// Returns true if the member type (i.e. the pointee type) is a /// data type rather than a function type. bool isMemberDataPointer() const { return !PointeeType->isFunctionProtoType(); } const Type *getClass() const { return Class; } CXXRecordDecl *getMostRecentCXXRecordDecl() const; bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, getPointeeType(), getClass()); } static void Profile(llvm::FoldingSetNodeID &ID, QualType Pointee, const Type *Class) { ID.AddPointer(Pointee.getAsOpaquePtr()); ID.AddPointer(Class); } static bool classof(const Type *T) { return T->getTypeClass() == MemberPointer; } }; /// Represents an array type, per C99 6.7.5.2 - Array Declarators. class ArrayType : public Type, public llvm::FoldingSetNode { public: /// Capture whether this is a normal array (e.g. int X[4]) /// an array with a static size (e.g. int X[static 4]), or an array /// with a star size (e.g. int X[*]). /// 'static' is only allowed on function parameters. enum ArraySizeModifier { Normal, Static, Star }; private: /// The element type of the array. QualType ElementType; protected: friend class ASTContext; // ASTContext creates these. ArrayType(TypeClass tc, QualType et, QualType can, ArraySizeModifier sm, unsigned tq, const Expr *sz = nullptr); public: QualType getElementType() const { return ElementType; } ArraySizeModifier getSizeModifier() const { return ArraySizeModifier(ArrayTypeBits.SizeModifier); } Qualifiers getIndexTypeQualifiers() const { return Qualifiers::fromCVRMask(getIndexTypeCVRQualifiers()); } unsigned getIndexTypeCVRQualifiers() const { return ArrayTypeBits.IndexTypeQuals; } static bool classof(const Type *T) { return T->getTypeClass() == ConstantArray || T->getTypeClass() == VariableArray || T->getTypeClass() == IncompleteArray || T->getTypeClass() == DependentSizedArray; } }; /// Represents the canonical version of C arrays with a specified constant size. /// For example, the canonical type for 'int A[4 + 4*100]' is a /// ConstantArrayType where the element type is 'int' and the size is 404. class ConstantArrayType final : public ArrayType, private llvm::TrailingObjects { friend class ASTContext; // ASTContext creates these. friend TrailingObjects; llvm::APInt Size; // Allows us to unique the type. ConstantArrayType(QualType et, QualType can, const llvm::APInt &size, const Expr *sz, ArraySizeModifier sm, unsigned tq) : ArrayType(ConstantArray, et, can, sm, tq, sz), Size(size) { ConstantArrayTypeBits.HasStoredSizeExpr = sz != nullptr; if (ConstantArrayTypeBits.HasStoredSizeExpr) { assert(!can.isNull() && "canonical constant array should not have size"); *getTrailingObjects() = sz; } } unsigned numTrailingObjects(OverloadToken) const { return ConstantArrayTypeBits.HasStoredSizeExpr; } public: const llvm::APInt &getSize() const { return Size; } const Expr *getSizeExpr() const { return ConstantArrayTypeBits.HasStoredSizeExpr ? *getTrailingObjects() : nullptr; } bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } /// Determine the number of bits required to address a member of // an array with the given element type and number of elements. static unsigned getNumAddressingBits(const ASTContext &Context, QualType ElementType, const llvm::APInt &NumElements); /// Determine the maximum number of active bits that an array's size /// can require, which limits the maximum size of the array. static unsigned getMaxSizeBits(const ASTContext &Context); void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Ctx) { Profile(ID, Ctx, getElementType(), getSize(), getSizeExpr(), getSizeModifier(), getIndexTypeCVRQualifiers()); } static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Ctx, QualType ET, const llvm::APInt &ArraySize, const Expr *SizeExpr, ArraySizeModifier SizeMod, unsigned TypeQuals); static bool classof(const Type *T) { return T->getTypeClass() == ConstantArray; } }; /// Represents a C array with an unspecified size. For example 'int A[]' has /// an IncompleteArrayType where the element type is 'int' and the size is /// unspecified. class IncompleteArrayType : public ArrayType { friend class ASTContext; // ASTContext creates these. IncompleteArrayType(QualType et, QualType can, ArraySizeModifier sm, unsigned tq) : ArrayType(IncompleteArray, et, can, sm, tq) {} public: friend class StmtIteratorBase; bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } static bool classof(const Type *T) { return T->getTypeClass() == IncompleteArray; } void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, getElementType(), getSizeModifier(), getIndexTypeCVRQualifiers()); } static void Profile(llvm::FoldingSetNodeID &ID, QualType ET, ArraySizeModifier SizeMod, unsigned TypeQuals) { ID.AddPointer(ET.getAsOpaquePtr()); ID.AddInteger(SizeMod); ID.AddInteger(TypeQuals); } }; /// Represents a C array with a specified size that is not an /// integer-constant-expression. For example, 'int s[x+foo()]'. /// Since the size expression is an arbitrary expression, we store it as such. /// /// Note: VariableArrayType's aren't uniqued (since the expressions aren't) and /// should not be: two lexically equivalent variable array types could mean /// different things, for example, these variables do not have the same type /// dynamically: /// /// void foo(int x) { /// int Y[x]; /// ++x; /// int Z[x]; /// } class VariableArrayType : public ArrayType { friend class ASTContext; // ASTContext creates these. /// An assignment-expression. VLA's are only permitted within /// a function block. Stmt *SizeExpr; /// The range spanned by the left and right array brackets. SourceRange Brackets; VariableArrayType(QualType et, QualType can, Expr *e, ArraySizeModifier sm, unsigned tq, SourceRange brackets) : ArrayType(VariableArray, et, can, sm, tq, e), SizeExpr((Stmt*) e), Brackets(brackets) {} public: friend class StmtIteratorBase; Expr *getSizeExpr() const { // We use C-style casts instead of cast<> here because we do not wish // to have a dependency of Type.h on Stmt.h/Expr.h. return (Expr*) SizeExpr; } SourceRange getBracketsRange() const { return Brackets; } SourceLocation getLBracketLoc() const { return Brackets.getBegin(); } SourceLocation getRBracketLoc() const { return Brackets.getEnd(); } bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } static bool classof(const Type *T) { return T->getTypeClass() == VariableArray; } void Profile(llvm::FoldingSetNodeID &ID) { llvm_unreachable("Cannot unique VariableArrayTypes."); } }; /// Represents an array type in C++ whose size is a value-dependent expression. /// /// For example: /// \code /// template /// class array { /// T data[Size]; /// }; /// \endcode /// /// For these types, we won't actually know what the array bound is /// until template instantiation occurs, at which point this will /// become either a ConstantArrayType or a VariableArrayType. class DependentSizedArrayType : public ArrayType { friend class ASTContext; // ASTContext creates these. const ASTContext &Context; /// An assignment expression that will instantiate to the /// size of the array. /// /// The expression itself might be null, in which case the array /// type will have its size deduced from an initializer. Stmt *SizeExpr; /// The range spanned by the left and right array brackets. SourceRange Brackets; DependentSizedArrayType(const ASTContext &Context, QualType et, QualType can, Expr *e, ArraySizeModifier sm, unsigned tq, SourceRange brackets); public: friend class StmtIteratorBase; Expr *getSizeExpr() const { // We use C-style casts instead of cast<> here because we do not wish // to have a dependency of Type.h on Stmt.h/Expr.h. return (Expr*) SizeExpr; } SourceRange getBracketsRange() const { return Brackets; } SourceLocation getLBracketLoc() const { return Brackets.getBegin(); } SourceLocation getRBracketLoc() const { return Brackets.getEnd(); } bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } static bool classof(const Type *T) { return T->getTypeClass() == DependentSizedArray; } void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, Context, getElementType(), getSizeModifier(), getIndexTypeCVRQualifiers(), getSizeExpr()); } static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context, QualType ET, ArraySizeModifier SizeMod, unsigned TypeQuals, Expr *E); }; /// Represents an extended address space qualifier where the input address space /// value is dependent. Non-dependent address spaces are not represented with a /// special Type subclass; they are stored on an ExtQuals node as part of a QualType. /// /// For example: /// \code /// template /// class AddressSpace { /// typedef T __attribute__((address_space(AddrSpace))) type; /// } /// \endcode class DependentAddressSpaceType : public Type, public llvm::FoldingSetNode { friend class ASTContext; const ASTContext &Context; Expr *AddrSpaceExpr; QualType PointeeType; SourceLocation loc; DependentAddressSpaceType(const ASTContext &Context, QualType PointeeType, QualType can, Expr *AddrSpaceExpr, SourceLocation loc); public: Expr *getAddrSpaceExpr() const { return AddrSpaceExpr; } QualType getPointeeType() const { return PointeeType; } SourceLocation getAttributeLoc() const { return loc; } bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } static bool classof(const Type *T) { return T->getTypeClass() == DependentAddressSpace; } void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, Context, getPointeeType(), getAddrSpaceExpr()); } static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context, QualType PointeeType, Expr *AddrSpaceExpr); }; /// Represents an extended vector type where either the type or size is /// dependent. /// /// For example: /// \code /// template /// class vector { /// typedef T __attribute__((ext_vector_type(Size))) type; /// } /// \endcode class DependentSizedExtVectorType : public Type, public llvm::FoldingSetNode { friend class ASTContext; const ASTContext &Context; Expr *SizeExpr; /// The element type of the array. QualType ElementType; SourceLocation loc; DependentSizedExtVectorType(const ASTContext &Context, QualType ElementType, QualType can, Expr *SizeExpr, SourceLocation loc); public: Expr *getSizeExpr() const { return SizeExpr; } QualType getElementType() const { return ElementType; } SourceLocation getAttributeLoc() const { return loc; } bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } static bool classof(const Type *T) { return T->getTypeClass() == DependentSizedExtVector; } void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, Context, getElementType(), getSizeExpr()); } static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context, QualType ElementType, Expr *SizeExpr); }; /// Represents a GCC generic vector type. This type is created using /// __attribute__((vector_size(n)), where "n" specifies the vector size in /// bytes; or from an Altivec __vector or vector declaration. /// Since the constructor takes the number of vector elements, the /// client is responsible for converting the size into the number of elements. class VectorType : public Type, public llvm::FoldingSetNode { public: enum VectorKind { /// not a target-specific vector type GenericVector, /// is AltiVec vector AltiVecVector, /// is AltiVec 'vector Pixel' AltiVecPixel, /// is AltiVec 'vector bool ...' AltiVecBool, /// is ARM Neon vector NeonVector, /// is ARM Neon polynomial vector NeonPolyVector }; protected: friend class ASTContext; // ASTContext creates these. /// The element type of the vector. QualType ElementType; VectorType(QualType vecType, unsigned nElements, QualType canonType, VectorKind vecKind); VectorType(TypeClass tc, QualType vecType, unsigned nElements, QualType canonType, VectorKind vecKind); public: QualType getElementType() const { return ElementType; } unsigned getNumElements() const { return VectorTypeBits.NumElements; } static bool isVectorSizeTooLarge(unsigned NumElements) { return NumElements > VectorTypeBitfields::MaxNumElements; } bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } VectorKind getVectorKind() const { return VectorKind(VectorTypeBits.VecKind); } void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, getElementType(), getNumElements(), getTypeClass(), getVectorKind()); } static void Profile(llvm::FoldingSetNodeID &ID, QualType ElementType, unsigned NumElements, TypeClass TypeClass, VectorKind VecKind) { ID.AddPointer(ElementType.getAsOpaquePtr()); ID.AddInteger(NumElements); ID.AddInteger(TypeClass); ID.AddInteger(VecKind); } static bool classof(const Type *T) { return T->getTypeClass() == Vector || T->getTypeClass() == ExtVector; } }; /// Represents a vector type where either the type or size is dependent. //// /// For example: /// \code /// template /// class vector { /// typedef T __attribute__((vector_size(Size))) type; /// } /// \endcode class DependentVectorType : public Type, public llvm::FoldingSetNode { friend class ASTContext; const ASTContext &Context; QualType ElementType; Expr *SizeExpr; SourceLocation Loc; DependentVectorType(const ASTContext &Context, QualType ElementType, QualType CanonType, Expr *SizeExpr, SourceLocation Loc, VectorType::VectorKind vecKind); public: Expr *getSizeExpr() const { return SizeExpr; } QualType getElementType() const { return ElementType; } SourceLocation getAttributeLoc() const { return Loc; } VectorType::VectorKind getVectorKind() const { return VectorType::VectorKind(VectorTypeBits.VecKind); } bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } static bool classof(const Type *T) { return T->getTypeClass() == DependentVector; } void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, Context, getElementType(), getSizeExpr(), getVectorKind()); } static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context, QualType ElementType, const Expr *SizeExpr, VectorType::VectorKind VecKind); }; /// ExtVectorType - Extended vector type. This type is created using /// __attribute__((ext_vector_type(n)), where "n" is the number of elements. /// Unlike vector_size, ext_vector_type is only allowed on typedef's. This /// class enables syntactic extensions, like Vector Components for accessing /// points (as .xyzw), colors (as .rgba), and textures (modeled after OpenGL /// Shading Language). class ExtVectorType : public VectorType { friend class ASTContext; // ASTContext creates these. ExtVectorType(QualType vecType, unsigned nElements, QualType canonType) : VectorType(ExtVector, vecType, nElements, canonType, GenericVector) {} public: static int getPointAccessorIdx(char c) { switch (c) { default: return -1; case 'x': case 'r': return 0; case 'y': case 'g': return 1; case 'z': case 'b': return 2; case 'w': case 'a': return 3; } } static int getNumericAccessorIdx(char c) { switch (c) { default: return -1; case '0': return 0; case '1': return 1; case '2': return 2; case '3': return 3; case '4': return 4; case '5': return 5; case '6': return 6; case '7': return 7; case '8': return 8; case '9': return 9; case 'A': case 'a': return 10; case 'B': case 'b': return 11; case 'C': case 'c': return 12; case 'D': case 'd': return 13; case 'E': case 'e': return 14; case 'F': case 'f': return 15; } } static int getAccessorIdx(char c, bool isNumericAccessor) { if (isNumericAccessor) return getNumericAccessorIdx(c); else return getPointAccessorIdx(c); } bool isAccessorWithinNumElements(char c, bool isNumericAccessor) const { if (int idx = getAccessorIdx(c, isNumericAccessor)+1) return unsigned(idx-1) < getNumElements(); return false; } bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } static bool classof(const Type *T) { return T->getTypeClass() == ExtVector; } }; /// FunctionType - C99 6.7.5.3 - Function Declarators. This is the common base /// class of FunctionNoProtoType and FunctionProtoType. class FunctionType : public Type { // The type returned by the function. QualType ResultType; public: /// Interesting information about a specific parameter that can't simply /// be reflected in parameter's type. This is only used by FunctionProtoType /// but is in FunctionType to make this class available during the /// specification of the bases of FunctionProtoType. /// /// It makes sense to model language features this way when there's some /// sort of parameter-specific override (such as an attribute) that /// affects how the function is called. For example, the ARC ns_consumed /// attribute changes whether a parameter is passed at +0 (the default) /// or +1 (ns_consumed). This must be reflected in the function type, /// but isn't really a change to the parameter type. /// /// One serious disadvantage of modelling language features this way is /// that they generally do not work with language features that attempt /// to destructure types. For example, template argument deduction will /// not be able to match a parameter declared as /// T (*)(U) /// against an argument of type /// void (*)(__attribute__((ns_consumed)) id) /// because the substitution of T=void, U=id into the former will /// not produce the latter. class ExtParameterInfo { enum { ABIMask = 0x0F, IsConsumed = 0x10, HasPassObjSize = 0x20, IsNoEscape = 0x40, }; unsigned char Data = 0; public: ExtParameterInfo() = default; /// Return the ABI treatment of this parameter. ParameterABI getABI() const { return ParameterABI(Data & ABIMask); } ExtParameterInfo withABI(ParameterABI kind) const { ExtParameterInfo copy = *this; copy.Data = (copy.Data & ~ABIMask) | unsigned(kind); return copy; } /// Is this parameter considered "consumed" by Objective-C ARC? /// Consumed parameters must have retainable object type. bool isConsumed() const { return (Data & IsConsumed); } ExtParameterInfo withIsConsumed(bool consumed) const { ExtParameterInfo copy = *this; if (consumed) copy.Data |= IsConsumed; else copy.Data &= ~IsConsumed; return copy; } bool hasPassObjectSize() const { return Data & HasPassObjSize; } ExtParameterInfo withHasPassObjectSize() const { ExtParameterInfo Copy = *this; Copy.Data |= HasPassObjSize; return Copy; } bool isNoEscape() const { return Data & IsNoEscape; } ExtParameterInfo withIsNoEscape(bool NoEscape) const { ExtParameterInfo Copy = *this; if (NoEscape) Copy.Data |= IsNoEscape; else Copy.Data &= ~IsNoEscape; return Copy; } unsigned char getOpaqueValue() const { return Data; } static ExtParameterInfo getFromOpaqueValue(unsigned char data) { ExtParameterInfo result; result.Data = data; return result; } friend bool operator==(ExtParameterInfo lhs, ExtParameterInfo rhs) { return lhs.Data == rhs.Data; } friend bool operator!=(ExtParameterInfo lhs, ExtParameterInfo rhs) { return lhs.Data != rhs.Data; } }; /// A class which abstracts out some details necessary for /// making a call. /// /// It is not actually used directly for storing this information in /// a FunctionType, although FunctionType does currently use the /// same bit-pattern. /// // If you add a field (say Foo), other than the obvious places (both, // constructors, compile failures), what you need to update is // * Operator== // * getFoo // * withFoo // * functionType. Add Foo, getFoo. // * ASTContext::getFooType // * ASTContext::mergeFunctionTypes // * FunctionNoProtoType::Profile // * FunctionProtoType::Profile // * TypePrinter::PrintFunctionProto // * AST read and write // * Codegen class ExtInfo { friend class FunctionType; // Feel free to rearrange or add bits, but if you go over 12, // you'll need to adjust both the Bits field below and // Type::FunctionTypeBitfields. // | CC |noreturn|produces|nocallersavedregs|regparm|nocfcheck| // |0 .. 4| 5 | 6 | 7 |8 .. 10| 11 | // // regparm is either 0 (no regparm attribute) or the regparm value+1. enum { CallConvMask = 0x1F }; enum { NoReturnMask = 0x20 }; enum { ProducesResultMask = 0x40 }; enum { NoCallerSavedRegsMask = 0x80 }; enum { NoCfCheckMask = 0x800 }; enum { RegParmMask = ~(CallConvMask | NoReturnMask | ProducesResultMask | NoCallerSavedRegsMask | NoCfCheckMask), RegParmOffset = 8 }; // Assumed to be the last field uint16_t Bits = CC_C; ExtInfo(unsigned Bits) : Bits(static_cast(Bits)) {} public: // Constructor with no defaults. Use this when you know that you // have all the elements (when reading an AST file for example). ExtInfo(bool noReturn, bool hasRegParm, unsigned regParm, CallingConv cc, bool producesResult, bool noCallerSavedRegs, bool NoCfCheck) { assert((!hasRegParm || regParm < 7) && "Invalid regparm value"); Bits = ((unsigned)cc) | (noReturn ? NoReturnMask : 0) | (producesResult ? ProducesResultMask : 0) | (noCallerSavedRegs ? NoCallerSavedRegsMask : 0) | (hasRegParm ? ((regParm + 1) << RegParmOffset) : 0) | (NoCfCheck ? NoCfCheckMask : 0); } // Constructor with all defaults. Use when for example creating a // function known to use defaults. ExtInfo() = default; // Constructor with just the calling convention, which is an important part // of the canonical type. ExtInfo(CallingConv CC) : Bits(CC) {} bool getNoReturn() const { return Bits & NoReturnMask; } bool getProducesResult() const { return Bits & ProducesResultMask; } bool getNoCallerSavedRegs() const { return Bits & NoCallerSavedRegsMask; } bool getNoCfCheck() const { return Bits & NoCfCheckMask; } bool getHasRegParm() const { return (Bits >> RegParmOffset) != 0; } unsigned getRegParm() const { unsigned RegParm = (Bits & RegParmMask) >> RegParmOffset; if (RegParm > 0) --RegParm; return RegParm; } CallingConv getCC() const { return CallingConv(Bits & CallConvMask); } bool operator==(ExtInfo Other) const { return Bits == Other.Bits; } bool operator!=(ExtInfo Other) const { return Bits != Other.Bits; } // Note that we don't have setters. That is by design, use // the following with methods instead of mutating these objects. ExtInfo withNoReturn(bool noReturn) const { if (noReturn) return ExtInfo(Bits | NoReturnMask); else return ExtInfo(Bits & ~NoReturnMask); } ExtInfo withProducesResult(bool producesResult) const { if (producesResult) return ExtInfo(Bits | ProducesResultMask); else return ExtInfo(Bits & ~ProducesResultMask); } ExtInfo withNoCallerSavedRegs(bool noCallerSavedRegs) const { if (noCallerSavedRegs) return ExtInfo(Bits | NoCallerSavedRegsMask); else return ExtInfo(Bits & ~NoCallerSavedRegsMask); } ExtInfo withNoCfCheck(bool noCfCheck) const { if (noCfCheck) return ExtInfo(Bits | NoCfCheckMask); else return ExtInfo(Bits & ~NoCfCheckMask); } ExtInfo withRegParm(unsigned RegParm) const { assert(RegParm < 7 && "Invalid regparm value"); return ExtInfo((Bits & ~RegParmMask) | ((RegParm + 1) << RegParmOffset)); } ExtInfo withCallingConv(CallingConv cc) const { return ExtInfo((Bits & ~CallConvMask) | (unsigned) cc); } void Profile(llvm::FoldingSetNodeID &ID) const { ID.AddInteger(Bits); } }; /// A simple holder for a QualType representing a type in an /// exception specification. Unfortunately needed by FunctionProtoType /// because TrailingObjects cannot handle repeated types. struct ExceptionType { QualType Type; }; /// A simple holder for various uncommon bits which do not fit in /// FunctionTypeBitfields. Aligned to alignof(void *) to maintain the /// alignment of subsequent objects in TrailingObjects. You must update /// hasExtraBitfields in FunctionProtoType after adding extra data here. struct alignas(void *) FunctionTypeExtraBitfields { /// The number of types in the exception specification. /// A whole unsigned is not needed here and according to /// [implimits] 8 bits would be enough here. unsigned NumExceptionType; }; protected: FunctionType(TypeClass tc, QualType res, QualType Canonical, bool Dependent, bool InstantiationDependent, bool VariablyModified, bool ContainsUnexpandedParameterPack, ExtInfo Info) : Type(tc, Canonical, Dependent, InstantiationDependent, VariablyModified, ContainsUnexpandedParameterPack), ResultType(res) { FunctionTypeBits.ExtInfo = Info.Bits; } Qualifiers getFastTypeQuals() const { return Qualifiers::fromFastMask(FunctionTypeBits.FastTypeQuals); } public: QualType getReturnType() const { return ResultType; } bool getHasRegParm() const { return getExtInfo().getHasRegParm(); } unsigned getRegParmType() const { return getExtInfo().getRegParm(); } /// Determine whether this function type includes the GNU noreturn /// attribute. The C++11 [[noreturn]] attribute does not affect the function /// type. bool getNoReturnAttr() const { return getExtInfo().getNoReturn(); } CallingConv getCallConv() const { return getExtInfo().getCC(); } ExtInfo getExtInfo() const { return ExtInfo(FunctionTypeBits.ExtInfo); } static_assert((~Qualifiers::FastMask & Qualifiers::CVRMask) == 0, "Const, volatile and restrict are assumed to be a subset of " "the fast qualifiers."); bool isConst() const { return getFastTypeQuals().hasConst(); } bool isVolatile() const { return getFastTypeQuals().hasVolatile(); } bool isRestrict() const { return getFastTypeQuals().hasRestrict(); } /// Determine the type of an expression that calls a function of /// this type. QualType getCallResultType(const ASTContext &Context) const { return getReturnType().getNonLValueExprType(Context); } static StringRef getNameForCallConv(CallingConv CC); static bool classof(const Type *T) { return T->getTypeClass() == FunctionNoProto || T->getTypeClass() == FunctionProto; } }; /// Represents a K&R-style 'int foo()' function, which has /// no information available about its arguments. class FunctionNoProtoType : public FunctionType, public llvm::FoldingSetNode { friend class ASTContext; // ASTContext creates these. FunctionNoProtoType(QualType Result, QualType Canonical, ExtInfo Info) : FunctionType(FunctionNoProto, Result, Canonical, /*Dependent=*/false, /*InstantiationDependent=*/false, Result->isVariablyModifiedType(), /*ContainsUnexpandedParameterPack=*/false, Info) {} public: // No additional state past what FunctionType provides. bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, getReturnType(), getExtInfo()); } static void Profile(llvm::FoldingSetNodeID &ID, QualType ResultType, ExtInfo Info) { Info.Profile(ID); ID.AddPointer(ResultType.getAsOpaquePtr()); } static bool classof(const Type *T) { return T->getTypeClass() == FunctionNoProto; } }; /// Represents a prototype with parameter type info, e.g. /// 'int foo(int)' or 'int foo(void)'. 'void' is represented as having no /// parameters, not as having a single void parameter. Such a type can have /// an exception specification, but this specification is not part of the /// canonical type. FunctionProtoType has several trailing objects, some of /// which optional. For more information about the trailing objects see /// the first comment inside FunctionProtoType. class FunctionProtoType final : public FunctionType, public llvm::FoldingSetNode, private llvm::TrailingObjects< FunctionProtoType, QualType, FunctionType::FunctionTypeExtraBitfields, FunctionType::ExceptionType, Expr *, FunctionDecl *, FunctionType::ExtParameterInfo, Qualifiers> { friend class ASTContext; // ASTContext creates these. friend TrailingObjects; // FunctionProtoType is followed by several trailing objects, some of // which optional. They are in order: // // * An array of getNumParams() QualType holding the parameter types. // Always present. Note that for the vast majority of FunctionProtoType, // these will be the only trailing objects. // // * Optionally if some extra data is stored in FunctionTypeExtraBitfields // (see FunctionTypeExtraBitfields and FunctionTypeBitfields): // a single FunctionTypeExtraBitfields. Present if and only if // hasExtraBitfields() is true. // // * Optionally exactly one of: // * an array of getNumExceptions() ExceptionType, // * a single Expr *, // * a pair of FunctionDecl *, // * a single FunctionDecl * // used to store information about the various types of exception // specification. See getExceptionSpecSize for the details. // // * Optionally an array of getNumParams() ExtParameterInfo holding // an ExtParameterInfo for each of the parameters. Present if and // only if hasExtParameterInfos() is true. // // * Optionally a Qualifiers object to represent extra qualifiers that can't // be represented by FunctionTypeBitfields.FastTypeQuals. Present if and only // if hasExtQualifiers() is true. // // The optional FunctionTypeExtraBitfields has to be before the data // related to the exception specification since it contains the number // of exception types. // // We put the ExtParameterInfos last. If all were equal, it would make // more sense to put these before the exception specification, because // it's much easier to skip past them compared to the elaborate switch // required to skip the exception specification. However, all is not // equal; ExtParameterInfos are used to model very uncommon features, // and it's better not to burden the more common paths. public: /// Holds information about the various types of exception specification. /// ExceptionSpecInfo is not stored as such in FunctionProtoType but is /// used to group together the various bits of information about the /// exception specification. struct ExceptionSpecInfo { /// The kind of exception specification this is. ExceptionSpecificationType Type = EST_None; /// Explicitly-specified list of exception types. ArrayRef Exceptions; /// Noexcept expression, if this is a computed noexcept specification. Expr *NoexceptExpr = nullptr; /// The function whose exception specification this is, for /// EST_Unevaluated and EST_Uninstantiated. FunctionDecl *SourceDecl = nullptr; /// The function template whose exception specification this is instantiated /// from, for EST_Uninstantiated. FunctionDecl *SourceTemplate = nullptr; ExceptionSpecInfo() = default; ExceptionSpecInfo(ExceptionSpecificationType EST) : Type(EST) {} }; /// Extra information about a function prototype. ExtProtoInfo is not /// stored as such in FunctionProtoType but is used to group together /// the various bits of extra information about a function prototype. struct ExtProtoInfo { FunctionType::ExtInfo ExtInfo; bool Variadic : 1; bool HasTrailingReturn : 1; Qualifiers TypeQuals; RefQualifierKind RefQualifier = RQ_None; ExceptionSpecInfo ExceptionSpec; const ExtParameterInfo *ExtParameterInfos = nullptr; ExtProtoInfo() : Variadic(false), HasTrailingReturn(false) {} ExtProtoInfo(CallingConv CC) : ExtInfo(CC), Variadic(false), HasTrailingReturn(false) {} ExtProtoInfo withExceptionSpec(const ExceptionSpecInfo &ESI) { ExtProtoInfo Result(*this); Result.ExceptionSpec = ESI; return Result; } }; private: unsigned numTrailingObjects(OverloadToken) const { return getNumParams(); } unsigned numTrailingObjects(OverloadToken) const { return hasExtraBitfields(); } unsigned numTrailingObjects(OverloadToken) const { return getExceptionSpecSize().NumExceptionType; } unsigned numTrailingObjects(OverloadToken) const { return getExceptionSpecSize().NumExprPtr; } unsigned numTrailingObjects(OverloadToken) const { return getExceptionSpecSize().NumFunctionDeclPtr; } unsigned numTrailingObjects(OverloadToken) const { return hasExtParameterInfos() ? getNumParams() : 0; } /// Determine whether there are any argument types that /// contain an unexpanded parameter pack. static bool containsAnyUnexpandedParameterPack(const QualType *ArgArray, unsigned numArgs) { for (unsigned Idx = 0; Idx < numArgs; ++Idx) if (ArgArray[Idx]->containsUnexpandedParameterPack()) return true; return false; } FunctionProtoType(QualType result, ArrayRef params, QualType canonical, const ExtProtoInfo &epi); /// This struct is returned by getExceptionSpecSize and is used to /// translate an ExceptionSpecificationType to the number and kind /// of trailing objects related to the exception specification. struct ExceptionSpecSizeHolder { unsigned NumExceptionType; unsigned NumExprPtr; unsigned NumFunctionDeclPtr; }; /// Return the number and kind of trailing objects /// related to the exception specification. static ExceptionSpecSizeHolder getExceptionSpecSize(ExceptionSpecificationType EST, unsigned NumExceptions) { switch (EST) { case EST_None: case EST_DynamicNone: case EST_MSAny: case EST_BasicNoexcept: case EST_Unparsed: case EST_NoThrow: return {0, 0, 0}; case EST_Dynamic: return {NumExceptions, 0, 0}; case EST_DependentNoexcept: case EST_NoexceptFalse: case EST_NoexceptTrue: return {0, 1, 0}; case EST_Uninstantiated: return {0, 0, 2}; case EST_Unevaluated: return {0, 0, 1}; } llvm_unreachable("bad exception specification kind"); } /// Return the number and kind of trailing objects /// related to the exception specification. ExceptionSpecSizeHolder getExceptionSpecSize() const { return getExceptionSpecSize(getExceptionSpecType(), getNumExceptions()); } /// Whether the trailing FunctionTypeExtraBitfields is present. static bool hasExtraBitfields(ExceptionSpecificationType EST) { // If the exception spec type is EST_Dynamic then we have > 0 exception // types and the exact number is stored in FunctionTypeExtraBitfields. return EST == EST_Dynamic; } /// Whether the trailing FunctionTypeExtraBitfields is present. bool hasExtraBitfields() const { return hasExtraBitfields(getExceptionSpecType()); } bool hasExtQualifiers() const { return FunctionTypeBits.HasExtQuals; } public: unsigned getNumParams() const { return FunctionTypeBits.NumParams; } QualType getParamType(unsigned i) const { assert(i < getNumParams() && "invalid parameter index"); return param_type_begin()[i]; } ArrayRef getParamTypes() const { return llvm::makeArrayRef(param_type_begin(), param_type_end()); } ExtProtoInfo getExtProtoInfo() const { ExtProtoInfo EPI; EPI.ExtInfo = getExtInfo(); EPI.Variadic = isVariadic(); EPI.HasTrailingReturn = hasTrailingReturn(); EPI.ExceptionSpec.Type = getExceptionSpecType(); EPI.TypeQuals = getMethodQuals(); EPI.RefQualifier = getRefQualifier(); if (EPI.ExceptionSpec.Type == EST_Dynamic) { EPI.ExceptionSpec.Exceptions = exceptions(); } else if (isComputedNoexcept(EPI.ExceptionSpec.Type)) { EPI.ExceptionSpec.NoexceptExpr = getNoexceptExpr(); } else if (EPI.ExceptionSpec.Type == EST_Uninstantiated) { EPI.ExceptionSpec.SourceDecl = getExceptionSpecDecl(); EPI.ExceptionSpec.SourceTemplate = getExceptionSpecTemplate(); } else if (EPI.ExceptionSpec.Type == EST_Unevaluated) { EPI.ExceptionSpec.SourceDecl = getExceptionSpecDecl(); } EPI.ExtParameterInfos = getExtParameterInfosOrNull(); return EPI; } /// Get the kind of exception specification on this function. ExceptionSpecificationType getExceptionSpecType() const { return static_cast( FunctionTypeBits.ExceptionSpecType); } /// Return whether this function has any kind of exception spec. bool hasExceptionSpec() const { return getExceptionSpecType() != EST_None; } /// Return whether this function has a dynamic (throw) exception spec. bool hasDynamicExceptionSpec() const { return isDynamicExceptionSpec(getExceptionSpecType()); } /// Return whether this function has a noexcept exception spec. bool hasNoexceptExceptionSpec() const { return isNoexceptExceptionSpec(getExceptionSpecType()); } /// Return whether this function has a dependent exception spec. bool hasDependentExceptionSpec() const; /// Return whether this function has an instantiation-dependent exception /// spec. bool hasInstantiationDependentExceptionSpec() const; /// Return the number of types in the exception specification. unsigned getNumExceptions() const { return getExceptionSpecType() == EST_Dynamic ? getTrailingObjects() ->NumExceptionType : 0; } /// Return the ith exception type, where 0 <= i < getNumExceptions(). QualType getExceptionType(unsigned i) const { assert(i < getNumExceptions() && "Invalid exception number!"); return exception_begin()[i]; } /// Return the expression inside noexcept(expression), or a null pointer /// if there is none (because the exception spec is not of this form). Expr *getNoexceptExpr() const { if (!isComputedNoexcept(getExceptionSpecType())) return nullptr; return *getTrailingObjects(); } /// If this function type has an exception specification which hasn't /// been determined yet (either because it has not been evaluated or because /// it has not been instantiated), this is the function whose exception /// specification is represented by this type. FunctionDecl *getExceptionSpecDecl() const { if (getExceptionSpecType() != EST_Uninstantiated && getExceptionSpecType() != EST_Unevaluated) return nullptr; return getTrailingObjects()[0]; } /// If this function type has an uninstantiated exception /// specification, this is the function whose exception specification /// should be instantiated to find the exception specification for /// this type. FunctionDecl *getExceptionSpecTemplate() const { if (getExceptionSpecType() != EST_Uninstantiated) return nullptr; return getTrailingObjects()[1]; } /// Determine whether this function type has a non-throwing exception /// specification. CanThrowResult canThrow() const; /// Determine whether this function type has a non-throwing exception /// specification. If this depends on template arguments, returns /// \c ResultIfDependent. bool isNothrow(bool ResultIfDependent = false) const { return ResultIfDependent ? canThrow() != CT_Can : canThrow() == CT_Cannot; } /// Whether this function prototype is variadic. bool isVariadic() const { return FunctionTypeBits.Variadic; } /// Determines whether this function prototype contains a /// parameter pack at the end. /// /// A function template whose last parameter is a parameter pack can be /// called with an arbitrary number of arguments, much like a variadic /// function. bool isTemplateVariadic() const; /// Whether this function prototype has a trailing return type. bool hasTrailingReturn() const { return FunctionTypeBits.HasTrailingReturn; } Qualifiers getMethodQuals() const { if (hasExtQualifiers()) return *getTrailingObjects(); else return getFastTypeQuals(); } /// Retrieve the ref-qualifier associated with this function type. RefQualifierKind getRefQualifier() const { return static_cast(FunctionTypeBits.RefQualifier); } using param_type_iterator = const QualType *; using param_type_range = llvm::iterator_range; param_type_range param_types() const { return param_type_range(param_type_begin(), param_type_end()); } param_type_iterator param_type_begin() const { return getTrailingObjects(); } param_type_iterator param_type_end() const { return param_type_begin() + getNumParams(); } using exception_iterator = const QualType *; ArrayRef exceptions() const { return llvm::makeArrayRef(exception_begin(), exception_end()); } exception_iterator exception_begin() const { return reinterpret_cast( getTrailingObjects()); } exception_iterator exception_end() const { return exception_begin() + getNumExceptions(); } /// Is there any interesting extra information for any of the parameters /// of this function type? bool hasExtParameterInfos() const { return FunctionTypeBits.HasExtParameterInfos; } ArrayRef getExtParameterInfos() const { assert(hasExtParameterInfos()); return ArrayRef(getTrailingObjects(), getNumParams()); } /// Return a pointer to the beginning of the array of extra parameter /// information, if present, or else null if none of the parameters /// carry it. This is equivalent to getExtProtoInfo().ExtParameterInfos. const ExtParameterInfo *getExtParameterInfosOrNull() const { if (!hasExtParameterInfos()) return nullptr; return getTrailingObjects(); } ExtParameterInfo getExtParameterInfo(unsigned I) const { assert(I < getNumParams() && "parameter index out of range"); if (hasExtParameterInfos()) return getTrailingObjects()[I]; return ExtParameterInfo(); } ParameterABI getParameterABI(unsigned I) const { assert(I < getNumParams() && "parameter index out of range"); if (hasExtParameterInfos()) return getTrailingObjects()[I].getABI(); return ParameterABI::Ordinary; } bool isParamConsumed(unsigned I) const { assert(I < getNumParams() && "parameter index out of range"); if (hasExtParameterInfos()) return getTrailingObjects()[I].isConsumed(); return false; } bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } void printExceptionSpecification(raw_ostream &OS, const PrintingPolicy &Policy) const; static bool classof(const Type *T) { return T->getTypeClass() == FunctionProto; } void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Ctx); static void Profile(llvm::FoldingSetNodeID &ID, QualType Result, param_type_iterator ArgTys, unsigned NumArgs, const ExtProtoInfo &EPI, const ASTContext &Context, bool Canonical); }; /// Represents the dependent type named by a dependently-scoped /// typename using declaration, e.g. /// using typename Base::foo; /// /// Template instantiation turns these into the underlying type. class UnresolvedUsingType : public Type { friend class ASTContext; // ASTContext creates these. UnresolvedUsingTypenameDecl *Decl; UnresolvedUsingType(const UnresolvedUsingTypenameDecl *D) : Type(UnresolvedUsing, QualType(), true, true, false, /*ContainsUnexpandedParameterPack=*/false), Decl(const_cast(D)) {} public: UnresolvedUsingTypenameDecl *getDecl() const { return Decl; } bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } static bool classof(const Type *T) { return T->getTypeClass() == UnresolvedUsing; } void Profile(llvm::FoldingSetNodeID &ID) { return Profile(ID, Decl); } static void Profile(llvm::FoldingSetNodeID &ID, UnresolvedUsingTypenameDecl *D) { ID.AddPointer(D); } }; class TypedefType : public Type { TypedefNameDecl *Decl; protected: friend class ASTContext; // ASTContext creates these. TypedefType(TypeClass tc, const TypedefNameDecl *D, QualType can) : Type(tc, can, can->isDependentType(), can->isInstantiationDependentType(), can->isVariablyModifiedType(), /*ContainsUnexpandedParameterPack=*/false), Decl(const_cast(D)) { assert(!isa(can) && "Invalid canonical type"); } public: TypedefNameDecl *getDecl() const { return Decl; } bool isSugared() const { return true; } QualType desugar() const; static bool classof(const Type *T) { return T->getTypeClass() == Typedef; } }; /// Sugar type that represents a type that was qualified by a qualifier written /// as a macro invocation. class MacroQualifiedType : public Type { friend class ASTContext; // ASTContext creates these. QualType UnderlyingTy; const IdentifierInfo *MacroII; MacroQualifiedType(QualType UnderlyingTy, QualType CanonTy, const IdentifierInfo *MacroII) : Type(MacroQualified, CanonTy, UnderlyingTy->isDependentType(), UnderlyingTy->isInstantiationDependentType(), UnderlyingTy->isVariablyModifiedType(), UnderlyingTy->containsUnexpandedParameterPack()), UnderlyingTy(UnderlyingTy), MacroII(MacroII) { assert(isa(UnderlyingTy) && "Expected a macro qualified type to only wrap attributed types."); } public: const IdentifierInfo *getMacroIdentifier() const { return MacroII; } QualType getUnderlyingType() const { return UnderlyingTy; } /// Return this attributed type's modified type with no qualifiers attached to /// it. QualType getModifiedType() const; bool isSugared() const { return true; } QualType desugar() const; static bool classof(const Type *T) { return T->getTypeClass() == MacroQualified; } }; /// Represents a `typeof` (or __typeof__) expression (a GCC extension). class TypeOfExprType : public Type { Expr *TOExpr; protected: friend class ASTContext; // ASTContext creates these. TypeOfExprType(Expr *E, QualType can = QualType()); public: Expr *getUnderlyingExpr() const { return TOExpr; } /// Remove a single level of sugar. QualType desugar() const; /// Returns whether this type directly provides sugar. bool isSugared() const; static bool classof(const Type *T) { return T->getTypeClass() == TypeOfExpr; } }; /// Internal representation of canonical, dependent /// `typeof(expr)` types. /// /// This class is used internally by the ASTContext to manage /// canonical, dependent types, only. Clients will only see instances /// of this class via TypeOfExprType nodes. class DependentTypeOfExprType : public TypeOfExprType, public llvm::FoldingSetNode { const ASTContext &Context; public: DependentTypeOfExprType(const ASTContext &Context, Expr *E) : TypeOfExprType(E), Context(Context) {} void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, Context, getUnderlyingExpr()); } static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context, Expr *E); }; /// Represents `typeof(type)`, a GCC extension. class TypeOfType : public Type { friend class ASTContext; // ASTContext creates these. QualType TOType; TypeOfType(QualType T, QualType can) : Type(TypeOf, can, T->isDependentType(), T->isInstantiationDependentType(), T->isVariablyModifiedType(), T->containsUnexpandedParameterPack()), TOType(T) { assert(!isa(can) && "Invalid canonical type"); } public: QualType getUnderlyingType() const { return TOType; } /// Remove a single level of sugar. QualType desugar() const { return getUnderlyingType(); } /// Returns whether this type directly provides sugar. bool isSugared() const { return true; } static bool classof(const Type *T) { return T->getTypeClass() == TypeOf; } }; /// Represents the type `decltype(expr)` (C++11). class DecltypeType : public Type { Expr *E; QualType UnderlyingType; protected: friend class ASTContext; // ASTContext creates these. DecltypeType(Expr *E, QualType underlyingType, QualType can = QualType()); public: Expr *getUnderlyingExpr() const { return E; } QualType getUnderlyingType() const { return UnderlyingType; } /// Remove a single level of sugar. QualType desugar() const; /// Returns whether this type directly provides sugar. bool isSugared() const; static bool classof(const Type *T) { return T->getTypeClass() == Decltype; } }; /// Internal representation of canonical, dependent /// decltype(expr) types. /// /// This class is used internally by the ASTContext to manage /// canonical, dependent types, only. Clients will only see instances /// of this class via DecltypeType nodes. class DependentDecltypeType : public DecltypeType, public llvm::FoldingSetNode { const ASTContext &Context; public: DependentDecltypeType(const ASTContext &Context, Expr *E); void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, Context, getUnderlyingExpr()); } static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context, Expr *E); }; /// A unary type transform, which is a type constructed from another. class UnaryTransformType : public Type { public: enum UTTKind { EnumUnderlyingType }; private: /// The untransformed type. QualType BaseType; /// The transformed type if not dependent, otherwise the same as BaseType. QualType UnderlyingType; UTTKind UKind; protected: friend class ASTContext; UnaryTransformType(QualType BaseTy, QualType UnderlyingTy, UTTKind UKind, QualType CanonicalTy); public: bool isSugared() const { return !isDependentType(); } QualType desugar() const { return UnderlyingType; } QualType getUnderlyingType() const { return UnderlyingType; } QualType getBaseType() const { return BaseType; } UTTKind getUTTKind() const { return UKind; } static bool classof(const Type *T) { return T->getTypeClass() == UnaryTransform; } }; /// Internal representation of canonical, dependent /// __underlying_type(type) types. /// /// This class is used internally by the ASTContext to manage /// canonical, dependent types, only. Clients will only see instances /// of this class via UnaryTransformType nodes. class DependentUnaryTransformType : public UnaryTransformType, public llvm::FoldingSetNode { public: DependentUnaryTransformType(const ASTContext &C, QualType BaseType, UTTKind UKind); void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, getBaseType(), getUTTKind()); } static void Profile(llvm::FoldingSetNodeID &ID, QualType BaseType, UTTKind UKind) { ID.AddPointer(BaseType.getAsOpaquePtr()); ID.AddInteger((unsigned)UKind); } }; class TagType : public Type { friend class ASTReader; /// Stores the TagDecl associated with this type. The decl may point to any /// TagDecl that declares the entity. TagDecl *decl; protected: TagType(TypeClass TC, const TagDecl *D, QualType can); public: TagDecl *getDecl() const; /// Determines whether this type is in the process of being defined. bool isBeingDefined() const; static bool classof(const Type *T) { return T->getTypeClass() == Enum || T->getTypeClass() == Record; } }; /// A helper class that allows the use of isa/cast/dyncast /// to detect TagType objects of structs/unions/classes. class RecordType : public TagType { protected: friend class ASTContext; // ASTContext creates these. explicit RecordType(const RecordDecl *D) : TagType(Record, reinterpret_cast(D), QualType()) {} explicit RecordType(TypeClass TC, RecordDecl *D) : TagType(TC, reinterpret_cast(D), QualType()) {} public: RecordDecl *getDecl() const { return reinterpret_cast(TagType::getDecl()); } /// Recursively check all fields in the record for const-ness. If any field /// is declared const, return true. Otherwise, return false. bool hasConstFields() const; bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } static bool classof(const Type *T) { return T->getTypeClass() == Record; } }; /// A helper class that allows the use of isa/cast/dyncast /// to detect TagType objects of enums. class EnumType : public TagType { friend class ASTContext; // ASTContext creates these. explicit EnumType(const EnumDecl *D) : TagType(Enum, reinterpret_cast(D), QualType()) {} public: EnumDecl *getDecl() const { return reinterpret_cast(TagType::getDecl()); } bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } static bool classof(const Type *T) { return T->getTypeClass() == Enum; } }; /// An attributed type is a type to which a type attribute has been applied. /// /// The "modified type" is the fully-sugared type to which the attributed /// type was applied; generally it is not canonically equivalent to the /// attributed type. The "equivalent type" is the minimally-desugared type /// which the type is canonically equivalent to. /// /// For example, in the following attributed type: /// int32_t __attribute__((vector_size(16))) /// - the modified type is the TypedefType for int32_t /// - the equivalent type is VectorType(16, int32_t) /// - the canonical type is VectorType(16, int) class AttributedType : public Type, public llvm::FoldingSetNode { public: using Kind = attr::Kind; private: friend class ASTContext; // ASTContext creates these QualType ModifiedType; QualType EquivalentType; AttributedType(QualType canon, attr::Kind attrKind, QualType modified, QualType equivalent) : Type(Attributed, canon, equivalent->isDependentType(), equivalent->isInstantiationDependentType(), equivalent->isVariablyModifiedType(), equivalent->containsUnexpandedParameterPack()), ModifiedType(modified), EquivalentType(equivalent) { AttributedTypeBits.AttrKind = attrKind; } public: Kind getAttrKind() const { return static_cast(AttributedTypeBits.AttrKind); } QualType getModifiedType() const { return ModifiedType; } QualType getEquivalentType() const { return EquivalentType; } bool isSugared() const { return true; } QualType desugar() const { return getEquivalentType(); } /// Does this attribute behave like a type qualifier? /// /// A type qualifier adjusts a type to provide specialized rules for /// a specific object, like the standard const and volatile qualifiers. /// This includes attributes controlling things like nullability, /// address spaces, and ARC ownership. The value of the object is still /// largely described by the modified type. /// /// In contrast, many type attributes "rewrite" their modified type to /// produce a fundamentally different type, not necessarily related in any /// formalizable way to the original type. For example, calling convention /// and vector attributes are not simple type qualifiers. /// /// Type qualifiers are often, but not always, reflected in the canonical /// type. bool isQualifier() const; bool isMSTypeSpec() const; bool isCallingConv() const; llvm::Optional getImmediateNullability() const; /// Retrieve the attribute kind corresponding to the given /// nullability kind. static Kind getNullabilityAttrKind(NullabilityKind kind) { switch (kind) { case NullabilityKind::NonNull: return attr::TypeNonNull; case NullabilityKind::Nullable: return attr::TypeNullable; case NullabilityKind::Unspecified: return attr::TypeNullUnspecified; } llvm_unreachable("Unknown nullability kind."); } /// Strip off the top-level nullability annotation on the given /// type, if it's there. /// /// \param T The type to strip. If the type is exactly an /// AttributedType specifying nullability (without looking through /// type sugar), the nullability is returned and this type changed /// to the underlying modified type. /// /// \returns the top-level nullability, if present. static Optional stripOuterNullability(QualType &T); void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, getAttrKind(), ModifiedType, EquivalentType); } static void Profile(llvm::FoldingSetNodeID &ID, Kind attrKind, QualType modified, QualType equivalent) { ID.AddInteger(attrKind); ID.AddPointer(modified.getAsOpaquePtr()); ID.AddPointer(equivalent.getAsOpaquePtr()); } static bool classof(const Type *T) { return T->getTypeClass() == Attributed; } }; class TemplateTypeParmType : public Type, public llvm::FoldingSetNode { friend class ASTContext; // ASTContext creates these // Helper data collector for canonical types. struct CanonicalTTPTInfo { unsigned Depth : 15; unsigned ParameterPack : 1; unsigned Index : 16; }; union { // Info for the canonical type. CanonicalTTPTInfo CanTTPTInfo; // Info for the non-canonical type. TemplateTypeParmDecl *TTPDecl; }; /// Build a non-canonical type. TemplateTypeParmType(TemplateTypeParmDecl *TTPDecl, QualType Canon) : Type(TemplateTypeParm, Canon, /*Dependent=*/true, /*InstantiationDependent=*/true, /*VariablyModified=*/false, Canon->containsUnexpandedParameterPack()), TTPDecl(TTPDecl) {} /// Build the canonical type. TemplateTypeParmType(unsigned D, unsigned I, bool PP) : Type(TemplateTypeParm, QualType(this, 0), /*Dependent=*/true, /*InstantiationDependent=*/true, /*VariablyModified=*/false, PP) { CanTTPTInfo.Depth = D; CanTTPTInfo.Index = I; CanTTPTInfo.ParameterPack = PP; } const CanonicalTTPTInfo& getCanTTPTInfo() const { QualType Can = getCanonicalTypeInternal(); return Can->castAs()->CanTTPTInfo; } public: unsigned getDepth() const { return getCanTTPTInfo().Depth; } unsigned getIndex() const { return getCanTTPTInfo().Index; } bool isParameterPack() const { return getCanTTPTInfo().ParameterPack; } TemplateTypeParmDecl *getDecl() const { return isCanonicalUnqualified() ? nullptr : TTPDecl; } IdentifierInfo *getIdentifier() const; bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, getDepth(), getIndex(), isParameterPack(), getDecl()); } static void Profile(llvm::FoldingSetNodeID &ID, unsigned Depth, unsigned Index, bool ParameterPack, TemplateTypeParmDecl *TTPDecl) { ID.AddInteger(Depth); ID.AddInteger(Index); ID.AddBoolean(ParameterPack); ID.AddPointer(TTPDecl); } static bool classof(const Type *T) { return T->getTypeClass() == TemplateTypeParm; } }; /// Represents the result of substituting a type for a template /// type parameter. /// /// Within an instantiated template, all template type parameters have /// been replaced with these. They are used solely to record that a /// type was originally written as a template type parameter; /// therefore they are never canonical. class SubstTemplateTypeParmType : public Type, public llvm::FoldingSetNode { friend class ASTContext; // The original type parameter. const TemplateTypeParmType *Replaced; SubstTemplateTypeParmType(const TemplateTypeParmType *Param, QualType Canon) : Type(SubstTemplateTypeParm, Canon, Canon->isDependentType(), Canon->isInstantiationDependentType(), Canon->isVariablyModifiedType(), Canon->containsUnexpandedParameterPack()), Replaced(Param) {} public: /// Gets the template parameter that was substituted for. const TemplateTypeParmType *getReplacedParameter() const { return Replaced; } /// Gets the type that was substituted for the template /// parameter. QualType getReplacementType() const { return getCanonicalTypeInternal(); } bool isSugared() const { return true; } QualType desugar() const { return getReplacementType(); } void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, getReplacedParameter(), getReplacementType()); } static void Profile(llvm::FoldingSetNodeID &ID, const TemplateTypeParmType *Replaced, QualType Replacement) { ID.AddPointer(Replaced); ID.AddPointer(Replacement.getAsOpaquePtr()); } static bool classof(const Type *T) { return T->getTypeClass() == SubstTemplateTypeParm; } }; /// Represents the result of substituting a set of types for a template /// type parameter pack. /// /// When a pack expansion in the source code contains multiple parameter packs /// and those parameter packs correspond to different levels of template /// parameter lists, this type node is used to represent a template type /// parameter pack from an outer level, which has already had its argument pack /// substituted but that still lives within a pack expansion that itself /// could not be instantiated. When actually performing a substitution into /// that pack expansion (e.g., when all template parameters have corresponding /// arguments), this type will be replaced with the \c SubstTemplateTypeParmType /// at the current pack substitution index. class SubstTemplateTypeParmPackType : public Type, public llvm::FoldingSetNode { friend class ASTContext; /// The original type parameter. const TemplateTypeParmType *Replaced; /// A pointer to the set of template arguments that this /// parameter pack is instantiated with. const TemplateArgument *Arguments; SubstTemplateTypeParmPackType(const TemplateTypeParmType *Param, QualType Canon, const TemplateArgument &ArgPack); public: IdentifierInfo *getIdentifier() const { return Replaced->getIdentifier(); } /// Gets the template parameter that was substituted for. const TemplateTypeParmType *getReplacedParameter() const { return Replaced; } unsigned getNumArgs() const { return SubstTemplateTypeParmPackTypeBits.NumArgs; } bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } TemplateArgument getArgumentPack() const; void Profile(llvm::FoldingSetNodeID &ID); static void Profile(llvm::FoldingSetNodeID &ID, const TemplateTypeParmType *Replaced, const TemplateArgument &ArgPack); static bool classof(const Type *T) { return T->getTypeClass() == SubstTemplateTypeParmPack; } }; /// Common base class for placeholders for types that get replaced by /// placeholder type deduction: C++11 auto, C++14 decltype(auto), C++17 deduced /// class template types, and (eventually) constrained type names from the C++ /// Concepts TS. /// /// These types are usually a placeholder for a deduced type. However, before /// the initializer is attached, or (usually) if the initializer is /// type-dependent, there is no deduced type and the type is canonical. In /// the latter case, it is also a dependent type. class DeducedType : public Type { protected: DeducedType(TypeClass TC, QualType DeducedAsType, bool IsDependent, bool IsInstantiationDependent, bool ContainsParameterPack) : Type(TC, // FIXME: Retain the sugared deduced type? DeducedAsType.isNull() ? QualType(this, 0) : DeducedAsType.getCanonicalType(), IsDependent, IsInstantiationDependent, /*VariablyModified=*/false, ContainsParameterPack) { if (!DeducedAsType.isNull()) { if (DeducedAsType->isDependentType()) setDependent(); if (DeducedAsType->isInstantiationDependentType()) setInstantiationDependent(); if (DeducedAsType->containsUnexpandedParameterPack()) setContainsUnexpandedParameterPack(); } } public: bool isSugared() const { return !isCanonicalUnqualified(); } QualType desugar() const { return getCanonicalTypeInternal(); } /// Get the type deduced for this placeholder type, or null if it's /// either not been deduced or was deduced to a dependent type. QualType getDeducedType() const { return !isCanonicalUnqualified() ? getCanonicalTypeInternal() : QualType(); } bool isDeduced() const { return !isCanonicalUnqualified() || isDependentType(); } static bool classof(const Type *T) { return T->getTypeClass() == Auto || T->getTypeClass() == DeducedTemplateSpecialization; } }; /// Represents a C++11 auto or C++14 decltype(auto) type. class AutoType : public DeducedType, public llvm::FoldingSetNode { friend class ASTContext; // ASTContext creates these AutoType(QualType DeducedAsType, AutoTypeKeyword Keyword, bool IsDeducedAsDependent, bool IsDeducedAsPack) : DeducedType(Auto, DeducedAsType, IsDeducedAsDependent, IsDeducedAsDependent, IsDeducedAsPack) { AutoTypeBits.Keyword = (unsigned)Keyword; } public: bool isDecltypeAuto() const { return getKeyword() == AutoTypeKeyword::DecltypeAuto; } AutoTypeKeyword getKeyword() const { return (AutoTypeKeyword)AutoTypeBits.Keyword; } void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, getDeducedType(), getKeyword(), isDependentType(), containsUnexpandedParameterPack()); } static void Profile(llvm::FoldingSetNodeID &ID, QualType Deduced, AutoTypeKeyword Keyword, bool IsDependent, bool IsPack) { ID.AddPointer(Deduced.getAsOpaquePtr()); ID.AddInteger((unsigned)Keyword); ID.AddBoolean(IsDependent); ID.AddBoolean(IsPack); } static bool classof(const Type *T) { return T->getTypeClass() == Auto; } }; /// Represents a C++17 deduced template specialization type. class DeducedTemplateSpecializationType : public DeducedType, public llvm::FoldingSetNode { friend class ASTContext; // ASTContext creates these /// The name of the template whose arguments will be deduced. TemplateName Template; DeducedTemplateSpecializationType(TemplateName Template, QualType DeducedAsType, bool IsDeducedAsDependent) : DeducedType(DeducedTemplateSpecialization, DeducedAsType, IsDeducedAsDependent || Template.isDependent(), IsDeducedAsDependent || Template.isInstantiationDependent(), Template.containsUnexpandedParameterPack()), Template(Template) {} public: /// Retrieve the name of the template that we are deducing. TemplateName getTemplateName() const { return Template;} void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, getTemplateName(), getDeducedType(), isDependentType()); } static void Profile(llvm::FoldingSetNodeID &ID, TemplateName Template, QualType Deduced, bool IsDependent) { Template.Profile(ID); ID.AddPointer(Deduced.getAsOpaquePtr()); ID.AddBoolean(IsDependent); } static bool classof(const Type *T) { return T->getTypeClass() == DeducedTemplateSpecialization; } }; /// Represents a type template specialization; the template /// must be a class template, a type alias template, or a template /// template parameter. A template which cannot be resolved to one of /// these, e.g. because it is written with a dependent scope /// specifier, is instead represented as a /// @c DependentTemplateSpecializationType. /// /// A non-dependent template specialization type is always "sugar", /// typically for a \c RecordType. For example, a class template /// specialization type of \c vector will refer to a tag type for /// the instantiation \c std::vector> /// /// Template specializations are dependent if either the template or /// any of the template arguments are dependent, in which case the /// type may also be canonical. /// /// Instances of this type are allocated with a trailing array of /// TemplateArguments, followed by a QualType representing the /// non-canonical aliased type when the template is a type alias /// template. class alignas(8) TemplateSpecializationType : public Type, public llvm::FoldingSetNode { friend class ASTContext; // ASTContext creates these /// The name of the template being specialized. This is /// either a TemplateName::Template (in which case it is a /// ClassTemplateDecl*, a TemplateTemplateParmDecl*, or a /// TypeAliasTemplateDecl*), a /// TemplateName::SubstTemplateTemplateParmPack, or a /// TemplateName::SubstTemplateTemplateParm (in which case the /// replacement must, recursively, be one of these). TemplateName Template; TemplateSpecializationType(TemplateName T, ArrayRef Args, QualType Canon, QualType Aliased); public: /// Determine whether any of the given template arguments are dependent. static bool anyDependentTemplateArguments(ArrayRef Args, bool &InstantiationDependent); static bool anyDependentTemplateArguments(const TemplateArgumentListInfo &, bool &InstantiationDependent); /// True if this template specialization type matches a current /// instantiation in the context in which it is found. bool isCurrentInstantiation() const { return isa(getCanonicalTypeInternal()); } /// Determine if this template specialization type is for a type alias /// template that has been substituted. /// /// Nearly every template specialization type whose template is an alias /// template will be substituted. However, this is not the case when /// the specialization contains a pack expansion but the template alias /// does not have a corresponding parameter pack, e.g., /// /// \code /// template struct S; /// template using A = S; /// template struct X { /// typedef A type; // not a type alias /// }; /// \endcode bool isTypeAlias() const { return TemplateSpecializationTypeBits.TypeAlias; } /// Get the aliased type, if this is a specialization of a type alias /// template. QualType getAliasedType() const { assert(isTypeAlias() && "not a type alias template specialization"); return *reinterpret_cast(end()); } using iterator = const TemplateArgument *; iterator begin() const { return getArgs(); } iterator end() const; // defined inline in TemplateBase.h /// Retrieve the name of the template that we are specializing. TemplateName getTemplateName() const { return Template; } /// Retrieve the template arguments. const TemplateArgument *getArgs() const { return reinterpret_cast(this + 1); } /// Retrieve the number of template arguments. unsigned getNumArgs() const { return TemplateSpecializationTypeBits.NumArgs; } /// Retrieve a specific template argument as a type. /// \pre \c isArgType(Arg) const TemplateArgument &getArg(unsigned Idx) const; // in TemplateBase.h ArrayRef template_arguments() const { return {getArgs(), getNumArgs()}; } bool isSugared() const { return !isDependentType() || isCurrentInstantiation() || isTypeAlias(); } QualType desugar() const { return isTypeAlias() ? getAliasedType() : getCanonicalTypeInternal(); } void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Ctx) { Profile(ID, Template, template_arguments(), Ctx); if (isTypeAlias()) getAliasedType().Profile(ID); } static void Profile(llvm::FoldingSetNodeID &ID, TemplateName T, ArrayRef Args, const ASTContext &Context); static bool classof(const Type *T) { return T->getTypeClass() == TemplateSpecialization; } }; /// Print a template argument list, including the '<' and '>' /// enclosing the template arguments. void printTemplateArgumentList(raw_ostream &OS, ArrayRef Args, const PrintingPolicy &Policy); void printTemplateArgumentList(raw_ostream &OS, ArrayRef Args, const PrintingPolicy &Policy); void printTemplateArgumentList(raw_ostream &OS, const TemplateArgumentListInfo &Args, const PrintingPolicy &Policy); /// The injected class name of a C++ class template or class /// template partial specialization. Used to record that a type was /// spelled with a bare identifier rather than as a template-id; the /// equivalent for non-templated classes is just RecordType. /// /// Injected class name types are always dependent. Template /// instantiation turns these into RecordTypes. /// /// Injected class name types are always canonical. This works /// because it is impossible to compare an injected class name type /// with the corresponding non-injected template type, for the same /// reason that it is impossible to directly compare template /// parameters from different dependent contexts: injected class name /// types can only occur within the scope of a particular templated /// declaration, and within that scope every template specialization /// will canonicalize to the injected class name (when appropriate /// according to the rules of the language). class InjectedClassNameType : public Type { friend class ASTContext; // ASTContext creates these. friend class ASTNodeImporter; friend class ASTReader; // FIXME: ASTContext::getInjectedClassNameType is not // currently suitable for AST reading, too much // interdependencies. CXXRecordDecl *Decl; /// The template specialization which this type represents. /// For example, in /// template class A { ... }; /// this is A, whereas in /// template class A > { ... }; /// this is A >. /// /// It is always unqualified, always a template specialization type, /// and always dependent. QualType InjectedType; InjectedClassNameType(CXXRecordDecl *D, QualType TST) : Type(InjectedClassName, QualType(), /*Dependent=*/true, /*InstantiationDependent=*/true, /*VariablyModified=*/false, /*ContainsUnexpandedParameterPack=*/false), Decl(D), InjectedType(TST) { assert(isa(TST)); assert(!TST.hasQualifiers()); assert(TST->isDependentType()); } public: QualType getInjectedSpecializationType() const { return InjectedType; } const TemplateSpecializationType *getInjectedTST() const { return cast(InjectedType.getTypePtr()); } TemplateName getTemplateName() const { return getInjectedTST()->getTemplateName(); } CXXRecordDecl *getDecl() const; bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } static bool classof(const Type *T) { return T->getTypeClass() == InjectedClassName; } }; /// The kind of a tag type. enum TagTypeKind { /// The "struct" keyword. TTK_Struct, /// The "__interface" keyword. TTK_Interface, /// The "union" keyword. TTK_Union, /// The "class" keyword. TTK_Class, /// The "enum" keyword. TTK_Enum }; /// The elaboration keyword that precedes a qualified type name or /// introduces an elaborated-type-specifier. enum ElaboratedTypeKeyword { /// The "struct" keyword introduces the elaborated-type-specifier. ETK_Struct, /// The "__interface" keyword introduces the elaborated-type-specifier. ETK_Interface, /// The "union" keyword introduces the elaborated-type-specifier. ETK_Union, /// The "class" keyword introduces the elaborated-type-specifier. ETK_Class, /// The "enum" keyword introduces the elaborated-type-specifier. ETK_Enum, /// The "typename" keyword precedes the qualified type name, e.g., /// \c typename T::type. ETK_Typename, /// No keyword precedes the qualified type name. ETK_None }; /// A helper class for Type nodes having an ElaboratedTypeKeyword. /// The keyword in stored in the free bits of the base class. /// Also provides a few static helpers for converting and printing /// elaborated type keyword and tag type kind enumerations. class TypeWithKeyword : public Type { protected: TypeWithKeyword(ElaboratedTypeKeyword Keyword, TypeClass tc, QualType Canonical, bool Dependent, bool InstantiationDependent, bool VariablyModified, bool ContainsUnexpandedParameterPack) : Type(tc, Canonical, Dependent, InstantiationDependent, VariablyModified, ContainsUnexpandedParameterPack) { TypeWithKeywordBits.Keyword = Keyword; } public: ElaboratedTypeKeyword getKeyword() const { return static_cast(TypeWithKeywordBits.Keyword); } /// Converts a type specifier (DeclSpec::TST) into an elaborated type keyword. static ElaboratedTypeKeyword getKeywordForTypeSpec(unsigned TypeSpec); /// Converts a type specifier (DeclSpec::TST) into a tag type kind. /// It is an error to provide a type specifier which *isn't* a tag kind here. static TagTypeKind getTagTypeKindForTypeSpec(unsigned TypeSpec); /// Converts a TagTypeKind into an elaborated type keyword. static ElaboratedTypeKeyword getKeywordForTagTypeKind(TagTypeKind Tag); /// Converts an elaborated type keyword into a TagTypeKind. /// It is an error to provide an elaborated type keyword /// which *isn't* a tag kind here. static TagTypeKind getTagTypeKindForKeyword(ElaboratedTypeKeyword Keyword); static bool KeywordIsTagTypeKind(ElaboratedTypeKeyword Keyword); static StringRef getKeywordName(ElaboratedTypeKeyword Keyword); static StringRef getTagTypeKindName(TagTypeKind Kind) { return getKeywordName(getKeywordForTagTypeKind(Kind)); } class CannotCastToThisType {}; static CannotCastToThisType classof(const Type *); }; /// Represents a type that was referred to using an elaborated type /// keyword, e.g., struct S, or via a qualified name, e.g., N::M::type, /// or both. /// /// This type is used to keep track of a type name as written in the /// source code, including tag keywords and any nested-name-specifiers. /// The type itself is always "sugar", used to express what was written /// in the source code but containing no additional semantic information. class ElaboratedType final : public TypeWithKeyword, public llvm::FoldingSetNode, private llvm::TrailingObjects { friend class ASTContext; // ASTContext creates these friend TrailingObjects; /// The nested name specifier containing the qualifier. NestedNameSpecifier *NNS; /// The type that this qualified name refers to. QualType NamedType; /// The (re)declaration of this tag type owned by this occurrence is stored /// as a trailing object if there is one. Use getOwnedTagDecl to obtain /// it, or obtain a null pointer if there is none. ElaboratedType(ElaboratedTypeKeyword Keyword, NestedNameSpecifier *NNS, QualType NamedType, QualType CanonType, TagDecl *OwnedTagDecl) : TypeWithKeyword(Keyword, Elaborated, CanonType, NamedType->isDependentType(), NamedType->isInstantiationDependentType(), NamedType->isVariablyModifiedType(), NamedType->containsUnexpandedParameterPack()), NNS(NNS), NamedType(NamedType) { ElaboratedTypeBits.HasOwnedTagDecl = false; if (OwnedTagDecl) { ElaboratedTypeBits.HasOwnedTagDecl = true; *getTrailingObjects() = OwnedTagDecl; } assert(!(Keyword == ETK_None && NNS == nullptr) && "ElaboratedType cannot have elaborated type keyword " "and name qualifier both null."); } public: /// Retrieve the qualification on this type. NestedNameSpecifier *getQualifier() const { return NNS; } /// Retrieve the type named by the qualified-id. QualType getNamedType() const { return NamedType; } /// Remove a single level of sugar. QualType desugar() const { return getNamedType(); } /// Returns whether this type directly provides sugar. bool isSugared() const { return true; } /// Return the (re)declaration of this type owned by this occurrence of this /// type, or nullptr if there is none. TagDecl *getOwnedTagDecl() const { return ElaboratedTypeBits.HasOwnedTagDecl ? *getTrailingObjects() : nullptr; } void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, getKeyword(), NNS, NamedType, getOwnedTagDecl()); } static void Profile(llvm::FoldingSetNodeID &ID, ElaboratedTypeKeyword Keyword, NestedNameSpecifier *NNS, QualType NamedType, TagDecl *OwnedTagDecl) { ID.AddInteger(Keyword); ID.AddPointer(NNS); NamedType.Profile(ID); ID.AddPointer(OwnedTagDecl); } static bool classof(const Type *T) { return T->getTypeClass() == Elaborated; } }; /// Represents a qualified type name for which the type name is /// dependent. /// /// DependentNameType represents a class of dependent types that involve a /// possibly dependent nested-name-specifier (e.g., "T::") followed by a /// name of a type. The DependentNameType may start with a "typename" (for a /// typename-specifier), "class", "struct", "union", or "enum" (for a /// dependent elaborated-type-specifier), or nothing (in contexts where we /// know that we must be referring to a type, e.g., in a base class specifier). /// Typically the nested-name-specifier is dependent, but in MSVC compatibility /// mode, this type is used with non-dependent names to delay name lookup until /// instantiation. class DependentNameType : public TypeWithKeyword, public llvm::FoldingSetNode { friend class ASTContext; // ASTContext creates these /// The nested name specifier containing the qualifier. NestedNameSpecifier *NNS; /// The type that this typename specifier refers to. const IdentifierInfo *Name; DependentNameType(ElaboratedTypeKeyword Keyword, NestedNameSpecifier *NNS, const IdentifierInfo *Name, QualType CanonType) : TypeWithKeyword(Keyword, DependentName, CanonType, /*Dependent=*/true, /*InstantiationDependent=*/true, /*VariablyModified=*/false, NNS->containsUnexpandedParameterPack()), NNS(NNS), Name(Name) {} public: /// Retrieve the qualification on this type. NestedNameSpecifier *getQualifier() const { return NNS; } /// Retrieve the type named by the typename specifier as an identifier. /// /// This routine will return a non-NULL identifier pointer when the /// form of the original typename was terminated by an identifier, /// e.g., "typename T::type". const IdentifierInfo *getIdentifier() const { return Name; } bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, getKeyword(), NNS, Name); } static void Profile(llvm::FoldingSetNodeID &ID, ElaboratedTypeKeyword Keyword, NestedNameSpecifier *NNS, const IdentifierInfo *Name) { ID.AddInteger(Keyword); ID.AddPointer(NNS); ID.AddPointer(Name); } static bool classof(const Type *T) { return T->getTypeClass() == DependentName; } }; /// Represents a template specialization type whose template cannot be /// resolved, e.g. /// A::template B class alignas(8) DependentTemplateSpecializationType : public TypeWithKeyword, public llvm::FoldingSetNode { friend class ASTContext; // ASTContext creates these /// The nested name specifier containing the qualifier. NestedNameSpecifier *NNS; /// The identifier of the template. const IdentifierInfo *Name; DependentTemplateSpecializationType(ElaboratedTypeKeyword Keyword, NestedNameSpecifier *NNS, const IdentifierInfo *Name, ArrayRef Args, QualType Canon); const TemplateArgument *getArgBuffer() const { return reinterpret_cast(this+1); } TemplateArgument *getArgBuffer() { return reinterpret_cast(this+1); } public: NestedNameSpecifier *getQualifier() const { return NNS; } const IdentifierInfo *getIdentifier() const { return Name; } /// Retrieve the template arguments. const TemplateArgument *getArgs() const { return getArgBuffer(); } /// Retrieve the number of template arguments. unsigned getNumArgs() const { return DependentTemplateSpecializationTypeBits.NumArgs; } const TemplateArgument &getArg(unsigned Idx) const; // in TemplateBase.h ArrayRef template_arguments() const { return {getArgs(), getNumArgs()}; } using iterator = const TemplateArgument *; iterator begin() const { return getArgs(); } iterator end() const; // inline in TemplateBase.h bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context) { Profile(ID, Context, getKeyword(), NNS, Name, {getArgs(), getNumArgs()}); } static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context, ElaboratedTypeKeyword Keyword, NestedNameSpecifier *Qualifier, const IdentifierInfo *Name, ArrayRef Args); static bool classof(const Type *T) { return T->getTypeClass() == DependentTemplateSpecialization; } }; /// Represents a pack expansion of types. /// /// Pack expansions are part of C++11 variadic templates. A pack /// expansion contains a pattern, which itself contains one or more /// "unexpanded" parameter packs. When instantiated, a pack expansion /// produces a series of types, each instantiated from the pattern of /// the expansion, where the Ith instantiation of the pattern uses the /// Ith arguments bound to each of the unexpanded parameter packs. The /// pack expansion is considered to "expand" these unexpanded /// parameter packs. /// /// \code /// template struct tuple; /// /// template /// struct tuple_of_references { /// typedef tuple type; /// }; /// \endcode /// /// Here, the pack expansion \c Types&... is represented via a /// PackExpansionType whose pattern is Types&. class PackExpansionType : public Type, public llvm::FoldingSetNode { friend class ASTContext; // ASTContext creates these /// The pattern of the pack expansion. QualType Pattern; PackExpansionType(QualType Pattern, QualType Canon, Optional NumExpansions) : Type(PackExpansion, Canon, /*Dependent=*/Pattern->isDependentType(), /*InstantiationDependent=*/true, /*VariablyModified=*/Pattern->isVariablyModifiedType(), /*ContainsUnexpandedParameterPack=*/false), Pattern(Pattern) { PackExpansionTypeBits.NumExpansions = NumExpansions ? *NumExpansions + 1 : 0; } public: /// Retrieve the pattern of this pack expansion, which is the /// type that will be repeatedly instantiated when instantiating the /// pack expansion itself. QualType getPattern() const { return Pattern; } /// Retrieve the number of expansions that this pack expansion will /// generate, if known. Optional getNumExpansions() const { if (PackExpansionTypeBits.NumExpansions) return PackExpansionTypeBits.NumExpansions - 1; return None; } bool isSugared() const { return !Pattern->isDependentType(); } QualType desugar() const { return isSugared() ? Pattern : QualType(this, 0); } void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, getPattern(), getNumExpansions()); } static void Profile(llvm::FoldingSetNodeID &ID, QualType Pattern, Optional NumExpansions) { ID.AddPointer(Pattern.getAsOpaquePtr()); ID.AddBoolean(NumExpansions.hasValue()); if (NumExpansions) ID.AddInteger(*NumExpansions); } static bool classof(const Type *T) { return T->getTypeClass() == PackExpansion; } }; /// This class wraps the list of protocol qualifiers. For types that can /// take ObjC protocol qualifers, they can subclass this class. template class ObjCProtocolQualifiers { protected: ObjCProtocolQualifiers() = default; ObjCProtocolDecl * const *getProtocolStorage() const { return const_cast(this)->getProtocolStorage(); } ObjCProtocolDecl **getProtocolStorage() { return static_cast(this)->getProtocolStorageImpl(); } void setNumProtocols(unsigned N) { static_cast(this)->setNumProtocolsImpl(N); } void initialize(ArrayRef protocols) { setNumProtocols(protocols.size()); assert(getNumProtocols() == protocols.size() && "bitfield overflow in protocol count"); if (!protocols.empty()) memcpy(getProtocolStorage(), protocols.data(), protocols.size() * sizeof(ObjCProtocolDecl*)); } public: using qual_iterator = ObjCProtocolDecl * const *; using qual_range = llvm::iterator_range; qual_range quals() const { return qual_range(qual_begin(), qual_end()); } qual_iterator qual_begin() const { return getProtocolStorage(); } qual_iterator qual_end() const { return qual_begin() + getNumProtocols(); } bool qual_empty() const { return getNumProtocols() == 0; } /// Return the number of qualifying protocols in this type, or 0 if /// there are none. unsigned getNumProtocols() const { return static_cast(this)->getNumProtocolsImpl(); } /// Fetch a protocol by index. ObjCProtocolDecl *getProtocol(unsigned I) const { assert(I < getNumProtocols() && "Out-of-range protocol access"); return qual_begin()[I]; } /// Retrieve all of the protocol qualifiers. ArrayRef getProtocols() const { return ArrayRef(qual_begin(), getNumProtocols()); } }; /// Represents a type parameter type in Objective C. It can take /// a list of protocols. class ObjCTypeParamType : public Type, public ObjCProtocolQualifiers, public llvm::FoldingSetNode { friend class ASTContext; friend class ObjCProtocolQualifiers; /// The number of protocols stored on this type. unsigned NumProtocols : 6; ObjCTypeParamDecl *OTPDecl; /// The protocols are stored after the ObjCTypeParamType node. In the /// canonical type, the list of protocols are sorted alphabetically /// and uniqued. ObjCProtocolDecl **getProtocolStorageImpl(); /// Return the number of qualifying protocols in this interface type, /// or 0 if there are none. unsigned getNumProtocolsImpl() const { return NumProtocols; } void setNumProtocolsImpl(unsigned N) { NumProtocols = N; } ObjCTypeParamType(const ObjCTypeParamDecl *D, QualType can, ArrayRef protocols); public: bool isSugared() const { return true; } QualType desugar() const { return getCanonicalTypeInternal(); } static bool classof(const Type *T) { return T->getTypeClass() == ObjCTypeParam; } void Profile(llvm::FoldingSetNodeID &ID); static void Profile(llvm::FoldingSetNodeID &ID, const ObjCTypeParamDecl *OTPDecl, ArrayRef protocols); ObjCTypeParamDecl *getDecl() const { return OTPDecl; } }; /// Represents a class type in Objective C. /// /// Every Objective C type is a combination of a base type, a set of /// type arguments (optional, for parameterized classes) and a list of /// protocols. /// /// Given the following declarations: /// \code /// \@class C; /// \@protocol P; /// \endcode /// /// 'C' is an ObjCInterfaceType C. It is sugar for an ObjCObjectType /// with base C and no protocols. /// /// 'C

' is an unspecialized ObjCObjectType with base C and protocol list [P]. /// 'C' is a specialized ObjCObjectType with type arguments 'C*' and no /// protocol list. /// 'C

' is a specialized ObjCObjectType with base C, type arguments 'C*', /// and protocol list [P]. /// /// 'id' is a TypedefType which is sugar for an ObjCObjectPointerType whose /// pointee is an ObjCObjectType with base BuiltinType::ObjCIdType /// and no protocols. /// /// 'id

' is an ObjCObjectPointerType whose pointee is an ObjCObjectType /// with base BuiltinType::ObjCIdType and protocol list [P]. Eventually /// this should get its own sugar class to better represent the source. class ObjCObjectType : public Type, public ObjCProtocolQualifiers { friend class ObjCProtocolQualifiers; // ObjCObjectType.NumTypeArgs - the number of type arguments stored // after the ObjCObjectPointerType node. // ObjCObjectType.NumProtocols - the number of protocols stored // after the type arguments of ObjCObjectPointerType node. // // These protocols are those written directly on the type. If // protocol qualifiers ever become additive, the iterators will need // to get kindof complicated. // // In the canonical object type, these are sorted alphabetically // and uniqued. /// Either a BuiltinType or an InterfaceType or sugar for either. QualType BaseType; /// Cached superclass type. mutable llvm::PointerIntPair CachedSuperClassType; QualType *getTypeArgStorage(); const QualType *getTypeArgStorage() const { return const_cast(this)->getTypeArgStorage(); } ObjCProtocolDecl **getProtocolStorageImpl(); /// Return the number of qualifying protocols in this interface type, /// or 0 if there are none. unsigned getNumProtocolsImpl() const { return ObjCObjectTypeBits.NumProtocols; } void setNumProtocolsImpl(unsigned N) { ObjCObjectTypeBits.NumProtocols = N; } protected: enum Nonce_ObjCInterface { Nonce_ObjCInterface }; ObjCObjectType(QualType Canonical, QualType Base, ArrayRef typeArgs, ArrayRef protocols, bool isKindOf); ObjCObjectType(enum Nonce_ObjCInterface) : Type(ObjCInterface, QualType(), false, false, false, false), BaseType(QualType(this_(), 0)) { ObjCObjectTypeBits.NumProtocols = 0; ObjCObjectTypeBits.NumTypeArgs = 0; ObjCObjectTypeBits.IsKindOf = 0; } void computeSuperClassTypeSlow() const; public: /// Gets the base type of this object type. This is always (possibly /// sugar for) one of: /// - the 'id' builtin type (as opposed to the 'id' type visible to the /// user, which is a typedef for an ObjCObjectPointerType) /// - the 'Class' builtin type (same caveat) /// - an ObjCObjectType (currently always an ObjCInterfaceType) QualType getBaseType() const { return BaseType; } bool isObjCId() const { return getBaseType()->isSpecificBuiltinType(BuiltinType::ObjCId); } bool isObjCClass() const { return getBaseType()->isSpecificBuiltinType(BuiltinType::ObjCClass); } bool isObjCUnqualifiedId() const { return qual_empty() && isObjCId(); } bool isObjCUnqualifiedClass() const { return qual_empty() && isObjCClass(); } bool isObjCUnqualifiedIdOrClass() const { if (!qual_empty()) return false; if (const BuiltinType *T = getBaseType()->getAs()) return T->getKind() == BuiltinType::ObjCId || T->getKind() == BuiltinType::ObjCClass; return false; } bool isObjCQualifiedId() const { return !qual_empty() && isObjCId(); } bool isObjCQualifiedClass() const { return !qual_empty() && isObjCClass(); } /// Gets the interface declaration for this object type, if the base type /// really is an interface. ObjCInterfaceDecl *getInterface() const; /// Determine whether this object type is "specialized", meaning /// that it has type arguments. bool isSpecialized() const; /// Determine whether this object type was written with type arguments. bool isSpecializedAsWritten() const { return ObjCObjectTypeBits.NumTypeArgs > 0; } /// Determine whether this object type is "unspecialized", meaning /// that it has no type arguments. bool isUnspecialized() const { return !isSpecialized(); } /// Determine whether this object type is "unspecialized" as /// written, meaning that it has no type arguments. bool isUnspecializedAsWritten() const { return !isSpecializedAsWritten(); } /// Retrieve the type arguments of this object type (semantically). ArrayRef getTypeArgs() const; /// Retrieve the type arguments of this object type as they were /// written. ArrayRef getTypeArgsAsWritten() const { return llvm::makeArrayRef(getTypeArgStorage(), ObjCObjectTypeBits.NumTypeArgs); } /// Whether this is a "__kindof" type as written. bool isKindOfTypeAsWritten() const { return ObjCObjectTypeBits.IsKindOf; } /// Whether this ia a "__kindof" type (semantically). bool isKindOfType() const; /// Retrieve the type of the superclass of this object type. /// /// This operation substitutes any type arguments into the /// superclass of the current class type, potentially producing a /// specialization of the superclass type. Produces a null type if /// there is no superclass. QualType getSuperClassType() const { if (!CachedSuperClassType.getInt()) computeSuperClassTypeSlow(); assert(CachedSuperClassType.getInt() && "Superclass not set?"); return QualType(CachedSuperClassType.getPointer(), 0); } /// Strip off the Objective-C "kindof" type and (with it) any /// protocol qualifiers. QualType stripObjCKindOfTypeAndQuals(const ASTContext &ctx) const; bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } static bool classof(const Type *T) { return T->getTypeClass() == ObjCObject || T->getTypeClass() == ObjCInterface; } }; /// A class providing a concrete implementation /// of ObjCObjectType, so as to not increase the footprint of /// ObjCInterfaceType. Code outside of ASTContext and the core type /// system should not reference this type. class ObjCObjectTypeImpl : public ObjCObjectType, public llvm::FoldingSetNode { friend class ASTContext; // If anyone adds fields here, ObjCObjectType::getProtocolStorage() // will need to be modified. ObjCObjectTypeImpl(QualType Canonical, QualType Base, ArrayRef typeArgs, ArrayRef protocols, bool isKindOf) : ObjCObjectType(Canonical, Base, typeArgs, protocols, isKindOf) {} public: void Profile(llvm::FoldingSetNodeID &ID); static void Profile(llvm::FoldingSetNodeID &ID, QualType Base, ArrayRef typeArgs, ArrayRef protocols, bool isKindOf); }; inline QualType *ObjCObjectType::getTypeArgStorage() { return reinterpret_cast(static_cast(this)+1); } inline ObjCProtocolDecl **ObjCObjectType::getProtocolStorageImpl() { return reinterpret_cast( getTypeArgStorage() + ObjCObjectTypeBits.NumTypeArgs); } inline ObjCProtocolDecl **ObjCTypeParamType::getProtocolStorageImpl() { return reinterpret_cast( static_cast(this)+1); } /// Interfaces are the core concept in Objective-C for object oriented design. /// They basically correspond to C++ classes. There are two kinds of interface /// types: normal interfaces like `NSString`, and qualified interfaces, which /// are qualified with a protocol list like `NSString`. /// /// ObjCInterfaceType guarantees the following properties when considered /// as a subtype of its superclass, ObjCObjectType: /// - There are no protocol qualifiers. To reinforce this, code which /// tries to invoke the protocol methods via an ObjCInterfaceType will /// fail to compile. /// - It is its own base type. That is, if T is an ObjCInterfaceType*, /// T->getBaseType() == QualType(T, 0). class ObjCInterfaceType : public ObjCObjectType { friend class ASTContext; // ASTContext creates these. friend class ASTReader; friend class ObjCInterfaceDecl; mutable ObjCInterfaceDecl *Decl; ObjCInterfaceType(const ObjCInterfaceDecl *D) : ObjCObjectType(Nonce_ObjCInterface), Decl(const_cast(D)) {} public: /// Get the declaration of this interface. ObjCInterfaceDecl *getDecl() const { return Decl; } bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } static bool classof(const Type *T) { return T->getTypeClass() == ObjCInterface; } // Nonsense to "hide" certain members of ObjCObjectType within this // class. People asking for protocols on an ObjCInterfaceType are // not going to get what they want: ObjCInterfaceTypes are // guaranteed to have no protocols. enum { qual_iterator, qual_begin, qual_end, getNumProtocols, getProtocol }; }; inline ObjCInterfaceDecl *ObjCObjectType::getInterface() const { QualType baseType = getBaseType(); while (const auto *ObjT = baseType->getAs()) { if (const auto *T = dyn_cast(ObjT)) return T->getDecl(); baseType = ObjT->getBaseType(); } return nullptr; } /// Represents a pointer to an Objective C object. /// /// These are constructed from pointer declarators when the pointee type is /// an ObjCObjectType (or sugar for one). In addition, the 'id' and 'Class' /// types are typedefs for these, and the protocol-qualified types 'id

' /// and 'Class

' are translated into these. /// /// Pointers to pointers to Objective C objects are still PointerTypes; /// only the first level of pointer gets it own type implementation. class ObjCObjectPointerType : public Type, public llvm::FoldingSetNode { friend class ASTContext; // ASTContext creates these. QualType PointeeType; ObjCObjectPointerType(QualType Canonical, QualType Pointee) : Type(ObjCObjectPointer, Canonical, Pointee->isDependentType(), Pointee->isInstantiationDependentType(), Pointee->isVariablyModifiedType(), Pointee->containsUnexpandedParameterPack()), PointeeType(Pointee) {} public: /// Gets the type pointed to by this ObjC pointer. /// The result will always be an ObjCObjectType or sugar thereof. QualType getPointeeType() const { return PointeeType; } /// Gets the type pointed to by this ObjC pointer. Always returns non-null. /// /// This method is equivalent to getPointeeType() except that /// it discards any typedefs (or other sugar) between this /// type and the "outermost" object type. So for: /// \code /// \@class A; \@protocol P; \@protocol Q; /// typedef A

AP; /// typedef A A1; /// typedef A1

A1P; /// typedef A1P A1PQ; /// \endcode /// For 'A*', getObjectType() will return 'A'. /// For 'A

*', getObjectType() will return 'A

'. /// For 'AP*', getObjectType() will return 'A

'. /// For 'A1*', getObjectType() will return 'A'. /// For 'A1

*', getObjectType() will return 'A1

'. /// For 'A1P*', getObjectType() will return 'A1

'. /// For 'A1PQ*', getObjectType() will return 'A1', because /// adding protocols to a protocol-qualified base discards the /// old qualifiers (for now). But if it didn't, getObjectType() /// would return 'A1P' (and we'd have to make iterating over /// qualifiers more complicated). const ObjCObjectType *getObjectType() const { return PointeeType->castAs(); } /// If this pointer points to an Objective C /// \@interface type, gets the type for that interface. Any protocol /// qualifiers on the interface are ignored. /// /// \return null if the base type for this pointer is 'id' or 'Class' const ObjCInterfaceType *getInterfaceType() const; /// If this pointer points to an Objective \@interface /// type, gets the declaration for that interface. /// /// \return null if the base type for this pointer is 'id' or 'Class' ObjCInterfaceDecl *getInterfaceDecl() const { return getObjectType()->getInterface(); } /// True if this is equivalent to the 'id' type, i.e. if /// its object type is the primitive 'id' type with no protocols. bool isObjCIdType() const { return getObjectType()->isObjCUnqualifiedId(); } /// True if this is equivalent to the 'Class' type, /// i.e. if its object tive is the primitive 'Class' type with no protocols. bool isObjCClassType() const { return getObjectType()->isObjCUnqualifiedClass(); } /// True if this is equivalent to the 'id' or 'Class' type, bool isObjCIdOrClassType() const { return getObjectType()->isObjCUnqualifiedIdOrClass(); } /// True if this is equivalent to 'id

' for some non-empty set of /// protocols. bool isObjCQualifiedIdType() const { return getObjectType()->isObjCQualifiedId(); } /// True if this is equivalent to 'Class

' for some non-empty set of /// protocols. bool isObjCQualifiedClassType() const { return getObjectType()->isObjCQualifiedClass(); } /// Whether this is a "__kindof" type. bool isKindOfType() const { return getObjectType()->isKindOfType(); } /// Whether this type is specialized, meaning that it has type arguments. bool isSpecialized() const { return getObjectType()->isSpecialized(); } /// Whether this type is specialized, meaning that it has type arguments. bool isSpecializedAsWritten() const { return getObjectType()->isSpecializedAsWritten(); } /// Whether this type is unspecialized, meaning that is has no type arguments. bool isUnspecialized() const { return getObjectType()->isUnspecialized(); } /// Determine whether this object type is "unspecialized" as /// written, meaning that it has no type arguments. bool isUnspecializedAsWritten() const { return !isSpecializedAsWritten(); } /// Retrieve the type arguments for this type. ArrayRef getTypeArgs() const { return getObjectType()->getTypeArgs(); } /// Retrieve the type arguments for this type. ArrayRef getTypeArgsAsWritten() const { return getObjectType()->getTypeArgsAsWritten(); } /// An iterator over the qualifiers on the object type. Provided /// for convenience. This will always iterate over the full set of /// protocols on a type, not just those provided directly. using qual_iterator = ObjCObjectType::qual_iterator; using qual_range = llvm::iterator_range; qual_range quals() const { return qual_range(qual_begin(), qual_end()); } qual_iterator qual_begin() const { return getObjectType()->qual_begin(); } qual_iterator qual_end() const { return getObjectType()->qual_end(); } bool qual_empty() const { return getObjectType()->qual_empty(); } /// Return the number of qualifying protocols on the object type. unsigned getNumProtocols() const { return getObjectType()->getNumProtocols(); } /// Retrieve a qualifying protocol by index on the object type. ObjCProtocolDecl *getProtocol(unsigned I) const { return getObjectType()->getProtocol(I); } bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } /// Retrieve the type of the superclass of this object pointer type. /// /// This operation substitutes any type arguments into the /// superclass of the current class type, potentially producing a /// pointer to a specialization of the superclass type. Produces a /// null type if there is no superclass. QualType getSuperClassType() const; /// Strip off the Objective-C "kindof" type and (with it) any /// protocol qualifiers. const ObjCObjectPointerType *stripObjCKindOfTypeAndQuals( const ASTContext &ctx) const; void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, getPointeeType()); } static void Profile(llvm::FoldingSetNodeID &ID, QualType T) { ID.AddPointer(T.getAsOpaquePtr()); } static bool classof(const Type *T) { return T->getTypeClass() == ObjCObjectPointer; } }; class AtomicType : public Type, public llvm::FoldingSetNode { friend class ASTContext; // ASTContext creates these. QualType ValueType; AtomicType(QualType ValTy, QualType Canonical) : Type(Atomic, Canonical, ValTy->isDependentType(), ValTy->isInstantiationDependentType(), ValTy->isVariablyModifiedType(), ValTy->containsUnexpandedParameterPack()), ValueType(ValTy) {} public: /// Gets the type contained by this atomic type, i.e. /// the type returned by performing an atomic load of this atomic type. QualType getValueType() const { return ValueType; } bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, getValueType()); } static void Profile(llvm::FoldingSetNodeID &ID, QualType T) { ID.AddPointer(T.getAsOpaquePtr()); } static bool classof(const Type *T) { return T->getTypeClass() == Atomic; } }; /// PipeType - OpenCL20. class PipeType : public Type, public llvm::FoldingSetNode { friend class ASTContext; // ASTContext creates these. QualType ElementType; bool isRead; PipeType(QualType elemType, QualType CanonicalPtr, bool isRead) : Type(Pipe, CanonicalPtr, elemType->isDependentType(), elemType->isInstantiationDependentType(), elemType->isVariablyModifiedType(), elemType->containsUnexpandedParameterPack()), ElementType(elemType), isRead(isRead) {} public: QualType getElementType() const { return ElementType; } bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, getElementType(), isReadOnly()); } static void Profile(llvm::FoldingSetNodeID &ID, QualType T, bool isRead) { ID.AddPointer(T.getAsOpaquePtr()); ID.AddBoolean(isRead); } static bool classof(const Type *T) { return T->getTypeClass() == Pipe; } bool isReadOnly() const { return isRead; } }; /// A qualifier set is used to build a set of qualifiers. class QualifierCollector : public Qualifiers { public: QualifierCollector(Qualifiers Qs = Qualifiers()) : Qualifiers(Qs) {} /// Collect any qualifiers on the given type and return an /// unqualified type. The qualifiers are assumed to be consistent /// with those already in the type. const Type *strip(QualType type) { addFastQualifiers(type.getLocalFastQualifiers()); if (!type.hasLocalNonFastQualifiers()) return type.getTypePtrUnsafe(); const ExtQuals *extQuals = type.getExtQualsUnsafe(); addConsistentQualifiers(extQuals->getQualifiers()); return extQuals->getBaseType(); } /// Apply the collected qualifiers to the given type. QualType apply(const ASTContext &Context, QualType QT) const; /// Apply the collected qualifiers to the given type. QualType apply(const ASTContext &Context, const Type* T) const; }; // Inline function definitions. inline SplitQualType SplitQualType::getSingleStepDesugaredType() const { SplitQualType desugar = Ty->getLocallyUnqualifiedSingleStepDesugaredType().split(); desugar.Quals.addConsistentQualifiers(Quals); return desugar; } inline const Type *QualType::getTypePtr() const { return getCommonPtr()->BaseType; } inline const Type *QualType::getTypePtrOrNull() const { return (isNull() ? nullptr : getCommonPtr()->BaseType); } inline SplitQualType QualType::split() const { if (!hasLocalNonFastQualifiers()) return SplitQualType(getTypePtrUnsafe(), Qualifiers::fromFastMask(getLocalFastQualifiers())); const ExtQuals *eq = getExtQualsUnsafe(); Qualifiers qs = eq->getQualifiers(); qs.addFastQualifiers(getLocalFastQualifiers()); return SplitQualType(eq->getBaseType(), qs); } inline Qualifiers QualType::getLocalQualifiers() const { Qualifiers Quals; if (hasLocalNonFastQualifiers()) Quals = getExtQualsUnsafe()->getQualifiers(); Quals.addFastQualifiers(getLocalFastQualifiers()); return Quals; } inline Qualifiers QualType::getQualifiers() const { Qualifiers quals = getCommonPtr()->CanonicalType.getLocalQualifiers(); quals.addFastQualifiers(getLocalFastQualifiers()); return quals; } inline unsigned QualType::getCVRQualifiers() const { unsigned cvr = getCommonPtr()->CanonicalType.getLocalCVRQualifiers(); cvr |= getLocalCVRQualifiers(); return cvr; } inline QualType QualType::getCanonicalType() const { QualType canon = getCommonPtr()->CanonicalType; return canon.withFastQualifiers(getLocalFastQualifiers()); } inline bool QualType::isCanonical() const { return getTypePtr()->isCanonicalUnqualified(); } inline bool QualType::isCanonicalAsParam() const { if (!isCanonical()) return false; if (hasLocalQualifiers()) return false; const Type *T = getTypePtr(); if (T->isVariablyModifiedType() && T->hasSizedVLAType()) return false; return !isa(T) && !isa(T); } inline bool QualType::isConstQualified() const { return isLocalConstQualified() || getCommonPtr()->CanonicalType.isLocalConstQualified(); } inline bool QualType::isRestrictQualified() const { return isLocalRestrictQualified() || getCommonPtr()->CanonicalType.isLocalRestrictQualified(); } inline bool QualType::isVolatileQualified() const { return isLocalVolatileQualified() || getCommonPtr()->CanonicalType.isLocalVolatileQualified(); } inline bool QualType::hasQualifiers() const { return hasLocalQualifiers() || getCommonPtr()->CanonicalType.hasLocalQualifiers(); } inline QualType QualType::getUnqualifiedType() const { if (!getTypePtr()->getCanonicalTypeInternal().hasLocalQualifiers()) return QualType(getTypePtr(), 0); return QualType(getSplitUnqualifiedTypeImpl(*this).Ty, 0); } inline SplitQualType QualType::getSplitUnqualifiedType() const { if (!getTypePtr()->getCanonicalTypeInternal().hasLocalQualifiers()) return split(); return getSplitUnqualifiedTypeImpl(*this); } inline void QualType::removeLocalConst() { removeLocalFastQualifiers(Qualifiers::Const); } inline void QualType::removeLocalRestrict() { removeLocalFastQualifiers(Qualifiers::Restrict); } inline void QualType::removeLocalVolatile() { removeLocalFastQualifiers(Qualifiers::Volatile); } inline void QualType::removeLocalCVRQualifiers(unsigned Mask) { assert(!(Mask & ~Qualifiers::CVRMask) && "mask has non-CVR bits"); static_assert((int)Qualifiers::CVRMask == (int)Qualifiers::FastMask, "Fast bits differ from CVR bits!"); // Fast path: we don't need to touch the slow qualifiers. removeLocalFastQualifiers(Mask); } /// Return the address space of this type. inline LangAS QualType::getAddressSpace() const { return getQualifiers().getAddressSpace(); } /// Return the gc attribute of this type. inline Qualifiers::GC QualType::getObjCGCAttr() const { return getQualifiers().getObjCGCAttr(); } inline bool QualType::hasNonTrivialToPrimitiveDefaultInitializeCUnion() const { if (auto *RD = getTypePtr()->getBaseElementTypeUnsafe()->getAsRecordDecl()) return hasNonTrivialToPrimitiveDefaultInitializeCUnion(RD); return false; } inline bool QualType::hasNonTrivialToPrimitiveDestructCUnion() const { if (auto *RD = getTypePtr()->getBaseElementTypeUnsafe()->getAsRecordDecl()) return hasNonTrivialToPrimitiveDestructCUnion(RD); return false; } inline bool QualType::hasNonTrivialToPrimitiveCopyCUnion() const { if (auto *RD = getTypePtr()->getBaseElementTypeUnsafe()->getAsRecordDecl()) return hasNonTrivialToPrimitiveCopyCUnion(RD); return false; } inline FunctionType::ExtInfo getFunctionExtInfo(const Type &t) { if (const auto *PT = t.getAs()) { if (const auto *FT = PT->getPointeeType()->getAs()) return FT->getExtInfo(); } else if (const auto *FT = t.getAs()) return FT->getExtInfo(); return FunctionType::ExtInfo(); } inline FunctionType::ExtInfo getFunctionExtInfo(QualType t) { return getFunctionExtInfo(*t); } /// Determine whether this type is more /// qualified than the Other type. For example, "const volatile int" /// is more qualified than "const int", "volatile int", and /// "int". However, it is not more qualified than "const volatile /// int". inline bool QualType::isMoreQualifiedThan(QualType other) const { Qualifiers MyQuals = getQualifiers(); Qualifiers OtherQuals = other.getQualifiers(); return (MyQuals != OtherQuals && MyQuals.compatiblyIncludes(OtherQuals)); } /// Determine whether this type is at last /// as qualified as the Other type. For example, "const volatile /// int" is at least as qualified as "const int", "volatile int", /// "int", and "const volatile int". inline bool QualType::isAtLeastAsQualifiedAs(QualType other) const { Qualifiers OtherQuals = other.getQualifiers(); // Ignore __unaligned qualifier if this type is a void. if (getUnqualifiedType()->isVoidType()) OtherQuals.removeUnaligned(); return getQualifiers().compatiblyIncludes(OtherQuals); } /// If Type is a reference type (e.g., const /// int&), returns the type that the reference refers to ("const /// int"). Otherwise, returns the type itself. This routine is used /// throughout Sema to implement C++ 5p6: /// /// If an expression initially has the type "reference to T" (8.3.2, /// 8.5.3), the type is adjusted to "T" prior to any further /// analysis, the expression designates the object or function /// denoted by the reference, and the expression is an lvalue. inline QualType QualType::getNonReferenceType() const { if (const auto *RefType = (*this)->getAs()) return RefType->getPointeeType(); else return *this; } inline bool QualType::isCForbiddenLValueType() const { return ((getTypePtr()->isVoidType() && !hasQualifiers()) || getTypePtr()->isFunctionType()); } /// Tests whether the type is categorized as a fundamental type. /// /// \returns True for types specified in C++0x [basic.fundamental]. inline bool Type::isFundamentalType() const { return isVoidType() || isNullPtrType() || // FIXME: It's really annoying that we don't have an // 'isArithmeticType()' which agrees with the standard definition. (isArithmeticType() && !isEnumeralType()); } /// Tests whether the type is categorized as a compound type. /// /// \returns True for types specified in C++0x [basic.compound]. inline bool Type::isCompoundType() const { // C++0x [basic.compound]p1: // Compound types can be constructed in the following ways: // -- arrays of objects of a given type [...]; return isArrayType() || // -- functions, which have parameters of given types [...]; isFunctionType() || // -- pointers to void or objects or functions [...]; isPointerType() || // -- references to objects or functions of a given type. [...] isReferenceType() || // -- classes containing a sequence of objects of various types, [...]; isRecordType() || // -- unions, which are classes capable of containing objects of different // types at different times; isUnionType() || // -- enumerations, which comprise a set of named constant values. [...]; isEnumeralType() || // -- pointers to non-static class members, [...]. isMemberPointerType(); } inline bool Type::isFunctionType() const { return isa(CanonicalType); } inline bool Type::isPointerType() const { return isa(CanonicalType); } inline bool Type::isAnyPointerType() const { return isPointerType() || isObjCObjectPointerType(); } inline bool Type::isBlockPointerType() const { return isa(CanonicalType); } inline bool Type::isReferenceType() const { return isa(CanonicalType); } inline bool Type::isLValueReferenceType() const { return isa(CanonicalType); } inline bool Type::isRValueReferenceType() const { return isa(CanonicalType); } inline bool Type::isFunctionPointerType() const { if (const auto *T = getAs()) return T->getPointeeType()->isFunctionType(); else return false; } inline bool Type::isFunctionReferenceType() const { if (const auto *T = getAs()) return T->getPointeeType()->isFunctionType(); else return false; } inline bool Type::isMemberPointerType() const { return isa(CanonicalType); } inline bool Type::isMemberFunctionPointerType() const { if (const auto *T = getAs()) return T->isMemberFunctionPointer(); else return false; } inline bool Type::isMemberDataPointerType() const { if (const auto *T = getAs()) return T->isMemberDataPointer(); else return false; } inline bool Type::isArrayType() const { return isa(CanonicalType); } inline bool Type::isConstantArrayType() const { return isa(CanonicalType); } inline bool Type::isIncompleteArrayType() const { return isa(CanonicalType); } inline bool Type::isVariableArrayType() const { return isa(CanonicalType); } inline bool Type::isDependentSizedArrayType() const { return isa(CanonicalType); } inline bool Type::isBuiltinType() const { return isa(CanonicalType); } inline bool Type::isRecordType() const { return isa(CanonicalType); } inline bool Type::isEnumeralType() const { return isa(CanonicalType); } inline bool Type::isAnyComplexType() const { return isa(CanonicalType); } inline bool Type::isVectorType() const { return isa(CanonicalType); } inline bool Type::isExtVectorType() const { return isa(CanonicalType); } inline bool Type::isDependentAddressSpaceType() const { return isa(CanonicalType); } inline bool Type::isObjCObjectPointerType() const { return isa(CanonicalType); } inline bool Type::isObjCObjectType() const { return isa(CanonicalType); } inline bool Type::isObjCObjectOrInterfaceType() const { return isa(CanonicalType) || isa(CanonicalType); } inline bool Type::isAtomicType() const { return isa(CanonicalType); } +inline bool Type::isUndeducedAutoType() const { + return isa(CanonicalType); +} + inline bool Type::isObjCQualifiedIdType() const { if (const auto *OPT = getAs()) return OPT->isObjCQualifiedIdType(); return false; } inline bool Type::isObjCQualifiedClassType() const { if (const auto *OPT = getAs()) return OPT->isObjCQualifiedClassType(); return false; } inline bool Type::isObjCIdType() const { if (const auto *OPT = getAs()) return OPT->isObjCIdType(); return false; } inline bool Type::isObjCClassType() const { if (const auto *OPT = getAs()) return OPT->isObjCClassType(); return false; } inline bool Type::isObjCSelType() const { if (const auto *OPT = getAs()) return OPT->getPointeeType()->isSpecificBuiltinType(BuiltinType::ObjCSel); return false; } inline bool Type::isObjCBuiltinType() const { return isObjCIdType() || isObjCClassType() || isObjCSelType(); } inline bool Type::isDecltypeType() const { return isa(this); } #define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \ inline bool Type::is##Id##Type() const { \ return isSpecificBuiltinType(BuiltinType::Id); \ } #include "clang/Basic/OpenCLImageTypes.def" inline bool Type::isSamplerT() const { return isSpecificBuiltinType(BuiltinType::OCLSampler); } inline bool Type::isEventT() const { return isSpecificBuiltinType(BuiltinType::OCLEvent); } inline bool Type::isClkEventT() const { return isSpecificBuiltinType(BuiltinType::OCLClkEvent); } inline bool Type::isQueueT() const { return isSpecificBuiltinType(BuiltinType::OCLQueue); } inline bool Type::isReserveIDT() const { return isSpecificBuiltinType(BuiltinType::OCLReserveID); } inline bool Type::isImageType() const { #define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) is##Id##Type() || return #include "clang/Basic/OpenCLImageTypes.def" false; // end boolean or operation } inline bool Type::isPipeType() const { return isa(CanonicalType); } #define EXT_OPAQUE_TYPE(ExtType, Id, Ext) \ inline bool Type::is##Id##Type() const { \ return isSpecificBuiltinType(BuiltinType::Id); \ } #include "clang/Basic/OpenCLExtensionTypes.def" inline bool Type::isOCLIntelSubgroupAVCType() const { #define INTEL_SUBGROUP_AVC_TYPE(ExtType, Id) \ isOCLIntelSubgroupAVC##Id##Type() || return #include "clang/Basic/OpenCLExtensionTypes.def" false; // end of boolean or operation } inline bool Type::isOCLExtOpaqueType() const { #define EXT_OPAQUE_TYPE(ExtType, Id, Ext) is##Id##Type() || return #include "clang/Basic/OpenCLExtensionTypes.def" false; // end of boolean or operation } inline bool Type::isOpenCLSpecificType() const { return isSamplerT() || isEventT() || isImageType() || isClkEventT() || isQueueT() || isReserveIDT() || isPipeType() || isOCLExtOpaqueType(); } inline bool Type::isTemplateTypeParmType() const { return isa(CanonicalType); } inline bool Type::isSpecificBuiltinType(unsigned K) const { if (const BuiltinType *BT = getAs()) if (BT->getKind() == (BuiltinType::Kind) K) return true; return false; } inline bool Type::isPlaceholderType() const { if (const auto *BT = dyn_cast(this)) return BT->isPlaceholderType(); return false; } inline const BuiltinType *Type::getAsPlaceholderType() const { if (const auto *BT = dyn_cast(this)) if (BT->isPlaceholderType()) return BT; return nullptr; } inline bool Type::isSpecificPlaceholderType(unsigned K) const { assert(BuiltinType::isPlaceholderTypeKind((BuiltinType::Kind) K)); if (const auto *BT = dyn_cast(this)) return (BT->getKind() == (BuiltinType::Kind) K); return false; } inline bool Type::isNonOverloadPlaceholderType() const { if (const auto *BT = dyn_cast(this)) return BT->isNonOverloadPlaceholderType(); return false; } inline bool Type::isVoidType() const { if (const auto *BT = dyn_cast(CanonicalType)) return BT->getKind() == BuiltinType::Void; return false; } inline bool Type::isHalfType() const { if (const auto *BT = dyn_cast(CanonicalType)) return BT->getKind() == BuiltinType::Half; // FIXME: Should we allow complex __fp16? Probably not. return false; } inline bool Type::isFloat16Type() const { if (const auto *BT = dyn_cast(CanonicalType)) return BT->getKind() == BuiltinType::Float16; return false; } inline bool Type::isFloat128Type() const { if (const auto *BT = dyn_cast(CanonicalType)) return BT->getKind() == BuiltinType::Float128; return false; } inline bool Type::isNullPtrType() const { if (const auto *BT = getAs()) return BT->getKind() == BuiltinType::NullPtr; return false; } bool IsEnumDeclComplete(EnumDecl *); bool IsEnumDeclScoped(EnumDecl *); inline bool Type::isIntegerType() const { if (const auto *BT = dyn_cast(CanonicalType)) return BT->getKind() >= BuiltinType::Bool && BT->getKind() <= BuiltinType::Int128; if (const EnumType *ET = dyn_cast(CanonicalType)) { // Incomplete enum types are not treated as integer types. // FIXME: In C++, enum types are never integer types. return IsEnumDeclComplete(ET->getDecl()) && !IsEnumDeclScoped(ET->getDecl()); } return false; } inline bool Type::isFixedPointType() const { if (const auto *BT = dyn_cast(CanonicalType)) { return BT->getKind() >= BuiltinType::ShortAccum && BT->getKind() <= BuiltinType::SatULongFract; } return false; } inline bool Type::isFixedPointOrIntegerType() const { return isFixedPointType() || isIntegerType(); } inline bool Type::isSaturatedFixedPointType() const { if (const auto *BT = dyn_cast(CanonicalType)) { return BT->getKind() >= BuiltinType::SatShortAccum && BT->getKind() <= BuiltinType::SatULongFract; } return false; } inline bool Type::isUnsaturatedFixedPointType() const { return isFixedPointType() && !isSaturatedFixedPointType(); } inline bool Type::isSignedFixedPointType() const { if (const auto *BT = dyn_cast(CanonicalType)) { return ((BT->getKind() >= BuiltinType::ShortAccum && BT->getKind() <= BuiltinType::LongAccum) || (BT->getKind() >= BuiltinType::ShortFract && BT->getKind() <= BuiltinType::LongFract) || (BT->getKind() >= BuiltinType::SatShortAccum && BT->getKind() <= BuiltinType::SatLongAccum) || (BT->getKind() >= BuiltinType::SatShortFract && BT->getKind() <= BuiltinType::SatLongFract)); } return false; } inline bool Type::isUnsignedFixedPointType() const { return isFixedPointType() && !isSignedFixedPointType(); } inline bool Type::isScalarType() const { if (const auto *BT = dyn_cast(CanonicalType)) return BT->getKind() > BuiltinType::Void && BT->getKind() <= BuiltinType::NullPtr; if (const EnumType *ET = dyn_cast(CanonicalType)) // Enums are scalar types, but only if they are defined. Incomplete enums // are not treated as scalar types. return IsEnumDeclComplete(ET->getDecl()); return isa(CanonicalType) || isa(CanonicalType) || isa(CanonicalType) || isa(CanonicalType) || isa(CanonicalType); } inline bool Type::isIntegralOrEnumerationType() const { if (const auto *BT = dyn_cast(CanonicalType)) return BT->getKind() >= BuiltinType::Bool && BT->getKind() <= BuiltinType::Int128; // Check for a complete enum type; incomplete enum types are not properly an // enumeration type in the sense required here. if (const auto *ET = dyn_cast(CanonicalType)) return IsEnumDeclComplete(ET->getDecl()); return false; } inline bool Type::isBooleanType() const { if (const auto *BT = dyn_cast(CanonicalType)) return BT->getKind() == BuiltinType::Bool; return false; } inline bool Type::isUndeducedType() const { auto *DT = getContainedDeducedType(); return DT && !DT->isDeduced(); } /// Determines whether this is a type for which one can define /// an overloaded operator. inline bool Type::isOverloadableType() const { return isDependentType() || isRecordType() || isEnumeralType(); } /// Determines whether this type can decay to a pointer type. inline bool Type::canDecayToPointerType() const { return isFunctionType() || isArrayType(); } inline bool Type::hasPointerRepresentation() const { return (isPointerType() || isReferenceType() || isBlockPointerType() || isObjCObjectPointerType() || isNullPtrType()); } inline bool Type::hasObjCPointerRepresentation() const { return isObjCObjectPointerType(); } inline const Type *Type::getBaseElementTypeUnsafe() const { const Type *type = this; while (const ArrayType *arrayType = type->getAsArrayTypeUnsafe()) type = arrayType->getElementType().getTypePtr(); return type; } inline const Type *Type::getPointeeOrArrayElementType() const { const Type *type = this; if (type->isAnyPointerType()) return type->getPointeeType().getTypePtr(); else if (type->isArrayType()) return type->getBaseElementTypeUnsafe(); return type; } /// Insertion operator for diagnostics. This allows sending Qualifiers into a /// diagnostic with <<. inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, Qualifiers Q) { DB.AddTaggedVal(Q.getAsOpaqueValue(), DiagnosticsEngine::ArgumentKind::ak_qual); return DB; } /// Insertion operator for partial diagnostics. This allows sending Qualifiers /// into a diagnostic with <<. inline const PartialDiagnostic &operator<<(const PartialDiagnostic &PD, Qualifiers Q) { PD.AddTaggedVal(Q.getAsOpaqueValue(), DiagnosticsEngine::ArgumentKind::ak_qual); return PD; } /// Insertion operator for diagnostics. This allows sending QualType's into a /// diagnostic with <<. inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, QualType T) { DB.AddTaggedVal(reinterpret_cast(T.getAsOpaquePtr()), DiagnosticsEngine::ak_qualtype); return DB; } /// Insertion operator for partial diagnostics. This allows sending QualType's /// into a diagnostic with <<. inline const PartialDiagnostic &operator<<(const PartialDiagnostic &PD, QualType T) { PD.AddTaggedVal(reinterpret_cast(T.getAsOpaquePtr()), DiagnosticsEngine::ak_qualtype); return PD; } // Helper class template that is used by Type::getAs to ensure that one does // not try to look through a qualified type to get to an array type. template using TypeIsArrayType = std::integral_constant::value || std::is_base_of::value>; // Member-template getAs'. template const T *Type::getAs() const { static_assert(!TypeIsArrayType::value, "ArrayType cannot be used with getAs!"); // If this is directly a T type, return it. if (const auto *Ty = dyn_cast(this)) return Ty; // If the canonical form of this type isn't the right kind, reject it. if (!isa(CanonicalType)) return nullptr; // If this is a typedef for the type, strip the typedef off without // losing all typedef information. return cast(getUnqualifiedDesugaredType()); } template const T *Type::getAsAdjusted() const { static_assert(!TypeIsArrayType::value, "ArrayType cannot be used with getAsAdjusted!"); // If this is directly a T type, return it. if (const auto *Ty = dyn_cast(this)) return Ty; // If the canonical form of this type isn't the right kind, reject it. if (!isa(CanonicalType)) return nullptr; // Strip off type adjustments that do not modify the underlying nature of the // type. const Type *Ty = this; while (Ty) { if (const auto *A = dyn_cast(Ty)) Ty = A->getModifiedType().getTypePtr(); else if (const auto *E = dyn_cast(Ty)) Ty = E->desugar().getTypePtr(); else if (const auto *P = dyn_cast(Ty)) Ty = P->desugar().getTypePtr(); else if (const auto *A = dyn_cast(Ty)) Ty = A->desugar().getTypePtr(); else if (const auto *M = dyn_cast(Ty)) Ty = M->desugar().getTypePtr(); else break; } // Just because the canonical type is correct does not mean we can use cast<>, // since we may not have stripped off all the sugar down to the base type. return dyn_cast(Ty); } inline const ArrayType *Type::getAsArrayTypeUnsafe() const { // If this is directly an array type, return it. if (const auto *arr = dyn_cast(this)) return arr; // If the canonical form of this type isn't the right kind, reject it. if (!isa(CanonicalType)) return nullptr; // If this is a typedef for the type, strip the typedef off without // losing all typedef information. return cast(getUnqualifiedDesugaredType()); } template const T *Type::castAs() const { static_assert(!TypeIsArrayType::value, "ArrayType cannot be used with castAs!"); if (const auto *ty = dyn_cast(this)) return ty; assert(isa(CanonicalType)); return cast(getUnqualifiedDesugaredType()); } inline const ArrayType *Type::castAsArrayTypeUnsafe() const { assert(isa(CanonicalType)); if (const auto *arr = dyn_cast(this)) return arr; return cast(getUnqualifiedDesugaredType()); } DecayedType::DecayedType(QualType OriginalType, QualType DecayedPtr, QualType CanonicalPtr) : AdjustedType(Decayed, OriginalType, DecayedPtr, CanonicalPtr) { #ifndef NDEBUG QualType Adjusted = getAdjustedType(); (void)AttributedType::stripOuterNullability(Adjusted); assert(isa(Adjusted)); #endif } QualType DecayedType::getPointeeType() const { QualType Decayed = getDecayedType(); (void)AttributedType::stripOuterNullability(Decayed); return cast(Decayed)->getPointeeType(); } // Get the decimal string representation of a fixed point type, represented // as a scaled integer. // TODO: At some point, we should change the arguments to instead just accept an // APFixedPoint instead of APSInt and scale. void FixedPointValueToString(SmallVectorImpl &Str, llvm::APSInt Val, unsigned Scale); } // namespace clang #endif // LLVM_CLANG_AST_TYPE_H diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 0a6f58a484ae..ac5a4953e00d 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -1,11719 +1,11721 @@ //===--- 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/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/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/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/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 #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; 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; 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; 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; } 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 Expr *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(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, }; 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 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_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_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 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); 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 * resolveAddressOfOnlyViableOverloadCandidate(Expr *E, DeclAccessPair &FoundResult); bool resolveAndFixAddressOfOnlyViableOverloadCandidate( 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); ExprResult CreateOverloadedBinOp(SourceLocation OpLoc, BinaryOperatorKind Opc, const UnresolvedSetImpl &Fns, Expr *LHS, Expr *RHS, bool RequiresADL = true, bool AllowRewrittenCandidates = true); 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); 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() { return DelayedDiagnostics.pushUndelayed(); } void PopParsingClass(ParsingClassState state) { 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, 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: /// 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); /// 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); /// 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, CXXMethodDecl *MD); /// 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); /// 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); /// 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, and false is returned. bool CheckConstraintExpression(Expr *CE); bool CalculateConstraintSatisfaction(ConceptDecl *NamedConcept, MultiLevelTemplateArgumentList &MLTAL, Expr *ConstraintExpr, bool &IsSatisfied); /// Check that the associated constraints of a template declaration match the /// associated constraints of an older declaration of which it is a /// redeclaration. bool CheckRedeclarationConstraintMatch(TemplateParameterList *Old, TemplateParameterList *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(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(Decl *D); 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(FunctionDecl *MD); bool CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD, CXXSpecialMember CSM); void CheckDelayedMemberExceptionSpecs(); bool CheckExplicitlyDefaultedComparison(FunctionDecl *MD, 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 isSpecialMemberAccessibleForDeletion(CXXMethodDecl *decl, AccessSpecifier access, QualType objectType); 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); 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); 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); 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, SourceLocation ConceptNameLoc, 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, 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. /// /// \returns true if an error occurred, false otherwise. bool CheckTemplateArgumentList(TemplateDecl *Template, SourceLocation TemplateLoc, TemplateArgumentListInfo &TemplateArgs, bool PartialTemplateArgs, SmallVectorImpl &Converted, bool UpdateArgsWithConversions = true); 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(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 *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); // Concepts Decl *ActOnConceptDefinition( Scope *S, MultiTemplateParamsArg TemplateParameterLists, IdentifierInfo *Name, SourceLocation NameLoc, Expr *ConstraintExpr); //===--------------------------------------------------------------------===// // 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 }; /// 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, /// 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); DeduceAutoResult DeduceAutoType(TypeLoc AutoTypeLoc, Expr *&Initializer, QualType &Result, Optional DependentDeductionDepth = None); 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 *P, TemplateDecl *AArg, SourceLocation Loc); 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 declaring an implicit special member function. DeclaringSpecialMember, /// 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 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, TemplateDecl *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, TemplateDecl *Template, sema::TemplateDeductionInfo &DeductionInfo, SourceRange InstantiationRange); /// 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); Decl *SubstDecl(Decl *D, DeclContext *Owner, const MultiLevelTemplateArgumentList &TemplateArgs); 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); 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 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(OpenMPProcBindClauseKind 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, OpenMPDependClauseKind DepKind, OpenMPLinearClauseKind LinKind, ArrayRef MapTypeModifiers, ArrayRef MapTypeModifiersLoc, OpenMPMapClauseKind MapType, bool IsMapTypeImplicit, SourceLocation DepLinMapLoc); /// 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, 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); /// 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); // 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, bool IsCompAssign = false); /// 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 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 }; ReferenceCompareResult CompareReferenceRelationship(SourceLocation Loc, QualType T1, QualType T2, bool &DerivedToBase, bool &ObjCConversion, bool &ObjCLifetimeConversion, bool &FunctionConversion); 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 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(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: 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"); assert(S.DelayedDllExportClasses.empty() && "there shouldn't be any pending delayed DLL export classes"); swapSavedState(); } private: Sema &S; decltype(DelayedOverridingExceptionSpecChecks) SavedOverridingExceptionSpecChecks; decltype(DelayedEquivalentExceptionSpecChecks) SavedEquivalentExceptionSpecChecks; decltype(DelayedDllExportClasses) SavedDllExportClasses; void swapSavedState() { SavedOverridingExceptionSpecChecks.swap( S.DelayedOverridingExceptionSpecChecks); SavedEquivalentExceptionSpecChecks.swap( S.DelayedEquivalentExceptionSpecChecks); SavedDllExportClasses.swap(S.DelayedDllExportClasses); } }; /// 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/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp index 3f722f8fd541..322b3a7fa740 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -1,4684 +1,4684 @@ //===--- Expr.cpp - Expression AST Node 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 the Expr class and subclasses. // //===----------------------------------------------------------------------===// #include "clang/AST/Expr.h" #include "clang/AST/APValue.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Attr.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/EvaluatedExprVisitor.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/Mangle.h" #include "clang/AST/RecordLayout.h" #include "clang/AST/StmtVisitor.h" #include "clang/Basic/Builtins.h" #include "clang/Basic/CharInfo.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/TargetInfo.h" #include "clang/Lex/Lexer.h" #include "clang/Lex/LiteralSupport.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" #include #include using namespace clang; const Expr *Expr::getBestDynamicClassTypeExpr() const { const Expr *E = this; while (true) { E = E->ignoreParenBaseCasts(); // Follow the RHS of a comma operator. if (auto *BO = dyn_cast(E)) { if (BO->getOpcode() == BO_Comma) { E = BO->getRHS(); continue; } } // Step into initializer for materialized temporaries. if (auto *MTE = dyn_cast(E)) { E = MTE->getSubExpr(); continue; } break; } return E; } const CXXRecordDecl *Expr::getBestDynamicClassType() const { const Expr *E = getBestDynamicClassTypeExpr(); QualType DerivedType = E->getType(); if (const PointerType *PTy = DerivedType->getAs()) DerivedType = PTy->getPointeeType(); if (DerivedType->isDependentType()) return nullptr; const RecordType *Ty = DerivedType->castAs(); Decl *D = Ty->getDecl(); return cast(D); } const Expr *Expr::skipRValueSubobjectAdjustments( SmallVectorImpl &CommaLHSs, SmallVectorImpl &Adjustments) const { const Expr *E = this; while (true) { E = E->IgnoreParens(); if (const CastExpr *CE = dyn_cast(E)) { if ((CE->getCastKind() == CK_DerivedToBase || CE->getCastKind() == CK_UncheckedDerivedToBase) && E->getType()->isRecordType()) { E = CE->getSubExpr(); auto *Derived = cast(E->getType()->castAs()->getDecl()); Adjustments.push_back(SubobjectAdjustment(CE, Derived)); continue; } if (CE->getCastKind() == CK_NoOp) { E = CE->getSubExpr(); continue; } } else if (const MemberExpr *ME = dyn_cast(E)) { if (!ME->isArrow()) { assert(ME->getBase()->getType()->isRecordType()); if (FieldDecl *Field = dyn_cast(ME->getMemberDecl())) { if (!Field->isBitField() && !Field->getType()->isReferenceType()) { E = ME->getBase(); Adjustments.push_back(SubobjectAdjustment(Field)); continue; } } } } else if (const BinaryOperator *BO = dyn_cast(E)) { if (BO->getOpcode() == BO_PtrMemD) { assert(BO->getRHS()->isRValue()); E = BO->getLHS(); const MemberPointerType *MPT = BO->getRHS()->getType()->getAs(); Adjustments.push_back(SubobjectAdjustment(MPT, BO->getRHS())); continue; } else if (BO->getOpcode() == BO_Comma) { CommaLHSs.push_back(BO->getLHS()); E = BO->getRHS(); continue; } } // Nothing changed. break; } return E; } bool Expr::isKnownToHaveBooleanValue(bool Semantic) const { const Expr *E = IgnoreParens(); // If this value has _Bool type, it is obvious 0/1. if (E->getType()->isBooleanType()) return true; // If this is a non-scalar-integer type, we don't care enough to try. if (!E->getType()->isIntegralOrEnumerationType()) return false; if (const UnaryOperator *UO = dyn_cast(E)) { switch (UO->getOpcode()) { case UO_Plus: return UO->getSubExpr()->isKnownToHaveBooleanValue(Semantic); case UO_LNot: return true; default: return false; } } // Only look through implicit casts. If the user writes // '(int) (a && b)' treat it as an arbitrary int. // FIXME: Should we look through any cast expression in !Semantic mode? if (const ImplicitCastExpr *CE = dyn_cast(E)) return CE->getSubExpr()->isKnownToHaveBooleanValue(Semantic); if (const BinaryOperator *BO = dyn_cast(E)) { switch (BO->getOpcode()) { default: return false; case BO_LT: // Relational operators. case BO_GT: case BO_LE: case BO_GE: case BO_EQ: // Equality operators. case BO_NE: case BO_LAnd: // AND operator. case BO_LOr: // Logical OR operator. return true; case BO_And: // Bitwise AND operator. case BO_Xor: // Bitwise XOR operator. case BO_Or: // Bitwise OR operator. // Handle things like (x==2)|(y==12). return BO->getLHS()->isKnownToHaveBooleanValue(Semantic) && BO->getRHS()->isKnownToHaveBooleanValue(Semantic); case BO_Comma: case BO_Assign: return BO->getRHS()->isKnownToHaveBooleanValue(Semantic); } } if (const ConditionalOperator *CO = dyn_cast(E)) return CO->getTrueExpr()->isKnownToHaveBooleanValue(Semantic) && CO->getFalseExpr()->isKnownToHaveBooleanValue(Semantic); if (isa(E)) return true; if (const auto *OVE = dyn_cast(E)) return OVE->getSourceExpr()->isKnownToHaveBooleanValue(Semantic); if (const FieldDecl *FD = E->getSourceBitField()) if (!Semantic && FD->getType()->isUnsignedIntegerType() && !FD->getBitWidth()->isValueDependent() && FD->getBitWidthValue(FD->getASTContext()) == 1) return true; return false; } // Amusing macro metaprogramming hack: check whether a class provides // a more specific implementation of getExprLoc(). // // See also Stmt.cpp:{getBeginLoc(),getEndLoc()}. namespace { /// This implementation is used when a class provides a custom /// implementation of getExprLoc. template SourceLocation getExprLocImpl(const Expr *expr, SourceLocation (T::*v)() const) { return static_cast(expr)->getExprLoc(); } /// This implementation is used when a class doesn't provide /// a custom implementation of getExprLoc. Overload resolution /// should pick it over the implementation above because it's /// more specialized according to function template partial ordering. template SourceLocation getExprLocImpl(const Expr *expr, SourceLocation (Expr::*v)() const) { return static_cast(expr)->getBeginLoc(); } } SourceLocation Expr::getExprLoc() const { switch (getStmtClass()) { case Stmt::NoStmtClass: llvm_unreachable("statement without class"); #define ABSTRACT_STMT(type) #define STMT(type, base) \ case Stmt::type##Class: break; #define EXPR(type, base) \ case Stmt::type##Class: return getExprLocImpl(this, &type::getExprLoc); #include "clang/AST/StmtNodes.inc" } llvm_unreachable("unknown expression kind"); } //===----------------------------------------------------------------------===// // Primary Expressions. //===----------------------------------------------------------------------===// static void AssertResultStorageKind(ConstantExpr::ResultStorageKind Kind) { assert((Kind == ConstantExpr::RSK_APValue || Kind == ConstantExpr::RSK_Int64 || Kind == ConstantExpr::RSK_None) && "Invalid StorageKind Value"); } ConstantExpr::ResultStorageKind ConstantExpr::getStorageKind(const APValue &Value) { switch (Value.getKind()) { case APValue::None: case APValue::Indeterminate: return ConstantExpr::RSK_None; case APValue::Int: if (!Value.getInt().needsCleanup()) return ConstantExpr::RSK_Int64; LLVM_FALLTHROUGH; default: return ConstantExpr::RSK_APValue; } } ConstantExpr::ResultStorageKind ConstantExpr::getStorageKind(const Type *T, const ASTContext &Context) { if (T->isIntegralOrEnumerationType() && Context.getTypeInfo(T).Width <= 64) return ConstantExpr::RSK_Int64; return ConstantExpr::RSK_APValue; } void ConstantExpr::DefaultInit(ResultStorageKind StorageKind) { ConstantExprBits.ResultKind = StorageKind; ConstantExprBits.APValueKind = APValue::None; ConstantExprBits.HasCleanup = false; if (StorageKind == ConstantExpr::RSK_APValue) ::new (getTrailingObjects()) APValue(); } ConstantExpr::ConstantExpr(Expr *subexpr, ResultStorageKind StorageKind) : FullExpr(ConstantExprClass, subexpr) { DefaultInit(StorageKind); } ConstantExpr *ConstantExpr::Create(const ASTContext &Context, Expr *E, ResultStorageKind StorageKind) { assert(!isa(E)); AssertResultStorageKind(StorageKind); unsigned Size = totalSizeToAlloc( StorageKind == ConstantExpr::RSK_APValue, StorageKind == ConstantExpr::RSK_Int64); void *Mem = Context.Allocate(Size, alignof(ConstantExpr)); ConstantExpr *Self = new (Mem) ConstantExpr(E, StorageKind); return Self; } ConstantExpr *ConstantExpr::Create(const ASTContext &Context, Expr *E, const APValue &Result) { ResultStorageKind StorageKind = getStorageKind(Result); ConstantExpr *Self = Create(Context, E, StorageKind); Self->SetResult(Result, Context); return Self; } ConstantExpr::ConstantExpr(ResultStorageKind StorageKind, EmptyShell Empty) : FullExpr(ConstantExprClass, Empty) { DefaultInit(StorageKind); } ConstantExpr *ConstantExpr::CreateEmpty(const ASTContext &Context, ResultStorageKind StorageKind, EmptyShell Empty) { AssertResultStorageKind(StorageKind); unsigned Size = totalSizeToAlloc( StorageKind == ConstantExpr::RSK_APValue, StorageKind == ConstantExpr::RSK_Int64); void *Mem = Context.Allocate(Size, alignof(ConstantExpr)); ConstantExpr *Self = new (Mem) ConstantExpr(StorageKind, Empty); return Self; } void ConstantExpr::MoveIntoResult(APValue &Value, const ASTContext &Context) { assert(getStorageKind(Value) == ConstantExprBits.ResultKind && "Invalid storage for this value kind"); ConstantExprBits.APValueKind = Value.getKind(); switch (ConstantExprBits.ResultKind) { case RSK_None: return; case RSK_Int64: Int64Result() = *Value.getInt().getRawData(); ConstantExprBits.BitWidth = Value.getInt().getBitWidth(); ConstantExprBits.IsUnsigned = Value.getInt().isUnsigned(); return; case RSK_APValue: if (!ConstantExprBits.HasCleanup && Value.needsCleanup()) { ConstantExprBits.HasCleanup = true; Context.addDestruction(&APValueResult()); } APValueResult() = std::move(Value); return; } llvm_unreachable("Invalid ResultKind Bits"); } llvm::APSInt ConstantExpr::getResultAsAPSInt() const { switch (ConstantExprBits.ResultKind) { case ConstantExpr::RSK_APValue: return APValueResult().getInt(); case ConstantExpr::RSK_Int64: return llvm::APSInt(llvm::APInt(ConstantExprBits.BitWidth, Int64Result()), ConstantExprBits.IsUnsigned); default: llvm_unreachable("invalid Accessor"); } } APValue ConstantExpr::getAPValueResult() const { switch (ConstantExprBits.ResultKind) { case ConstantExpr::RSK_APValue: return APValueResult(); case ConstantExpr::RSK_Int64: return APValue( llvm::APSInt(llvm::APInt(ConstantExprBits.BitWidth, Int64Result()), ConstantExprBits.IsUnsigned)); case ConstantExpr::RSK_None: return APValue(); } llvm_unreachable("invalid ResultKind"); } /// Compute the type-, value-, and instantiation-dependence of a /// declaration reference /// based on the declaration being referenced. static void computeDeclRefDependence(const ASTContext &Ctx, NamedDecl *D, QualType T, bool &TypeDependent, bool &ValueDependent, bool &InstantiationDependent) { TypeDependent = false; ValueDependent = false; InstantiationDependent = false; // (TD) C++ [temp.dep.expr]p3: // An id-expression is type-dependent if it contains: // // and // // (VD) C++ [temp.dep.constexpr]p2: // An identifier is value-dependent if it is: // (TD) - an identifier that was declared with dependent type // (VD) - a name declared with a dependent type, if (T->isDependentType()) { TypeDependent = true; ValueDependent = true; InstantiationDependent = true; return; } else if (T->isInstantiationDependentType()) { InstantiationDependent = true; } // (TD) - a conversion-function-id that specifies a dependent type if (D->getDeclName().getNameKind() == DeclarationName::CXXConversionFunctionName) { QualType T = D->getDeclName().getCXXNameType(); if (T->isDependentType()) { TypeDependent = true; ValueDependent = true; InstantiationDependent = true; return; } if (T->isInstantiationDependentType()) InstantiationDependent = true; } // (VD) - the name of a non-type template parameter, if (isa(D)) { ValueDependent = true; InstantiationDependent = true; return; } // (VD) - a constant with integral or enumeration type and is // initialized with an expression that is value-dependent. // (VD) - a constant with literal type and is initialized with an // expression that is value-dependent [C++11]. // (VD) - FIXME: Missing from the standard: // - an entity with reference type and is initialized with an // expression that is value-dependent [C++11] if (VarDecl *Var = dyn_cast(D)) { if ((Ctx.getLangOpts().CPlusPlus11 ? Var->getType()->isLiteralType(Ctx) : Var->getType()->isIntegralOrEnumerationType()) && (Var->getType().isConstQualified() || Var->getType()->isReferenceType())) { if (const Expr *Init = Var->getAnyInitializer()) if (Init->isValueDependent()) { ValueDependent = true; InstantiationDependent = true; } } // (VD) - FIXME: Missing from the standard: // - a member function or a static data member of the current // instantiation if (Var->isStaticDataMember() && Var->getDeclContext()->isDependentContext()) { ValueDependent = true; InstantiationDependent = true; TypeSourceInfo *TInfo = Var->getFirstDecl()->getTypeSourceInfo(); if (TInfo->getType()->isIncompleteArrayType()) TypeDependent = true; } return; } // (VD) - FIXME: Missing from the standard: // - a member function or a static data member of the current // instantiation if (isa(D) && D->getDeclContext()->isDependentContext()) { ValueDependent = true; InstantiationDependent = true; } } void DeclRefExpr::computeDependence(const ASTContext &Ctx) { bool TypeDependent = false; bool ValueDependent = false; bool InstantiationDependent = false; computeDeclRefDependence(Ctx, getDecl(), getType(), TypeDependent, ValueDependent, InstantiationDependent); ExprBits.TypeDependent |= TypeDependent; ExprBits.ValueDependent |= ValueDependent; ExprBits.InstantiationDependent |= InstantiationDependent; // Is the declaration a parameter pack? if (getDecl()->isParameterPack()) ExprBits.ContainsUnexpandedParameterPack = true; } DeclRefExpr::DeclRefExpr(const ASTContext &Ctx, ValueDecl *D, bool RefersToEnclosingVariableOrCapture, QualType T, ExprValueKind VK, SourceLocation L, const DeclarationNameLoc &LocInfo, NonOdrUseReason NOUR) : Expr(DeclRefExprClass, T, VK, OK_Ordinary, false, false, false, false), D(D), DNLoc(LocInfo) { DeclRefExprBits.HasQualifier = false; DeclRefExprBits.HasTemplateKWAndArgsInfo = false; DeclRefExprBits.HasFoundDecl = false; DeclRefExprBits.HadMultipleCandidates = false; DeclRefExprBits.RefersToEnclosingVariableOrCapture = RefersToEnclosingVariableOrCapture; DeclRefExprBits.NonOdrUseReason = NOUR; DeclRefExprBits.Loc = L; computeDependence(Ctx); } DeclRefExpr::DeclRefExpr(const ASTContext &Ctx, NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateKWLoc, ValueDecl *D, bool RefersToEnclosingVariableOrCapture, const DeclarationNameInfo &NameInfo, NamedDecl *FoundD, const TemplateArgumentListInfo *TemplateArgs, QualType T, ExprValueKind VK, NonOdrUseReason NOUR) : Expr(DeclRefExprClass, T, VK, OK_Ordinary, false, false, false, false), D(D), DNLoc(NameInfo.getInfo()) { DeclRefExprBits.Loc = NameInfo.getLoc(); DeclRefExprBits.HasQualifier = QualifierLoc ? 1 : 0; if (QualifierLoc) { new (getTrailingObjects()) NestedNameSpecifierLoc(QualifierLoc); auto *NNS = QualifierLoc.getNestedNameSpecifier(); if (NNS->isInstantiationDependent()) ExprBits.InstantiationDependent = true; if (NNS->containsUnexpandedParameterPack()) ExprBits.ContainsUnexpandedParameterPack = true; } DeclRefExprBits.HasFoundDecl = FoundD ? 1 : 0; if (FoundD) *getTrailingObjects() = FoundD; DeclRefExprBits.HasTemplateKWAndArgsInfo = (TemplateArgs || TemplateKWLoc.isValid()) ? 1 : 0; DeclRefExprBits.RefersToEnclosingVariableOrCapture = RefersToEnclosingVariableOrCapture; DeclRefExprBits.NonOdrUseReason = NOUR; if (TemplateArgs) { bool Dependent = false; bool InstantiationDependent = false; bool ContainsUnexpandedParameterPack = false; getTrailingObjects()->initializeFrom( TemplateKWLoc, *TemplateArgs, getTrailingObjects(), Dependent, InstantiationDependent, ContainsUnexpandedParameterPack); assert(!Dependent && "built a DeclRefExpr with dependent template args"); ExprBits.InstantiationDependent |= InstantiationDependent; ExprBits.ContainsUnexpandedParameterPack |= ContainsUnexpandedParameterPack; } else if (TemplateKWLoc.isValid()) { getTrailingObjects()->initializeFrom( TemplateKWLoc); } DeclRefExprBits.HadMultipleCandidates = 0; computeDependence(Ctx); } DeclRefExpr *DeclRefExpr::Create(const ASTContext &Context, NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateKWLoc, ValueDecl *D, bool RefersToEnclosingVariableOrCapture, SourceLocation NameLoc, QualType T, ExprValueKind VK, NamedDecl *FoundD, const TemplateArgumentListInfo *TemplateArgs, NonOdrUseReason NOUR) { return Create(Context, QualifierLoc, TemplateKWLoc, D, RefersToEnclosingVariableOrCapture, DeclarationNameInfo(D->getDeclName(), NameLoc), T, VK, FoundD, TemplateArgs, NOUR); } DeclRefExpr *DeclRefExpr::Create(const ASTContext &Context, NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateKWLoc, ValueDecl *D, bool RefersToEnclosingVariableOrCapture, const DeclarationNameInfo &NameInfo, QualType T, ExprValueKind VK, NamedDecl *FoundD, const TemplateArgumentListInfo *TemplateArgs, NonOdrUseReason NOUR) { // Filter out cases where the found Decl is the same as the value refenenced. if (D == FoundD) FoundD = nullptr; bool HasTemplateKWAndArgsInfo = TemplateArgs || TemplateKWLoc.isValid(); std::size_t Size = totalSizeToAlloc( QualifierLoc ? 1 : 0, FoundD ? 1 : 0, HasTemplateKWAndArgsInfo ? 1 : 0, TemplateArgs ? TemplateArgs->size() : 0); void *Mem = Context.Allocate(Size, alignof(DeclRefExpr)); return new (Mem) DeclRefExpr(Context, QualifierLoc, TemplateKWLoc, D, RefersToEnclosingVariableOrCapture, NameInfo, FoundD, TemplateArgs, T, VK, NOUR); } DeclRefExpr *DeclRefExpr::CreateEmpty(const ASTContext &Context, bool HasQualifier, bool HasFoundDecl, bool HasTemplateKWAndArgsInfo, unsigned NumTemplateArgs) { assert(NumTemplateArgs == 0 || HasTemplateKWAndArgsInfo); std::size_t Size = totalSizeToAlloc( HasQualifier ? 1 : 0, HasFoundDecl ? 1 : 0, HasTemplateKWAndArgsInfo, NumTemplateArgs); void *Mem = Context.Allocate(Size, alignof(DeclRefExpr)); return new (Mem) DeclRefExpr(EmptyShell()); } SourceLocation DeclRefExpr::getBeginLoc() const { if (hasQualifier()) return getQualifierLoc().getBeginLoc(); return getNameInfo().getBeginLoc(); } SourceLocation DeclRefExpr::getEndLoc() const { if (hasExplicitTemplateArgs()) return getRAngleLoc(); return getNameInfo().getEndLoc(); } PredefinedExpr::PredefinedExpr(SourceLocation L, QualType FNTy, IdentKind IK, StringLiteral *SL) : Expr(PredefinedExprClass, FNTy, VK_LValue, OK_Ordinary, FNTy->isDependentType(), FNTy->isDependentType(), FNTy->isInstantiationDependentType(), /*ContainsUnexpandedParameterPack=*/false) { PredefinedExprBits.Kind = IK; assert((getIdentKind() == IK) && "IdentKind do not fit in PredefinedExprBitfields!"); bool HasFunctionName = SL != nullptr; PredefinedExprBits.HasFunctionName = HasFunctionName; PredefinedExprBits.Loc = L; if (HasFunctionName) setFunctionName(SL); } PredefinedExpr::PredefinedExpr(EmptyShell Empty, bool HasFunctionName) : Expr(PredefinedExprClass, Empty) { PredefinedExprBits.HasFunctionName = HasFunctionName; } PredefinedExpr *PredefinedExpr::Create(const ASTContext &Ctx, SourceLocation L, QualType FNTy, IdentKind IK, StringLiteral *SL) { bool HasFunctionName = SL != nullptr; void *Mem = Ctx.Allocate(totalSizeToAlloc(HasFunctionName), alignof(PredefinedExpr)); return new (Mem) PredefinedExpr(L, FNTy, IK, SL); } PredefinedExpr *PredefinedExpr::CreateEmpty(const ASTContext &Ctx, bool HasFunctionName) { void *Mem = Ctx.Allocate(totalSizeToAlloc(HasFunctionName), alignof(PredefinedExpr)); return new (Mem) PredefinedExpr(EmptyShell(), HasFunctionName); } StringRef PredefinedExpr::getIdentKindName(PredefinedExpr::IdentKind IK) { switch (IK) { case Func: return "__func__"; case Function: return "__FUNCTION__"; case FuncDName: return "__FUNCDNAME__"; case LFunction: return "L__FUNCTION__"; case PrettyFunction: return "__PRETTY_FUNCTION__"; case FuncSig: return "__FUNCSIG__"; case LFuncSig: return "L__FUNCSIG__"; case PrettyFunctionNoVirtual: break; } llvm_unreachable("Unknown ident kind for PredefinedExpr"); } // FIXME: Maybe this should use DeclPrinter with a special "print predefined // expr" policy instead. std::string PredefinedExpr::ComputeName(IdentKind IK, const Decl *CurrentDecl) { ASTContext &Context = CurrentDecl->getASTContext(); if (IK == PredefinedExpr::FuncDName) { if (const NamedDecl *ND = dyn_cast(CurrentDecl)) { std::unique_ptr MC; MC.reset(Context.createMangleContext()); if (MC->shouldMangleDeclName(ND)) { SmallString<256> Buffer; llvm::raw_svector_ostream Out(Buffer); if (const CXXConstructorDecl *CD = dyn_cast(ND)) MC->mangleCXXCtor(CD, Ctor_Base, Out); else if (const CXXDestructorDecl *DD = dyn_cast(ND)) MC->mangleCXXDtor(DD, Dtor_Base, Out); else MC->mangleName(ND, Out); if (!Buffer.empty() && Buffer.front() == '\01') return Buffer.substr(1); return Buffer.str(); } else return ND->getIdentifier()->getName(); } return ""; } if (isa(CurrentDecl)) { // For blocks we only emit something if it is enclosed in a function // For top-level block we'd like to include the name of variable, but we // don't have it at this point. auto DC = CurrentDecl->getDeclContext(); if (DC->isFileContext()) return ""; SmallString<256> Buffer; llvm::raw_svector_ostream Out(Buffer); if (auto *DCBlock = dyn_cast(DC)) // For nested blocks, propagate up to the parent. Out << ComputeName(IK, DCBlock); else if (auto *DCDecl = dyn_cast(DC)) Out << ComputeName(IK, DCDecl) << "_block_invoke"; return Out.str(); } if (const FunctionDecl *FD = dyn_cast(CurrentDecl)) { if (IK != PrettyFunction && IK != PrettyFunctionNoVirtual && IK != FuncSig && IK != LFuncSig) return FD->getNameAsString(); SmallString<256> Name; llvm::raw_svector_ostream Out(Name); if (const CXXMethodDecl *MD = dyn_cast(FD)) { if (MD->isVirtual() && IK != PrettyFunctionNoVirtual) Out << "virtual "; if (MD->isStatic()) Out << "static "; } PrintingPolicy Policy(Context.getLangOpts()); std::string Proto; llvm::raw_string_ostream POut(Proto); const FunctionDecl *Decl = FD; if (const FunctionDecl* Pattern = FD->getTemplateInstantiationPattern()) Decl = Pattern; const FunctionType *AFT = Decl->getType()->getAs(); const FunctionProtoType *FT = nullptr; if (FD->hasWrittenPrototype()) FT = dyn_cast(AFT); if (IK == FuncSig || IK == LFuncSig) { switch (AFT->getCallConv()) { case CC_C: POut << "__cdecl "; break; case CC_X86StdCall: POut << "__stdcall "; break; case CC_X86FastCall: POut << "__fastcall "; break; case CC_X86ThisCall: POut << "__thiscall "; break; case CC_X86VectorCall: POut << "__vectorcall "; break; case CC_X86RegCall: POut << "__regcall "; break; // Only bother printing the conventions that MSVC knows about. default: break; } } FD->printQualifiedName(POut, Policy); POut << "("; if (FT) { for (unsigned i = 0, e = Decl->getNumParams(); i != e; ++i) { if (i) POut << ", "; POut << Decl->getParamDecl(i)->getType().stream(Policy); } if (FT->isVariadic()) { if (FD->getNumParams()) POut << ", "; POut << "..."; } else if ((IK == FuncSig || IK == LFuncSig || !Context.getLangOpts().CPlusPlus) && !Decl->getNumParams()) { POut << "void"; } } POut << ")"; if (const CXXMethodDecl *MD = dyn_cast(FD)) { assert(FT && "We must have a written prototype in this case."); if (FT->isConst()) POut << " const"; if (FT->isVolatile()) POut << " volatile"; RefQualifierKind Ref = MD->getRefQualifier(); if (Ref == RQ_LValue) POut << " &"; else if (Ref == RQ_RValue) POut << " &&"; } typedef SmallVector SpecsTy; SpecsTy Specs; const DeclContext *Ctx = FD->getDeclContext(); while (Ctx && isa(Ctx)) { const ClassTemplateSpecializationDecl *Spec = dyn_cast(Ctx); if (Spec && !Spec->isExplicitSpecialization()) Specs.push_back(Spec); Ctx = Ctx->getParent(); } std::string TemplateParams; llvm::raw_string_ostream TOut(TemplateParams); for (SpecsTy::reverse_iterator I = Specs.rbegin(), E = Specs.rend(); I != E; ++I) { const TemplateParameterList *Params = (*I)->getSpecializedTemplate()->getTemplateParameters(); const TemplateArgumentList &Args = (*I)->getTemplateArgs(); assert(Params->size() == Args.size()); for (unsigned i = 0, numParams = Params->size(); i != numParams; ++i) { StringRef Param = Params->getParam(i)->getName(); if (Param.empty()) continue; TOut << Param << " = "; Args.get(i).print(Policy, TOut); TOut << ", "; } } FunctionTemplateSpecializationInfo *FSI = FD->getTemplateSpecializationInfo(); if (FSI && !FSI->isExplicitSpecialization()) { const TemplateParameterList* Params = FSI->getTemplate()->getTemplateParameters(); const TemplateArgumentList* Args = FSI->TemplateArguments; assert(Params->size() == Args->size()); for (unsigned i = 0, e = Params->size(); i != e; ++i) { StringRef Param = Params->getParam(i)->getName(); if (Param.empty()) continue; TOut << Param << " = "; Args->get(i).print(Policy, TOut); TOut << ", "; } } TOut.flush(); if (!TemplateParams.empty()) { // remove the trailing comma and space TemplateParams.resize(TemplateParams.size() - 2); POut << " [" << TemplateParams << "]"; } POut.flush(); // Print "auto" for all deduced return types. This includes C++1y return // type deduction and lambdas. For trailing return types resolve the // decltype expression. Otherwise print the real type when this is // not a constructor or destructor. if (isa(FD) && cast(FD)->getParent()->isLambda()) Proto = "auto " + Proto; else if (FT && FT->getReturnType()->getAs()) FT->getReturnType() ->getAs() ->getUnderlyingType() .getAsStringInternal(Proto, Policy); else if (!isa(FD) && !isa(FD)) AFT->getReturnType().getAsStringInternal(Proto, Policy); Out << Proto; return Name.str().str(); } if (const CapturedDecl *CD = dyn_cast(CurrentDecl)) { for (const DeclContext *DC = CD->getParent(); DC; DC = DC->getParent()) // Skip to its enclosing function or method, but not its enclosing // CapturedDecl. if (DC->isFunctionOrMethod() && (DC->getDeclKind() != Decl::Captured)) { const Decl *D = Decl::castFromDeclContext(DC); return ComputeName(IK, D); } llvm_unreachable("CapturedDecl not inside a function or method"); } if (const ObjCMethodDecl *MD = dyn_cast(CurrentDecl)) { SmallString<256> Name; llvm::raw_svector_ostream Out(Name); Out << (MD->isInstanceMethod() ? '-' : '+'); Out << '['; // For incorrect code, there might not be an ObjCInterfaceDecl. Do // a null check to avoid a crash. if (const ObjCInterfaceDecl *ID = MD->getClassInterface()) Out << *ID; if (const ObjCCategoryImplDecl *CID = dyn_cast(MD->getDeclContext())) Out << '(' << *CID << ')'; Out << ' '; MD->getSelector().print(Out); Out << ']'; return Name.str().str(); } if (isa(CurrentDecl) && IK == PrettyFunction) { // __PRETTY_FUNCTION__ -> "top level", the others produce an empty string. return "top level"; } return ""; } void APNumericStorage::setIntValue(const ASTContext &C, const llvm::APInt &Val) { if (hasAllocation()) C.Deallocate(pVal); BitWidth = Val.getBitWidth(); unsigned NumWords = Val.getNumWords(); const uint64_t* Words = Val.getRawData(); if (NumWords > 1) { pVal = new (C) uint64_t[NumWords]; std::copy(Words, Words + NumWords, pVal); } else if (NumWords == 1) VAL = Words[0]; else VAL = 0; } IntegerLiteral::IntegerLiteral(const ASTContext &C, const llvm::APInt &V, QualType type, SourceLocation l) : Expr(IntegerLiteralClass, type, VK_RValue, OK_Ordinary, false, false, false, false), Loc(l) { assert(type->isIntegerType() && "Illegal type in IntegerLiteral"); assert(V.getBitWidth() == C.getIntWidth(type) && "Integer type is not the correct size for constant."); setValue(C, V); } IntegerLiteral * IntegerLiteral::Create(const ASTContext &C, const llvm::APInt &V, QualType type, SourceLocation l) { return new (C) IntegerLiteral(C, V, type, l); } IntegerLiteral * IntegerLiteral::Create(const ASTContext &C, EmptyShell Empty) { return new (C) IntegerLiteral(Empty); } FixedPointLiteral::FixedPointLiteral(const ASTContext &C, const llvm::APInt &V, QualType type, SourceLocation l, unsigned Scale) : Expr(FixedPointLiteralClass, type, VK_RValue, OK_Ordinary, false, false, false, false), Loc(l), Scale(Scale) { assert(type->isFixedPointType() && "Illegal type in FixedPointLiteral"); assert(V.getBitWidth() == C.getTypeInfo(type).Width && "Fixed point type is not the correct size for constant."); setValue(C, V); } FixedPointLiteral *FixedPointLiteral::CreateFromRawInt(const ASTContext &C, const llvm::APInt &V, QualType type, SourceLocation l, unsigned Scale) { return new (C) FixedPointLiteral(C, V, type, l, Scale); } std::string FixedPointLiteral::getValueAsString(unsigned Radix) const { // Currently the longest decimal number that can be printed is the max for an // unsigned long _Accum: 4294967295.99999999976716935634613037109375 // which is 43 characters. SmallString<64> S; FixedPointValueToString( S, llvm::APSInt::getUnsigned(getValue().getZExtValue()), Scale); return S.str(); } FloatingLiteral::FloatingLiteral(const ASTContext &C, const llvm::APFloat &V, bool isexact, QualType Type, SourceLocation L) : Expr(FloatingLiteralClass, Type, VK_RValue, OK_Ordinary, false, false, false, false), Loc(L) { setSemantics(V.getSemantics()); FloatingLiteralBits.IsExact = isexact; setValue(C, V); } FloatingLiteral::FloatingLiteral(const ASTContext &C, EmptyShell Empty) : Expr(FloatingLiteralClass, Empty) { setRawSemantics(llvm::APFloatBase::S_IEEEhalf); FloatingLiteralBits.IsExact = false; } FloatingLiteral * FloatingLiteral::Create(const ASTContext &C, const llvm::APFloat &V, bool isexact, QualType Type, SourceLocation L) { return new (C) FloatingLiteral(C, V, isexact, Type, L); } FloatingLiteral * FloatingLiteral::Create(const ASTContext &C, EmptyShell Empty) { return new (C) FloatingLiteral(C, Empty); } /// 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 FloatingLiteral::getValueAsApproximateDouble() const { llvm::APFloat V = getValue(); bool ignored; V.convert(llvm::APFloat::IEEEdouble(), llvm::APFloat::rmNearestTiesToEven, &ignored); return V.convertToDouble(); } unsigned StringLiteral::mapCharByteWidth(TargetInfo const &Target, StringKind SK) { unsigned CharByteWidth = 0; switch (SK) { case Ascii: case UTF8: CharByteWidth = Target.getCharWidth(); break; case Wide: CharByteWidth = Target.getWCharWidth(); break; case UTF16: CharByteWidth = Target.getChar16Width(); break; case UTF32: CharByteWidth = Target.getChar32Width(); break; } assert((CharByteWidth & 7) == 0 && "Assumes character size is byte multiple"); CharByteWidth /= 8; assert((CharByteWidth == 1 || CharByteWidth == 2 || CharByteWidth == 4) && "The only supported character byte widths are 1,2 and 4!"); return CharByteWidth; } StringLiteral::StringLiteral(const ASTContext &Ctx, StringRef Str, StringKind Kind, bool Pascal, QualType Ty, const SourceLocation *Loc, unsigned NumConcatenated) : Expr(StringLiteralClass, Ty, VK_LValue, OK_Ordinary, false, false, false, false) { assert(Ctx.getAsConstantArrayType(Ty) && "StringLiteral must be of constant array type!"); unsigned CharByteWidth = mapCharByteWidth(Ctx.getTargetInfo(), Kind); unsigned ByteLength = Str.size(); assert((ByteLength % CharByteWidth == 0) && "The size of the data must be a multiple of CharByteWidth!"); // Avoid the expensive division. The compiler should be able to figure it // out by itself. However as of clang 7, even with the appropriate // llvm_unreachable added just here, it is not able to do so. unsigned Length; switch (CharByteWidth) { case 1: Length = ByteLength; break; case 2: Length = ByteLength / 2; break; case 4: Length = ByteLength / 4; break; default: llvm_unreachable("Unsupported character width!"); } StringLiteralBits.Kind = Kind; StringLiteralBits.CharByteWidth = CharByteWidth; StringLiteralBits.IsPascal = Pascal; StringLiteralBits.NumConcatenated = NumConcatenated; *getTrailingObjects() = Length; // Initialize the trailing array of SourceLocation. // This is safe since SourceLocation is POD-like. std::memcpy(getTrailingObjects(), Loc, NumConcatenated * sizeof(SourceLocation)); // Initialize the trailing array of char holding the string data. std::memcpy(getTrailingObjects(), Str.data(), ByteLength); } StringLiteral::StringLiteral(EmptyShell Empty, unsigned NumConcatenated, unsigned Length, unsigned CharByteWidth) : Expr(StringLiteralClass, Empty) { StringLiteralBits.CharByteWidth = CharByteWidth; StringLiteralBits.NumConcatenated = NumConcatenated; *getTrailingObjects() = Length; } StringLiteral *StringLiteral::Create(const ASTContext &Ctx, StringRef Str, StringKind Kind, bool Pascal, QualType Ty, const SourceLocation *Loc, unsigned NumConcatenated) { void *Mem = Ctx.Allocate(totalSizeToAlloc( 1, NumConcatenated, Str.size()), alignof(StringLiteral)); return new (Mem) StringLiteral(Ctx, Str, Kind, Pascal, Ty, Loc, NumConcatenated); } StringLiteral *StringLiteral::CreateEmpty(const ASTContext &Ctx, unsigned NumConcatenated, unsigned Length, unsigned CharByteWidth) { void *Mem = Ctx.Allocate(totalSizeToAlloc( 1, NumConcatenated, Length * CharByteWidth), alignof(StringLiteral)); return new (Mem) StringLiteral(EmptyShell(), NumConcatenated, Length, CharByteWidth); } void StringLiteral::outputString(raw_ostream &OS) const { switch (getKind()) { case Ascii: break; // no prefix. case Wide: OS << 'L'; break; case UTF8: OS << "u8"; break; case UTF16: OS << 'u'; break; case UTF32: OS << 'U'; break; } OS << '"'; static const char Hex[] = "0123456789ABCDEF"; unsigned LastSlashX = getLength(); for (unsigned I = 0, N = getLength(); I != N; ++I) { switch (uint32_t Char = getCodeUnit(I)) { default: // FIXME: Convert UTF-8 back to codepoints before rendering. // Convert UTF-16 surrogate pairs back to codepoints before rendering. // Leave invalid surrogates alone; we'll use \x for those. if (getKind() == UTF16 && I != N - 1 && Char >= 0xd800 && Char <= 0xdbff) { uint32_t Trail = getCodeUnit(I + 1); if (Trail >= 0xdc00 && Trail <= 0xdfff) { Char = 0x10000 + ((Char - 0xd800) << 10) + (Trail - 0xdc00); ++I; } } if (Char > 0xff) { // If this is a wide string, output characters over 0xff using \x // escapes. Otherwise, this is a UTF-16 or UTF-32 string, and Char is a // codepoint: use \x escapes for invalid codepoints. if (getKind() == Wide || (Char >= 0xd800 && Char <= 0xdfff) || Char >= 0x110000) { // FIXME: Is this the best way to print wchar_t? OS << "\\x"; int Shift = 28; while ((Char >> Shift) == 0) Shift -= 4; for (/**/; Shift >= 0; Shift -= 4) OS << Hex[(Char >> Shift) & 15]; LastSlashX = I; break; } if (Char > 0xffff) OS << "\\U00" << Hex[(Char >> 20) & 15] << Hex[(Char >> 16) & 15]; else OS << "\\u"; OS << Hex[(Char >> 12) & 15] << Hex[(Char >> 8) & 15] << Hex[(Char >> 4) & 15] << Hex[(Char >> 0) & 15]; break; } // If we used \x... for the previous character, and this character is a // hexadecimal digit, prevent it being slurped as part of the \x. if (LastSlashX + 1 == I) { switch (Char) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': OS << "\"\""; } } assert(Char <= 0xff && "Characters above 0xff should already have been handled."); if (isPrintable(Char)) OS << (char)Char; else // Output anything hard as an octal escape. OS << '\\' << (char)('0' + ((Char >> 6) & 7)) << (char)('0' + ((Char >> 3) & 7)) << (char)('0' + ((Char >> 0) & 7)); break; // Handle some common non-printable cases to make dumps prettier. case '\\': OS << "\\\\"; break; case '"': OS << "\\\""; break; case '\a': OS << "\\a"; break; case '\b': OS << "\\b"; break; case '\f': OS << "\\f"; break; case '\n': OS << "\\n"; break; case '\r': OS << "\\r"; break; case '\t': OS << "\\t"; break; case '\v': OS << "\\v"; break; } } OS << '"'; } /// 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. /// /// The *StartToken sets the first token to be searched in this function and /// the *StartTokenByteOffset is the byte offset of the first token. Before /// returning, it updates the *StartToken to the TokNo of the token being found /// and sets *StartTokenByteOffset to the byte offset of the token in the /// string. /// Using these two parameters can reduce the time complexity from O(n^2) to /// O(n) if one wants to get the location of byte for all the tokens in a /// string. /// SourceLocation StringLiteral::getLocationOfByte(unsigned ByteNo, const SourceManager &SM, const LangOptions &Features, const TargetInfo &Target, unsigned *StartToken, unsigned *StartTokenByteOffset) const { assert((getKind() == StringLiteral::Ascii || getKind() == StringLiteral::UTF8) && "Only narrow string literals are currently supported"); // Loop over all of the tokens in this string until we find the one that // contains the byte we're looking for. unsigned TokNo = 0; unsigned StringOffset = 0; if (StartToken) TokNo = *StartToken; if (StartTokenByteOffset) { StringOffset = *StartTokenByteOffset; ByteNo -= StringOffset; } while (1) { assert(TokNo < getNumConcatenated() && "Invalid byte number!"); SourceLocation StrTokLoc = getStrTokenLoc(TokNo); // Get the spelling of the string so that we can get the data that makes up // the string literal, not the identifier for the macro it is potentially // expanded through. SourceLocation StrTokSpellingLoc = SM.getSpellingLoc(StrTokLoc); // Re-lex the token to get its length and original spelling. std::pair LocInfo = SM.getDecomposedLoc(StrTokSpellingLoc); bool Invalid = false; StringRef Buffer = SM.getBufferData(LocInfo.first, &Invalid); if (Invalid) { if (StartTokenByteOffset != nullptr) *StartTokenByteOffset = StringOffset; if (StartToken != nullptr) *StartToken = TokNo; return StrTokSpellingLoc; } const char *StrData = Buffer.data()+LocInfo.second; // Create a lexer starting at the beginning of this token. Lexer TheLexer(SM.getLocForStartOfFile(LocInfo.first), Features, Buffer.begin(), StrData, Buffer.end()); Token TheTok; TheLexer.LexFromRawLexer(TheTok); // Use the StringLiteralParser to compute the length of the string in bytes. StringLiteralParser SLP(TheTok, SM, Features, Target); unsigned TokNumBytes = SLP.GetStringLength(); // If the byte is in this token, return the location of the byte. if (ByteNo < TokNumBytes || (ByteNo == TokNumBytes && TokNo == getNumConcatenated() - 1)) { unsigned Offset = SLP.getOffsetOfStringByte(TheTok, ByteNo); // Now that we know the offset of the token in the spelling, use the // preprocessor to get the offset in the original source. if (StartTokenByteOffset != nullptr) *StartTokenByteOffset = StringOffset; if (StartToken != nullptr) *StartToken = TokNo; return Lexer::AdvanceToTokenCharacter(StrTokLoc, Offset, SM, Features); } // Move to the next string token. StringOffset += TokNumBytes; ++TokNo; ByteNo -= TokNumBytes; } } /// getOpcodeStr - Turn an Opcode enum value into the punctuation char it /// corresponds to, e.g. "sizeof" or "[pre]++". StringRef UnaryOperator::getOpcodeStr(Opcode Op) { switch (Op) { #define UNARY_OPERATION(Name, Spelling) case UO_##Name: return Spelling; #include "clang/AST/OperationKinds.def" } llvm_unreachable("Unknown unary operator"); } UnaryOperatorKind UnaryOperator::getOverloadedOpcode(OverloadedOperatorKind OO, bool Postfix) { switch (OO) { default: llvm_unreachable("No unary operator for overloaded function"); case OO_PlusPlus: return Postfix ? UO_PostInc : UO_PreInc; case OO_MinusMinus: return Postfix ? UO_PostDec : UO_PreDec; case OO_Amp: return UO_AddrOf; case OO_Star: return UO_Deref; case OO_Plus: return UO_Plus; case OO_Minus: return UO_Minus; case OO_Tilde: return UO_Not; case OO_Exclaim: return UO_LNot; case OO_Coawait: return UO_Coawait; } } OverloadedOperatorKind UnaryOperator::getOverloadedOperator(Opcode Opc) { switch (Opc) { case UO_PostInc: case UO_PreInc: return OO_PlusPlus; case UO_PostDec: case UO_PreDec: return OO_MinusMinus; case UO_AddrOf: return OO_Amp; case UO_Deref: return OO_Star; case UO_Plus: return OO_Plus; case UO_Minus: return OO_Minus; case UO_Not: return OO_Tilde; case UO_LNot: return OO_Exclaim; case UO_Coawait: return OO_Coawait; default: return OO_None; } } //===----------------------------------------------------------------------===// // Postfix Operators. //===----------------------------------------------------------------------===// CallExpr::CallExpr(StmtClass SC, Expr *Fn, ArrayRef PreArgs, ArrayRef Args, QualType Ty, ExprValueKind VK, SourceLocation RParenLoc, unsigned MinNumArgs, ADLCallKind UsesADL) : Expr(SC, Ty, VK, OK_Ordinary, Fn->isTypeDependent(), Fn->isValueDependent(), Fn->isInstantiationDependent(), Fn->containsUnexpandedParameterPack()), RParenLoc(RParenLoc) { NumArgs = std::max(Args.size(), MinNumArgs); unsigned NumPreArgs = PreArgs.size(); CallExprBits.NumPreArgs = NumPreArgs; assert((NumPreArgs == getNumPreArgs()) && "NumPreArgs overflow!"); unsigned OffsetToTrailingObjects = offsetToTrailingObjects(SC); CallExprBits.OffsetToTrailingObjects = OffsetToTrailingObjects; assert((CallExprBits.OffsetToTrailingObjects == OffsetToTrailingObjects) && "OffsetToTrailingObjects overflow!"); CallExprBits.UsesADL = static_cast(UsesADL); setCallee(Fn); for (unsigned I = 0; I != NumPreArgs; ++I) { updateDependenciesFromArg(PreArgs[I]); setPreArg(I, PreArgs[I]); } for (unsigned I = 0; I != Args.size(); ++I) { updateDependenciesFromArg(Args[I]); setArg(I, Args[I]); } for (unsigned I = Args.size(); I != NumArgs; ++I) { setArg(I, nullptr); } } CallExpr::CallExpr(StmtClass SC, unsigned NumPreArgs, unsigned NumArgs, EmptyShell Empty) : Expr(SC, Empty), NumArgs(NumArgs) { CallExprBits.NumPreArgs = NumPreArgs; assert((NumPreArgs == getNumPreArgs()) && "NumPreArgs overflow!"); unsigned OffsetToTrailingObjects = offsetToTrailingObjects(SC); CallExprBits.OffsetToTrailingObjects = OffsetToTrailingObjects; assert((CallExprBits.OffsetToTrailingObjects == OffsetToTrailingObjects) && "OffsetToTrailingObjects overflow!"); } CallExpr *CallExpr::Create(const ASTContext &Ctx, Expr *Fn, ArrayRef Args, QualType Ty, ExprValueKind VK, SourceLocation RParenLoc, unsigned MinNumArgs, ADLCallKind UsesADL) { unsigned NumArgs = std::max(Args.size(), MinNumArgs); unsigned SizeOfTrailingObjects = CallExpr::sizeOfTrailingObjects(/*NumPreArgs=*/0, NumArgs); void *Mem = Ctx.Allocate(sizeof(CallExpr) + SizeOfTrailingObjects, alignof(CallExpr)); return new (Mem) CallExpr(CallExprClass, Fn, /*PreArgs=*/{}, Args, Ty, VK, RParenLoc, MinNumArgs, UsesADL); } CallExpr *CallExpr::CreateTemporary(void *Mem, Expr *Fn, QualType Ty, ExprValueKind VK, SourceLocation RParenLoc, ADLCallKind UsesADL) { assert(!(reinterpret_cast(Mem) % alignof(CallExpr)) && "Misaligned memory in CallExpr::CreateTemporary!"); return new (Mem) CallExpr(CallExprClass, Fn, /*PreArgs=*/{}, /*Args=*/{}, Ty, VK, RParenLoc, /*MinNumArgs=*/0, UsesADL); } CallExpr *CallExpr::CreateEmpty(const ASTContext &Ctx, unsigned NumArgs, EmptyShell Empty) { unsigned SizeOfTrailingObjects = CallExpr::sizeOfTrailingObjects(/*NumPreArgs=*/0, NumArgs); void *Mem = Ctx.Allocate(sizeof(CallExpr) + SizeOfTrailingObjects, alignof(CallExpr)); return new (Mem) CallExpr(CallExprClass, /*NumPreArgs=*/0, NumArgs, Empty); } unsigned CallExpr::offsetToTrailingObjects(StmtClass SC) { switch (SC) { case CallExprClass: return sizeof(CallExpr); case CXXOperatorCallExprClass: return sizeof(CXXOperatorCallExpr); case CXXMemberCallExprClass: return sizeof(CXXMemberCallExpr); case UserDefinedLiteralClass: return sizeof(UserDefinedLiteral); case CUDAKernelCallExprClass: return sizeof(CUDAKernelCallExpr); default: llvm_unreachable("unexpected class deriving from CallExpr!"); } } void CallExpr::updateDependenciesFromArg(Expr *Arg) { if (Arg->isTypeDependent()) ExprBits.TypeDependent = true; if (Arg->isValueDependent()) ExprBits.ValueDependent = true; if (Arg->isInstantiationDependent()) ExprBits.InstantiationDependent = true; if (Arg->containsUnexpandedParameterPack()) ExprBits.ContainsUnexpandedParameterPack = true; } Decl *Expr::getReferencedDeclOfCallee() { Expr *CEE = IgnoreParenImpCasts(); while (SubstNonTypeTemplateParmExpr *NTTP = dyn_cast(CEE)) { CEE = NTTP->getReplacement()->IgnoreParenCasts(); } // If we're calling a dereference, look at the pointer instead. if (BinaryOperator *BO = dyn_cast(CEE)) { if (BO->isPtrMemOp()) CEE = BO->getRHS()->IgnoreParenCasts(); } else if (UnaryOperator *UO = dyn_cast(CEE)) { if (UO->getOpcode() == UO_Deref) CEE = UO->getSubExpr()->IgnoreParenCasts(); } if (DeclRefExpr *DRE = dyn_cast(CEE)) return DRE->getDecl(); if (MemberExpr *ME = dyn_cast(CEE)) return ME->getMemberDecl(); if (auto *BE = dyn_cast(CEE)) return BE->getBlockDecl(); return nullptr; } /// getBuiltinCallee - If this is a call to a builtin, return the builtin ID. If /// not, return 0. unsigned CallExpr::getBuiltinCallee() const { // All simple function calls (e.g. func()) are implicitly cast to pointer to // function. As a result, we try and obtain the DeclRefExpr from the // ImplicitCastExpr. const ImplicitCastExpr *ICE = dyn_cast(getCallee()); if (!ICE) // FIXME: deal with more complex calls (e.g. (func)(), (*func)()). return 0; const DeclRefExpr *DRE = dyn_cast(ICE->getSubExpr()); if (!DRE) return 0; const FunctionDecl *FDecl = dyn_cast(DRE->getDecl()); if (!FDecl) return 0; if (!FDecl->getIdentifier()) return 0; return FDecl->getBuiltinID(); } bool CallExpr::isUnevaluatedBuiltinCall(const ASTContext &Ctx) const { if (unsigned BI = getBuiltinCallee()) return Ctx.BuiltinInfo.isUnevaluated(BI); return false; } QualType CallExpr::getCallReturnType(const ASTContext &Ctx) const { const Expr *Callee = getCallee(); QualType CalleeType = Callee->getType(); if (const auto *FnTypePtr = CalleeType->getAs()) { CalleeType = FnTypePtr->getPointeeType(); } else if (const auto *BPT = CalleeType->getAs()) { CalleeType = BPT->getPointeeType(); } else if (CalleeType->isSpecificPlaceholderType(BuiltinType::BoundMember)) { if (isa(Callee->IgnoreParens())) return Ctx.VoidTy; // This should never be overloaded and so should never return null. CalleeType = Expr::findBoundMemberType(Callee); } const FunctionType *FnType = CalleeType->castAs(); return FnType->getReturnType(); } const Attr *CallExpr::getUnusedResultAttr(const ASTContext &Ctx) const { // If the return type is a struct, union, or enum that is marked nodiscard, // then return the return type attribute. if (const TagDecl *TD = getCallReturnType(Ctx)->getAsTagDecl()) if (const auto *A = TD->getAttr()) return A; // Otherwise, see if the callee is marked nodiscard and return that attribute // instead. const Decl *D = getCalleeDecl(); return D ? D->getAttr() : nullptr; } SourceLocation CallExpr::getBeginLoc() const { if (isa(this)) return cast(this)->getBeginLoc(); SourceLocation begin = getCallee()->getBeginLoc(); if (begin.isInvalid() && getNumArgs() > 0 && getArg(0)) begin = getArg(0)->getBeginLoc(); return begin; } SourceLocation CallExpr::getEndLoc() const { if (isa(this)) return cast(this)->getEndLoc(); SourceLocation end = getRParenLoc(); if (end.isInvalid() && getNumArgs() > 0 && getArg(getNumArgs() - 1)) end = getArg(getNumArgs() - 1)->getEndLoc(); return end; } OffsetOfExpr *OffsetOfExpr::Create(const ASTContext &C, QualType type, SourceLocation OperatorLoc, TypeSourceInfo *tsi, ArrayRef comps, ArrayRef exprs, SourceLocation RParenLoc) { void *Mem = C.Allocate( totalSizeToAlloc(comps.size(), exprs.size())); return new (Mem) OffsetOfExpr(C, type, OperatorLoc, tsi, comps, exprs, RParenLoc); } OffsetOfExpr *OffsetOfExpr::CreateEmpty(const ASTContext &C, unsigned numComps, unsigned numExprs) { void *Mem = C.Allocate(totalSizeToAlloc(numComps, numExprs)); return new (Mem) OffsetOfExpr(numComps, numExprs); } OffsetOfExpr::OffsetOfExpr(const ASTContext &C, QualType type, SourceLocation OperatorLoc, TypeSourceInfo *tsi, ArrayRef comps, ArrayRef exprs, SourceLocation RParenLoc) : Expr(OffsetOfExprClass, type, VK_RValue, OK_Ordinary, /*TypeDependent=*/false, /*ValueDependent=*/tsi->getType()->isDependentType(), tsi->getType()->isInstantiationDependentType(), tsi->getType()->containsUnexpandedParameterPack()), OperatorLoc(OperatorLoc), RParenLoc(RParenLoc), TSInfo(tsi), NumComps(comps.size()), NumExprs(exprs.size()) { for (unsigned i = 0; i != comps.size(); ++i) { setComponent(i, comps[i]); } for (unsigned i = 0; i != exprs.size(); ++i) { if (exprs[i]->isTypeDependent() || exprs[i]->isValueDependent()) ExprBits.ValueDependent = true; if (exprs[i]->containsUnexpandedParameterPack()) ExprBits.ContainsUnexpandedParameterPack = true; setIndexExpr(i, exprs[i]); } } IdentifierInfo *OffsetOfNode::getFieldName() const { assert(getKind() == Field || getKind() == Identifier); if (getKind() == Field) return getField()->getIdentifier(); return reinterpret_cast (Data & ~(uintptr_t)Mask); } UnaryExprOrTypeTraitExpr::UnaryExprOrTypeTraitExpr( UnaryExprOrTypeTrait ExprKind, Expr *E, 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. E->isTypeDependent(), E->isInstantiationDependent(), E->containsUnexpandedParameterPack()), OpLoc(op), RParenLoc(rp) { UnaryExprOrTypeTraitExprBits.Kind = ExprKind; UnaryExprOrTypeTraitExprBits.IsType = false; Argument.Ex = E; // Check to see if we are in the situation where alignof(decl) should be // dependent because decl's alignment is dependent. if (ExprKind == UETT_AlignOf || ExprKind == UETT_PreferredAlignOf) { if (!isValueDependent() || !isInstantiationDependent()) { E = E->IgnoreParens(); const ValueDecl *D = nullptr; if (const auto *DRE = dyn_cast(E)) D = DRE->getDecl(); else if (const auto *ME = dyn_cast(E)) D = ME->getMemberDecl(); if (D) { for (const auto *I : D->specific_attrs()) { if (I->isAlignmentDependent()) { setValueDependent(true); setInstantiationDependent(true); break; } } } } } } MemberExpr::MemberExpr(Expr *Base, bool IsArrow, SourceLocation OperatorLoc, ValueDecl *MemberDecl, const DeclarationNameInfo &NameInfo, QualType T, ExprValueKind VK, ExprObjectKind OK, NonOdrUseReason NOUR) : Expr(MemberExprClass, T, VK, OK, Base->isTypeDependent(), Base->isValueDependent(), Base->isInstantiationDependent(), Base->containsUnexpandedParameterPack()), Base(Base), MemberDecl(MemberDecl), MemberDNLoc(NameInfo.getInfo()), MemberLoc(NameInfo.getLoc()) { assert(!NameInfo.getName() || MemberDecl->getDeclName() == NameInfo.getName()); MemberExprBits.IsArrow = IsArrow; MemberExprBits.HasQualifierOrFoundDecl = false; MemberExprBits.HasTemplateKWAndArgsInfo = false; MemberExprBits.HadMultipleCandidates = false; MemberExprBits.NonOdrUseReason = NOUR; MemberExprBits.OperatorLoc = OperatorLoc; } MemberExpr *MemberExpr::Create( const ASTContext &C, Expr *Base, bool IsArrow, SourceLocation OperatorLoc, NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateKWLoc, ValueDecl *MemberDecl, DeclAccessPair FoundDecl, DeclarationNameInfo NameInfo, const TemplateArgumentListInfo *TemplateArgs, QualType T, ExprValueKind VK, ExprObjectKind OK, NonOdrUseReason NOUR) { bool HasQualOrFound = QualifierLoc || FoundDecl.getDecl() != MemberDecl || FoundDecl.getAccess() != MemberDecl->getAccess(); bool HasTemplateKWAndArgsInfo = TemplateArgs || TemplateKWLoc.isValid(); std::size_t Size = totalSizeToAlloc( HasQualOrFound ? 1 : 0, HasTemplateKWAndArgsInfo ? 1 : 0, TemplateArgs ? TemplateArgs->size() : 0); void *Mem = C.Allocate(Size, alignof(MemberExpr)); MemberExpr *E = new (Mem) MemberExpr(Base, IsArrow, OperatorLoc, MemberDecl, NameInfo, T, VK, OK, NOUR); if (HasQualOrFound) { // FIXME: Wrong. We should be looking at the member declaration we found. if (QualifierLoc && QualifierLoc.getNestedNameSpecifier()->isDependent()) { E->setValueDependent(true); E->setTypeDependent(true); E->setInstantiationDependent(true); } else if (QualifierLoc && QualifierLoc.getNestedNameSpecifier()->isInstantiationDependent()) E->setInstantiationDependent(true); E->MemberExprBits.HasQualifierOrFoundDecl = true; MemberExprNameQualifier *NQ = E->getTrailingObjects(); NQ->QualifierLoc = QualifierLoc; NQ->FoundDecl = FoundDecl; } E->MemberExprBits.HasTemplateKWAndArgsInfo = TemplateArgs || TemplateKWLoc.isValid(); if (TemplateArgs) { bool Dependent = false; bool InstantiationDependent = false; bool ContainsUnexpandedParameterPack = false; E->getTrailingObjects()->initializeFrom( TemplateKWLoc, *TemplateArgs, E->getTrailingObjects(), Dependent, InstantiationDependent, ContainsUnexpandedParameterPack); if (InstantiationDependent) E->setInstantiationDependent(true); } else if (TemplateKWLoc.isValid()) { E->getTrailingObjects()->initializeFrom( TemplateKWLoc); } return E; } MemberExpr *MemberExpr::CreateEmpty(const ASTContext &Context, bool HasQualifier, bool HasFoundDecl, bool HasTemplateKWAndArgsInfo, unsigned NumTemplateArgs) { assert((!NumTemplateArgs || HasTemplateKWAndArgsInfo) && "template args but no template arg info?"); bool HasQualOrFound = HasQualifier || HasFoundDecl; std::size_t Size = totalSizeToAlloc(HasQualOrFound ? 1 : 0, HasTemplateKWAndArgsInfo ? 1 : 0, NumTemplateArgs); void *Mem = Context.Allocate(Size, alignof(MemberExpr)); return new (Mem) MemberExpr(EmptyShell()); } SourceLocation MemberExpr::getBeginLoc() const { if (isImplicitAccess()) { if (hasQualifier()) return getQualifierLoc().getBeginLoc(); return MemberLoc; } // FIXME: We don't want this to happen. Rather, we should be able to // detect all kinds of implicit accesses more cleanly. SourceLocation BaseStartLoc = getBase()->getBeginLoc(); if (BaseStartLoc.isValid()) return BaseStartLoc; return MemberLoc; } SourceLocation MemberExpr::getEndLoc() const { SourceLocation EndLoc = getMemberNameInfo().getEndLoc(); if (hasExplicitTemplateArgs()) EndLoc = getRAngleLoc(); else if (EndLoc.isInvalid()) EndLoc = getBase()->getEndLoc(); return EndLoc; } bool CastExpr::CastConsistency() const { switch (getCastKind()) { case CK_DerivedToBase: case CK_UncheckedDerivedToBase: case CK_DerivedToBaseMemberPointer: case CK_BaseToDerived: case CK_BaseToDerivedMemberPointer: assert(!path_empty() && "Cast kind should have a base path!"); break; case CK_CPointerToObjCPointerCast: assert(getType()->isObjCObjectPointerType()); assert(getSubExpr()->getType()->isPointerType()); goto CheckNoBasePath; case CK_BlockPointerToObjCPointerCast: assert(getType()->isObjCObjectPointerType()); assert(getSubExpr()->getType()->isBlockPointerType()); goto CheckNoBasePath; case CK_ReinterpretMemberPointer: assert(getType()->isMemberPointerType()); assert(getSubExpr()->getType()->isMemberPointerType()); goto CheckNoBasePath; case CK_BitCast: // Arbitrary casts to C pointer types count as bitcasts. // Otherwise, we should only have block and ObjC pointer casts // here if they stay within the type kind. if (!getType()->isPointerType()) { assert(getType()->isObjCObjectPointerType() == getSubExpr()->getType()->isObjCObjectPointerType()); assert(getType()->isBlockPointerType() == getSubExpr()->getType()->isBlockPointerType()); } goto CheckNoBasePath; case CK_AnyPointerToBlockPointerCast: assert(getType()->isBlockPointerType()); assert(getSubExpr()->getType()->isAnyPointerType() && !getSubExpr()->getType()->isBlockPointerType()); goto CheckNoBasePath; case CK_CopyAndAutoreleaseBlockObject: assert(getType()->isBlockPointerType()); assert(getSubExpr()->getType()->isBlockPointerType()); goto CheckNoBasePath; case CK_FunctionToPointerDecay: assert(getType()->isPointerType()); assert(getSubExpr()->getType()->isFunctionType()); goto CheckNoBasePath; case CK_AddressSpaceConversion: { auto Ty = getType(); auto SETy = getSubExpr()->getType(); assert(getValueKindForType(Ty) == Expr::getValueKindForType(SETy)); - if (/*isRValue()*/ !Ty->getPointeeType().isNull()) { + if (isRValue()) { Ty = Ty->getPointeeType(); SETy = SETy->getPointeeType(); } assert(!Ty.isNull() && !SETy.isNull() && Ty.getAddressSpace() != SETy.getAddressSpace()); goto CheckNoBasePath; } // These should not have an inheritance path. case CK_Dynamic: case CK_ToUnion: case CK_ArrayToPointerDecay: case CK_NullToMemberPointer: case CK_NullToPointer: case CK_ConstructorConversion: case CK_IntegralToPointer: case CK_PointerToIntegral: case CK_ToVoid: case CK_VectorSplat: case CK_IntegralCast: case CK_BooleanToSignedIntegral: case CK_IntegralToFloating: case CK_FloatingToIntegral: case CK_FloatingCast: case CK_ObjCObjectLValueCast: case CK_FloatingRealToComplex: case CK_FloatingComplexToReal: case CK_FloatingComplexCast: case CK_FloatingComplexToIntegralComplex: case CK_IntegralRealToComplex: case CK_IntegralComplexToReal: case CK_IntegralComplexCast: case CK_IntegralComplexToFloatingComplex: case CK_ARCProduceObject: case CK_ARCConsumeObject: case CK_ARCReclaimReturnedObject: case CK_ARCExtendBlockObject: case CK_ZeroToOCLOpaqueType: case CK_IntToOCLSampler: case CK_FixedPointCast: case CK_FixedPointToIntegral: case CK_IntegralToFixedPoint: assert(!getType()->isBooleanType() && "unheralded conversion to bool"); goto CheckNoBasePath; case CK_Dependent: case CK_LValueToRValue: case CK_NoOp: case CK_AtomicToNonAtomic: case CK_NonAtomicToAtomic: case CK_PointerToBoolean: case CK_IntegralToBoolean: case CK_FloatingToBoolean: case CK_MemberPointerToBoolean: case CK_FloatingComplexToBoolean: case CK_IntegralComplexToBoolean: case CK_LValueBitCast: // -> bool& case CK_LValueToRValueBitCast: case CK_UserDefinedConversion: // operator bool() case CK_BuiltinFnToFnPtr: case CK_FixedPointToBoolean: CheckNoBasePath: assert(path_empty() && "Cast kind should not have a base path!"); break; } return true; } const char *CastExpr::getCastKindName(CastKind CK) { switch (CK) { #define CAST_OPERATION(Name) case CK_##Name: return #Name; #include "clang/AST/OperationKinds.def" } llvm_unreachable("Unhandled cast kind!"); } namespace { const Expr *skipImplicitTemporary(const Expr *E) { // Skip through reference binding to temporary. if (auto *Materialize = dyn_cast(E)) E = Materialize->getSubExpr(); // Skip any temporary bindings; they're implicit. if (auto *Binder = dyn_cast(E)) E = Binder->getSubExpr(); return E; } } Expr *CastExpr::getSubExprAsWritten() { const Expr *SubExpr = nullptr; const CastExpr *E = this; do { SubExpr = skipImplicitTemporary(E->getSubExpr()); // Conversions by constructor and conversion functions have a // subexpression describing the call; strip it off. if (E->getCastKind() == CK_ConstructorConversion) SubExpr = skipImplicitTemporary(cast(SubExpr)->getArg(0)); else if (E->getCastKind() == CK_UserDefinedConversion) { assert((isa(SubExpr) || isa(SubExpr)) && "Unexpected SubExpr for CK_UserDefinedConversion."); if (auto *MCE = dyn_cast(SubExpr)) SubExpr = MCE->getImplicitObjectArgument(); } // If the subexpression we're left with is an implicit cast, look // through that, too. } while ((E = dyn_cast(SubExpr))); return const_cast(SubExpr); } NamedDecl *CastExpr::getConversionFunction() const { const Expr *SubExpr = nullptr; for (const CastExpr *E = this; E; E = dyn_cast(SubExpr)) { SubExpr = skipImplicitTemporary(E->getSubExpr()); if (E->getCastKind() == CK_ConstructorConversion) return cast(SubExpr)->getConstructor(); if (E->getCastKind() == CK_UserDefinedConversion) { if (auto *MCE = dyn_cast(SubExpr)) return MCE->getMethodDecl(); } } return nullptr; } CXXBaseSpecifier **CastExpr::path_buffer() { switch (getStmtClass()) { #define ABSTRACT_STMT(x) #define CASTEXPR(Type, Base) \ case Stmt::Type##Class: \ return static_cast(this)->getTrailingObjects(); #define STMT(Type, Base) #include "clang/AST/StmtNodes.inc" default: llvm_unreachable("non-cast expressions not possible here"); } } const FieldDecl *CastExpr::getTargetFieldForToUnionCast(QualType unionType, QualType opType) { auto RD = unionType->castAs()->getDecl(); return getTargetFieldForToUnionCast(RD, opType); } const FieldDecl *CastExpr::getTargetFieldForToUnionCast(const RecordDecl *RD, QualType OpType) { auto &Ctx = RD->getASTContext(); RecordDecl::field_iterator Field, FieldEnd; for (Field = RD->field_begin(), FieldEnd = RD->field_end(); Field != FieldEnd; ++Field) { if (Ctx.hasSameUnqualifiedType(Field->getType(), OpType) && !Field->isUnnamedBitfield()) { return *Field; } } return nullptr; } ImplicitCastExpr *ImplicitCastExpr::Create(const ASTContext &C, QualType T, CastKind Kind, Expr *Operand, const CXXCastPath *BasePath, ExprValueKind VK) { unsigned PathSize = (BasePath ? BasePath->size() : 0); void *Buffer = C.Allocate(totalSizeToAlloc(PathSize)); // Per C++ [conv.lval]p3, lvalue-to-rvalue conversions on class and // std::nullptr_t have special semantics not captured by CK_LValueToRValue. assert((Kind != CK_LValueToRValue || !(T->isNullPtrType() || T->getAsCXXRecordDecl())) && "invalid type for lvalue-to-rvalue conversion"); ImplicitCastExpr *E = new (Buffer) ImplicitCastExpr(T, Kind, Operand, PathSize, VK); if (PathSize) std::uninitialized_copy_n(BasePath->data(), BasePath->size(), E->getTrailingObjects()); return E; } ImplicitCastExpr *ImplicitCastExpr::CreateEmpty(const ASTContext &C, unsigned PathSize) { void *Buffer = C.Allocate(totalSizeToAlloc(PathSize)); return new (Buffer) ImplicitCastExpr(EmptyShell(), PathSize); } CStyleCastExpr *CStyleCastExpr::Create(const ASTContext &C, QualType T, ExprValueKind VK, CastKind K, Expr *Op, const CXXCastPath *BasePath, TypeSourceInfo *WrittenTy, SourceLocation L, SourceLocation R) { unsigned PathSize = (BasePath ? BasePath->size() : 0); void *Buffer = C.Allocate(totalSizeToAlloc(PathSize)); CStyleCastExpr *E = new (Buffer) CStyleCastExpr(T, VK, K, Op, PathSize, WrittenTy, L, R); if (PathSize) std::uninitialized_copy_n(BasePath->data(), BasePath->size(), E->getTrailingObjects()); return E; } CStyleCastExpr *CStyleCastExpr::CreateEmpty(const ASTContext &C, unsigned PathSize) { void *Buffer = C.Allocate(totalSizeToAlloc(PathSize)); return new (Buffer) CStyleCastExpr(EmptyShell(), PathSize); } /// getOpcodeStr - Turn an Opcode enum value into the punctuation char it /// corresponds to, e.g. "<<=". StringRef BinaryOperator::getOpcodeStr(Opcode Op) { switch (Op) { #define BINARY_OPERATION(Name, Spelling) case BO_##Name: return Spelling; #include "clang/AST/OperationKinds.def" } llvm_unreachable("Invalid OpCode!"); } BinaryOperatorKind BinaryOperator::getOverloadedOpcode(OverloadedOperatorKind OO) { switch (OO) { default: llvm_unreachable("Not an overloadable binary operator"); case OO_Plus: return BO_Add; case OO_Minus: return BO_Sub; case OO_Star: return BO_Mul; case OO_Slash: return BO_Div; case OO_Percent: return BO_Rem; case OO_Caret: return BO_Xor; case OO_Amp: return BO_And; case OO_Pipe: return BO_Or; case OO_Equal: return BO_Assign; case OO_Spaceship: return BO_Cmp; case OO_Less: return BO_LT; case OO_Greater: return BO_GT; case OO_PlusEqual: return BO_AddAssign; case OO_MinusEqual: return BO_SubAssign; case OO_StarEqual: return BO_MulAssign; case OO_SlashEqual: return BO_DivAssign; case OO_PercentEqual: return BO_RemAssign; case OO_CaretEqual: return BO_XorAssign; case OO_AmpEqual: return BO_AndAssign; case OO_PipeEqual: return BO_OrAssign; case OO_LessLess: return BO_Shl; case OO_GreaterGreater: return BO_Shr; case OO_LessLessEqual: return BO_ShlAssign; case OO_GreaterGreaterEqual: return BO_ShrAssign; case OO_EqualEqual: return BO_EQ; case OO_ExclaimEqual: return BO_NE; case OO_LessEqual: return BO_LE; case OO_GreaterEqual: return BO_GE; case OO_AmpAmp: return BO_LAnd; case OO_PipePipe: return BO_LOr; case OO_Comma: return BO_Comma; case OO_ArrowStar: return BO_PtrMemI; } } OverloadedOperatorKind BinaryOperator::getOverloadedOperator(Opcode Opc) { static const OverloadedOperatorKind OverOps[] = { /* .* Cannot be overloaded */OO_None, OO_ArrowStar, OO_Star, OO_Slash, OO_Percent, OO_Plus, OO_Minus, OO_LessLess, OO_GreaterGreater, OO_Spaceship, OO_Less, OO_Greater, OO_LessEqual, OO_GreaterEqual, OO_EqualEqual, OO_ExclaimEqual, OO_Amp, OO_Caret, OO_Pipe, OO_AmpAmp, OO_PipePipe, OO_Equal, OO_StarEqual, OO_SlashEqual, OO_PercentEqual, OO_PlusEqual, OO_MinusEqual, OO_LessLessEqual, OO_GreaterGreaterEqual, OO_AmpEqual, OO_CaretEqual, OO_PipeEqual, OO_Comma }; return OverOps[Opc]; } bool BinaryOperator::isNullPointerArithmeticExtension(ASTContext &Ctx, Opcode Opc, Expr *LHS, Expr *RHS) { if (Opc != BO_Add) return false; // Check that we have one pointer and one integer operand. Expr *PExp; if (LHS->getType()->isPointerType()) { if (!RHS->getType()->isIntegerType()) return false; PExp = LHS; } else if (RHS->getType()->isPointerType()) { if (!LHS->getType()->isIntegerType()) return false; PExp = RHS; } else { return false; } // Check that the pointer is a nullptr. if (!PExp->IgnoreParenCasts() ->isNullPointerConstant(Ctx, Expr::NPC_ValueDependentIsNotNull)) return false; // Check that the pointee type is char-sized. const PointerType *PTy = PExp->getType()->getAs(); if (!PTy || !PTy->getPointeeType()->isCharType()) return false; return true; } static QualType getDecayedSourceLocExprType(const ASTContext &Ctx, SourceLocExpr::IdentKind Kind) { switch (Kind) { case SourceLocExpr::File: case SourceLocExpr::Function: { QualType ArrTy = Ctx.getStringLiteralArrayType(Ctx.CharTy, 0); return Ctx.getPointerType(ArrTy->getAsArrayTypeUnsafe()->getElementType()); } case SourceLocExpr::Line: case SourceLocExpr::Column: return Ctx.UnsignedIntTy; } llvm_unreachable("unhandled case"); } SourceLocExpr::SourceLocExpr(const ASTContext &Ctx, IdentKind Kind, SourceLocation BLoc, SourceLocation RParenLoc, DeclContext *ParentContext) : Expr(SourceLocExprClass, getDecayedSourceLocExprType(Ctx, Kind), VK_RValue, OK_Ordinary, false, false, false, false), BuiltinLoc(BLoc), RParenLoc(RParenLoc), ParentContext(ParentContext) { SourceLocExprBits.Kind = Kind; } StringRef SourceLocExpr::getBuiltinStr() const { switch (getIdentKind()) { case File: return "__builtin_FILE"; case Function: return "__builtin_FUNCTION"; case Line: return "__builtin_LINE"; case Column: return "__builtin_COLUMN"; } llvm_unreachable("unexpected IdentKind!"); } APValue SourceLocExpr::EvaluateInContext(const ASTContext &Ctx, const Expr *DefaultExpr) const { SourceLocation Loc; const DeclContext *Context; std::tie(Loc, Context) = [&]() -> std::pair { if (auto *DIE = dyn_cast_or_null(DefaultExpr)) return {DIE->getUsedLocation(), DIE->getUsedContext()}; if (auto *DAE = dyn_cast_or_null(DefaultExpr)) return {DAE->getUsedLocation(), DAE->getUsedContext()}; return {this->getLocation(), this->getParentContext()}; }(); PresumedLoc PLoc = Ctx.getSourceManager().getPresumedLoc( Ctx.getSourceManager().getExpansionRange(Loc).getEnd()); auto MakeStringLiteral = [&](StringRef Tmp) { using LValuePathEntry = APValue::LValuePathEntry; StringLiteral *Res = Ctx.getPredefinedStringLiteralFromCache(Tmp); // Decay the string to a pointer to the first character. LValuePathEntry Path[1] = {LValuePathEntry::ArrayIndex(0)}; return APValue(Res, CharUnits::Zero(), Path, /*OnePastTheEnd=*/false); }; switch (getIdentKind()) { case SourceLocExpr::File: return MakeStringLiteral(PLoc.getFilename()); case SourceLocExpr::Function: { const Decl *CurDecl = dyn_cast_or_null(Context); return MakeStringLiteral( CurDecl ? PredefinedExpr::ComputeName(PredefinedExpr::Function, CurDecl) : std::string("")); } case SourceLocExpr::Line: case SourceLocExpr::Column: { llvm::APSInt IntVal(Ctx.getIntWidth(Ctx.UnsignedIntTy), /*isUnsigned=*/true); IntVal = getIdentKind() == SourceLocExpr::Line ? PLoc.getLine() : PLoc.getColumn(); return APValue(IntVal); } } llvm_unreachable("unhandled case"); } InitListExpr::InitListExpr(const ASTContext &C, SourceLocation lbraceloc, ArrayRef initExprs, SourceLocation rbraceloc) : Expr(InitListExprClass, QualType(), VK_RValue, OK_Ordinary, false, false, false, false), InitExprs(C, initExprs.size()), LBraceLoc(lbraceloc), RBraceLoc(rbraceloc), AltForm(nullptr, true) { sawArrayRangeDesignator(false); for (unsigned I = 0; I != initExprs.size(); ++I) { if (initExprs[I]->isTypeDependent()) ExprBits.TypeDependent = true; if (initExprs[I]->isValueDependent()) ExprBits.ValueDependent = true; if (initExprs[I]->isInstantiationDependent()) ExprBits.InstantiationDependent = true; if (initExprs[I]->containsUnexpandedParameterPack()) ExprBits.ContainsUnexpandedParameterPack = true; } InitExprs.insert(C, InitExprs.end(), initExprs.begin(), initExprs.end()); } void InitListExpr::reserveInits(const ASTContext &C, unsigned NumInits) { if (NumInits > InitExprs.size()) InitExprs.reserve(C, NumInits); } void InitListExpr::resizeInits(const ASTContext &C, unsigned NumInits) { InitExprs.resize(C, NumInits, nullptr); } Expr *InitListExpr::updateInit(const ASTContext &C, unsigned Init, Expr *expr) { if (Init >= InitExprs.size()) { InitExprs.insert(C, InitExprs.end(), Init - InitExprs.size() + 1, nullptr); setInit(Init, expr); return nullptr; } Expr *Result = cast_or_null(InitExprs[Init]); setInit(Init, expr); return Result; } void InitListExpr::setArrayFiller(Expr *filler) { assert(!hasArrayFiller() && "Filler already set!"); ArrayFillerOrUnionFieldInit = filler; // Fill out any "holes" in the array due to designated initializers. Expr **inits = getInits(); for (unsigned i = 0, e = getNumInits(); i != e; ++i) if (inits[i] == nullptr) inits[i] = filler; } bool InitListExpr::isStringLiteralInit() const { if (getNumInits() != 1) return false; const ArrayType *AT = getType()->getAsArrayTypeUnsafe(); if (!AT || !AT->getElementType()->isIntegerType()) return false; // It is possible for getInit() to return null. const Expr *Init = getInit(0); if (!Init) return false; Init = Init->IgnoreParens(); return isa(Init) || isa(Init); } bool InitListExpr::isTransparent() const { assert(isSemanticForm() && "syntactic form never semantically transparent"); // A glvalue InitListExpr is always just sugar. if (isGLValue()) { assert(getNumInits() == 1 && "multiple inits in glvalue init list"); return true; } // Otherwise, we're sugar if and only if we have exactly one initializer that // is of the same type. if (getNumInits() != 1 || !getInit(0)) return false; // Don't confuse aggregate initialization of a struct X { X &x; }; with a // transparent struct copy. if (!getInit(0)->isRValue() && getType()->isRecordType()) return false; return getType().getCanonicalType() == getInit(0)->getType().getCanonicalType(); } bool InitListExpr::isIdiomaticZeroInitializer(const LangOptions &LangOpts) const { assert(isSyntacticForm() && "only test syntactic form as zero initializer"); if (LangOpts.CPlusPlus || getNumInits() != 1 || !getInit(0)) { return false; } const IntegerLiteral *Lit = dyn_cast(getInit(0)->IgnoreImplicit()); return Lit && Lit->getValue() == 0; } SourceLocation InitListExpr::getBeginLoc() const { if (InitListExpr *SyntacticForm = getSyntacticForm()) return SyntacticForm->getBeginLoc(); SourceLocation Beg = LBraceLoc; if (Beg.isInvalid()) { // Find the first non-null initializer. for (InitExprsTy::const_iterator I = InitExprs.begin(), E = InitExprs.end(); I != E; ++I) { if (Stmt *S = *I) { Beg = S->getBeginLoc(); break; } } } return Beg; } SourceLocation InitListExpr::getEndLoc() const { if (InitListExpr *SyntacticForm = getSyntacticForm()) return SyntacticForm->getEndLoc(); SourceLocation End = RBraceLoc; if (End.isInvalid()) { // Find the first non-null initializer from the end. for (InitExprsTy::const_reverse_iterator I = InitExprs.rbegin(), E = InitExprs.rend(); I != E; ++I) { if (Stmt *S = *I) { End = S->getEndLoc(); break; } } } return End; } /// getFunctionType - Return the underlying function type for this block. /// const FunctionProtoType *BlockExpr::getFunctionType() const { // The block pointer is never sugared, but the function type might be. return cast(getType()) ->getPointeeType()->castAs(); } SourceLocation BlockExpr::getCaretLocation() const { return TheBlock->getCaretLocation(); } const Stmt *BlockExpr::getBody() const { return TheBlock->getBody(); } Stmt *BlockExpr::getBody() { return TheBlock->getBody(); } //===----------------------------------------------------------------------===// // Generic Expression Routines //===----------------------------------------------------------------------===// /// isUnusedResultAWarning - Return true if this immediate expression should /// be warned about if the result is unused. If so, fill in Loc and Ranges /// with location to warn on and the source range[s] to report with the /// warning. bool Expr::isUnusedResultAWarning(const Expr *&WarnE, SourceLocation &Loc, SourceRange &R1, SourceRange &R2, ASTContext &Ctx) const { // Don't warn if the expr is type dependent. The type could end up // instantiating to void. if (isTypeDependent()) return false; switch (getStmtClass()) { default: if (getType()->isVoidType()) return false; WarnE = this; Loc = getExprLoc(); R1 = getSourceRange(); return true; case ParenExprClass: return cast(this)->getSubExpr()-> isUnusedResultAWarning(WarnE, Loc, R1, R2, Ctx); case GenericSelectionExprClass: return cast(this)->getResultExpr()-> isUnusedResultAWarning(WarnE, Loc, R1, R2, Ctx); case CoawaitExprClass: case CoyieldExprClass: return cast(this)->getResumeExpr()-> isUnusedResultAWarning(WarnE, Loc, R1, R2, Ctx); case ChooseExprClass: return cast(this)->getChosenSubExpr()-> isUnusedResultAWarning(WarnE, Loc, R1, R2, Ctx); case UnaryOperatorClass: { const UnaryOperator *UO = cast(this); switch (UO->getOpcode()) { case UO_Plus: case UO_Minus: case UO_AddrOf: case UO_Not: case UO_LNot: case UO_Deref: break; case UO_Coawait: // This is just the 'operator co_await' call inside the guts of a // dependent co_await call. case UO_PostInc: case UO_PostDec: case UO_PreInc: case UO_PreDec: // ++/-- return false; // Not a warning. case UO_Real: case UO_Imag: // accessing a piece of a volatile complex is a side-effect. if (Ctx.getCanonicalType(UO->getSubExpr()->getType()) .isVolatileQualified()) return false; break; case UO_Extension: return UO->getSubExpr()->isUnusedResultAWarning(WarnE, Loc, R1, R2, Ctx); } WarnE = this; Loc = UO->getOperatorLoc(); R1 = UO->getSubExpr()->getSourceRange(); return true; } case BinaryOperatorClass: { const BinaryOperator *BO = cast(this); switch (BO->getOpcode()) { default: break; // Consider the RHS of comma for side effects. LHS was checked by // Sema::CheckCommaOperands. case BO_Comma: // ((foo = ), 0) is an idiom for hiding the result (and // lvalue-ness) of an assignment written in a macro. if (IntegerLiteral *IE = dyn_cast(BO->getRHS()->IgnoreParens())) if (IE->getValue() == 0) return false; return BO->getRHS()->isUnusedResultAWarning(WarnE, Loc, R1, R2, Ctx); // Consider '||', '&&' to have side effects if the LHS or RHS does. case BO_LAnd: case BO_LOr: if (!BO->getLHS()->isUnusedResultAWarning(WarnE, Loc, R1, R2, Ctx) || !BO->getRHS()->isUnusedResultAWarning(WarnE, Loc, R1, R2, Ctx)) return false; break; } if (BO->isAssignmentOp()) return false; WarnE = this; Loc = BO->getOperatorLoc(); R1 = BO->getLHS()->getSourceRange(); R2 = BO->getRHS()->getSourceRange(); return true; } case CompoundAssignOperatorClass: case VAArgExprClass: case AtomicExprClass: return false; case ConditionalOperatorClass: { // If only one of the LHS or RHS is a warning, the operator might // be being used for control flow. Only warn if both the LHS and // RHS are warnings. const auto *Exp = cast(this); return Exp->getLHS()->isUnusedResultAWarning(WarnE, Loc, R1, R2, Ctx) && Exp->getRHS()->isUnusedResultAWarning(WarnE, Loc, R1, R2, Ctx); } case BinaryConditionalOperatorClass: { const auto *Exp = cast(this); return Exp->getFalseExpr()->isUnusedResultAWarning(WarnE, Loc, R1, R2, Ctx); } case MemberExprClass: WarnE = this; Loc = cast(this)->getMemberLoc(); R1 = SourceRange(Loc, Loc); R2 = cast(this)->getBase()->getSourceRange(); return true; case ArraySubscriptExprClass: WarnE = this; Loc = cast(this)->getRBracketLoc(); R1 = cast(this)->getLHS()->getSourceRange(); R2 = cast(this)->getRHS()->getSourceRange(); return true; case CXXOperatorCallExprClass: { // Warn about operator ==,!=,<,>,<=, and >= even when user-defined operator // overloads as there is no reasonable way to define these such that they // have non-trivial, desirable side-effects. See the -Wunused-comparison // warning: operators == and != are commonly typo'ed, and so warning on them // provides additional value as well. If this list is updated, // DiagnoseUnusedComparison should be as well. const CXXOperatorCallExpr *Op = cast(this); switch (Op->getOperator()) { default: break; case OO_EqualEqual: case OO_ExclaimEqual: case OO_Less: case OO_Greater: case OO_GreaterEqual: case OO_LessEqual: if (Op->getCallReturnType(Ctx)->isReferenceType() || Op->getCallReturnType(Ctx)->isVoidType()) break; WarnE = this; Loc = Op->getOperatorLoc(); R1 = Op->getSourceRange(); return true; } // Fallthrough for generic call handling. LLVM_FALLTHROUGH; } case CallExprClass: case CXXMemberCallExprClass: case UserDefinedLiteralClass: { // If this is a direct call, get the callee. const CallExpr *CE = cast(this); if (const Decl *FD = CE->getCalleeDecl()) { // If the callee has attribute pure, const, or warn_unused_result, warn // about it. void foo() { strlen("bar"); } should warn. // // Note: If new cases are added here, DiagnoseUnusedExprResult should be // updated to match for QoI. if (CE->hasUnusedResultAttr(Ctx) || FD->hasAttr() || FD->hasAttr()) { WarnE = this; Loc = CE->getCallee()->getBeginLoc(); R1 = CE->getCallee()->getSourceRange(); if (unsigned NumArgs = CE->getNumArgs()) R2 = SourceRange(CE->getArg(0)->getBeginLoc(), CE->getArg(NumArgs - 1)->getEndLoc()); return true; } } return false; } // If we don't know precisely what we're looking at, let's not warn. case UnresolvedLookupExprClass: case CXXUnresolvedConstructExprClass: return false; case CXXTemporaryObjectExprClass: case CXXConstructExprClass: { if (const CXXRecordDecl *Type = getType()->getAsCXXRecordDecl()) { const auto *WarnURAttr = Type->getAttr(); if (Type->hasAttr() || (WarnURAttr && WarnURAttr->IsCXX11NoDiscard())) { WarnE = this; Loc = getBeginLoc(); R1 = getSourceRange(); return true; } } const auto *CE = cast(this); if (const CXXConstructorDecl *Ctor = CE->getConstructor()) { const auto *WarnURAttr = Ctor->getAttr(); if (WarnURAttr && WarnURAttr->IsCXX11NoDiscard()) { WarnE = this; Loc = getBeginLoc(); R1 = getSourceRange(); if (unsigned NumArgs = CE->getNumArgs()) R2 = SourceRange(CE->getArg(0)->getBeginLoc(), CE->getArg(NumArgs - 1)->getEndLoc()); return true; } } return false; } case ObjCMessageExprClass: { const ObjCMessageExpr *ME = cast(this); if (Ctx.getLangOpts().ObjCAutoRefCount && ME->isInstanceMessage() && !ME->getType()->isVoidType() && ME->getMethodFamily() == OMF_init) { WarnE = this; Loc = getExprLoc(); R1 = ME->getSourceRange(); return true; } if (const ObjCMethodDecl *MD = ME->getMethodDecl()) if (MD->hasAttr()) { WarnE = this; Loc = getExprLoc(); return true; } return false; } case ObjCPropertyRefExprClass: WarnE = this; Loc = getExprLoc(); R1 = getSourceRange(); return true; case PseudoObjectExprClass: { const PseudoObjectExpr *PO = cast(this); // Only complain about things that have the form of a getter. if (isa(PO->getSyntacticForm()) || isa(PO->getSyntacticForm())) return false; WarnE = this; Loc = getExprLoc(); R1 = getSourceRange(); return true; } case StmtExprClass: { // Statement exprs don't logically have side effects themselves, but are // sometimes used in macros in ways that give them a type that is unused. // For example ({ blah; foo(); }) will end up with a type if foo has a type. // however, if the result of the stmt expr is dead, we don't want to emit a // warning. const CompoundStmt *CS = cast(this)->getSubStmt(); if (!CS->body_empty()) { if (const Expr *E = dyn_cast(CS->body_back())) return E->isUnusedResultAWarning(WarnE, Loc, R1, R2, Ctx); if (const LabelStmt *Label = dyn_cast(CS->body_back())) if (const Expr *E = dyn_cast(Label->getSubStmt())) return E->isUnusedResultAWarning(WarnE, Loc, R1, R2, Ctx); } if (getType()->isVoidType()) return false; WarnE = this; Loc = cast(this)->getLParenLoc(); R1 = getSourceRange(); return true; } case CXXFunctionalCastExprClass: case CStyleCastExprClass: { // Ignore an explicit cast to void unless the operand is a non-trivial // volatile lvalue. const CastExpr *CE = cast(this); if (CE->getCastKind() == CK_ToVoid) { if (CE->getSubExpr()->isGLValue() && CE->getSubExpr()->getType().isVolatileQualified()) { const DeclRefExpr *DRE = dyn_cast(CE->getSubExpr()->IgnoreParens()); if (!(DRE && isa(DRE->getDecl()) && cast(DRE->getDecl())->hasLocalStorage()) && !isa(CE->getSubExpr()->IgnoreParens())) { return CE->getSubExpr()->isUnusedResultAWarning(WarnE, Loc, R1, R2, Ctx); } } return false; } // If this is a cast to a constructor conversion, check the operand. // Otherwise, the result of the cast is unused. if (CE->getCastKind() == CK_ConstructorConversion) return CE->getSubExpr()->isUnusedResultAWarning(WarnE, Loc, R1, R2, Ctx); WarnE = this; if (const CXXFunctionalCastExpr *CXXCE = dyn_cast(this)) { Loc = CXXCE->getBeginLoc(); R1 = CXXCE->getSubExpr()->getSourceRange(); } else { const CStyleCastExpr *CStyleCE = cast(this); Loc = CStyleCE->getLParenLoc(); R1 = CStyleCE->getSubExpr()->getSourceRange(); } return true; } case ImplicitCastExprClass: { const CastExpr *ICE = cast(this); // lvalue-to-rvalue conversion on a volatile lvalue is a side-effect. if (ICE->getCastKind() == CK_LValueToRValue && ICE->getSubExpr()->getType().isVolatileQualified()) return false; return ICE->getSubExpr()->isUnusedResultAWarning(WarnE, Loc, R1, R2, Ctx); } case CXXDefaultArgExprClass: return (cast(this) ->getExpr()->isUnusedResultAWarning(WarnE, Loc, R1, R2, Ctx)); case CXXDefaultInitExprClass: return (cast(this) ->getExpr()->isUnusedResultAWarning(WarnE, Loc, R1, R2, Ctx)); case CXXNewExprClass: // FIXME: In theory, there might be new expressions that don't have side // effects (e.g. a placement new with an uninitialized POD). case CXXDeleteExprClass: return false; case MaterializeTemporaryExprClass: return cast(this) ->getSubExpr() ->isUnusedResultAWarning(WarnE, Loc, R1, R2, Ctx); case CXXBindTemporaryExprClass: return cast(this)->getSubExpr() ->isUnusedResultAWarning(WarnE, Loc, R1, R2, Ctx); case ExprWithCleanupsClass: return cast(this)->getSubExpr() ->isUnusedResultAWarning(WarnE, Loc, R1, R2, Ctx); } } /// isOBJCGCCandidate - Check if an expression is objc gc'able. /// returns true, if it is; false otherwise. bool Expr::isOBJCGCCandidate(ASTContext &Ctx) const { const Expr *E = IgnoreParens(); switch (E->getStmtClass()) { default: return false; case ObjCIvarRefExprClass: return true; case Expr::UnaryOperatorClass: return cast(E)->getSubExpr()->isOBJCGCCandidate(Ctx); case ImplicitCastExprClass: return cast(E)->getSubExpr()->isOBJCGCCandidate(Ctx); case MaterializeTemporaryExprClass: return cast(E)->getSubExpr()->isOBJCGCCandidate( Ctx); case CStyleCastExprClass: return cast(E)->getSubExpr()->isOBJCGCCandidate(Ctx); case DeclRefExprClass: { const Decl *D = cast(E)->getDecl(); if (const VarDecl *VD = dyn_cast(D)) { if (VD->hasGlobalStorage()) return true; QualType T = VD->getType(); // dereferencing to a pointer is always a gc'able candidate, // unless it is __weak. return T->isPointerType() && (Ctx.getObjCGCAttrKind(T) != Qualifiers::Weak); } return false; } case MemberExprClass: { const MemberExpr *M = cast(E); return M->getBase()->isOBJCGCCandidate(Ctx); } case ArraySubscriptExprClass: return cast(E)->getBase()->isOBJCGCCandidate(Ctx); } } bool Expr::isBoundMemberFunction(ASTContext &Ctx) const { if (isTypeDependent()) return false; return ClassifyLValue(Ctx) == Expr::LV_MemberFunction; } QualType Expr::findBoundMemberType(const Expr *expr) { assert(expr->hasPlaceholderType(BuiltinType::BoundMember)); // Bound member expressions are always one of these possibilities: // x->m x.m x->*y x.*y // (possibly parenthesized) expr = expr->IgnoreParens(); if (const MemberExpr *mem = dyn_cast(expr)) { assert(isa(mem->getMemberDecl())); return mem->getMemberDecl()->getType(); } if (const BinaryOperator *op = dyn_cast(expr)) { QualType type = op->getRHS()->getType()->castAs() ->getPointeeType(); assert(type->isFunctionType()); return type; } assert(isa(expr) || isa(expr)); return QualType(); } static Expr *IgnoreImpCastsSingleStep(Expr *E) { if (auto *ICE = dyn_cast(E)) return ICE->getSubExpr(); if (auto *FE = dyn_cast(E)) return FE->getSubExpr(); return E; } static Expr *IgnoreImpCastsExtraSingleStep(Expr *E) { // FIXME: Skip MaterializeTemporaryExpr and SubstNonTypeTemplateParmExpr in // addition to what IgnoreImpCasts() skips to account for the current // behaviour of IgnoreParenImpCasts(). Expr *SubE = IgnoreImpCastsSingleStep(E); if (SubE != E) return SubE; if (auto *MTE = dyn_cast(E)) return MTE->getSubExpr(); if (auto *NTTP = dyn_cast(E)) return NTTP->getReplacement(); return E; } static Expr *IgnoreCastsSingleStep(Expr *E) { if (auto *CE = dyn_cast(E)) return CE->getSubExpr(); if (auto *FE = dyn_cast(E)) return FE->getSubExpr(); if (auto *MTE = dyn_cast(E)) return MTE->getSubExpr(); if (auto *NTTP = dyn_cast(E)) return NTTP->getReplacement(); return E; } static Expr *IgnoreLValueCastsSingleStep(Expr *E) { // Skip what IgnoreCastsSingleStep skips, except that only // lvalue-to-rvalue casts are skipped. if (auto *CE = dyn_cast(E)) if (CE->getCastKind() != CK_LValueToRValue) return E; return IgnoreCastsSingleStep(E); } static Expr *IgnoreBaseCastsSingleStep(Expr *E) { if (auto *CE = dyn_cast(E)) if (CE->getCastKind() == CK_DerivedToBase || CE->getCastKind() == CK_UncheckedDerivedToBase || CE->getCastKind() == CK_NoOp) return CE->getSubExpr(); return E; } static Expr *IgnoreImplicitSingleStep(Expr *E) { Expr *SubE = IgnoreImpCastsSingleStep(E); if (SubE != E) return SubE; if (auto *MTE = dyn_cast(E)) return MTE->getSubExpr(); if (auto *BTE = dyn_cast(E)) return BTE->getSubExpr(); return E; } static Expr *IgnoreParensSingleStep(Expr *E) { if (auto *PE = dyn_cast(E)) return PE->getSubExpr(); if (auto *UO = dyn_cast(E)) { if (UO->getOpcode() == UO_Extension) return UO->getSubExpr(); } else if (auto *GSE = dyn_cast(E)) { if (!GSE->isResultDependent()) return GSE->getResultExpr(); } else if (auto *CE = dyn_cast(E)) { if (!CE->isConditionDependent()) return CE->getChosenSubExpr(); } else if (auto *CE = dyn_cast(E)) return CE->getSubExpr(); return E; } static Expr *IgnoreNoopCastsSingleStep(const ASTContext &Ctx, Expr *E) { if (auto *CE = dyn_cast(E)) { // We ignore integer <-> casts that are of the same width, ptr<->ptr and // ptr<->int casts of the same width. We also ignore all identity casts. Expr *SubExpr = CE->getSubExpr(); bool IsIdentityCast = Ctx.hasSameUnqualifiedType(E->getType(), SubExpr->getType()); bool IsSameWidthCast = (E->getType()->isPointerType() || E->getType()->isIntegralType(Ctx)) && (SubExpr->getType()->isPointerType() || SubExpr->getType()->isIntegralType(Ctx)) && (Ctx.getTypeSize(E->getType()) == Ctx.getTypeSize(SubExpr->getType())); if (IsIdentityCast || IsSameWidthCast) return SubExpr; } else if (auto *NTTP = dyn_cast(E)) return NTTP->getReplacement(); return E; } static Expr *IgnoreExprNodesImpl(Expr *E) { return E; } template static Expr *IgnoreExprNodesImpl(Expr *E, FnTy &&Fn, FnTys &&... Fns) { return IgnoreExprNodesImpl(Fn(E), std::forward(Fns)...); } /// Given an expression E and functions Fn_1,...,Fn_n : Expr * -> Expr *, /// Recursively apply each of the functions to E until reaching a fixed point. /// Note that a null E is valid; in this case nothing is done. template static Expr *IgnoreExprNodes(Expr *E, FnTys &&... Fns) { Expr *LastE = nullptr; while (E != LastE) { LastE = E; E = IgnoreExprNodesImpl(E, std::forward(Fns)...); } return E; } Expr *Expr::IgnoreImpCasts() { return IgnoreExprNodes(this, IgnoreImpCastsSingleStep); } Expr *Expr::IgnoreCasts() { return IgnoreExprNodes(this, IgnoreCastsSingleStep); } Expr *Expr::IgnoreImplicit() { return IgnoreExprNodes(this, IgnoreImplicitSingleStep); } Expr *Expr::IgnoreParens() { return IgnoreExprNodes(this, IgnoreParensSingleStep); } Expr *Expr::IgnoreParenImpCasts() { return IgnoreExprNodes(this, IgnoreParensSingleStep, IgnoreImpCastsExtraSingleStep); } Expr *Expr::IgnoreParenCasts() { return IgnoreExprNodes(this, IgnoreParensSingleStep, IgnoreCastsSingleStep); } Expr *Expr::IgnoreConversionOperator() { if (auto *MCE = dyn_cast(this)) { if (MCE->getMethodDecl() && isa(MCE->getMethodDecl())) return MCE->getImplicitObjectArgument(); } return this; } Expr *Expr::IgnoreParenLValueCasts() { return IgnoreExprNodes(this, IgnoreParensSingleStep, IgnoreLValueCastsSingleStep); } Expr *Expr::ignoreParenBaseCasts() { return IgnoreExprNodes(this, IgnoreParensSingleStep, IgnoreBaseCastsSingleStep); } Expr *Expr::IgnoreParenNoopCasts(const ASTContext &Ctx) { return IgnoreExprNodes(this, IgnoreParensSingleStep, [&Ctx](Expr *E) { return IgnoreNoopCastsSingleStep(Ctx, E); }); } bool Expr::isDefaultArgument() const { const Expr *E = this; if (const MaterializeTemporaryExpr *M = dyn_cast(E)) E = M->getSubExpr(); while (const ImplicitCastExpr *ICE = dyn_cast(E)) E = ICE->getSubExprAsWritten(); return isa(E); } /// Skip over any no-op casts and any temporary-binding /// expressions. static const Expr *skipTemporaryBindingsNoOpCastsAndParens(const Expr *E) { if (const MaterializeTemporaryExpr *M = dyn_cast(E)) E = M->getSubExpr(); while (const ImplicitCastExpr *ICE = dyn_cast(E)) { if (ICE->getCastKind() == CK_NoOp) E = ICE->getSubExpr(); else break; } while (const CXXBindTemporaryExpr *BE = dyn_cast(E)) E = BE->getSubExpr(); while (const ImplicitCastExpr *ICE = dyn_cast(E)) { if (ICE->getCastKind() == CK_NoOp) E = ICE->getSubExpr(); else break; } return E->IgnoreParens(); } /// isTemporaryObject - Determines if this expression produces a /// temporary of the given class type. bool Expr::isTemporaryObject(ASTContext &C, const CXXRecordDecl *TempTy) const { if (!C.hasSameUnqualifiedType(getType(), C.getTypeDeclType(TempTy))) return false; const Expr *E = skipTemporaryBindingsNoOpCastsAndParens(this); // Temporaries are by definition pr-values of class type. if (!E->Classify(C).isPRValue()) { // In this context, property reference is a message call and is pr-value. if (!isa(E)) return false; } // Black-list a few cases which yield pr-values of class type that don't // refer to temporaries of that type: // - implicit derived-to-base conversions if (isa(E)) { switch (cast(E)->getCastKind()) { case CK_DerivedToBase: case CK_UncheckedDerivedToBase: return false; default: break; } } // - member expressions (all) if (isa(E)) return false; if (const BinaryOperator *BO = dyn_cast(E)) if (BO->isPtrMemOp()) return false; // - opaque values (all) if (isa(E)) return false; return true; } bool Expr::isImplicitCXXThis() const { const Expr *E = this; // Strip away parentheses and casts we don't care about. while (true) { if (const ParenExpr *Paren = dyn_cast(E)) { E = Paren->getSubExpr(); continue; } if (const ImplicitCastExpr *ICE = dyn_cast(E)) { if (ICE->getCastKind() == CK_NoOp || ICE->getCastKind() == CK_LValueToRValue || ICE->getCastKind() == CK_DerivedToBase || ICE->getCastKind() == CK_UncheckedDerivedToBase) { E = ICE->getSubExpr(); continue; } } if (const UnaryOperator* UnOp = dyn_cast(E)) { if (UnOp->getOpcode() == UO_Extension) { E = UnOp->getSubExpr(); continue; } } if (const MaterializeTemporaryExpr *M = dyn_cast(E)) { E = M->getSubExpr(); continue; } break; } if (const CXXThisExpr *This = dyn_cast(E)) return This->isImplicit(); return false; } /// hasAnyTypeDependentArguments - Determines if any of the expressions /// in Exprs is type-dependent. bool Expr::hasAnyTypeDependentArguments(ArrayRef Exprs) { for (unsigned I = 0; I < Exprs.size(); ++I) if (Exprs[I]->isTypeDependent()) return true; return false; } bool Expr::isConstantInitializer(ASTContext &Ctx, bool IsForRef, const Expr **Culprit) const { assert(!isValueDependent() && "Expression evaluator can't be called on a dependent expression."); // This function is attempting whether an expression is an initializer // which can be evaluated at compile-time. It very closely parallels // ConstExprEmitter in CGExprConstant.cpp; if they don't match, it // will lead to unexpected results. Like ConstExprEmitter, it falls back // to isEvaluatable most of the time. // // If we ever capture reference-binding directly in the AST, we can // kill the second parameter. if (IsForRef) { EvalResult Result; if (EvaluateAsLValue(Result, Ctx) && !Result.HasSideEffects) return true; if (Culprit) *Culprit = this; return false; } switch (getStmtClass()) { default: break; case StringLiteralClass: case ObjCEncodeExprClass: return true; case CXXTemporaryObjectExprClass: case CXXConstructExprClass: { const CXXConstructExpr *CE = cast(this); if (CE->getConstructor()->isTrivial() && CE->getConstructor()->getParent()->hasTrivialDestructor()) { // Trivial default constructor if (!CE->getNumArgs()) return true; // Trivial copy constructor assert(CE->getNumArgs() == 1 && "trivial ctor with > 1 argument"); return CE->getArg(0)->isConstantInitializer(Ctx, false, Culprit); } break; } case ConstantExprClass: { // FIXME: We should be able to return "true" here, but it can lead to extra // error messages. E.g. in Sema/array-init.c. const Expr *Exp = cast(this)->getSubExpr(); return Exp->isConstantInitializer(Ctx, false, Culprit); } case CompoundLiteralExprClass: { // This handles gcc's extension that allows global initializers like // "struct x {int x;} x = (struct x) {};". // FIXME: This accepts other cases it shouldn't! const Expr *Exp = cast(this)->getInitializer(); return Exp->isConstantInitializer(Ctx, false, Culprit); } case DesignatedInitUpdateExprClass: { const DesignatedInitUpdateExpr *DIUE = cast(this); return DIUE->getBase()->isConstantInitializer(Ctx, false, Culprit) && DIUE->getUpdater()->isConstantInitializer(Ctx, false, Culprit); } case InitListExprClass: { const InitListExpr *ILE = cast(this); assert(ILE->isSemanticForm() && "InitListExpr must be in semantic form"); if (ILE->getType()->isArrayType()) { unsigned numInits = ILE->getNumInits(); for (unsigned i = 0; i < numInits; i++) { if (!ILE->getInit(i)->isConstantInitializer(Ctx, false, Culprit)) return false; } return true; } if (ILE->getType()->isRecordType()) { unsigned ElementNo = 0; RecordDecl *RD = ILE->getType()->castAs()->getDecl(); for (const auto *Field : RD->fields()) { // If this is a union, skip all the fields that aren't being initialized. if (RD->isUnion() && ILE->getInitializedFieldInUnion() != Field) continue; // Don't emit anonymous bitfields, they just affect layout. if (Field->isUnnamedBitfield()) continue; if (ElementNo < ILE->getNumInits()) { const Expr *Elt = ILE->getInit(ElementNo++); if (Field->isBitField()) { // Bitfields have to evaluate to an integer. EvalResult Result; if (!Elt->EvaluateAsInt(Result, Ctx)) { if (Culprit) *Culprit = Elt; return false; } } else { bool RefType = Field->getType()->isReferenceType(); if (!Elt->isConstantInitializer(Ctx, RefType, Culprit)) return false; } } } return true; } break; } case ImplicitValueInitExprClass: case NoInitExprClass: return true; case ParenExprClass: return cast(this)->getSubExpr() ->isConstantInitializer(Ctx, IsForRef, Culprit); case GenericSelectionExprClass: return cast(this)->getResultExpr() ->isConstantInitializer(Ctx, IsForRef, Culprit); case ChooseExprClass: if (cast(this)->isConditionDependent()) { if (Culprit) *Culprit = this; return false; } return cast(this)->getChosenSubExpr() ->isConstantInitializer(Ctx, IsForRef, Culprit); case UnaryOperatorClass: { const UnaryOperator* Exp = cast(this); if (Exp->getOpcode() == UO_Extension) return Exp->getSubExpr()->isConstantInitializer(Ctx, false, Culprit); break; } case CXXFunctionalCastExprClass: case CXXStaticCastExprClass: case ImplicitCastExprClass: case CStyleCastExprClass: case ObjCBridgedCastExprClass: case CXXDynamicCastExprClass: case CXXReinterpretCastExprClass: case CXXConstCastExprClass: { const CastExpr *CE = cast(this); // Handle misc casts we want to ignore. if (CE->getCastKind() == CK_NoOp || CE->getCastKind() == CK_LValueToRValue || CE->getCastKind() == CK_ToUnion || CE->getCastKind() == CK_ConstructorConversion || CE->getCastKind() == CK_NonAtomicToAtomic || CE->getCastKind() == CK_AtomicToNonAtomic || CE->getCastKind() == CK_IntToOCLSampler) return CE->getSubExpr()->isConstantInitializer(Ctx, false, Culprit); break; } case MaterializeTemporaryExprClass: return cast(this) ->getSubExpr() ->isConstantInitializer(Ctx, false, Culprit); case SubstNonTypeTemplateParmExprClass: return cast(this)->getReplacement() ->isConstantInitializer(Ctx, false, Culprit); case CXXDefaultArgExprClass: return cast(this)->getExpr() ->isConstantInitializer(Ctx, false, Culprit); case CXXDefaultInitExprClass: return cast(this)->getExpr() ->isConstantInitializer(Ctx, false, Culprit); } // Allow certain forms of UB in constant initializers: signed integer // overflow and floating-point division by zero. We'll give a warning on // these, but they're common enough that we have to accept them. if (isEvaluatable(Ctx, SE_AllowUndefinedBehavior)) return true; if (Culprit) *Culprit = this; return false; } bool CallExpr::isBuiltinAssumeFalse(const ASTContext &Ctx) const { const FunctionDecl* FD = getDirectCallee(); if (!FD || (FD->getBuiltinID() != Builtin::BI__assume && FD->getBuiltinID() != Builtin::BI__builtin_assume)) return false; const Expr* Arg = getArg(0); bool ArgVal; return !Arg->isValueDependent() && Arg->EvaluateAsBooleanCondition(ArgVal, Ctx) && !ArgVal; } namespace { /// Look for any side effects within a Stmt. class SideEffectFinder : public ConstEvaluatedExprVisitor { typedef ConstEvaluatedExprVisitor Inherited; const bool IncludePossibleEffects; bool HasSideEffects; public: explicit SideEffectFinder(const ASTContext &Context, bool IncludePossible) : Inherited(Context), IncludePossibleEffects(IncludePossible), HasSideEffects(false) { } bool hasSideEffects() const { return HasSideEffects; } void VisitExpr(const Expr *E) { if (!HasSideEffects && E->HasSideEffects(Context, IncludePossibleEffects)) HasSideEffects = true; } }; } bool Expr::HasSideEffects(const ASTContext &Ctx, bool IncludePossibleEffects) const { // In circumstances where we care about definite side effects instead of // potential side effects, we want to ignore expressions that are part of a // macro expansion as a potential side effect. if (!IncludePossibleEffects && getExprLoc().isMacroID()) return false; if (isInstantiationDependent()) return IncludePossibleEffects; switch (getStmtClass()) { case NoStmtClass: #define ABSTRACT_STMT(Type) #define STMT(Type, Base) case Type##Class: #define EXPR(Type, Base) #include "clang/AST/StmtNodes.inc" llvm_unreachable("unexpected Expr kind"); case DependentScopeDeclRefExprClass: case CXXUnresolvedConstructExprClass: case CXXDependentScopeMemberExprClass: case UnresolvedLookupExprClass: case UnresolvedMemberExprClass: case PackExpansionExprClass: case SubstNonTypeTemplateParmPackExprClass: case FunctionParmPackExprClass: case TypoExprClass: case CXXFoldExprClass: llvm_unreachable("shouldn't see dependent / unresolved nodes here"); case DeclRefExprClass: case ObjCIvarRefExprClass: case PredefinedExprClass: case IntegerLiteralClass: case FixedPointLiteralClass: case FloatingLiteralClass: case ImaginaryLiteralClass: case StringLiteralClass: case CharacterLiteralClass: case OffsetOfExprClass: case ImplicitValueInitExprClass: case UnaryExprOrTypeTraitExprClass: case AddrLabelExprClass: case GNUNullExprClass: case ArrayInitIndexExprClass: case NoInitExprClass: case CXXBoolLiteralExprClass: case CXXNullPtrLiteralExprClass: case CXXThisExprClass: case CXXScalarValueInitExprClass: case TypeTraitExprClass: case ArrayTypeTraitExprClass: case ExpressionTraitExprClass: case CXXNoexceptExprClass: case SizeOfPackExprClass: case ObjCStringLiteralClass: case ObjCEncodeExprClass: case ObjCBoolLiteralExprClass: case ObjCAvailabilityCheckExprClass: case CXXUuidofExprClass: case OpaqueValueExprClass: case SourceLocExprClass: case ConceptSpecializationExprClass: // These never have a side-effect. return false; case ConstantExprClass: // FIXME: Move this into the "return false;" block above. return cast(this)->getSubExpr()->HasSideEffects( Ctx, IncludePossibleEffects); case CallExprClass: case CXXOperatorCallExprClass: case CXXMemberCallExprClass: case CUDAKernelCallExprClass: case UserDefinedLiteralClass: { // We don't know a call definitely has side effects, except for calls // to pure/const functions that definitely don't. // If the call itself is considered side-effect free, check the operands. const Decl *FD = cast(this)->getCalleeDecl(); bool IsPure = FD && (FD->hasAttr() || FD->hasAttr()); if (IsPure || !IncludePossibleEffects) break; return true; } case BlockExprClass: case CXXBindTemporaryExprClass: if (!IncludePossibleEffects) break; return true; case MSPropertyRefExprClass: case MSPropertySubscriptExprClass: case CompoundAssignOperatorClass: case VAArgExprClass: case AtomicExprClass: case CXXThrowExprClass: case CXXNewExprClass: case CXXDeleteExprClass: case CoawaitExprClass: case DependentCoawaitExprClass: case CoyieldExprClass: // These always have a side-effect. return true; case StmtExprClass: { // StmtExprs have a side-effect if any substatement does. SideEffectFinder Finder(Ctx, IncludePossibleEffects); Finder.Visit(cast(this)->getSubStmt()); return Finder.hasSideEffects(); } case ExprWithCleanupsClass: if (IncludePossibleEffects) if (cast(this)->cleanupsHaveSideEffects()) return true; break; case ParenExprClass: case ArraySubscriptExprClass: case OMPArraySectionExprClass: case MemberExprClass: case ConditionalOperatorClass: case BinaryConditionalOperatorClass: case CompoundLiteralExprClass: case ExtVectorElementExprClass: case DesignatedInitExprClass: case DesignatedInitUpdateExprClass: case ArrayInitLoopExprClass: case ParenListExprClass: case CXXPseudoDestructorExprClass: case CXXRewrittenBinaryOperatorClass: case CXXStdInitializerListExprClass: case SubstNonTypeTemplateParmExprClass: case MaterializeTemporaryExprClass: case ShuffleVectorExprClass: case ConvertVectorExprClass: case AsTypeExprClass: // These have a side-effect if any subexpression does. break; case UnaryOperatorClass: if (cast(this)->isIncrementDecrementOp()) return true; break; case BinaryOperatorClass: if (cast(this)->isAssignmentOp()) return true; break; case InitListExprClass: // FIXME: The children for an InitListExpr doesn't include the array filler. if (const Expr *E = cast(this)->getArrayFiller()) if (E->HasSideEffects(Ctx, IncludePossibleEffects)) return true; break; case GenericSelectionExprClass: return cast(this)->getResultExpr()-> HasSideEffects(Ctx, IncludePossibleEffects); case ChooseExprClass: return cast(this)->getChosenSubExpr()->HasSideEffects( Ctx, IncludePossibleEffects); case CXXDefaultArgExprClass: return cast(this)->getExpr()->HasSideEffects( Ctx, IncludePossibleEffects); case CXXDefaultInitExprClass: { const FieldDecl *FD = cast(this)->getField(); if (const Expr *E = FD->getInClassInitializer()) return E->HasSideEffects(Ctx, IncludePossibleEffects); // If we've not yet parsed the initializer, assume it has side-effects. return true; } case CXXDynamicCastExprClass: { // A dynamic_cast expression has side-effects if it can throw. const CXXDynamicCastExpr *DCE = cast(this); if (DCE->getTypeAsWritten()->isReferenceType() && DCE->getCastKind() == CK_Dynamic) return true; } LLVM_FALLTHROUGH; case ImplicitCastExprClass: case CStyleCastExprClass: case CXXStaticCastExprClass: case CXXReinterpretCastExprClass: case CXXConstCastExprClass: case CXXFunctionalCastExprClass: case BuiltinBitCastExprClass: { // While volatile reads are side-effecting in both C and C++, we treat them // as having possible (not definite) side-effects. This allows idiomatic // code to behave without warning, such as sizeof(*v) for a volatile- // qualified pointer. if (!IncludePossibleEffects) break; const CastExpr *CE = cast(this); if (CE->getCastKind() == CK_LValueToRValue && CE->getSubExpr()->getType().isVolatileQualified()) return true; break; } case CXXTypeidExprClass: // typeid might throw if its subexpression is potentially-evaluated, so has // side-effects in that case whether or not its subexpression does. return cast(this)->isPotentiallyEvaluated(); case CXXConstructExprClass: case CXXTemporaryObjectExprClass: { const CXXConstructExpr *CE = cast(this); if (!CE->getConstructor()->isTrivial() && IncludePossibleEffects) return true; // A trivial constructor does not add any side-effects of its own. Just look // at its arguments. break; } case CXXInheritedCtorInitExprClass: { const auto *ICIE = cast(this); if (!ICIE->getConstructor()->isTrivial() && IncludePossibleEffects) return true; break; } case LambdaExprClass: { const LambdaExpr *LE = cast(this); for (Expr *E : LE->capture_inits()) if (E->HasSideEffects(Ctx, IncludePossibleEffects)) return true; return false; } case PseudoObjectExprClass: { // Only look for side-effects in the semantic form, and look past // OpaqueValueExpr bindings in that form. const PseudoObjectExpr *PO = cast(this); for (PseudoObjectExpr::const_semantics_iterator I = PO->semantics_begin(), E = PO->semantics_end(); I != E; ++I) { const Expr *Subexpr = *I; if (const OpaqueValueExpr *OVE = dyn_cast(Subexpr)) Subexpr = OVE->getSourceExpr(); if (Subexpr->HasSideEffects(Ctx, IncludePossibleEffects)) return true; } return false; } case ObjCBoxedExprClass: case ObjCArrayLiteralClass: case ObjCDictionaryLiteralClass: case ObjCSelectorExprClass: case ObjCProtocolExprClass: case ObjCIsaExprClass: case ObjCIndirectCopyRestoreExprClass: case ObjCSubscriptRefExprClass: case ObjCBridgedCastExprClass: case ObjCMessageExprClass: case ObjCPropertyRefExprClass: // FIXME: Classify these cases better. if (IncludePossibleEffects) return true; break; } // Recurse to children. for (const Stmt *SubStmt : children()) if (SubStmt && cast(SubStmt)->HasSideEffects(Ctx, IncludePossibleEffects)) return true; return false; } namespace { /// Look for a call to a non-trivial function within an expression. class NonTrivialCallFinder : public ConstEvaluatedExprVisitor { typedef ConstEvaluatedExprVisitor Inherited; bool NonTrivial; public: explicit NonTrivialCallFinder(const ASTContext &Context) : Inherited(Context), NonTrivial(false) { } bool hasNonTrivialCall() const { return NonTrivial; } void VisitCallExpr(const CallExpr *E) { if (const CXXMethodDecl *Method = dyn_cast_or_null(E->getCalleeDecl())) { if (Method->isTrivial()) { // Recurse to children of the call. Inherited::VisitStmt(E); return; } } NonTrivial = true; } void VisitCXXConstructExpr(const CXXConstructExpr *E) { if (E->getConstructor()->isTrivial()) { // Recurse to children of the call. Inherited::VisitStmt(E); return; } NonTrivial = true; } void VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *E) { if (E->getTemporary()->getDestructor()->isTrivial()) { Inherited::VisitStmt(E); return; } NonTrivial = true; } }; } bool Expr::hasNonTrivialCall(const ASTContext &Ctx) const { NonTrivialCallFinder Finder(Ctx); Finder.Visit(this); return Finder.hasNonTrivialCall(); } /// isNullPointerConstant - C99 6.3.2.3p3 - Return whether this is a null /// pointer constant or not, as well as the specific kind of constant detected. /// Null pointer constants can be integer constant expressions with the /// value zero, casts of zero to void*, nullptr (C++0X), or __null /// (a GNU extension). Expr::NullPointerConstantKind Expr::isNullPointerConstant(ASTContext &Ctx, NullPointerConstantValueDependence NPC) const { if (isValueDependent() && (!Ctx.getLangOpts().CPlusPlus11 || Ctx.getLangOpts().MSVCCompat)) { switch (NPC) { case NPC_NeverValueDependent: llvm_unreachable("Unexpected value dependent expression!"); case NPC_ValueDependentIsNull: if (isTypeDependent() || getType()->isIntegralType(Ctx)) return NPCK_ZeroExpression; else return NPCK_NotNull; case NPC_ValueDependentIsNotNull: return NPCK_NotNull; } } // Strip off a cast to void*, if it exists. Except in C++. if (const ExplicitCastExpr *CE = dyn_cast(this)) { if (!Ctx.getLangOpts().CPlusPlus) { // Check that it is a cast to void*. if (const PointerType *PT = CE->getType()->getAs()) { QualType Pointee = PT->getPointeeType(); Qualifiers Qs = Pointee.getQualifiers(); // Only (void*)0 or equivalent are treated as nullptr. If pointee type // has non-default address space it is not treated as nullptr. // (__generic void*)0 in OpenCL 2.0 should not be treated as nullptr // since it cannot be assigned to a pointer to constant address space. if ((Ctx.getLangOpts().OpenCLVersion >= 200 && Pointee.getAddressSpace() == LangAS::opencl_generic) || (Ctx.getLangOpts().OpenCL && Ctx.getLangOpts().OpenCLVersion < 200 && Pointee.getAddressSpace() == LangAS::opencl_private)) Qs.removeAddressSpace(); if (Pointee->isVoidType() && Qs.empty() && // to void* CE->getSubExpr()->getType()->isIntegerType()) // from int return CE->getSubExpr()->isNullPointerConstant(Ctx, NPC); } } } else if (const ImplicitCastExpr *ICE = dyn_cast(this)) { // Ignore the ImplicitCastExpr type entirely. return ICE->getSubExpr()->isNullPointerConstant(Ctx, NPC); } else if (const ParenExpr *PE = dyn_cast(this)) { // Accept ((void*)0) as a null pointer constant, as many other // implementations do. return PE->getSubExpr()->isNullPointerConstant(Ctx, NPC); } else if (const GenericSelectionExpr *GE = dyn_cast(this)) { if (GE->isResultDependent()) return NPCK_NotNull; return GE->getResultExpr()->isNullPointerConstant(Ctx, NPC); } else if (const ChooseExpr *CE = dyn_cast(this)) { if (CE->isConditionDependent()) return NPCK_NotNull; return CE->getChosenSubExpr()->isNullPointerConstant(Ctx, NPC); } else if (const CXXDefaultArgExpr *DefaultArg = dyn_cast(this)) { // See through default argument expressions. return DefaultArg->getExpr()->isNullPointerConstant(Ctx, NPC); } else if (const CXXDefaultInitExpr *DefaultInit = dyn_cast(this)) { // See through default initializer expressions. return DefaultInit->getExpr()->isNullPointerConstant(Ctx, NPC); } else if (isa(this)) { // The GNU __null extension is always a null pointer constant. return NPCK_GNUNull; } else if (const MaterializeTemporaryExpr *M = dyn_cast(this)) { return M->getSubExpr()->isNullPointerConstant(Ctx, NPC); } else if (const OpaqueValueExpr *OVE = dyn_cast(this)) { if (const Expr *Source = OVE->getSourceExpr()) return Source->isNullPointerConstant(Ctx, NPC); } // C++11 nullptr_t is always a null pointer constant. if (getType()->isNullPtrType()) return NPCK_CXX11_nullptr; if (const RecordType *UT = getType()->getAsUnionType()) if (!Ctx.getLangOpts().CPlusPlus11 && UT && UT->getDecl()->hasAttr()) if (const CompoundLiteralExpr *CLE = dyn_cast(this)){ const Expr *InitExpr = CLE->getInitializer(); if (const InitListExpr *ILE = dyn_cast(InitExpr)) return ILE->getInit(0)->isNullPointerConstant(Ctx, NPC); } // This expression must be an integer type. if (!getType()->isIntegerType() || (Ctx.getLangOpts().CPlusPlus && getType()->isEnumeralType())) return NPCK_NotNull; if (Ctx.getLangOpts().CPlusPlus11) { // C++11 [conv.ptr]p1: A null pointer constant is an integer literal with // value zero or a prvalue of type std::nullptr_t. // Microsoft mode permits C++98 rules reflecting MSVC behavior. const IntegerLiteral *Lit = dyn_cast(this); if (Lit && !Lit->getValue()) return NPCK_ZeroLiteral; else if (!Ctx.getLangOpts().MSVCCompat || !isCXX98IntegralConstantExpr(Ctx)) return NPCK_NotNull; } else { // If we have an integer constant expression, we need to *evaluate* it and // test for the value 0. if (!isIntegerConstantExpr(Ctx)) return NPCK_NotNull; } if (EvaluateKnownConstInt(Ctx) != 0) return NPCK_NotNull; if (isa(this)) return NPCK_ZeroLiteral; return NPCK_ZeroExpression; } /// If this expression is an l-value for an Objective C /// property, find the underlying property reference expression. const ObjCPropertyRefExpr *Expr::getObjCProperty() const { const Expr *E = this; while (true) { assert((E->getValueKind() == VK_LValue && E->getObjectKind() == OK_ObjCProperty) && "expression is not a property reference"); E = E->IgnoreParenCasts(); if (const BinaryOperator *BO = dyn_cast(E)) { if (BO->getOpcode() == BO_Comma) { E = BO->getRHS(); continue; } } break; } return cast(E); } bool Expr::isObjCSelfExpr() const { const Expr *E = IgnoreParenImpCasts(); const DeclRefExpr *DRE = dyn_cast(E); if (!DRE) return false; const ImplicitParamDecl *Param = dyn_cast(DRE->getDecl()); if (!Param) return false; const ObjCMethodDecl *M = dyn_cast(Param->getDeclContext()); if (!M) return false; return M->getSelfDecl() == Param; } FieldDecl *Expr::getSourceBitField() { Expr *E = this->IgnoreParens(); while (ImplicitCastExpr *ICE = dyn_cast(E)) { if (ICE->getCastKind() == CK_LValueToRValue || (ICE->getValueKind() != VK_RValue && ICE->getCastKind() == CK_NoOp)) E = ICE->getSubExpr()->IgnoreParens(); else break; } if (MemberExpr *MemRef = dyn_cast(E)) if (FieldDecl *Field = dyn_cast(MemRef->getMemberDecl())) if (Field->isBitField()) return Field; if (ObjCIvarRefExpr *IvarRef = dyn_cast(E)) { FieldDecl *Ivar = IvarRef->getDecl(); if (Ivar->isBitField()) return Ivar; } if (DeclRefExpr *DeclRef = dyn_cast(E)) { if (FieldDecl *Field = dyn_cast(DeclRef->getDecl())) if (Field->isBitField()) return Field; if (BindingDecl *BD = dyn_cast(DeclRef->getDecl())) if (Expr *E = BD->getBinding()) return E->getSourceBitField(); } if (BinaryOperator *BinOp = dyn_cast(E)) { if (BinOp->isAssignmentOp() && BinOp->getLHS()) return BinOp->getLHS()->getSourceBitField(); if (BinOp->getOpcode() == BO_Comma && BinOp->getRHS()) return BinOp->getRHS()->getSourceBitField(); } if (UnaryOperator *UnOp = dyn_cast(E)) if (UnOp->isPrefix() && UnOp->isIncrementDecrementOp()) return UnOp->getSubExpr()->getSourceBitField(); return nullptr; } bool Expr::refersToVectorElement() const { // FIXME: Why do we not just look at the ObjectKind here? const Expr *E = this->IgnoreParens(); while (const ImplicitCastExpr *ICE = dyn_cast(E)) { if (ICE->getValueKind() != VK_RValue && ICE->getCastKind() == CK_NoOp) E = ICE->getSubExpr()->IgnoreParens(); else break; } if (const ArraySubscriptExpr *ASE = dyn_cast(E)) return ASE->getBase()->getType()->isVectorType(); if (isa(E)) return true; if (auto *DRE = dyn_cast(E)) if (auto *BD = dyn_cast(DRE->getDecl())) if (auto *E = BD->getBinding()) return E->refersToVectorElement(); return false; } bool Expr::refersToGlobalRegisterVar() const { const Expr *E = this->IgnoreParenImpCasts(); if (const DeclRefExpr *DRE = dyn_cast(E)) if (const auto *VD = dyn_cast(DRE->getDecl())) if (VD->getStorageClass() == SC_Register && VD->hasAttr() && !VD->isLocalVarDecl()) return true; return false; } bool Expr::isSameComparisonOperand(const Expr* E1, const Expr* E2) { E1 = E1->IgnoreParens(); E2 = E2->IgnoreParens(); if (E1->getStmtClass() != E2->getStmtClass()) return false; switch (E1->getStmtClass()) { default: return false; case CXXThisExprClass: return true; case DeclRefExprClass: { // DeclRefExpr without an ImplicitCastExpr can happen for integral // template parameters. const auto *DRE1 = cast(E1); const auto *DRE2 = cast(E2); return DRE1->isRValue() && DRE2->isRValue() && DRE1->getDecl() == DRE2->getDecl(); } case ImplicitCastExprClass: { // Peel off implicit casts. while (true) { const auto *ICE1 = dyn_cast(E1); const auto *ICE2 = dyn_cast(E2); if (!ICE1 || !ICE2) return false; if (ICE1->getCastKind() != ICE2->getCastKind()) return false; E1 = ICE1->getSubExpr()->IgnoreParens(); E2 = ICE2->getSubExpr()->IgnoreParens(); // The final cast must be one of these types. if (ICE1->getCastKind() == CK_LValueToRValue || ICE1->getCastKind() == CK_ArrayToPointerDecay || ICE1->getCastKind() == CK_FunctionToPointerDecay) { break; } } const auto *DRE1 = dyn_cast(E1); const auto *DRE2 = dyn_cast(E2); if (DRE1 && DRE2) return declaresSameEntity(DRE1->getDecl(), DRE2->getDecl()); const auto *Ivar1 = dyn_cast(E1); const auto *Ivar2 = dyn_cast(E2); if (Ivar1 && Ivar2) { return Ivar1->isFreeIvar() && Ivar2->isFreeIvar() && declaresSameEntity(Ivar1->getDecl(), Ivar2->getDecl()); } const auto *Array1 = dyn_cast(E1); const auto *Array2 = dyn_cast(E2); if (Array1 && Array2) { if (!isSameComparisonOperand(Array1->getBase(), Array2->getBase())) return false; auto Idx1 = Array1->getIdx(); auto Idx2 = Array2->getIdx(); const auto Integer1 = dyn_cast(Idx1); const auto Integer2 = dyn_cast(Idx2); if (Integer1 && Integer2) { if (!llvm::APInt::isSameValue(Integer1->getValue(), Integer2->getValue())) return false; } else { if (!isSameComparisonOperand(Idx1, Idx2)) return false; } return true; } // Walk the MemberExpr chain. while (isa(E1) && isa(E2)) { const auto *ME1 = cast(E1); const auto *ME2 = cast(E2); if (!declaresSameEntity(ME1->getMemberDecl(), ME2->getMemberDecl())) return false; if (const auto *D = dyn_cast(ME1->getMemberDecl())) if (D->isStaticDataMember()) return true; E1 = ME1->getBase()->IgnoreParenImpCasts(); E2 = ME2->getBase()->IgnoreParenImpCasts(); } if (isa(E1) && isa(E2)) return true; // A static member variable can end the MemberExpr chain with either // a MemberExpr or a DeclRefExpr. auto getAnyDecl = [](const Expr *E) -> const ValueDecl * { if (const auto *DRE = dyn_cast(E)) return DRE->getDecl(); if (const auto *ME = dyn_cast(E)) return ME->getMemberDecl(); return nullptr; }; const ValueDecl *VD1 = getAnyDecl(E1); const ValueDecl *VD2 = getAnyDecl(E2); return declaresSameEntity(VD1, VD2); } } } /// isArrow - Return true if the base expression is a pointer to vector, /// return false if the base expression is a vector. bool ExtVectorElementExpr::isArrow() const { return getBase()->getType()->isPointerType(); } unsigned ExtVectorElementExpr::getNumElements() const { if (const VectorType *VT = getType()->getAs()) return VT->getNumElements(); return 1; } /// containsDuplicateElements - Return true if any element access is repeated. bool ExtVectorElementExpr::containsDuplicateElements() const { // FIXME: Refactor this code to an accessor on the AST node which returns the // "type" of component access, and share with code below and in Sema. StringRef Comp = Accessor->getName(); // Halving swizzles do not contain duplicate elements. if (Comp == "hi" || Comp == "lo" || Comp == "even" || Comp == "odd") return false; // Advance past s-char prefix on hex swizzles. if (Comp[0] == 's' || Comp[0] == 'S') Comp = Comp.substr(1); for (unsigned i = 0, e = Comp.size(); i != e; ++i) if (Comp.substr(i + 1).find(Comp[i]) != StringRef::npos) return true; return false; } /// getEncodedElementAccess - We encode the fields as a llvm ConstantArray. void ExtVectorElementExpr::getEncodedElementAccess( SmallVectorImpl &Elts) const { StringRef Comp = Accessor->getName(); bool isNumericAccessor = false; if (Comp[0] == 's' || Comp[0] == 'S') { Comp = Comp.substr(1); isNumericAccessor = true; } bool isHi = Comp == "hi"; bool isLo = Comp == "lo"; bool isEven = Comp == "even"; bool isOdd = Comp == "odd"; for (unsigned i = 0, e = getNumElements(); i != e; ++i) { uint64_t Index; if (isHi) Index = e + i; else if (isLo) Index = i; else if (isEven) Index = 2 * i; else if (isOdd) Index = 2 * i + 1; else Index = ExtVectorType::getAccessorIdx(Comp[i], isNumericAccessor); Elts.push_back(Index); } } ShuffleVectorExpr::ShuffleVectorExpr(const ASTContext &C, ArrayRef args, QualType Type, SourceLocation BLoc, SourceLocation RP) : Expr(ShuffleVectorExprClass, Type, VK_RValue, OK_Ordinary, Type->isDependentType(), Type->isDependentType(), Type->isInstantiationDependentType(), Type->containsUnexpandedParameterPack()), BuiltinLoc(BLoc), RParenLoc(RP), NumExprs(args.size()) { SubExprs = new (C) Stmt*[args.size()]; for (unsigned i = 0; i != args.size(); i++) { if (args[i]->isTypeDependent()) ExprBits.TypeDependent = true; if (args[i]->isValueDependent()) ExprBits.ValueDependent = true; if (args[i]->isInstantiationDependent()) ExprBits.InstantiationDependent = true; if (args[i]->containsUnexpandedParameterPack()) ExprBits.ContainsUnexpandedParameterPack = true; SubExprs[i] = args[i]; } } void ShuffleVectorExpr::setExprs(const ASTContext &C, ArrayRef Exprs) { if (SubExprs) C.Deallocate(SubExprs); this->NumExprs = Exprs.size(); SubExprs = new (C) Stmt*[NumExprs]; memcpy(SubExprs, Exprs.data(), sizeof(Expr *) * Exprs.size()); } GenericSelectionExpr::GenericSelectionExpr( const ASTContext &, SourceLocation GenericLoc, Expr *ControllingExpr, ArrayRef AssocTypes, ArrayRef AssocExprs, SourceLocation DefaultLoc, SourceLocation RParenLoc, bool ContainsUnexpandedParameterPack, unsigned ResultIndex) : Expr(GenericSelectionExprClass, AssocExprs[ResultIndex]->getType(), AssocExprs[ResultIndex]->getValueKind(), AssocExprs[ResultIndex]->getObjectKind(), AssocExprs[ResultIndex]->isTypeDependent(), AssocExprs[ResultIndex]->isValueDependent(), AssocExprs[ResultIndex]->isInstantiationDependent(), ContainsUnexpandedParameterPack), NumAssocs(AssocExprs.size()), ResultIndex(ResultIndex), DefaultLoc(DefaultLoc), RParenLoc(RParenLoc) { assert(AssocTypes.size() == AssocExprs.size() && "Must have the same number of association expressions" " and TypeSourceInfo!"); assert(ResultIndex < NumAssocs && "ResultIndex is out-of-bounds!"); GenericSelectionExprBits.GenericLoc = GenericLoc; getTrailingObjects()[ControllingIndex] = ControllingExpr; std::copy(AssocExprs.begin(), AssocExprs.end(), getTrailingObjects() + AssocExprStartIndex); std::copy(AssocTypes.begin(), AssocTypes.end(), getTrailingObjects()); } GenericSelectionExpr::GenericSelectionExpr( const ASTContext &Context, SourceLocation GenericLoc, Expr *ControllingExpr, ArrayRef AssocTypes, ArrayRef AssocExprs, SourceLocation DefaultLoc, SourceLocation RParenLoc, bool ContainsUnexpandedParameterPack) : Expr(GenericSelectionExprClass, Context.DependentTy, VK_RValue, OK_Ordinary, /*isTypeDependent=*/true, /*isValueDependent=*/true, /*isInstantiationDependent=*/true, ContainsUnexpandedParameterPack), NumAssocs(AssocExprs.size()), ResultIndex(ResultDependentIndex), DefaultLoc(DefaultLoc), RParenLoc(RParenLoc) { assert(AssocTypes.size() == AssocExprs.size() && "Must have the same number of association expressions" " and TypeSourceInfo!"); GenericSelectionExprBits.GenericLoc = GenericLoc; getTrailingObjects()[ControllingIndex] = ControllingExpr; std::copy(AssocExprs.begin(), AssocExprs.end(), getTrailingObjects() + AssocExprStartIndex); std::copy(AssocTypes.begin(), AssocTypes.end(), getTrailingObjects()); } GenericSelectionExpr::GenericSelectionExpr(EmptyShell Empty, unsigned NumAssocs) : Expr(GenericSelectionExprClass, Empty), NumAssocs(NumAssocs) {} GenericSelectionExpr *GenericSelectionExpr::Create( const ASTContext &Context, SourceLocation GenericLoc, Expr *ControllingExpr, ArrayRef AssocTypes, ArrayRef AssocExprs, SourceLocation DefaultLoc, SourceLocation RParenLoc, bool ContainsUnexpandedParameterPack, unsigned ResultIndex) { unsigned NumAssocs = AssocExprs.size(); void *Mem = Context.Allocate( totalSizeToAlloc(1 + NumAssocs, NumAssocs), alignof(GenericSelectionExpr)); return new (Mem) GenericSelectionExpr( Context, GenericLoc, ControllingExpr, AssocTypes, AssocExprs, DefaultLoc, RParenLoc, ContainsUnexpandedParameterPack, ResultIndex); } GenericSelectionExpr *GenericSelectionExpr::Create( const ASTContext &Context, SourceLocation GenericLoc, Expr *ControllingExpr, ArrayRef AssocTypes, ArrayRef AssocExprs, SourceLocation DefaultLoc, SourceLocation RParenLoc, bool ContainsUnexpandedParameterPack) { unsigned NumAssocs = AssocExprs.size(); void *Mem = Context.Allocate( totalSizeToAlloc(1 + NumAssocs, NumAssocs), alignof(GenericSelectionExpr)); return new (Mem) GenericSelectionExpr( Context, GenericLoc, ControllingExpr, AssocTypes, AssocExprs, DefaultLoc, RParenLoc, ContainsUnexpandedParameterPack); } GenericSelectionExpr * GenericSelectionExpr::CreateEmpty(const ASTContext &Context, unsigned NumAssocs) { void *Mem = Context.Allocate( totalSizeToAlloc(1 + NumAssocs, NumAssocs), alignof(GenericSelectionExpr)); return new (Mem) GenericSelectionExpr(EmptyShell(), NumAssocs); } //===----------------------------------------------------------------------===// // DesignatedInitExpr //===----------------------------------------------------------------------===// IdentifierInfo *DesignatedInitExpr::Designator::getFieldName() const { assert(Kind == FieldDesignator && "Only valid on a field designator"); if (Field.NameOrField & 0x01) return reinterpret_cast(Field.NameOrField&~0x01); else return getField()->getIdentifier(); } DesignatedInitExpr::DesignatedInitExpr(const ASTContext &C, QualType Ty, llvm::ArrayRef Designators, SourceLocation EqualOrColonLoc, bool GNUSyntax, ArrayRef IndexExprs, Expr *Init) : Expr(DesignatedInitExprClass, Ty, Init->getValueKind(), Init->getObjectKind(), Init->isTypeDependent(), Init->isValueDependent(), Init->isInstantiationDependent(), Init->containsUnexpandedParameterPack()), EqualOrColonLoc(EqualOrColonLoc), GNUSyntax(GNUSyntax), NumDesignators(Designators.size()), NumSubExprs(IndexExprs.size() + 1) { this->Designators = new (C) Designator[NumDesignators]; // Record the initializer itself. child_iterator Child = child_begin(); *Child++ = Init; // Copy the designators and their subexpressions, computing // value-dependence along the way. unsigned IndexIdx = 0; for (unsigned I = 0; I != NumDesignators; ++I) { this->Designators[I] = Designators[I]; if (this->Designators[I].isArrayDesignator()) { // Compute type- and value-dependence. Expr *Index = IndexExprs[IndexIdx]; if (Index->isTypeDependent() || Index->isValueDependent()) ExprBits.TypeDependent = ExprBits.ValueDependent = true; if (Index->isInstantiationDependent()) ExprBits.InstantiationDependent = true; // Propagate unexpanded parameter packs. if (Index->containsUnexpandedParameterPack()) ExprBits.ContainsUnexpandedParameterPack = true; // Copy the index expressions into permanent storage. *Child++ = IndexExprs[IndexIdx++]; } else if (this->Designators[I].isArrayRangeDesignator()) { // Compute type- and value-dependence. Expr *Start = IndexExprs[IndexIdx]; Expr *End = IndexExprs[IndexIdx + 1]; if (Start->isTypeDependent() || Start->isValueDependent() || End->isTypeDependent() || End->isValueDependent()) { ExprBits.TypeDependent = ExprBits.ValueDependent = true; ExprBits.InstantiationDependent = true; } else if (Start->isInstantiationDependent() || End->isInstantiationDependent()) { ExprBits.InstantiationDependent = true; } // Propagate unexpanded parameter packs. if (Start->containsUnexpandedParameterPack() || End->containsUnexpandedParameterPack()) ExprBits.ContainsUnexpandedParameterPack = true; // Copy the start/end expressions into permanent storage. *Child++ = IndexExprs[IndexIdx++]; *Child++ = IndexExprs[IndexIdx++]; } } assert(IndexIdx == IndexExprs.size() && "Wrong number of index expressions"); } DesignatedInitExpr * DesignatedInitExpr::Create(const ASTContext &C, llvm::ArrayRef Designators, ArrayRef IndexExprs, SourceLocation ColonOrEqualLoc, bool UsesColonSyntax, Expr *Init) { void *Mem = C.Allocate(totalSizeToAlloc(IndexExprs.size() + 1), alignof(DesignatedInitExpr)); return new (Mem) DesignatedInitExpr(C, C.VoidTy, Designators, ColonOrEqualLoc, UsesColonSyntax, IndexExprs, Init); } DesignatedInitExpr *DesignatedInitExpr::CreateEmpty(const ASTContext &C, unsigned NumIndexExprs) { void *Mem = C.Allocate(totalSizeToAlloc(NumIndexExprs + 1), alignof(DesignatedInitExpr)); return new (Mem) DesignatedInitExpr(NumIndexExprs + 1); } void DesignatedInitExpr::setDesignators(const ASTContext &C, const Designator *Desigs, unsigned NumDesigs) { Designators = new (C) Designator[NumDesigs]; NumDesignators = NumDesigs; for (unsigned I = 0; I != NumDesigs; ++I) Designators[I] = Desigs[I]; } SourceRange DesignatedInitExpr::getDesignatorsSourceRange() const { DesignatedInitExpr *DIE = const_cast(this); if (size() == 1) return DIE->getDesignator(0)->getSourceRange(); return SourceRange(DIE->getDesignator(0)->getBeginLoc(), DIE->getDesignator(size() - 1)->getEndLoc()); } SourceLocation DesignatedInitExpr::getBeginLoc() const { SourceLocation StartLoc; auto *DIE = const_cast(this); Designator &First = *DIE->getDesignator(0); if (First.isFieldDesignator()) { if (GNUSyntax) StartLoc = SourceLocation::getFromRawEncoding(First.Field.FieldLoc); else StartLoc = SourceLocation::getFromRawEncoding(First.Field.DotLoc); } else StartLoc = SourceLocation::getFromRawEncoding(First.ArrayOrRange.LBracketLoc); return StartLoc; } SourceLocation DesignatedInitExpr::getEndLoc() const { return getInit()->getEndLoc(); } Expr *DesignatedInitExpr::getArrayIndex(const Designator& D) const { assert(D.Kind == Designator::ArrayDesignator && "Requires array designator"); return getSubExpr(D.ArrayOrRange.Index + 1); } Expr *DesignatedInitExpr::getArrayRangeStart(const Designator &D) const { assert(D.Kind == Designator::ArrayRangeDesignator && "Requires array range designator"); return getSubExpr(D.ArrayOrRange.Index + 1); } Expr *DesignatedInitExpr::getArrayRangeEnd(const Designator &D) const { assert(D.Kind == Designator::ArrayRangeDesignator && "Requires array range designator"); return getSubExpr(D.ArrayOrRange.Index + 2); } /// Replaces the designator at index @p Idx with the series /// of designators in [First, Last). void DesignatedInitExpr::ExpandDesignator(const ASTContext &C, unsigned Idx, const Designator *First, const Designator *Last) { unsigned NumNewDesignators = Last - First; if (NumNewDesignators == 0) { std::copy_backward(Designators + Idx + 1, Designators + NumDesignators, Designators + Idx); --NumNewDesignators; return; } else if (NumNewDesignators == 1) { Designators[Idx] = *First; return; } Designator *NewDesignators = new (C) Designator[NumDesignators - 1 + NumNewDesignators]; std::copy(Designators, Designators + Idx, NewDesignators); std::copy(First, Last, NewDesignators + Idx); std::copy(Designators + Idx + 1, Designators + NumDesignators, NewDesignators + Idx + NumNewDesignators); Designators = NewDesignators; NumDesignators = NumDesignators - 1 + NumNewDesignators; } DesignatedInitUpdateExpr::DesignatedInitUpdateExpr(const ASTContext &C, SourceLocation lBraceLoc, Expr *baseExpr, SourceLocation rBraceLoc) : Expr(DesignatedInitUpdateExprClass, baseExpr->getType(), VK_RValue, OK_Ordinary, false, false, false, false) { BaseAndUpdaterExprs[0] = baseExpr; InitListExpr *ILE = new (C) InitListExpr(C, lBraceLoc, None, rBraceLoc); ILE->setType(baseExpr->getType()); BaseAndUpdaterExprs[1] = ILE; } SourceLocation DesignatedInitUpdateExpr::getBeginLoc() const { return getBase()->getBeginLoc(); } SourceLocation DesignatedInitUpdateExpr::getEndLoc() const { return getBase()->getEndLoc(); } ParenListExpr::ParenListExpr(SourceLocation LParenLoc, ArrayRef Exprs, SourceLocation RParenLoc) : Expr(ParenListExprClass, QualType(), VK_RValue, OK_Ordinary, false, false, false, false), LParenLoc(LParenLoc), RParenLoc(RParenLoc) { ParenListExprBits.NumExprs = Exprs.size(); for (unsigned I = 0, N = Exprs.size(); I != N; ++I) { if (Exprs[I]->isTypeDependent()) ExprBits.TypeDependent = true; if (Exprs[I]->isValueDependent()) ExprBits.ValueDependent = true; if (Exprs[I]->isInstantiationDependent()) ExprBits.InstantiationDependent = true; if (Exprs[I]->containsUnexpandedParameterPack()) ExprBits.ContainsUnexpandedParameterPack = true; getTrailingObjects()[I] = Exprs[I]; } } ParenListExpr::ParenListExpr(EmptyShell Empty, unsigned NumExprs) : Expr(ParenListExprClass, Empty) { ParenListExprBits.NumExprs = NumExprs; } ParenListExpr *ParenListExpr::Create(const ASTContext &Ctx, SourceLocation LParenLoc, ArrayRef Exprs, SourceLocation RParenLoc) { void *Mem = Ctx.Allocate(totalSizeToAlloc(Exprs.size()), alignof(ParenListExpr)); return new (Mem) ParenListExpr(LParenLoc, Exprs, RParenLoc); } ParenListExpr *ParenListExpr::CreateEmpty(const ASTContext &Ctx, unsigned NumExprs) { void *Mem = Ctx.Allocate(totalSizeToAlloc(NumExprs), alignof(ParenListExpr)); return new (Mem) ParenListExpr(EmptyShell(), NumExprs); } const OpaqueValueExpr *OpaqueValueExpr::findInCopyConstruct(const Expr *e) { if (const ExprWithCleanups *ewc = dyn_cast(e)) e = ewc->getSubExpr(); if (const MaterializeTemporaryExpr *m = dyn_cast(e)) e = m->getSubExpr(); e = cast(e)->getArg(0); while (const ImplicitCastExpr *ice = dyn_cast(e)) e = ice->getSubExpr(); return cast(e); } PseudoObjectExpr *PseudoObjectExpr::Create(const ASTContext &Context, EmptyShell sh, unsigned numSemanticExprs) { void *buffer = Context.Allocate(totalSizeToAlloc(1 + numSemanticExprs), alignof(PseudoObjectExpr)); return new(buffer) PseudoObjectExpr(sh, numSemanticExprs); } PseudoObjectExpr::PseudoObjectExpr(EmptyShell shell, unsigned numSemanticExprs) : Expr(PseudoObjectExprClass, shell) { PseudoObjectExprBits.NumSubExprs = numSemanticExprs + 1; } PseudoObjectExpr *PseudoObjectExpr::Create(const ASTContext &C, Expr *syntax, ArrayRef semantics, unsigned resultIndex) { assert(syntax && "no syntactic expression!"); assert(semantics.size() && "no semantic expressions!"); QualType type; ExprValueKind VK; if (resultIndex == NoResult) { type = C.VoidTy; VK = VK_RValue; } else { assert(resultIndex < semantics.size()); type = semantics[resultIndex]->getType(); VK = semantics[resultIndex]->getValueKind(); assert(semantics[resultIndex]->getObjectKind() == OK_Ordinary); } void *buffer = C.Allocate(totalSizeToAlloc(semantics.size() + 1), alignof(PseudoObjectExpr)); return new(buffer) PseudoObjectExpr(type, VK, syntax, semantics, resultIndex); } PseudoObjectExpr::PseudoObjectExpr(QualType type, ExprValueKind VK, Expr *syntax, ArrayRef semantics, unsigned resultIndex) : Expr(PseudoObjectExprClass, type, VK, OK_Ordinary, /*filled in at end of ctor*/ false, false, false, false) { PseudoObjectExprBits.NumSubExprs = semantics.size() + 1; PseudoObjectExprBits.ResultIndex = resultIndex + 1; for (unsigned i = 0, e = semantics.size() + 1; i != e; ++i) { Expr *E = (i == 0 ? syntax : semantics[i-1]); getSubExprsBuffer()[i] = E; if (E->isTypeDependent()) ExprBits.TypeDependent = true; if (E->isValueDependent()) ExprBits.ValueDependent = true; if (E->isInstantiationDependent()) ExprBits.InstantiationDependent = true; if (E->containsUnexpandedParameterPack()) ExprBits.ContainsUnexpandedParameterPack = true; if (isa(E)) assert(cast(E)->getSourceExpr() != nullptr && "opaque-value semantic expressions for pseudo-object " "operations must have sources"); } } //===----------------------------------------------------------------------===// // Child Iterators for iterating over subexpressions/substatements //===----------------------------------------------------------------------===// // UnaryExprOrTypeTraitExpr Stmt::child_range UnaryExprOrTypeTraitExpr::children() { const_child_range CCR = const_cast(this)->children(); return child_range(cast_away_const(CCR.begin()), cast_away_const(CCR.end())); } Stmt::const_child_range UnaryExprOrTypeTraitExpr::children() const { // If this is of a type and the type is a VLA type (and not a typedef), the // size expression of the VLA needs to be treated as an executable expression. // Why isn't this weirdness documented better in StmtIterator? if (isArgumentType()) { if (const VariableArrayType *T = dyn_cast(getArgumentType().getTypePtr())) return const_child_range(const_child_iterator(T), const_child_iterator()); return const_child_range(const_child_iterator(), const_child_iterator()); } return const_child_range(&Argument.Ex, &Argument.Ex + 1); } AtomicExpr::AtomicExpr(SourceLocation BLoc, ArrayRef args, QualType t, AtomicOp op, SourceLocation RP) : Expr(AtomicExprClass, t, VK_RValue, OK_Ordinary, false, false, false, false), NumSubExprs(args.size()), BuiltinLoc(BLoc), RParenLoc(RP), Op(op) { assert(args.size() == getNumSubExprs(op) && "wrong number of subexpressions"); for (unsigned i = 0; i != args.size(); i++) { if (args[i]->isTypeDependent()) ExprBits.TypeDependent = true; if (args[i]->isValueDependent()) ExprBits.ValueDependent = true; if (args[i]->isInstantiationDependent()) ExprBits.InstantiationDependent = true; if (args[i]->containsUnexpandedParameterPack()) ExprBits.ContainsUnexpandedParameterPack = true; SubExprs[i] = args[i]; } } unsigned AtomicExpr::getNumSubExprs(AtomicOp Op) { switch (Op) { case AO__c11_atomic_init: case AO__opencl_atomic_init: case AO__c11_atomic_load: case AO__atomic_load_n: return 2; case AO__opencl_atomic_load: case AO__c11_atomic_store: case AO__c11_atomic_exchange: case AO__atomic_load: case AO__atomic_store: case AO__atomic_store_n: case AO__atomic_exchange_n: case AO__c11_atomic_fetch_add: case AO__c11_atomic_fetch_sub: case AO__c11_atomic_fetch_and: case AO__c11_atomic_fetch_or: case AO__c11_atomic_fetch_xor: case AO__c11_atomic_fetch_max: case AO__c11_atomic_fetch_min: case AO__atomic_fetch_add: case AO__atomic_fetch_sub: case AO__atomic_fetch_and: case AO__atomic_fetch_or: case AO__atomic_fetch_xor: case AO__atomic_fetch_nand: case AO__atomic_add_fetch: case AO__atomic_sub_fetch: case AO__atomic_and_fetch: case AO__atomic_or_fetch: case AO__atomic_xor_fetch: case AO__atomic_nand_fetch: case AO__atomic_min_fetch: case AO__atomic_max_fetch: case AO__atomic_fetch_min: case AO__atomic_fetch_max: return 3; case AO__opencl_atomic_store: case AO__opencl_atomic_exchange: case AO__opencl_atomic_fetch_add: case AO__opencl_atomic_fetch_sub: case AO__opencl_atomic_fetch_and: case AO__opencl_atomic_fetch_or: case AO__opencl_atomic_fetch_xor: case AO__opencl_atomic_fetch_min: case AO__opencl_atomic_fetch_max: case AO__atomic_exchange: return 4; case AO__c11_atomic_compare_exchange_strong: case AO__c11_atomic_compare_exchange_weak: return 5; case AO__opencl_atomic_compare_exchange_strong: case AO__opencl_atomic_compare_exchange_weak: case AO__atomic_compare_exchange: case AO__atomic_compare_exchange_n: return 6; } llvm_unreachable("unknown atomic op"); } QualType AtomicExpr::getValueType() const { auto T = getPtr()->getType()->castAs()->getPointeeType(); if (auto AT = T->getAs()) return AT->getValueType(); return T; } QualType OMPArraySectionExpr::getBaseOriginalType(const Expr *Base) { unsigned ArraySectionCount = 0; while (auto *OASE = dyn_cast(Base->IgnoreParens())) { Base = OASE->getBase(); ++ArraySectionCount; } while (auto *ASE = dyn_cast(Base->IgnoreParenImpCasts())) { Base = ASE->getBase(); ++ArraySectionCount; } Base = Base->IgnoreParenImpCasts(); auto OriginalTy = Base->getType(); if (auto *DRE = dyn_cast(Base)) if (auto *PVD = dyn_cast(DRE->getDecl())) OriginalTy = PVD->getOriginalType().getNonReferenceType(); for (unsigned Cnt = 0; Cnt < ArraySectionCount; ++Cnt) { if (OriginalTy->isAnyPointerType()) OriginalTy = OriginalTy->getPointeeType(); else { assert (OriginalTy->isArrayType()); OriginalTy = OriginalTy->castAsArrayTypeUnsafe()->getElementType(); } } return OriginalTy; } diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 6ea4923dc2ba..dffb460cedc9 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -1,17769 +1,17809 @@ //===--- SemaDecl.cpp - Semantic Analysis for Declarations ----------------===// // // 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 declarations. // //===----------------------------------------------------------------------===// #include "TypeLocBuilder.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" #include "clang/AST/ASTLambda.h" #include "clang/AST/CXXInheritance.h" #include "clang/AST/CharUnits.h" #include "clang/AST/CommentDiagnostic.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/EvaluatedExprVisitor.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/NonTrivialTypeVisitor.h" #include "clang/AST/StmtCXX.h" #include "clang/Basic/Builtins.h" #include "clang/Basic/PartialDiagnostic.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/TargetInfo.h" #include "clang/Lex/HeaderSearch.h" // TODO: Sema shouldn't depend on Lex #include "clang/Lex/Lexer.h" // TODO: Extract static functions to fix layering. #include "clang/Lex/ModuleLoader.h" // TODO: Sema shouldn't depend on Lex #include "clang/Lex/Preprocessor.h" // Included for isCodeCompletionEnabled() #include "clang/Sema/CXXFieldCollector.h" #include "clang/Sema/DeclSpec.h" #include "clang/Sema/DelayedDiagnostic.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/SemaInternal.h" #include "clang/Sema/Template.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/Triple.h" #include #include #include using namespace clang; using namespace sema; Sema::DeclGroupPtrTy Sema::ConvertDeclToDeclGroup(Decl *Ptr, Decl *OwnedType) { if (OwnedType) { Decl *Group[2] = { OwnedType, Ptr }; return DeclGroupPtrTy::make(DeclGroupRef::Create(Context, Group, 2)); } return DeclGroupPtrTy::make(DeclGroupRef(Ptr)); } namespace { class TypeNameValidatorCCC final : public CorrectionCandidateCallback { public: TypeNameValidatorCCC(bool AllowInvalid, bool WantClass = false, bool AllowTemplates = false, bool AllowNonTemplates = true) : AllowInvalidDecl(AllowInvalid), WantClassName(WantClass), AllowTemplates(AllowTemplates), AllowNonTemplates(AllowNonTemplates) { WantExpressionKeywords = false; WantCXXNamedCasts = false; WantRemainingKeywords = false; } bool ValidateCandidate(const TypoCorrection &candidate) override { if (NamedDecl *ND = candidate.getCorrectionDecl()) { if (!AllowInvalidDecl && ND->isInvalidDecl()) return false; if (getAsTypeTemplateDecl(ND)) return AllowTemplates; bool IsType = isa(ND) || isa(ND); if (!IsType) return false; if (AllowNonTemplates) return true; // An injected-class-name of a class template (specialization) is valid // as a template or as a non-template. if (AllowTemplates) { auto *RD = dyn_cast(ND); if (!RD || !RD->isInjectedClassName()) return false; RD = cast(RD->getDeclContext()); return RD->getDescribedClassTemplate() || isa(RD); } return false; } return !WantClassName && candidate.isKeyword(); } std::unique_ptr clone() override { return std::make_unique(*this); } private: bool AllowInvalidDecl; bool WantClassName; bool AllowTemplates; bool AllowNonTemplates; }; } // end anonymous namespace /// Determine whether the token kind starts a simple-type-specifier. bool Sema::isSimpleTypeSpecifier(tok::TokenKind Kind) const { switch (Kind) { // FIXME: Take into account the current language when deciding whether a // token kind is a valid type specifier case tok::kw_short: case tok::kw_long: case tok::kw___int64: case tok::kw___int128: case tok::kw_signed: case tok::kw_unsigned: case tok::kw_void: case tok::kw_char: case tok::kw_int: case tok::kw_half: case tok::kw_float: case tok::kw_double: case tok::kw__Float16: case tok::kw___float128: case tok::kw_wchar_t: case tok::kw_bool: case tok::kw___underlying_type: case tok::kw___auto_type: return true; case tok::annot_typename: case tok::kw_char16_t: case tok::kw_char32_t: case tok::kw_typeof: case tok::annot_decltype: case tok::kw_decltype: return getLangOpts().CPlusPlus; case tok::kw_char8_t: return getLangOpts().Char8; default: break; } return false; } namespace { enum class UnqualifiedTypeNameLookupResult { NotFound, FoundNonType, FoundType }; } // end anonymous namespace /// Tries to perform unqualified lookup of the type decls in bases for /// dependent class. /// \return \a NotFound if no any decls is found, \a FoundNotType if found not a /// type decl, \a FoundType if only type decls are found. static UnqualifiedTypeNameLookupResult lookupUnqualifiedTypeNameInBase(Sema &S, const IdentifierInfo &II, SourceLocation NameLoc, const CXXRecordDecl *RD) { if (!RD->hasDefinition()) return UnqualifiedTypeNameLookupResult::NotFound; // Look for type decls in base classes. UnqualifiedTypeNameLookupResult FoundTypeDecl = UnqualifiedTypeNameLookupResult::NotFound; for (const auto &Base : RD->bases()) { const CXXRecordDecl *BaseRD = nullptr; if (auto *BaseTT = Base.getType()->getAs()) BaseRD = BaseTT->getAsCXXRecordDecl(); else if (auto *TST = Base.getType()->getAs()) { // Look for type decls in dependent base classes that have known primary // templates. if (!TST || !TST->isDependentType()) continue; auto *TD = TST->getTemplateName().getAsTemplateDecl(); if (!TD) continue; if (auto *BasePrimaryTemplate = dyn_cast_or_null(TD->getTemplatedDecl())) { if (BasePrimaryTemplate->getCanonicalDecl() != RD->getCanonicalDecl()) BaseRD = BasePrimaryTemplate; else if (auto *CTD = dyn_cast(TD)) { if (const ClassTemplatePartialSpecializationDecl *PS = CTD->findPartialSpecialization(Base.getType())) if (PS->getCanonicalDecl() != RD->getCanonicalDecl()) BaseRD = PS; } } } if (BaseRD) { for (NamedDecl *ND : BaseRD->lookup(&II)) { if (!isa(ND)) return UnqualifiedTypeNameLookupResult::FoundNonType; FoundTypeDecl = UnqualifiedTypeNameLookupResult::FoundType; } if (FoundTypeDecl == UnqualifiedTypeNameLookupResult::NotFound) { switch (lookupUnqualifiedTypeNameInBase(S, II, NameLoc, BaseRD)) { case UnqualifiedTypeNameLookupResult::FoundNonType: return UnqualifiedTypeNameLookupResult::FoundNonType; case UnqualifiedTypeNameLookupResult::FoundType: FoundTypeDecl = UnqualifiedTypeNameLookupResult::FoundType; break; case UnqualifiedTypeNameLookupResult::NotFound: break; } } } } return FoundTypeDecl; } static ParsedType recoverFromTypeInKnownDependentBase(Sema &S, const IdentifierInfo &II, SourceLocation NameLoc) { // Lookup in the parent class template context, if any. const CXXRecordDecl *RD = nullptr; UnqualifiedTypeNameLookupResult FoundTypeDecl = UnqualifiedTypeNameLookupResult::NotFound; for (DeclContext *DC = S.CurContext; DC && FoundTypeDecl == UnqualifiedTypeNameLookupResult::NotFound; DC = DC->getParent()) { // Look for type decls in dependent base classes that have known primary // templates. RD = dyn_cast(DC); if (RD && RD->getDescribedClassTemplate()) FoundTypeDecl = lookupUnqualifiedTypeNameInBase(S, II, NameLoc, RD); } if (FoundTypeDecl != UnqualifiedTypeNameLookupResult::FoundType) return nullptr; // We found some types in dependent base classes. Recover as if the user // wrote 'typename MyClass::II' instead of 'II'. We'll fully resolve the // lookup during template instantiation. S.Diag(NameLoc, diag::ext_found_via_dependent_bases_lookup) << &II; ASTContext &Context = S.Context; auto *NNS = NestedNameSpecifier::Create(Context, nullptr, false, cast(Context.getRecordType(RD))); QualType T = Context.getDependentNameType(ETK_Typename, NNS, &II); CXXScopeSpec SS; SS.MakeTrivial(Context, NNS, SourceRange(NameLoc)); TypeLocBuilder Builder; DependentNameTypeLoc DepTL = Builder.push(T); DepTL.setNameLoc(NameLoc); DepTL.setElaboratedKeywordLoc(SourceLocation()); DepTL.setQualifierLoc(SS.getWithLocInContext(Context)); return S.CreateParsedType(T, Builder.getTypeSourceInfo(Context, T)); } /// If the identifier refers to a type name within this scope, /// return the declaration of that type. /// /// This routine performs ordinary name lookup of the identifier II /// within the given scope, with optional C++ scope specifier SS, to /// determine whether the name refers to a type. If so, returns an /// opaque pointer (actually a QualType) corresponding to that /// type. Otherwise, returns NULL. ParsedType Sema::getTypeName(const IdentifierInfo &II, SourceLocation NameLoc, Scope *S, CXXScopeSpec *SS, bool isClassName, bool HasTrailingDot, ParsedType ObjectTypePtr, bool IsCtorOrDtorName, bool WantNontrivialTypeSourceInfo, bool IsClassTemplateDeductionContext, IdentifierInfo **CorrectedII) { // FIXME: Consider allowing this outside C++1z mode as an extension. bool AllowDeducedTemplate = IsClassTemplateDeductionContext && getLangOpts().CPlusPlus17 && !IsCtorOrDtorName && !isClassName && !HasTrailingDot; // Determine where we will perform name lookup. DeclContext *LookupCtx = nullptr; if (ObjectTypePtr) { QualType ObjectType = ObjectTypePtr.get(); if (ObjectType->isRecordType()) LookupCtx = computeDeclContext(ObjectType); } else if (SS && SS->isNotEmpty()) { LookupCtx = computeDeclContext(*SS, false); if (!LookupCtx) { if (isDependentScopeSpecifier(*SS)) { // C++ [temp.res]p3: // A qualified-id that refers to a type and in which the // nested-name-specifier depends on a template-parameter (14.6.2) // shall be prefixed by the keyword typename to indicate that the // qualified-id denotes a type, forming an // elaborated-type-specifier (7.1.5.3). // // We therefore do not perform any name lookup if the result would // refer to a member of an unknown specialization. if (!isClassName && !IsCtorOrDtorName) return nullptr; // We know from the grammar that this name refers to a type, // so build a dependent node to describe the type. if (WantNontrivialTypeSourceInfo) return ActOnTypenameType(S, SourceLocation(), *SS, II, NameLoc).get(); NestedNameSpecifierLoc QualifierLoc = SS->getWithLocInContext(Context); QualType T = CheckTypenameType(ETK_None, SourceLocation(), QualifierLoc, II, NameLoc); return ParsedType::make(T); } return nullptr; } if (!LookupCtx->isDependentContext() && RequireCompleteDeclContext(*SS, LookupCtx)) return nullptr; } // FIXME: LookupNestedNameSpecifierName isn't the right kind of // lookup for class-names. LookupNameKind Kind = isClassName ? LookupNestedNameSpecifierName : LookupOrdinaryName; LookupResult Result(*this, &II, NameLoc, Kind); if (LookupCtx) { // Perform "qualified" name lookup into the declaration context we // computed, which is either the type of the base of a member access // expression or the declaration context associated with a prior // nested-name-specifier. LookupQualifiedName(Result, LookupCtx); if (ObjectTypePtr && Result.empty()) { // 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. LookupName(Result, S); } } else { // Perform unqualified name lookup. LookupName(Result, S); // For unqualified lookup in a class template in MSVC mode, look into // dependent base classes where the primary class template is known. if (Result.empty() && getLangOpts().MSVCCompat && (!SS || SS->isEmpty())) { if (ParsedType TypeInBase = recoverFromTypeInKnownDependentBase(*this, II, NameLoc)) return TypeInBase; } } NamedDecl *IIDecl = nullptr; switch (Result.getResultKind()) { case LookupResult::NotFound: case LookupResult::NotFoundInCurrentInstantiation: if (CorrectedII) { TypeNameValidatorCCC CCC(/*AllowInvalid=*/true, isClassName, AllowDeducedTemplate); TypoCorrection Correction = CorrectTypo(Result.getLookupNameInfo(), Kind, S, SS, CCC, CTK_ErrorRecovery); IdentifierInfo *NewII = Correction.getCorrectionAsIdentifierInfo(); TemplateTy Template; bool MemberOfUnknownSpecialization; UnqualifiedId TemplateName; TemplateName.setIdentifier(NewII, NameLoc); NestedNameSpecifier *NNS = Correction.getCorrectionSpecifier(); CXXScopeSpec NewSS, *NewSSPtr = SS; if (SS && NNS) { NewSS.MakeTrivial(Context, NNS, SourceRange(NameLoc)); NewSSPtr = &NewSS; } if (Correction && (NNS || NewII != &II) && // Ignore a correction to a template type as the to-be-corrected // identifier is not a template (typo correction for template names // is handled elsewhere). !(getLangOpts().CPlusPlus && NewSSPtr && isTemplateName(S, *NewSSPtr, false, TemplateName, nullptr, false, Template, MemberOfUnknownSpecialization))) { ParsedType Ty = getTypeName(*NewII, NameLoc, S, NewSSPtr, isClassName, HasTrailingDot, ObjectTypePtr, IsCtorOrDtorName, WantNontrivialTypeSourceInfo, IsClassTemplateDeductionContext); if (Ty) { diagnoseTypo(Correction, PDiag(diag::err_unknown_type_or_class_name_suggest) << Result.getLookupName() << isClassName); if (SS && NNS) SS->MakeTrivial(Context, NNS, SourceRange(NameLoc)); *CorrectedII = NewII; return Ty; } } } // If typo correction failed or was not performed, fall through LLVM_FALLTHROUGH; case LookupResult::FoundOverloaded: case LookupResult::FoundUnresolvedValue: Result.suppressDiagnostics(); return nullptr; case LookupResult::Ambiguous: // Recover from type-hiding ambiguities by hiding the type. We'll // do the lookup again when looking for an object, and we can // diagnose the error then. If we don't do this, then the error // about hiding the type will be immediately followed by an error // that only makes sense if the identifier was treated like a type. if (Result.getAmbiguityKind() == LookupResult::AmbiguousTagHiding) { Result.suppressDiagnostics(); return nullptr; } // Look to see if we have a type anywhere in the list of results. for (LookupResult::iterator Res = Result.begin(), ResEnd = Result.end(); Res != ResEnd; ++Res) { if (isa(*Res) || isa(*Res) || (AllowDeducedTemplate && getAsTypeTemplateDecl(*Res))) { if (!IIDecl || (*Res)->getLocation().getRawEncoding() < IIDecl->getLocation().getRawEncoding()) IIDecl = *Res; } } if (!IIDecl) { // None of the entities we found is a type, so there is no way // to even assume that the result is a type. In this case, don't // complain about the ambiguity. The parser will either try to // perform this lookup again (e.g., as an object name), which // will produce the ambiguity, or will complain that it expected // a type name. Result.suppressDiagnostics(); return nullptr; } // We found a type within the ambiguous lookup; diagnose the // ambiguity and then return that type. This might be the right // answer, or it might not be, but it suppresses any attempt to // perform the name lookup again. break; case LookupResult::Found: IIDecl = Result.getFoundDecl(); break; } assert(IIDecl && "Didn't find decl"); QualType T; if (TypeDecl *TD = dyn_cast(IIDecl)) { // C++ [class.qual]p2: A lookup that would find the injected-class-name // instead names the constructors of the class, except when naming a class. // This is ill-formed when we're not actually forming a ctor or dtor name. auto *LookupRD = dyn_cast_or_null(LookupCtx); auto *FoundRD = dyn_cast(TD); if (!isClassName && !IsCtorOrDtorName && LookupRD && FoundRD && FoundRD->isInjectedClassName() && declaresSameEntity(LookupRD, cast(FoundRD->getParent()))) Diag(NameLoc, diag::err_out_of_line_qualified_id_type_names_constructor) << &II << /*Type*/1; DiagnoseUseOfDecl(IIDecl, NameLoc); T = Context.getTypeDeclType(TD); MarkAnyDeclReferenced(TD->getLocation(), TD, /*OdrUse=*/false); } else if (ObjCInterfaceDecl *IDecl = dyn_cast(IIDecl)) { (void)DiagnoseUseOfDecl(IDecl, NameLoc); if (!HasTrailingDot) T = Context.getObjCInterfaceType(IDecl); } else if (AllowDeducedTemplate) { if (auto *TD = getAsTypeTemplateDecl(IIDecl)) T = Context.getDeducedTemplateSpecializationType(TemplateName(TD), QualType(), false); } if (T.isNull()) { // If it's not plausibly a type, suppress diagnostics. Result.suppressDiagnostics(); return nullptr; } // NOTE: avoid constructing an ElaboratedType(Loc) if this is a // constructor or destructor name (in such a case, the scope specifier // will be attached to the enclosing Expr or Decl node). if (SS && SS->isNotEmpty() && !IsCtorOrDtorName && !isa(IIDecl)) { if (WantNontrivialTypeSourceInfo) { // Construct a type with type-source information. TypeLocBuilder Builder; Builder.pushTypeSpec(T).setNameLoc(NameLoc); T = getElaboratedType(ETK_None, *SS, T); ElaboratedTypeLoc ElabTL = Builder.push(T); ElabTL.setElaboratedKeywordLoc(SourceLocation()); ElabTL.setQualifierLoc(SS->getWithLocInContext(Context)); return CreateParsedType(T, Builder.getTypeSourceInfo(Context, T)); } else { T = getElaboratedType(ETK_None, *SS, T); } } return ParsedType::make(T); } // Builds a fake NNS for the given decl context. static NestedNameSpecifier * synthesizeCurrentNestedNameSpecifier(ASTContext &Context, DeclContext *DC) { for (;; DC = DC->getLookupParent()) { DC = DC->getPrimaryContext(); auto *ND = dyn_cast(DC); if (ND && !ND->isInline() && !ND->isAnonymousNamespace()) return NestedNameSpecifier::Create(Context, nullptr, ND); else if (auto *RD = dyn_cast(DC)) return NestedNameSpecifier::Create(Context, nullptr, RD->isTemplateDecl(), RD->getTypeForDecl()); else if (isa(DC)) return NestedNameSpecifier::GlobalSpecifier(Context); } llvm_unreachable("something isn't in TU scope?"); } /// Find the parent class with dependent bases of the innermost enclosing method /// context. Do not look for enclosing CXXRecordDecls directly, or we will end /// up allowing unqualified dependent type names at class-level, which MSVC /// correctly rejects. static const CXXRecordDecl * findRecordWithDependentBasesOfEnclosingMethod(const DeclContext *DC) { for (; DC && DC->isDependentContext(); DC = DC->getLookupParent()) { DC = DC->getPrimaryContext(); if (const auto *MD = dyn_cast(DC)) if (MD->getParent()->hasAnyDependentBases()) return MD->getParent(); } return nullptr; } ParsedType Sema::ActOnMSVCUnknownTypeName(const IdentifierInfo &II, SourceLocation NameLoc, bool IsTemplateTypeArg) { assert(getLangOpts().MSVCCompat && "shouldn't be called in non-MSVC mode"); NestedNameSpecifier *NNS = nullptr; if (IsTemplateTypeArg && getCurScope()->isTemplateParamScope()) { // If we weren't able to parse a default template argument, delay lookup // until instantiation time by making a non-dependent DependentTypeName. We // pretend we saw a NestedNameSpecifier referring to the current scope, and // lookup is retried. // FIXME: This hurts our diagnostic quality, since we get errors like "no // type named 'Foo' in 'current_namespace'" when the user didn't write any // name specifiers. NNS = synthesizeCurrentNestedNameSpecifier(Context, CurContext); Diag(NameLoc, diag::ext_ms_delayed_template_argument) << &II; } else if (const CXXRecordDecl *RD = findRecordWithDependentBasesOfEnclosingMethod(CurContext)) { // Build a DependentNameType that will perform lookup into RD at // instantiation time. NNS = NestedNameSpecifier::Create(Context, nullptr, RD->isTemplateDecl(), RD->getTypeForDecl()); // Diagnose that this identifier was undeclared, and retry the lookup during // template instantiation. Diag(NameLoc, diag::ext_undeclared_unqual_id_with_dependent_base) << &II << RD; } else { // This is not a situation that we should recover from. return ParsedType(); } QualType T = Context.getDependentNameType(ETK_None, NNS, &II); // Build type location information. We synthesized the qualifier, so we have // to build a fake NestedNameSpecifierLoc. NestedNameSpecifierLocBuilder NNSLocBuilder; NNSLocBuilder.MakeTrivial(Context, NNS, SourceRange(NameLoc)); NestedNameSpecifierLoc QualifierLoc = NNSLocBuilder.getWithLocInContext(Context); TypeLocBuilder Builder; DependentNameTypeLoc DepTL = Builder.push(T); DepTL.setNameLoc(NameLoc); DepTL.setElaboratedKeywordLoc(SourceLocation()); DepTL.setQualifierLoc(QualifierLoc); return CreateParsedType(T, Builder.getTypeSourceInfo(Context, T)); } /// isTagName() - This method is called *for error recovery purposes only* /// to determine if the specified name is a valid tag name ("struct foo"). If /// so, this returns the TST for the tag corresponding to it (TST_enum, /// TST_union, TST_struct, TST_interface, TST_class). This is used to diagnose /// cases in C where the user forgot to specify the tag. DeclSpec::TST Sema::isTagName(IdentifierInfo &II, Scope *S) { // Do a tag name lookup in this scope. LookupResult R(*this, &II, SourceLocation(), LookupTagName); LookupName(R, S, false); R.suppressDiagnostics(); if (R.getResultKind() == LookupResult::Found) if (const TagDecl *TD = R.getAsSingle()) { switch (TD->getTagKind()) { case TTK_Struct: return DeclSpec::TST_struct; case TTK_Interface: return DeclSpec::TST_interface; case TTK_Union: return DeclSpec::TST_union; case TTK_Class: return DeclSpec::TST_class; case TTK_Enum: return DeclSpec::TST_enum; } } return DeclSpec::TST_unspecified; } /// isMicrosoftMissingTypename - In Microsoft mode, within class scope, /// if a CXXScopeSpec's type is equal to the type of one of the base classes /// then downgrade the missing typename error to a warning. /// This is needed for MSVC compatibility; Example: /// @code /// template class A { /// public: /// typedef int TYPE; /// }; /// template class B : public A { /// public: /// A::TYPE a; // no typename required because A is a base class. /// }; /// @endcode bool Sema::isMicrosoftMissingTypename(const CXXScopeSpec *SS, Scope *S) { if (CurContext->isRecord()) { if (SS->getScopeRep()->getKind() == NestedNameSpecifier::Super) return true; const Type *Ty = SS->getScopeRep()->getAsType(); CXXRecordDecl *RD = cast(CurContext); for (const auto &Base : RD->bases()) if (Ty && Context.hasSameUnqualifiedType(QualType(Ty, 1), Base.getType())) return true; return S->isFunctionPrototypeScope(); } return CurContext->isFunctionOrMethod() || S->isFunctionPrototypeScope(); } void Sema::DiagnoseUnknownTypeName(IdentifierInfo *&II, SourceLocation IILoc, Scope *S, CXXScopeSpec *SS, ParsedType &SuggestedType, bool IsTemplateName) { // Don't report typename errors for editor placeholders. if (II->isEditorPlaceholder()) return; // We don't have anything to suggest (yet). SuggestedType = nullptr; // There may have been a typo in the name of the type. Look up typo // results, in case we have something that we can suggest. TypeNameValidatorCCC CCC(/*AllowInvalid=*/false, /*WantClass=*/false, /*AllowTemplates=*/IsTemplateName, /*AllowNonTemplates=*/!IsTemplateName); if (TypoCorrection Corrected = CorrectTypo(DeclarationNameInfo(II, IILoc), LookupOrdinaryName, S, SS, CCC, CTK_ErrorRecovery)) { // FIXME: Support error recovery for the template-name case. bool CanRecover = !IsTemplateName; if (Corrected.isKeyword()) { // We corrected to a keyword. diagnoseTypo(Corrected, PDiag(IsTemplateName ? diag::err_no_template_suggest : diag::err_unknown_typename_suggest) << II); II = Corrected.getCorrectionAsIdentifierInfo(); } else { // We found a similarly-named type or interface; suggest that. if (!SS || !SS->isSet()) { diagnoseTypo(Corrected, PDiag(IsTemplateName ? diag::err_no_template_suggest : diag::err_unknown_typename_suggest) << II, CanRecover); } else if (DeclContext *DC = computeDeclContext(*SS, false)) { std::string CorrectedStr(Corrected.getAsString(getLangOpts())); bool DroppedSpecifier = Corrected.WillReplaceSpecifier() && II->getName().equals(CorrectedStr); diagnoseTypo(Corrected, PDiag(IsTemplateName ? diag::err_no_member_template_suggest : diag::err_unknown_nested_typename_suggest) << II << DC << DroppedSpecifier << SS->getRange(), CanRecover); } else { llvm_unreachable("could not have corrected a typo here"); } if (!CanRecover) return; CXXScopeSpec tmpSS; if (Corrected.getCorrectionSpecifier()) tmpSS.MakeTrivial(Context, Corrected.getCorrectionSpecifier(), SourceRange(IILoc)); // FIXME: Support class template argument deduction here. SuggestedType = getTypeName(*Corrected.getCorrectionAsIdentifierInfo(), IILoc, S, tmpSS.isSet() ? &tmpSS : SS, false, false, nullptr, /*IsCtorOrDtorName=*/false, /*WantNontrivialTypeSourceInfo=*/true); } return; } if (getLangOpts().CPlusPlus && !IsTemplateName) { // See if II is a class template that the user forgot to pass arguments to. UnqualifiedId Name; Name.setIdentifier(II, IILoc); CXXScopeSpec EmptySS; TemplateTy TemplateResult; bool MemberOfUnknownSpecialization; if (isTemplateName(S, SS ? *SS : EmptySS, /*hasTemplateKeyword=*/false, Name, nullptr, true, TemplateResult, MemberOfUnknownSpecialization) == TNK_Type_template) { diagnoseMissingTemplateArguments(TemplateResult.get(), IILoc); return; } } // FIXME: Should we move the logic that tries to recover from a missing tag // (struct, union, enum) from Parser::ParseImplicitInt here, instead? if (!SS || (!SS->isSet() && !SS->isInvalid())) Diag(IILoc, IsTemplateName ? diag::err_no_template : diag::err_unknown_typename) << II; else if (DeclContext *DC = computeDeclContext(*SS, false)) Diag(IILoc, IsTemplateName ? diag::err_no_member_template : diag::err_typename_nested_not_found) << II << DC << SS->getRange(); else if (isDependentScopeSpecifier(*SS)) { unsigned DiagID = diag::err_typename_missing; if (getLangOpts().MSVCCompat && isMicrosoftMissingTypename(SS, S)) DiagID = diag::ext_typename_missing; Diag(SS->getRange().getBegin(), DiagID) << SS->getScopeRep() << II->getName() << SourceRange(SS->getRange().getBegin(), IILoc) << FixItHint::CreateInsertion(SS->getRange().getBegin(), "typename "); SuggestedType = ActOnTypenameType(S, SourceLocation(), *SS, *II, IILoc).get(); } else { assert(SS && SS->isInvalid() && "Invalid scope specifier has already been diagnosed"); } } /// Determine whether the given result set contains either a type name /// or static bool isResultTypeOrTemplate(LookupResult &R, const Token &NextToken) { bool CheckTemplate = R.getSema().getLangOpts().CPlusPlus && NextToken.is(tok::less); for (LookupResult::iterator I = R.begin(), IEnd = R.end(); I != IEnd; ++I) { if (isa(*I) || isa(*I)) return true; if (CheckTemplate && isa(*I)) return true; } return false; } static bool isTagTypeWithMissingTag(Sema &SemaRef, LookupResult &Result, Scope *S, CXXScopeSpec &SS, IdentifierInfo *&Name, SourceLocation NameLoc) { LookupResult R(SemaRef, Name, NameLoc, Sema::LookupTagName); SemaRef.LookupParsedName(R, S, &SS); if (TagDecl *Tag = R.getAsSingle()) { StringRef FixItTagName; switch (Tag->getTagKind()) { case TTK_Class: FixItTagName = "class "; break; case TTK_Enum: FixItTagName = "enum "; break; case TTK_Struct: FixItTagName = "struct "; break; case TTK_Interface: FixItTagName = "__interface "; break; case TTK_Union: FixItTagName = "union "; break; } StringRef TagName = FixItTagName.drop_back(); SemaRef.Diag(NameLoc, diag::err_use_of_tag_name_without_tag) << Name << TagName << SemaRef.getLangOpts().CPlusPlus << FixItHint::CreateInsertion(NameLoc, FixItTagName); for (LookupResult::iterator I = Result.begin(), IEnd = Result.end(); I != IEnd; ++I) SemaRef.Diag((*I)->getLocation(), diag::note_decl_hiding_tag_type) << Name << TagName; // Replace lookup results with just the tag decl. Result.clear(Sema::LookupTagName); SemaRef.LookupParsedName(Result, S, &SS); return true; } return false; } /// Build a ParsedType for a simple-type-specifier with a nested-name-specifier. static ParsedType buildNestedType(Sema &S, CXXScopeSpec &SS, QualType T, SourceLocation NameLoc) { ASTContext &Context = S.Context; TypeLocBuilder Builder; Builder.pushTypeSpec(T).setNameLoc(NameLoc); T = S.getElaboratedType(ETK_None, SS, T); ElaboratedTypeLoc ElabTL = Builder.push(T); ElabTL.setElaboratedKeywordLoc(SourceLocation()); ElabTL.setQualifierLoc(SS.getWithLocInContext(Context)); return S.CreateParsedType(T, Builder.getTypeSourceInfo(Context, T)); } Sema::NameClassification Sema::ClassifyName(Scope *S, CXXScopeSpec &SS, IdentifierInfo *&Name, SourceLocation NameLoc, const Token &NextToken, CorrectionCandidateCallback *CCC) { DeclarationNameInfo NameInfo(Name, NameLoc); ObjCMethodDecl *CurMethod = getCurMethodDecl(); assert(NextToken.isNot(tok::coloncolon) && "parse nested name specifiers before calling ClassifyName"); if (getLangOpts().CPlusPlus && SS.isSet() && isCurrentClassName(*Name, S, &SS)) { // Per [class.qual]p2, this names the constructors of SS, not the // injected-class-name. We don't have a classification for that. // There's not much point caching this result, since the parser // will reject it later. return NameClassification::Unknown(); } LookupResult Result(*this, Name, NameLoc, LookupOrdinaryName); LookupParsedName(Result, S, &SS, !CurMethod); // For unqualified lookup in a class template in MSVC mode, look into // dependent base classes where the primary class template is known. if (Result.empty() && SS.isEmpty() && getLangOpts().MSVCCompat) { if (ParsedType TypeInBase = recoverFromTypeInKnownDependentBase(*this, *Name, NameLoc)) return TypeInBase; } // Perform lookup for Objective-C instance variables (including automatically // synthesized instance variables), if we're in an Objective-C method. // FIXME: This lookup really, really needs to be folded in to the normal // unqualified lookup mechanism. if (!SS.isSet() && CurMethod && !isResultTypeOrTemplate(Result, NextToken)) { DeclResult Ivar = LookupIvarInObjCMethod(Result, S, Name); if (Ivar.isInvalid()) return NameClassification::Error(); if (Ivar.isUsable()) return NameClassification::NonType(cast(Ivar.get())); // We defer builtin creation until after ivar lookup inside ObjC methods. if (Result.empty()) LookupBuiltin(Result); } bool SecondTry = false; bool IsFilteredTemplateName = false; Corrected: switch (Result.getResultKind()) { case LookupResult::NotFound: // If an unqualified-id is followed by a '(', then we have a function // call. if (!SS.isSet() && NextToken.is(tok::l_paren)) { // In C++, this is an ADL-only call. // FIXME: Reference? if (getLangOpts().CPlusPlus) return NameClassification::UndeclaredNonType(); // C90 6.3.2.2: // If the expression that precedes the parenthesized argument list in a // function call consists solely of an identifier, and if no // declaration is visible for this identifier, the identifier is // implicitly declared exactly as if, in the innermost block containing // the function call, the declaration // // extern int identifier (); // // appeared. // // We also allow this in C99 as an extension. if (NamedDecl *D = ImplicitlyDefineFunction(NameLoc, *Name, S)) return NameClassification::NonType(D); } if (getLangOpts().CPlusPlus2a && !SS.isSet() && NextToken.is(tok::less)) { // In C++20 onwards, this could be an ADL-only call to a function // template, and we're required to assume that this is a template name. // // FIXME: Find a way to still do typo correction in this case. TemplateName Template = Context.getAssumedTemplateName(NameInfo.getName()); return NameClassification::UndeclaredTemplate(Template); } // In C, we first see whether there is a tag type by the same name, in // which case it's likely that the user just forgot to write "enum", // "struct", or "union". if (!getLangOpts().CPlusPlus && !SecondTry && isTagTypeWithMissingTag(*this, Result, S, SS, Name, NameLoc)) { break; } // Perform typo correction to determine if there is another name that is // close to this name. if (!SecondTry && CCC) { SecondTry = true; if (TypoCorrection Corrected = CorrectTypo(Result.getLookupNameInfo(), Result.getLookupKind(), S, &SS, *CCC, CTK_ErrorRecovery)) { unsigned UnqualifiedDiag = diag::err_undeclared_var_use_suggest; unsigned QualifiedDiag = diag::err_no_member_suggest; NamedDecl *FirstDecl = Corrected.getFoundDecl(); NamedDecl *UnderlyingFirstDecl = Corrected.getCorrectionDecl(); if (getLangOpts().CPlusPlus && NextToken.is(tok::less) && UnderlyingFirstDecl && isa(UnderlyingFirstDecl)) { UnqualifiedDiag = diag::err_no_template_suggest; QualifiedDiag = diag::err_no_member_template_suggest; } else if (UnderlyingFirstDecl && (isa(UnderlyingFirstDecl) || isa(UnderlyingFirstDecl) || isa(UnderlyingFirstDecl))) { UnqualifiedDiag = diag::err_unknown_typename_suggest; QualifiedDiag = diag::err_unknown_nested_typename_suggest; } if (SS.isEmpty()) { diagnoseTypo(Corrected, PDiag(UnqualifiedDiag) << Name); } else {// FIXME: is this even reachable? Test it. std::string CorrectedStr(Corrected.getAsString(getLangOpts())); bool DroppedSpecifier = Corrected.WillReplaceSpecifier() && Name->getName().equals(CorrectedStr); diagnoseTypo(Corrected, PDiag(QualifiedDiag) << Name << computeDeclContext(SS, false) << DroppedSpecifier << SS.getRange()); } // Update the name, so that the caller has the new name. Name = Corrected.getCorrectionAsIdentifierInfo(); // Typo correction corrected to a keyword. if (Corrected.isKeyword()) return Name; // Also update the LookupResult... // FIXME: This should probably go away at some point Result.clear(); Result.setLookupName(Corrected.getCorrection()); if (FirstDecl) Result.addDecl(FirstDecl); // If we found an Objective-C instance variable, let // LookupInObjCMethod build the appropriate expression to // reference the ivar. // FIXME: This is a gross hack. if (ObjCIvarDecl *Ivar = Result.getAsSingle()) { DeclResult R = LookupIvarInObjCMethod(Result, S, Ivar->getIdentifier()); if (R.isInvalid()) return NameClassification::Error(); if (R.isUsable()) return NameClassification::NonType(Ivar); } goto Corrected; } } // We failed to correct; just fall through and let the parser deal with it. Result.suppressDiagnostics(); return NameClassification::Unknown(); case LookupResult::NotFoundInCurrentInstantiation: { // We performed name lookup into the current instantiation, and there were // dependent bases, so we treat this result the same way as any other // dependent nested-name-specifier. // C++ [temp.res]p2: // A name used in a template declaration or definition and that is // dependent on a template-parameter is assumed not to name a type // unless the applicable name lookup finds a type name or the name is // qualified by the keyword typename. // // FIXME: If the next token is '<', we might want to ask the parser to // perform some heroics to see if we actually have a // template-argument-list, which would indicate a missing 'template' // keyword here. return NameClassification::DependentNonType(); } case LookupResult::Found: case LookupResult::FoundOverloaded: case LookupResult::FoundUnresolvedValue: break; case LookupResult::Ambiguous: if (getLangOpts().CPlusPlus && NextToken.is(tok::less) && hasAnyAcceptableTemplateNames(Result, /*AllowFunctionTemplates=*/true, /*AllowDependent=*/false)) { // C++ [temp.local]p3: // A lookup that finds an injected-class-name (10.2) can result in an // ambiguity in certain cases (for example, if it is found in more than // one base class). If all of the injected-class-names that are found // refer to specializations of the same class template, and if the name // is followed by a template-argument-list, the reference refers to the // class template itself and not a specialization thereof, and is not // ambiguous. // // This filtering can make an ambiguous result into an unambiguous one, // so try again after filtering out template names. FilterAcceptableTemplateNames(Result); if (!Result.isAmbiguous()) { IsFilteredTemplateName = true; break; } } // Diagnose the ambiguity and return an error. return NameClassification::Error(); } if (getLangOpts().CPlusPlus && NextToken.is(tok::less) && (IsFilteredTemplateName || hasAnyAcceptableTemplateNames( Result, /*AllowFunctionTemplates=*/true, /*AllowDependent=*/false, /*AllowNonTemplateFunctions*/ !SS.isSet() && getLangOpts().CPlusPlus2a))) { // C++ [temp.names]p3: // After name lookup (3.4) finds that a name is a template-name or that // an operator-function-id or a literal- operator-id refers to a set of // overloaded functions any member of which is a function template if // this is followed by a <, the < is always taken as the delimiter of a // template-argument-list and never as the less-than operator. // C++2a [temp.names]p2: // A name is also considered to refer to a template if it is an // unqualified-id followed by a < and name lookup finds either one // or more functions or finds nothing. if (!IsFilteredTemplateName) FilterAcceptableTemplateNames(Result); bool IsFunctionTemplate; bool IsVarTemplate; TemplateName Template; if (Result.end() - Result.begin() > 1) { IsFunctionTemplate = true; Template = Context.getOverloadedTemplateName(Result.begin(), Result.end()); } else if (!Result.empty()) { auto *TD = cast(getAsTemplateNameDecl( *Result.begin(), /*AllowFunctionTemplates=*/true, /*AllowDependent=*/false)); IsFunctionTemplate = isa(TD); IsVarTemplate = isa(TD); if (SS.isSet() && !SS.isInvalid()) Template = Context.getQualifiedTemplateName(SS.getScopeRep(), /*TemplateKeyword=*/false, TD); else Template = TemplateName(TD); } else { // All results were non-template functions. This is a function template // name. IsFunctionTemplate = true; Template = Context.getAssumedTemplateName(NameInfo.getName()); } if (IsFunctionTemplate) { // Function templates always go through overload resolution, at which // point we'll perform the various checks (e.g., accessibility) we need // to based on which function we selected. Result.suppressDiagnostics(); return NameClassification::FunctionTemplate(Template); } return IsVarTemplate ? NameClassification::VarTemplate(Template) : NameClassification::TypeTemplate(Template); } NamedDecl *FirstDecl = (*Result.begin())->getUnderlyingDecl(); if (TypeDecl *Type = dyn_cast(FirstDecl)) { DiagnoseUseOfDecl(Type, NameLoc); MarkAnyDeclReferenced(Type->getLocation(), Type, /*OdrUse=*/false); QualType T = Context.getTypeDeclType(Type); if (SS.isNotEmpty()) return buildNestedType(*this, SS, T, NameLoc); return ParsedType::make(T); } ObjCInterfaceDecl *Class = dyn_cast(FirstDecl); if (!Class) { // FIXME: It's unfortunate that we don't have a Type node for handling this. if (ObjCCompatibleAliasDecl *Alias = dyn_cast(FirstDecl)) Class = Alias->getClassInterface(); } if (Class) { DiagnoseUseOfDecl(Class, NameLoc); if (NextToken.is(tok::period)) { // Interface. is parsed as a property reference expression. // Just return "unknown" as a fall-through for now. Result.suppressDiagnostics(); return NameClassification::Unknown(); } QualType T = Context.getObjCInterfaceType(Class); return ParsedType::make(T); } // We can have a type template here if we're classifying a template argument. if (isa(FirstDecl) && !isa(FirstDecl) && !isa(FirstDecl)) return NameClassification::TypeTemplate( TemplateName(cast(FirstDecl))); // Check for a tag type hidden by a non-type decl in a few cases where it // seems likely a type is wanted instead of the non-type that was found. bool NextIsOp = NextToken.isOneOf(tok::amp, tok::star); if ((NextToken.is(tok::identifier) || (NextIsOp && FirstDecl->getUnderlyingDecl()->isFunctionOrFunctionTemplate())) && isTagTypeWithMissingTag(*this, Result, S, SS, Name, NameLoc)) { TypeDecl *Type = Result.getAsSingle(); DiagnoseUseOfDecl(Type, NameLoc); QualType T = Context.getTypeDeclType(Type); if (SS.isNotEmpty()) return buildNestedType(*this, SS, T, NameLoc); return ParsedType::make(T); } // FIXME: This is context-dependent. We need to defer building the member // expression until the classification is consumed. if (FirstDecl->isCXXClassMember()) return NameClassification::ContextIndependentExpr( BuildPossibleImplicitMemberExpr(SS, SourceLocation(), Result, nullptr, S)); // If we already know which single declaration is referenced, just annotate // that declaration directly. bool ADL = UseArgumentDependentLookup(SS, Result, NextToken.is(tok::l_paren)); if (Result.isSingleResult() && !ADL) return NameClassification::NonType(Result.getRepresentativeDecl()); // Build an UnresolvedLookupExpr. Note that this doesn't depend on the // context in which we performed classification, so it's safe to do now. return NameClassification::ContextIndependentExpr( BuildDeclarationNameExpr(SS, Result, ADL)); } ExprResult Sema::ActOnNameClassifiedAsUndeclaredNonType(IdentifierInfo *Name, SourceLocation NameLoc) { assert(getLangOpts().CPlusPlus && "ADL-only call in C?"); CXXScopeSpec SS; LookupResult Result(*this, Name, NameLoc, LookupOrdinaryName); return BuildDeclarationNameExpr(SS, Result, /*ADL=*/true); } ExprResult Sema::ActOnNameClassifiedAsDependentNonType(const CXXScopeSpec &SS, IdentifierInfo *Name, SourceLocation NameLoc, bool IsAddressOfOperand) { DeclarationNameInfo NameInfo(Name, NameLoc); return ActOnDependentIdExpression(SS, /*TemplateKWLoc=*/SourceLocation(), NameInfo, IsAddressOfOperand, /*TemplateArgs=*/nullptr); } ExprResult Sema::ActOnNameClassifiedAsNonType(Scope *S, const CXXScopeSpec &SS, NamedDecl *Found, SourceLocation NameLoc, const Token &NextToken) { if (getCurMethodDecl() && SS.isEmpty()) if (auto *Ivar = dyn_cast(Found->getUnderlyingDecl())) return BuildIvarRefExpr(S, NameLoc, Ivar); // Reconstruct the lookup result. LookupResult Result(*this, Found->getDeclName(), NameLoc, LookupOrdinaryName); Result.addDecl(Found); Result.resolveKind(); bool ADL = UseArgumentDependentLookup(SS, Result, NextToken.is(tok::l_paren)); return BuildDeclarationNameExpr(SS, Result, ADL); } Sema::TemplateNameKindForDiagnostics Sema::getTemplateNameKindForDiagnostics(TemplateName Name) { auto *TD = Name.getAsTemplateDecl(); if (!TD) return TemplateNameKindForDiagnostics::DependentTemplate; if (isa(TD)) return TemplateNameKindForDiagnostics::ClassTemplate; if (isa(TD)) return TemplateNameKindForDiagnostics::FunctionTemplate; if (isa(TD)) return TemplateNameKindForDiagnostics::VarTemplate; if (isa(TD)) return TemplateNameKindForDiagnostics::AliasTemplate; if (isa(TD)) return TemplateNameKindForDiagnostics::TemplateTemplateParam; if (isa(TD)) return TemplateNameKindForDiagnostics::Concept; return TemplateNameKindForDiagnostics::DependentTemplate; } // Determines the context to return to after temporarily entering a // context. This depends in an unnecessarily complicated way on the // exact ordering of callbacks from the parser. DeclContext *Sema::getContainingDC(DeclContext *DC) { // Functions defined inline within classes aren't parsed until we've // finished parsing the top-level class, so the top-level class is // the context we'll need to return to. // A Lambda call operator whose parent is a class must not be treated // as an inline member function. A Lambda can be used legally // either as an in-class member initializer or a default argument. These // are parsed once the class has been marked complete and so the containing // context would be the nested class (when the lambda is defined in one); // If the class is not complete, then the lambda is being used in an // ill-formed fashion (such as to specify the width of a bit-field, or // in an array-bound) - in which case we still want to return the // lexically containing DC (which could be a nested class). if (isa(DC) && !isLambdaCallOperator(DC)) { DC = DC->getLexicalParent(); // A function not defined within a class will always return to its // lexical context. if (!isa(DC)) return DC; // A C++ inline method/friend is parsed *after* the topmost class // it was declared in is fully parsed ("complete"); the topmost // class is the context we need to return to. while (CXXRecordDecl *RD = dyn_cast(DC->getLexicalParent())) DC = RD; // Return the declaration context of the topmost class the inline method is // declared in. return DC; } return DC->getLexicalParent(); } void Sema::PushDeclContext(Scope *S, DeclContext *DC) { assert(getContainingDC(DC) == CurContext && "The next DeclContext should be lexically contained in the current one."); CurContext = DC; S->setEntity(DC); } void Sema::PopDeclContext() { assert(CurContext && "DeclContext imbalance!"); CurContext = getContainingDC(CurContext); assert(CurContext && "Popped translation unit!"); } Sema::SkippedDefinitionContext Sema::ActOnTagStartSkippedDefinition(Scope *S, Decl *D) { // Unlike PushDeclContext, the context to which we return is not necessarily // the containing DC of TD, because the new context will be some pre-existing // TagDecl definition instead of a fresh one. auto Result = static_cast(CurContext); CurContext = cast(D)->getDefinition(); assert(CurContext && "skipping definition of undefined tag"); // Start lookups from the parent of the current context; we don't want to look // into the pre-existing complete definition. S->setEntity(CurContext->getLookupParent()); return Result; } void Sema::ActOnTagFinishSkippedDefinition(SkippedDefinitionContext Context) { CurContext = static_cast(Context); } /// EnterDeclaratorContext - Used when we must lookup names in the context /// of a declarator's nested name specifier. /// void Sema::EnterDeclaratorContext(Scope *S, DeclContext *DC) { // C++0x [basic.lookup.unqual]p13: // A name used in the definition of a static data member of class // X (after the qualified-id of the static member) is looked up as // if the name was used in a member function of X. // C++0x [basic.lookup.unqual]p14: // If a variable member of a namespace is defined outside of the // scope of its namespace then any name used in the definition of // the variable member (after the declarator-id) is looked up as // if the definition of the variable member occurred in its // namespace. // Both of these imply that we should push a scope whose context // is the semantic context of the declaration. We can't use // PushDeclContext here because that context is not necessarily // lexically contained in the current context. Fortunately, // the containing scope should have the appropriate information. assert(!S->getEntity() && "scope already has entity"); #ifndef NDEBUG Scope *Ancestor = S->getParent(); while (!Ancestor->getEntity()) Ancestor = Ancestor->getParent(); assert(Ancestor->getEntity() == CurContext && "ancestor context mismatch"); #endif CurContext = DC; S->setEntity(DC); } void Sema::ExitDeclaratorContext(Scope *S) { assert(S->getEntity() == CurContext && "Context imbalance!"); // Switch back to the lexical context. The safety of this is // enforced by an assert in EnterDeclaratorContext. Scope *Ancestor = S->getParent(); while (!Ancestor->getEntity()) Ancestor = Ancestor->getParent(); CurContext = Ancestor->getEntity(); // We don't need to do anything with the scope, which is going to // disappear. } void Sema::ActOnReenterFunctionContext(Scope* S, Decl *D) { // We assume that the caller has already called // ActOnReenterTemplateScope so getTemplatedDecl() works. FunctionDecl *FD = D->getAsFunction(); if (!FD) return; // Same implementation as PushDeclContext, but enters the context // from the lexical parent, rather than the top-level class. assert(CurContext == FD->getLexicalParent() && "The next DeclContext should be lexically contained in the current one."); CurContext = FD; S->setEntity(CurContext); for (unsigned P = 0, NumParams = FD->getNumParams(); P < NumParams; ++P) { ParmVarDecl *Param = FD->getParamDecl(P); // If the parameter has an identifier, then add it to the scope if (Param->getIdentifier()) { S->AddDecl(Param); IdResolver.AddDecl(Param); } } } void Sema::ActOnExitFunctionContext() { // Same implementation as PopDeclContext, but returns to the lexical parent, // rather than the top-level class. assert(CurContext && "DeclContext imbalance!"); CurContext = CurContext->getLexicalParent(); assert(CurContext && "Popped translation unit!"); } /// Determine whether we allow overloading of the function /// PrevDecl with another declaration. /// /// This routine determines whether overloading is possible, not /// whether some new function is actually an overload. It will return /// true in C++ (where we can always provide overloads) or, as an /// extension, in C when the previous function is already an /// overloaded function declaration or has the "overloadable" /// attribute. static bool AllowOverloadingOfFunction(LookupResult &Previous, ASTContext &Context, const FunctionDecl *New) { if (Context.getLangOpts().CPlusPlus) return true; if (Previous.getResultKind() == LookupResult::FoundOverloaded) return true; return Previous.getResultKind() == LookupResult::Found && (Previous.getFoundDecl()->hasAttr() || New->hasAttr()); } /// Add this decl to the scope shadowed decl chains. void Sema::PushOnScopeChains(NamedDecl *D, Scope *S, bool AddToContext) { // Move up the scope chain until we find the nearest enclosing // non-transparent context. The declaration will be introduced into this // scope. while (S->getEntity() && S->getEntity()->isTransparentContext()) S = S->getParent(); // Add scoped declarations into their context, so that they can be // found later. Declarations without a context won't be inserted // into any context. if (AddToContext) CurContext->addDecl(D); // Out-of-line definitions shouldn't be pushed into scope in C++, unless they // are function-local declarations. if (getLangOpts().CPlusPlus && D->isOutOfLine() && !D->getDeclContext()->getRedeclContext()->Equals( D->getLexicalDeclContext()->getRedeclContext()) && !D->getLexicalDeclContext()->isFunctionOrMethod()) return; // Template instantiations should also not be pushed into scope. if (isa(D) && cast(D)->isFunctionTemplateSpecialization()) return; // If this replaces anything in the current scope, IdentifierResolver::iterator I = IdResolver.begin(D->getDeclName()), IEnd = IdResolver.end(); for (; I != IEnd; ++I) { if (S->isDeclScope(*I) && D->declarationReplaces(*I)) { S->RemoveDecl(*I); IdResolver.RemoveDecl(*I); // Should only need to replace one decl. break; } } S->AddDecl(D); if (isa(D) && !cast(D)->isGnuLocal()) { // Implicitly-generated labels may end up getting generated in an order that // isn't strictly lexical, which breaks name lookup. Be careful to insert // the label at the appropriate place in the identifier chain. for (I = IdResolver.begin(D->getDeclName()); I != IEnd; ++I) { DeclContext *IDC = (*I)->getLexicalDeclContext()->getRedeclContext(); if (IDC == CurContext) { if (!S->isDeclScope(*I)) continue; } else if (IDC->Encloses(CurContext)) break; } IdResolver.InsertDeclAfter(I, D); } else { IdResolver.AddDecl(D); } } bool Sema::isDeclInScope(NamedDecl *D, DeclContext *Ctx, Scope *S, bool AllowInlineNamespace) { return IdResolver.isDeclInScope(D, Ctx, S, AllowInlineNamespace); } Scope *Sema::getScopeForDeclContext(Scope *S, DeclContext *DC) { DeclContext *TargetDC = DC->getPrimaryContext(); do { if (DeclContext *ScopeDC = S->getEntity()) if (ScopeDC->getPrimaryContext() == TargetDC) return S; } while ((S = S->getParent())); return nullptr; } static bool isOutOfScopePreviousDeclaration(NamedDecl *, DeclContext*, ASTContext&); /// Filters out lookup results that don't fall within the given scope /// as determined by isDeclInScope. void Sema::FilterLookupForScope(LookupResult &R, DeclContext *Ctx, Scope *S, bool ConsiderLinkage, bool AllowInlineNamespace) { LookupResult::Filter F = R.makeFilter(); while (F.hasNext()) { NamedDecl *D = F.next(); if (isDeclInScope(D, Ctx, S, AllowInlineNamespace)) continue; if (ConsiderLinkage && isOutOfScopePreviousDeclaration(D, Ctx, Context)) continue; F.erase(); } F.done(); } /// We've determined that \p New is a redeclaration of \p Old. Check that they /// have compatible owning modules. bool Sema::CheckRedeclarationModuleOwnership(NamedDecl *New, NamedDecl *Old) { // FIXME: The Modules TS is not clear about how friend declarations are // to be treated. It's not meaningful to have different owning modules for // linkage in redeclarations of the same entity, so for now allow the // redeclaration and change the owning modules to match. if (New->getFriendObjectKind() && Old->getOwningModuleForLinkage() != New->getOwningModuleForLinkage()) { New->setLocalOwningModule(Old->getOwningModule()); makeMergedDefinitionVisible(New); return false; } Module *NewM = New->getOwningModule(); Module *OldM = Old->getOwningModule(); if (NewM && NewM->Kind == Module::PrivateModuleFragment) NewM = NewM->Parent; if (OldM && OldM->Kind == Module::PrivateModuleFragment) OldM = OldM->Parent; if (NewM == OldM) return false; bool NewIsModuleInterface = NewM && NewM->isModulePurview(); bool OldIsModuleInterface = OldM && OldM->isModulePurview(); if (NewIsModuleInterface || OldIsModuleInterface) { // C++ Modules TS [basic.def.odr] 6.2/6.7 [sic]: // if a declaration of D [...] appears in the purview of a module, all // other such declarations shall appear in the purview of the same module Diag(New->getLocation(), diag::err_mismatched_owning_module) << New << NewIsModuleInterface << (NewIsModuleInterface ? NewM->getFullModuleName() : "") << OldIsModuleInterface << (OldIsModuleInterface ? OldM->getFullModuleName() : ""); Diag(Old->getLocation(), diag::note_previous_declaration); New->setInvalidDecl(); return true; } return false; } static bool isUsingDecl(NamedDecl *D) { return isa(D) || isa(D) || isa(D); } /// Removes using shadow declarations from the lookup results. static void RemoveUsingDecls(LookupResult &R) { LookupResult::Filter F = R.makeFilter(); while (F.hasNext()) if (isUsingDecl(F.next())) F.erase(); F.done(); } /// Check for this common pattern: /// @code /// class S { /// S(const S&); // DO NOT IMPLEMENT /// void operator=(const S&); // DO NOT IMPLEMENT /// }; /// @endcode static bool IsDisallowedCopyOrAssign(const CXXMethodDecl *D) { // FIXME: Should check for private access too but access is set after we get // the decl here. if (D->doesThisDeclarationHaveABody()) return false; if (const CXXConstructorDecl *CD = dyn_cast(D)) return CD->isCopyConstructor(); return D->isCopyAssignmentOperator(); } // We need this to handle // // typedef struct { // void *foo() { return 0; } // } A; // // When we see foo we don't know if after the typedef we will get 'A' or '*A' // for example. If 'A', foo will have external linkage. If we have '*A', // foo will have no linkage. Since we can't know until we get to the end // of the typedef, this function finds out if D might have non-external linkage. // Callers should verify at the end of the TU if it D has external linkage or // not. bool Sema::mightHaveNonExternalLinkage(const DeclaratorDecl *D) { const DeclContext *DC = D->getDeclContext(); while (!DC->isTranslationUnit()) { if (const RecordDecl *RD = dyn_cast(DC)){ if (!RD->hasNameForLinkage()) return true; } DC = DC->getParent(); } return !D->isExternallyVisible(); } // FIXME: This needs to be refactored; some other isInMainFile users want // these semantics. static bool isMainFileLoc(const Sema &S, SourceLocation Loc) { if (S.TUKind != TU_Complete) return false; return S.SourceMgr.isInMainFile(Loc); } bool Sema::ShouldWarnIfUnusedFileScopedDecl(const DeclaratorDecl *D) const { assert(D); if (D->isInvalidDecl() || D->isUsed() || D->hasAttr()) return false; // Ignore all entities declared within templates, and out-of-line definitions // of members of class templates. if (D->getDeclContext()->isDependentContext() || D->getLexicalDeclContext()->isDependentContext()) return false; if (const FunctionDecl *FD = dyn_cast(D)) { if (FD->getTemplateSpecializationKind() == TSK_ImplicitInstantiation) return false; // A non-out-of-line declaration of a member specialization was implicitly // instantiated; it's the out-of-line declaration that we're interested in. if (FD->getTemplateSpecializationKind() == TSK_ExplicitSpecialization && FD->getMemberSpecializationInfo() && !FD->isOutOfLine()) return false; if (const CXXMethodDecl *MD = dyn_cast(FD)) { if (MD->isVirtual() || IsDisallowedCopyOrAssign(MD)) return false; } else { // 'static inline' functions are defined in headers; don't warn. if (FD->isInlined() && !isMainFileLoc(*this, FD->getLocation())) return false; } if (FD->doesThisDeclarationHaveABody() && Context.DeclMustBeEmitted(FD)) return false; } else if (const VarDecl *VD = dyn_cast(D)) { // Constants and utility variables are defined in headers with internal // linkage; don't warn. (Unlike functions, there isn't a convenient marker // like "inline".) if (!isMainFileLoc(*this, VD->getLocation())) return false; if (Context.DeclMustBeEmitted(VD)) return false; if (VD->isStaticDataMember() && VD->getTemplateSpecializationKind() == TSK_ImplicitInstantiation) return false; if (VD->isStaticDataMember() && VD->getTemplateSpecializationKind() == TSK_ExplicitSpecialization && VD->getMemberSpecializationInfo() && !VD->isOutOfLine()) return false; if (VD->isInline() && !isMainFileLoc(*this, VD->getLocation())) return false; } else { return false; } // Only warn for unused decls internal to the translation unit. // FIXME: This seems like a bogus check; it suppresses -Wunused-function // for inline functions defined in the main source file, for instance. return mightHaveNonExternalLinkage(D); } void Sema::MarkUnusedFileScopedDecl(const DeclaratorDecl *D) { if (!D) return; if (const FunctionDecl *FD = dyn_cast(D)) { const FunctionDecl *First = FD->getFirstDecl(); if (FD != First && ShouldWarnIfUnusedFileScopedDecl(First)) return; // First should already be in the vector. } if (const VarDecl *VD = dyn_cast(D)) { const VarDecl *First = VD->getFirstDecl(); if (VD != First && ShouldWarnIfUnusedFileScopedDecl(First)) return; // First should already be in the vector. } if (ShouldWarnIfUnusedFileScopedDecl(D)) UnusedFileScopedDecls.push_back(D); } static bool ShouldDiagnoseUnusedDecl(const NamedDecl *D) { if (D->isInvalidDecl()) return false; bool Referenced = false; if (auto *DD = dyn_cast(D)) { // For a decomposition declaration, warn if none of the bindings are // referenced, instead of if the variable itself is referenced (which // it is, by the bindings' expressions). for (auto *BD : DD->bindings()) { if (BD->isReferenced()) { Referenced = true; break; } } } else if (!D->getDeclName()) { return false; } else if (D->isReferenced() || D->isUsed()) { Referenced = true; } if (Referenced || D->hasAttr() || D->hasAttr()) return false; if (isa(D)) return true; // Except for labels, we only care about unused decls that are local to // functions. bool WithinFunction = D->getDeclContext()->isFunctionOrMethod(); if (const auto *R = dyn_cast(D->getDeclContext())) // For dependent types, the diagnostic is deferred. WithinFunction = WithinFunction || (R->isLocalClass() && !R->isDependentType()); if (!WithinFunction) return false; if (isa(D)) return true; // White-list anything that isn't a local variable. if (!isa(D) || isa(D) || isa(D)) return false; // Types of valid local variables should be complete, so this should succeed. if (const VarDecl *VD = dyn_cast(D)) { // White-list anything with an __attribute__((unused)) type. const auto *Ty = VD->getType().getTypePtr(); // Only look at the outermost level of typedef. if (const TypedefType *TT = Ty->getAs()) { if (TT->getDecl()->hasAttr()) return false; } // If we failed to complete the type for some reason, or if the type is // dependent, don't diagnose the variable. if (Ty->isIncompleteType() || Ty->isDependentType()) return fals