| //===--- Type.h - C Language Family Type Representation ---------*- C++ -*-===// |
| // |
| // The LLVM Compiler Infrastructure |
| // |
| // This file is distributed under the University of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // This file defines the Type interface and subclasses. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #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/Diagnostic.h" |
| #include "clang/Basic/ExceptionSpecificationType.h" |
| #include "clang/Basic/IdentifierTable.h" |
| #include "clang/Basic/LLVM.h" |
| #include "clang/Basic/Linkage.h" |
| #include "clang/Basic/PartialDiagnostic.h" |
| #include "clang/Basic/Specifiers.h" |
| #include "clang/Basic/Visibility.h" |
| #include "llvm/ADT/APSInt.h" |
| #include "llvm/ADT/FoldingSet.h" |
| #include "llvm/ADT/iterator_range.h" |
| #include "llvm/ADT/Optional.h" |
| #include "llvm/ADT/PointerIntPair.h" |
| #include "llvm/ADT/PointerUnion.h" |
| #include "llvm/ADT/Twine.h" |
| #include "llvm/Support/ErrorHandling.h" |
| |
| namespace clang { |
| enum { |
| TypeAlignmentInBits = 4, |
| TypeAlignment = 1 << TypeAlignmentInBits |
| }; |
| class Type; |
| class ExtQuals; |
| class QualType; |
| } |
| |
| namespace llvm { |
| template <typename T> |
| class PointerLikeTypeTraits; |
| template<> |
| class PointerLikeTypeTraits< ::clang::Type*> { |
| public: |
| 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<> |
| class PointerLikeTypeTraits< ::clang::ExtQuals*> { |
| public: |
| 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 }; |
| }; |
| |
| template <> |
| struct isPodLike<clang::QualType> { static const bool value = true; }; |
| } |
| |
| namespace clang { |
| class ASTContext; |
| class TypedefNameDecl; |
| class TemplateDecl; |
| class TemplateTypeParmDecl; |
| class NonTypeTemplateParmDecl; |
| class TemplateTemplateParmDecl; |
| class TagDecl; |
| class RecordDecl; |
| class CXXRecordDecl; |
| class EnumDecl; |
| class FieldDecl; |
| class FunctionDecl; |
| class ObjCInterfaceDecl; |
| class ObjCProtocolDecl; |
| class ObjCMethodDecl; |
| class UnresolvedUsingTypenameDecl; |
| class Expr; |
| class Stmt; |
| class SourceLocation; |
| class StmtIteratorBase; |
| class TemplateArgument; |
| class TemplateArgumentLoc; |
| class TemplateArgumentListInfo; |
| class ElaboratedType; |
| class ExtQuals; |
| class ExtQualsTypeCommonBase; |
| struct PrintingPolicy; |
| |
| template <typename> class CanQual; |
| typedef CanQual<Type> CanQualType; |
| |
| // Provide forward declarations for all of the *Type classes |
| #define TYPE(Class, Base) class Class##Type; |
| #include "clang/AST/TypeNodes.def" |
| |
| /// Qualifiers - The collection of all-type qualifiers we support. |
| /// Clang supports five independent qualifiers: |
| /// * C99: const, volatile, and restrict |
| /// * 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. |
| /// 24 bits should be enough for anyone. |
| MaxAddressSpace = 0xffffffu, |
| |
| /// The width of the "fast" qualifier mask. |
| FastWidth = 3, |
| |
| /// The fast qualifier mask. |
| FastMask = (1 << FastWidth) - 1 |
| }; |
| |
| Qualifiers() : Mask(0) {} |
| |
| /// \brief 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; |
| } |
| |
| // 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; } |
| void setConst(bool flag) { |
| Mask = (Mask & ~Const) | (flag ? Const : 0); |
| } |
| void removeConst() { Mask &= ~Const; } |
| void addConst() { Mask |= Const; } |
| |
| bool hasVolatile() const { return Mask & Volatile; } |
| void setVolatile(bool flag) { |
| Mask = (Mask & ~Volatile) | (flag ? Volatile : 0); |
| } |
| void removeVolatile() { Mask &= ~Volatile; } |
| void addVolatile() { Mask |= Volatile; } |
| |
| bool hasRestrict() const { return Mask & Restrict; } |
| void setRestrict(bool flag) { |
| Mask = (Mask & ~Restrict) | (flag ? Restrict : 0); |
| } |
| void removeRestrict() { Mask &= ~Restrict; } |
| void addRestrict() { Mask |= Restrict; } |
| |
| bool hasCVRQualifiers() const { return getCVRQualifiers(); } |
| unsigned getCVRQualifiers() const { return Mask & CVRMask; } |
| 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; |
| } |
| |
| 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; |
| } |
| |
| 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; } |
| unsigned getAddressSpace() const { return Mask >> AddressSpaceShift; } |
| void setAddressSpace(unsigned space) { |
| assert(space <= MaxAddressSpace); |
| Mask = (Mask & ~AddressSpaceMask) |
| | (((uint32_t) space) << AddressSpaceShift); |
| } |
| void removeAddressSpace() { setAddressSpace(0); } |
| void addAddressSpace(unsigned space) { |
| assert(space); |
| 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; |
| } |
| |
| /// hasNonFastQualifiers - 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; |
| } |
| |
| /// hasQualifiers - Return true if the set contains any qualifiers. |
| bool hasQualifiers() const { return Mask; } |
| bool empty() const { return !Mask; } |
| |
| /// \brief 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()); |
| } |
| } |
| |
| /// \brief 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(); |
| } |
| } |
| |
| /// \brief 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; |
| } |
| |
| /// \brief 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 |
| // Address spaces must match exactly. |
| getAddressSpace() == other.getAddressSpace() && |
| // 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)); |
| } |
| |
| /// \brief 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. |
| bool compatiblyIncludesObjCLifetime(Qualifiers other) const { |
| if (getObjCLifetime() == other.getObjCLifetime()) |
| return true; |
| |
| if (getObjCLifetime() == OCL_Weak || other.getObjCLifetime() == OCL_Weak) |
| return false; |
| |
| return hasConst(); |
| } |
| |
| /// \brief 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; } |
| |
| LLVM_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; |
| } |
| |
| /// \brief 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 .. 7|8 ... 31| |
| // |C R V|GCAttr|Lifetime|AddressSpace| |
| uint32_t Mask; |
| |
| static const uint32_t GCAttrMask = 0x18; |
| static const uint32_t GCAttrShift = 3; |
| static const uint32_t LifetimeMask = 0xE0; |
| static const uint32_t LifetimeShift = 5; |
| static const uint32_t AddressSpaceMask = ~(CVRMask|GCAttrMask|LifetimeMask); |
| static const uint32_t AddressSpaceShift = 8; |
| }; |
| |
| /// 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; |
| |
| /// The local qualifiers. |
| Qualifiers Quals; |
| |
| SplitQualType() : Ty(0), Quals() {} |
| SplitQualType(const Type *ty, Qualifiers qs) : Ty(ty), Quals(qs) {} |
| |
| SplitQualType getSingleStepDesugaredType() const; // end of this file |
| |
| // Make std::tie work. |
| std::pair<const Type *,Qualifiers> asPair() const { |
| return std::pair<const Type *, Qualifiers>(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; |
| } |
| }; |
| |
| /// QualType - 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 { |
| // Thankfully, these are efficiently composable. |
| llvm::PointerIntPair<llvm::PointerUnion<const Type*,const ExtQuals*>, |
| Qualifiers::FastWidth> Value; |
| |
| const ExtQuals *getExtQualsUnsafe() const { |
| return Value.getPointer().get<const ExtQuals*>(); |
| } |
| |
| const Type *getTypePtrUnsafe() const { |
| return Value.getPointer().get<const Type*>(); |
| } |
| |
| const ExtQualsTypeCommonBase *getCommonPtr() const { |
| assert(!isNull() && "Cannot retrieve a NULL type pointer"); |
| uintptr_t CommonPtrVal |
| = reinterpret_cast<uintptr_t>(Value.getOpaqueValue()); |
| CommonPtrVal &= ~(uintptr_t)((1 << TypeAlignmentInBits) - 1); |
| return reinterpret_cast<ExtQualsTypeCommonBase*>(CommonPtrVal); |
| } |
| |
| friend class QualifierCollector; |
| public: |
| QualType() {} |
| |
| 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<void*>(Ptr)); |
| return T; |
| } |
| |
| const Type &operator*() const { |
| return *getTypePtr(); |
| } |
| |
| const Type *operator->() const { |
| return getTypePtr(); |
| } |
| |
| bool isCanonical() const; |
| bool isCanonicalAsParam() const; |
| |
| /// isNull - Return true if this QualType doesn't point to a type yet. |
| bool isNull() const { |
| return Value.getPointer().isNull(); |
| } |
| |
| /// \brief 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); |
| } |
| |
| /// \brief Determine whether this type is const-qualified. |
| bool isConstQualified() const; |
| |
| /// \brief 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); |
| } |
| |
| /// \brief Determine whether this type is restrict-qualified. |
| bool isRestrictQualified() const; |
| |
| /// \brief 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); |
| } |
| |
| /// \brief Determine whether this type is volatile-qualified. |
| bool isVolatileQualified() const; |
| |
| /// \brief 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(); |
| } |
| |
| /// \brief Determine whether this type has any qualifiers. |
| bool hasQualifiers() const; |
| |
| /// \brief 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<const ExtQuals*>(); |
| } |
| |
| /// \brief Retrieve the set of qualifiers local to this particular QualType |
| /// instance, not including any qualifiers acquired through typedefs or |
| /// other sugar. |
| Qualifiers getLocalQualifiers() const; |
| |
| /// \brief Retrieve the set of qualifiers applied to this type. |
| Qualifiers getQualifiers() const; |
| |
| /// \brief 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(); |
| } |
| |
| /// \brief Retrieve the set of CVR (const-volatile-restrict) qualifiers |
| /// applied to this type. |
| unsigned getCVRQualifiers() const; |
| |
| bool isConstant(ASTContext& Ctx) const { |
| return QualType::isConstant(*this, Ctx); |
| } |
| |
| /// \brief Determine whether this is a Plain Old Data (POD) type (C++ 3.9p10). |
| bool isPODType(ASTContext &Context) const; |
| |
| /// isCXX98PODType() - 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(ASTContext &Context) const; |
| |
| /// isCXX11PODType() - 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) |
| bool isCXX11PODType(ASTContext &Context) const; |
| |
| /// isTrivialType - Return true if this is a trivial type |
| /// (C++0x [basic.types]p9) |
| bool isTrivialType(ASTContext &Context) const; |
| |
| /// isTriviallyCopyableType - Return true if this is a trivially |
| /// copyable type (C++0x [basic.types]p9) |
| bool isTriviallyCopyableType(ASTContext &Context) const; |
| |
| // Don't promise in the API that anything besides 'const' can be |
| // easily added. |
| |
| /// addConst - add the specified type qualifier to this QualType. |
| void addConst() { |
| addFastQualifiers(Qualifiers::Const); |
| } |
| QualType withConst() const { |
| return withFastQualifiers(Qualifiers::Const); |
| } |
| |
| /// addVolatile - add the specified 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; |
| |
| /// \brief 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); } |
| |
| /// \brief 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; |
| |
| /// getSplitUnqualifiedType - 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; |
| |
| /// \brief Determine whether this type is more qualified than the other |
| /// given type, requiring exact equality for non-CVR qualifiers. |
| bool isMoreQualifiedThan(QualType Other) const; |
| |
| /// \brief 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; |
| |
| /// \brief 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; |
| |
| /// getDesugaredType - 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); |
| } |
| |
| /// \brief 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); |
| } |
| |
| /// IgnoreParens - Returns the specified type after dropping any |
| /// outer-level parentheses. |
| QualType IgnoreParens() const { |
| if (isa<ParenType>(*this)) |
| return QualType::IgnoreParens(*this); |
| return *this; |
| } |
| |
| /// operator==/!= - 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; |
| } |
| std::string getAsString() const { |
| return getAsString(split()); |
| } |
| static std::string getAsString(SplitQualType split) { |
| return getAsString(split.Ty, split.Quals); |
| } |
| static std::string getAsString(const Type *ty, Qualifiers qs); |
| |
| std::string getAsString(const PrintingPolicy &Policy) const; |
| |
| void print(raw_ostream &OS, const PrintingPolicy &Policy, |
| const Twine &PlaceHolder = Twine()) const { |
| print(split(), OS, Policy, PlaceHolder); |
| } |
| static void print(SplitQualType split, raw_ostream &OS, |
| const PrintingPolicy &policy, const Twine &PlaceHolder) { |
| return print(split.Ty, split.Quals, OS, policy, PlaceHolder); |
| } |
| static void print(const Type *ty, Qualifiers qs, |
| raw_ostream &OS, const PrintingPolicy &policy, |
| const Twine &PlaceHolder); |
| |
| void getAsStringInternal(std::string &Str, |
| const PrintingPolicy &Policy) const { |
| return getAsStringInternal(split(), Str, Policy); |
| } |
| 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; |
| public: |
| StreamedQualTypeHelper(const QualType &T, const PrintingPolicy &Policy, |
| const Twine &PlaceHolder) |
| : T(T), Policy(Policy), PlaceHolder(PlaceHolder) { } |
| |
| friend raw_ostream &operator<<(raw_ostream &OS, |
| const StreamedQualTypeHelper &SQT) { |
| SQT.T.print(OS, SQT.Policy, SQT.PlaceHolder); |
| return OS; |
| } |
| }; |
| |
| StreamedQualTypeHelper stream(const PrintingPolicy &Policy, |
| const Twine &PlaceHolder = Twine()) const { |
| return StreamedQualTypeHelper(*this, Policy, PlaceHolder); |
| } |
| |
| void dump(const char *s) const; |
| void dump() const; |
| |
| void Profile(llvm::FoldingSetNodeID &ID) const { |
| ID.AddPointer(getAsOpaquePtr()); |
| } |
| |
| /// getAddressSpace - Return the address space of this type. |
| inline unsigned getAddressSpace() const; |
| |
| /// getObjCGCAttr - Returns gc attribute of this type. |
| inline Qualifiers::GC getObjCGCAttr() const; |
| |
| /// isObjCGCWeak true when Type is objc's weak. |
| bool isObjCGCWeak() const { |
| return getObjCGCAttr() == Qualifiers::Weak; |
| } |
| |
| /// isObjCGCStrong true when Type is objc's strong. |
| bool isObjCGCStrong() const { |
| return getObjCGCAttr() == Qualifiers::Strong; |
| } |
| |
| /// getObjCLifetime - 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(); |
| } |
| |
| enum DestructionKind { |
| DK_none, |
| DK_cxx_destructor, |
| DK_objc_strong_lifetime, |
| DK_objc_weak_lifetime |
| }; |
| |
| /// isDestructedType - nonzero 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); |
| } |
| |
| /// \brief 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; |
| |
| 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, 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); |
| }; |
| |
| } // end 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> { |
| typedef const ::clang::Type *SimpleType; |
| static SimpleType getSimplifiedValue(::clang::QualType Val) { |
| return Val.getTypePtr(); |
| } |
| }; |
| |
| // Teach SmallPtrSet that QualType is "basically a pointer". |
| template<> |
| class PointerLikeTypeTraits<clang::QualType> { |
| public: |
| 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 }; |
| }; |
| |
| } // end namespace llvm |
| |
| namespace clang { |
| |
| /// \brief 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 { |
| ExtQualsTypeCommonBase(const Type *baseType, QualType canon) |
| : BaseType(baseType), CanonicalType(canon) {} |
| |
| /// \brief 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; |
| |
| /// \brief The canonical type of this type. A QualType. |
| QualType CanonicalType; |
| |
| friend class QualType; |
| friend class Type; |
| friend class ExtQuals; |
| }; |
| |
| /// ExtQuals - 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. |
| |
| /// Quals - 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(); } |
| unsigned 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); |
| } |
| }; |
| |
| /// \brief The kind of C++0x ref-qualifier associated with a function type, |
| /// which determines whether a member function's "this" object can be an |
| /// lvalue, rvalue, or neither. |
| enum RefQualifierKind { |
| /// \brief No ref-qualifier was provided. |
| RQ_None = 0, |
| /// \brief An lvalue ref-qualifier was provided (\c &). |
| RQ_LValue, |
| /// \brief An rvalue ref-qualifier was provided (\c &&). |
| RQ_RValue |
| }; |
| |
| /// Type - This is 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 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.def" |
| TagFirst = Record, TagLast = Enum |
| }; |
| |
| private: |
| Type(const Type &) LLVM_DELETED_FUNCTION; |
| void operator=(const Type &) LLVM_DELETED_FUNCTION; |
| |
| /// Bitfields required by the Type class. |
| class TypeBitfields { |
| friend class Type; |
| template <class T> friend class TypePropertyCache; |
| |
| /// TypeClass bitfield - Enum that specifies what subclass this belongs to. |
| unsigned TC : 8; |
| |
| /// Dependent - Whether this type is a dependent type (C++ [temp.dep.type]). |
| unsigned Dependent : 1; |
| |
| /// \brief 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; |
| |
| /// \brief Whether this type is a variably-modified type (C99 6.7.5). |
| unsigned VariablyModified : 1; |
| |
| /// \brief Whether this type contains an unexpanded parameter pack |
| /// (for C++0x variadic templates). |
| unsigned ContainsUnexpandedParameterPack : 1; |
| |
| /// \brief True if the cache (i.e. the bitfields here starting with |
| /// 'Cache') is valid. |
| mutable unsigned CacheValid : 1; |
| |
| /// \brief Linkage of this type. |
| mutable unsigned CachedLinkage : 3; |
| |
| /// \brief Whether this type involves and local or unnamed types. |
| mutable unsigned CachedLocalOrUnnamed : 1; |
| |
| /// \brief FromAST - 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<Linkage>(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; |
| |
| /// IndexTypeQuals - CVR qualifiers from declarations like |
| /// 'int X[static restrict 4]'. For function parameters only. |
| unsigned IndexTypeQuals : 3; |
| |
| /// SizeModifier - storage class qualifiers from declarations like |
| /// 'int X[static restrict 4]'. For function parameters only. |
| /// Actually an ArrayType::ArraySizeModifier. |
| unsigned SizeModifier : 3; |
| }; |
| |
| class BuiltinTypeBitfields { |
| friend class BuiltinType; |
| |
| unsigned : NumTypeBits; |
| |
| /// The kind (BuiltinType::Kind) of builtin type this is. |
| unsigned Kind : 8; |
| }; |
| |
| class FunctionTypeBitfields { |
| friend class FunctionType; |
| |
| unsigned : NumTypeBits; |
| |
| /// Extra information which affects how the function is called, like |
| /// regparm and the calling convention. |
| unsigned ExtInfo : 9; |
| |
| /// TypeQuals - 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 TypeQuals : 3; |
| }; |
| |
| class ObjCObjectTypeBitfields { |
| friend class ObjCObjectType; |
| |
| unsigned : NumTypeBits; |
| |
| /// NumProtocols - The number of protocols stored directly on this |
| /// object type. |
| unsigned NumProtocols : 32 - NumTypeBits; |
| }; |
| |
| 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; |
| }; |
| |
| class VectorTypeBitfields { |
| friend class VectorType; |
| |
| unsigned : NumTypeBits; |
| |
| /// VecKind - The kind of vector, either a generic vector type or some |
| /// target-specific vector type such as for AltiVec or Neon. |
| unsigned VecKind : 3; |
| |
| /// NumElements - The number of elements in the vector. |
| unsigned NumElements : 29 - NumTypeBits; |
| |
| enum { MaxNumElements = (1 << (29 - NumTypeBits)) - 1 }; |
| }; |
| |
| class AttributedTypeBitfields { |
| friend class AttributedType; |
| |
| unsigned : NumTypeBits; |
| |
| /// AttrKind - an AttributedType::Kind |
| unsigned AttrKind : 32 - NumTypeBits; |
| }; |
| |
| class AutoTypeBitfields { |
| friend class AutoType; |
| |
| unsigned : NumTypeBits; |
| |
| /// Was this placeholder type spelled as 'decltype(auto)'? |
| unsigned IsDecltypeAuto : 1; |
| }; |
| |
| union { |
| TypeBitfields TypeBits; |
| ArrayTypeBitfields ArrayTypeBits; |
| AttributedTypeBitfields AttributedTypeBits; |
| AutoTypeBitfields AutoTypeBits; |
| BuiltinTypeBitfields BuiltinTypeBits; |
| FunctionTypeBitfields FunctionTypeBits; |
| ObjCObjectTypeBitfields ObjCObjectTypeBits; |
| ReferenceTypeBitfields ReferenceTypeBits; |
| TypeWithKeywordBitfields TypeWithKeywordBits; |
| VectorTypeBitfields VectorTypeBits; |
| }; |
| |
| private: |
| /// \brief Set whether this type comes from an AST file. |
| void setFromAST(bool V = true) const { |
| TypeBits.FromAST = V; |
| } |
| |
| template <class T> friend class TypePropertyCache; |
| |
| protected: |
| // silence VC++ warning C4355: 'this' : used in base member initializer list |
| Type *this_() { return this; } |
| 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; |
| } |
| friend class ASTContext; |
| |
| 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: |
| TypeClass getTypeClass() const { return static_cast<TypeClass>(TypeBits.TC); } |
| |
| /// \brief Whether this type comes from an AST file. |
| bool isFromAST() const { return TypeBits.FromAST; } |
| |
| /// \brief 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<typename ...T> |
| /// 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. |
| |
| /// isIncompleteType - 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. |
| /// |
| /// \brief 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 = 0) const; |
| |
| /// isIncompleteOrObjectType - Return true if this is an incomplete or object |
| /// type, in other words, not a function type. |
| bool isIncompleteOrObjectType() const { |
| return !isFunctionType(); |
| } |
| |
| /// \brief 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(); |
| } |
| |
| /// isLiteralType - Return true if this is a literal type |
| /// (C++11 [basic.types]p10) |
| bool isLiteralType(const ASTContext &Ctx) const; |
| |
| /// \brief 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. |
| |
| /// isBuiltinType - returns true if the type is a builtin type. |
| bool isBuiltinType() const; |
| |
| /// isSpecificBuiltinType - Test for a particular builtin type. |
| bool isSpecificBuiltinType(unsigned K) const; |
| |
| /// isPlaceholderType - 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; |
| |
| /// isSpecificPlaceholderType - Test for a specific placeholder type. |
| bool isSpecificPlaceholderType(unsigned K) const; |
| |
| /// isNonOverloadPlaceholderType - 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; |
| bool isBooleanType() const; |
| bool isCharType() const; |
| bool isWideCharType() const; |
| bool isChar16Type() const; |
| bool isChar32Type() const; |
| bool isAnyCharacterType() const; |
| bool isIntegralType(ASTContext &Ctx) const; |
| |
| /// \brief Determine whether this type is an integral or enumeration type. |
| bool isIntegralOrEnumerationType() const; |
| /// \brief 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 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<FunctionNoProtoType>(); } |
| bool isFunctionProtoType() const { return getAs<FunctionProtoType>(); } |
| 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 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 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 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)) |
| // 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<foo> |
| bool isObjCQualifiedIdType() const; // id<foo> |
| bool isObjCQualifiedClassType() const; // Class<foo> |
| bool isObjCObjectOrInterfaceType() const; |
| bool isObjCIdType() const; // id |
| bool isObjCClassType() const; // Class |
| 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++0x nullptr_t |
| bool isAtomicType() const; // C11 _Atomic() |
| |
| bool isImage1dT() const; // OpenCL image1d_t |
| bool isImage1dArrayT() const; // OpenCL image1d_array_t |
| bool isImage1dBufferT() const; // OpenCL image1d_buffer_t |
| bool isImage2dT() const; // OpenCL image2d_t |
| bool isImage2dArrayT() const; // OpenCL image2d_array_t |
| bool isImage3dT() const; // OpenCL image3d_t |
| |
| bool isImageType() const; // Any OpenCL image type |
| |
| bool isSamplerT() const; // OpenCL sampler_t |
| bool isEventT() const; // OpenCL event_t |
| |
| 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 |
| }; |
| /// getScalarTypeKind - Given that this is a scalar type, classify it. |
| ScalarTypeKind getScalarTypeKind() const; |
| |
| /// isDependentType - 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; } |
| |
| /// \brief 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; |
| } |
| |
| /// \brief Determine whether this type is an undeduced type, meaning that |
| /// it somehow involves a C++11 'auto' type which has not yet been deduced. |
| bool isUndeducedType() const; |
| |
| /// \brief Whether this type is a variably-modified type (C99 6.7.5). |
| bool isVariablyModifiedType() const { return TypeBits.VariablyModified; } |
| |
| /// \brief Whether this type involves a variable-length array type |
| /// with a definite size. |
| bool hasSizedVLAType() const; |
| |
| /// \brief Whether this type is or contains a local or unnamed type. |
| bool hasUnnamedOrLocalType() const; |
| |
| bool isOverloadableType() const; |
| |
| /// \brief Determine wither this type is a C++ elaborated-type-specifier. |
| bool isElaboratedTypeSpecifier() const; |
| |
| bool canDecayToPointerType() const; |
| |
| /// hasPointerRepresentation - 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; |
| |
| /// hasObjCPointerRepresentation - Whether this type can represent |
| /// an objective pointer type for the purpose of GC'ability |
| bool hasObjCPointerRepresentation() const; |
| |
| /// \brief Determine whether this type has an integer representation |
| /// of some sort, e.g., it is an integer type or a vector. |
| bool hasIntegerRepresentation() const; |
| |
| /// \brief 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; |
| |
| /// \brief 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; |
| |
| /// \brief 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. |
| // 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; |
| |
| /// \brief 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; |
| |
| /// If this is a pointer or reference to a RecordType, return the |
| /// CXXRecordDecl that that 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; |
| |
| /// \brief 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; |
| |
| /// Member-template getAs<specific type>'. Look through sugar for |
| /// an instance of \<specific type>. This scheme will eventually |
| /// replace the specific getAsXXXX methods above. |
| /// |
| /// There are some specializations of this member template listed |
| /// immediately following this class. |
| template <typename T> const T *getAs() const; |
| |
| /// A variant of getAs<> for array types which silently discards |
| /// qualifiers from the outermost type. |
| const ArrayType *getAsArrayTypeUnsafe() const; |
| |
| /// Member-template castAs<specific type>. Look through sugar for |
| /// the underlying instance of \<specific type>. |
| /// |
| /// This method has the same relationship to getAs<T> as cast<T> has |
| /// to dyn_cast<T>; which is to say, the underlying type *must* |
| /// have the intended type, and this method will never return null. |
| template <typename T> const T *castAs() const; |
| |
| /// A variant of castAs<> for array type which silently discards |
| /// qualifiers from the outermost type. |
| const ArrayType *castAsArrayTypeUnsafe() const; |
| |
| /// getBaseElementTypeUnsafe - Get the base element type of this |
| /// type, potentially discarding type qualifiers. This method |
| /// should never be used when type qualifiers are meaningful. |
| const Type *getBaseElementTypeUnsafe() const; |
| |
| /// getArrayElementTypeNoTypeQual - If this is an array type, return the |
| /// element type of the array, potentially with type qualifiers missing. |
| /// This method should never be used when type qualifiers are meaningful. |
| const Type *getArrayElementTypeNoTypeQual() const; |
| |
| /// getPointeeType - If this is a pointer, ObjC object pointer, or block |
| /// pointer, this returns the respective pointee. |
| QualType getPointeeType() const; |
| |
| /// getUnqualifiedDesugaredType() - 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 |
| |
| /// isSignedIntegerType - 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; |
| |
| /// isUnsignedIntegerType - 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; |
| |
| /// isConstantSizeType - 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; |
| |
| /// isSpecifierType - Returns true if this type can be represented by some |
| /// set of type specifiers. |
| bool isSpecifierType() const; |
| |
| /// \brief Determine the linkage of this type. |
| Linkage getLinkage() const; |
| |
| /// \brief Determine the visibility of this type. |
| Visibility getVisibility() const { |
| return getLinkageAndVisibility().getVisibility(); |
| } |
| |
| /// \brief Return true if the visibility was explicitly set is the code. |
| bool isVisibilityExplicit() const { |
| return getLinkageAndVisibility().isVisibilityExplicit(); |
| } |
| |
| /// \brief Determine the linkage and visibility of this type. |
| LinkageInfo getLinkageAndVisibility() const; |
| |
| /// \brief True if the computed linkage is valid. Used for consistency |
| /// checking. Should always return true. |
| bool isLinkageValid() const; |
| |
| const char *getTypeClassName() const; |
| |
| QualType getCanonicalTypeInternal() const { |
| return CanonicalType; |
| } |
| CanQualType getCanonicalTypeUnqualified() const; // in CanonicalType.h |
| void dump() const; |
| |
| friend class ASTReader; |
| friend class ASTWriter; |
| }; |
| |
| /// \brief 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; |
| |
| /// \brief 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; |
| |
| /// \brief 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<Class##Type>(CanonicalType); \ |
| } \ |
| template <> inline const Class##Type *Type::castAs() const { \ |
| return cast<Class##Type>(CanonicalType); \ |
| } |
| #include "clang/AST/TypeNodes.def" |
| |
| |
| /// BuiltinType - 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 { |
| #define BUILTIN_TYPE(Id, SingletonId) Id, |
| #define LAST_BUILTIN_TYPE(Id) LastKind = Id |
| #include "clang/AST/BuiltinTypes.def" |
| }; |
| |
| public: |
| BuiltinType(Kind K) |
| : Type(Builtin, QualType(), /*Dependent=*/(K == Dependent), |
| /*InstantiationDependent=*/(K == Dependent), |
| /*VariablyModified=*/false, |
| /*Unexpanded paramter pack=*/false) { |
| BuiltinTypeBits.Kind = K; |
| } |
| |
| Kind getKind() const { return static_cast<Kind>(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() <= LongDouble; |
| } |
| |
| /// 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; } |
| }; |
| |
| /// ComplexType - C99 6.2.5p11 - Complex values. This supports the C99 complex |
| /// types (_Complex float etc) as well as the GCC integer complex extensions. |
| /// |
| class ComplexType : public Type, public llvm::FoldingSetNode { |
| QualType ElementType; |
| ComplexType(QualType Element, QualType CanonicalPtr) : |
| Type(Complex, CanonicalPtr, Element->isDependentType(), |
| Element->isInstantiationDependentType(), |
| Element->isVariablyModifiedType(), |
| Element->containsUnexpandedParameterPack()), |
| ElementType(Element) { |
| } |
| friend class ASTContext; // ASTContext creates these. |
| |
| 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; } |
| }; |
| |
| /// ParenType - Sugar for parentheses used when specifying types. |
| /// |
| class ParenType : public Type, public llvm::FoldingSetNode { |
| QualType Inner; |
| |
| ParenType(QualType InnerType, QualType CanonType) : |
| Type(Paren, CanonType, InnerType->isDependentType(), |
| InnerType->isInstantiationDependentType(), |
| InnerType->isVariablyModifiedType(), |
| InnerType->containsUnexpandedParameterPack()), |
| Inner(InnerType) { |
| } |
| friend class ASTContext; // ASTContext creates these. |
| |
| 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 { |
| QualType PointeeType; |
| |
| PointerType(QualType Pointee, QualType CanonicalPtr) : |
| Type(Pointer, CanonicalPtr, Pointee->isDependentType(), |
| Pointee->isInstantiationDependentType(), |
| Pointee->isVariablyModifiedType(), |
| Pointee->containsUnexpandedParameterPack()), |
| PointeeType(Pointee) { |
| } |
| friend class ASTContext; // ASTContext creates these. |
| |
| public: |
| |
| 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() == Pointer; } |
| }; |
| |
| /// \brief 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: |
| AdjustedType(TypeClass TC, QualType OriginalTy, QualType AdjustedTy, |
| QualType CanonicalPtr) |
| : Type(TC, CanonicalPtr, OriginalTy->isDependentType(), |
| OriginalTy->isInstantiationDependentType(), |
| OriginalTy->isVariablyModifiedType(), |
| OriginalTy->containsUnexpandedParameterPack()), |
| OriginalTy(OriginalTy), AdjustedTy(AdjustedTy) {} |
| |
| friend class ASTContext; // ASTContext creates these. |
| |
| 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; |
| } |
| }; |
| |
| /// \brief Represents a pointer type decayed from an array or function type. |
| class DecayedType : public AdjustedType { |
| |
| DecayedType(QualType OriginalType, QualType DecayedPtr, QualType CanonicalPtr) |
| : AdjustedType(Decayed, OriginalType, DecayedPtr, CanonicalPtr) { |
| assert(isa<PointerType>(getAdjustedType())); |
| } |
| |
| friend class ASTContext; // ASTContext creates these. |
| |
| public: |
| QualType getDecayedType() const { return getAdjustedType(); } |
| |
| QualType getPointeeType() const { |
| return cast<PointerType>(getDecayedType())->getPointeeType(); |
| } |
| |
| static bool classof(const Type *T) { return T->getTypeClass() == Decayed; } |
| }; |
| |
| /// BlockPointerType - 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 { |
| QualType PointeeType; // Block is some kind of pointer type |
| BlockPointerType(QualType Pointee, QualType CanonicalCls) : |
| Type(BlockPointer, CanonicalCls, Pointee->isDependentType(), |
| Pointee->isInstantiationDependentType(), |
| Pointee->isVariablyModifiedType(), |
| Pointee->containsUnexpandedParameterPack()), |
| PointeeType(Pointee) { |
| } |
| friend class ASTContext; // ASTContext creates these. |
| |
| 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; |
| } |
| }; |
| |
| /// ReferenceType - 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<ReferenceType>(); |
| 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; |
| } |
| }; |
| |
| /// LValueReferenceType - C++ [dcl.ref] - Lvalue reference |
| /// |
| class LValueReferenceType : public ReferenceType { |
| LValueReferenceType(QualType Referencee, QualType CanonicalRef, |
| bool SpelledAsLValue) : |
| ReferenceType(LValueReference, Referencee, CanonicalRef, SpelledAsLValue) |
| {} |
| friend class ASTContext; // ASTContext creates these |
| public: |
| bool isSugared() const { return false; } |
| QualType desugar() const { return QualType(this, 0); } |
| |
| static bool classof(const Type *T) { |
| return T->getTypeClass() == LValueReference; |
| } |
| }; |
| |
| /// RValueReferenceType - C++0x [dcl.ref] - Rvalue reference |
| /// |
| class RValueReferenceType : public ReferenceType { |
| RValueReferenceType(QualType Referencee, QualType CanonicalRef) : |
| ReferenceType(RValueReference, Referencee, CanonicalRef, false) { |
| } |
| friend class ASTContext; // ASTContext creates these |
| public: |
| bool isSugared() const { return false; } |
| QualType desugar() const { return QualType(this, 0); } |
| |
| static bool classof(const Type *T) { |
| return T->getTypeClass() == RValueReference; |
| } |
| }; |
| |
| /// MemberPointerType - C++ 8.3.3 - Pointers to members |
| /// |
| class MemberPointerType : public Type, public llvm::FoldingSetNode { |
| 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) { |
| } |
| friend class ASTContext; // ASTContext creates these. |
| |
| 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; |
| } |
| }; |
| |
| /// ArrayType - C99 6.7.5.2 - Array Declarators. |
| /// |
| class ArrayType : public Type, public llvm::FoldingSetNode { |
| public: |
| /// ArraySizeModifier - 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: |
| /// ElementType - The element type of the array. |
| QualType ElementType; |
| |
| protected: |
| // C++ [temp.dep.type]p1: |
| // A type is dependent if it is... |
| // - an array type constructed from any dependent type or whose |
| // size is specified by a constant expression that is |
| // value-dependent, |
| ArrayType(TypeClass tc, QualType et, QualType can, |
| ArraySizeModifier sm, unsigned tq, |
| bool ContainsUnexpandedParameterPack) |
| : Type(tc, can, et->isDependentType() || tc == DependentSizedArray, |
| et->isInstantiationDependentType() || tc == DependentSizedArray, |
| (tc == VariableArray || et->isVariablyModifiedType()), |
| ContainsUnexpandedParameterPack), |
| ElementType(et) { |
| ArrayTypeBits.IndexTypeQuals = tq; |
| ArrayTypeBits.SizeModifier = sm; |
| } |
| |
| friend class ASTContext; // ASTContext creates these. |
| |
| 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; |
| } |
| }; |
| |
| /// ConstantArrayType - This class 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 : public ArrayType { |
| llvm::APInt Size; // Allows us to unique the type. |
| |
| ConstantArrayType(QualType et, QualType can, const llvm::APInt &size, |
| ArraySizeModifier sm, unsigned tq) |
| : ArrayType(ConstantArray, et, can, sm, tq, |
| et->containsUnexpandedParameterPack()), |
| Size(size) {} |
| protected: |
| ConstantArrayType(TypeClass tc, QualType et, QualType can, |
| const llvm::APInt &size, ArraySizeModifier sm, unsigned tq) |
| : ArrayType(tc, et, can, sm, tq, et->containsUnexpandedParameterPack()), |
| Size(size) {} |
| friend class ASTContext; // ASTContext creates these. |
| public: |
| const llvm::APInt &getSize() const { return Size; } |
| bool isSugared() const { return false; } |
| QualType desugar() const { return QualType(this, 0); } |
| |
| |
| /// \brief 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(ASTContext &Context, |
| QualType ElementType, |
| const llvm::APInt &NumElements); |
| |
| /// \brief 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(ASTContext &Context); |
| |
| void Profile(llvm::FoldingSetNodeID &ID) { |
| Profile(ID, getElementType(), getSize(), |
| getSizeModifier(), getIndexTypeCVRQualifiers()); |
| } |
| static void Profile(llvm::FoldingSetNodeID &ID, QualType ET, |
| const llvm::APInt &ArraySize, ArraySizeModifier SizeMod, |
| unsigned TypeQuals) { |
| ID.AddPointer(ET.getAsOpaquePtr()); |
| ID.AddInteger(ArraySize.getZExtValue()); |
| ID.AddInteger(SizeMod); |
| ID.AddInteger(TypeQuals); |
| } |
| static bool classof(const Type *T) { |
| return T->getTypeClass() == ConstantArray; |
| } |
| }; |
| |
| /// IncompleteArrayType - This class represents C arrays 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 { |
| |
| IncompleteArrayType(QualType et, QualType can, |
| ArraySizeModifier sm, unsigned tq) |
| : ArrayType(IncompleteArray, et, can, sm, tq, |
| et->containsUnexpandedParameterPack()) {} |
| friend class ASTContext; // ASTContext creates these. |
| public: |
| bool isSugared() const { return false; } |
| QualType desugar() const { return QualType(this, 0); } |
| |
| static bool classof(const Type *T) { |
| return T->getTypeClass() == IncompleteArray; |
| } |
| |
| friend class StmtIteratorBase; |
| |
| 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); |
| } |
| }; |
| |
| /// VariableArrayType - This class represents C arrays with a specified size |
| /// which 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 { |
| /// SizeExpr - An assignment expression. VLA's are only permitted within |
| /// a function block. |
| Stmt *SizeExpr; |
| /// Brackets - 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, |
| et->containsUnexpandedParameterPack()), |
| SizeExpr((Stmt*) e), Brackets(brackets) {} |
| friend class ASTContext; // ASTContext creates these. |
| |
| public: |
| 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; |
| } |
| |
| friend class StmtIteratorBase; |
| |
| void Profile(llvm::FoldingSetNodeID &ID) { |
| llvm_unreachable("Cannot unique VariableArrayTypes."); |
| } |
| }; |
| |
| /// DependentSizedArrayType - This type represents an array type in |
| /// C++ whose size is a value-dependent expression. For example: |
| /// |
| /// \code |
| /// template<typename T, int Size> |
| /// 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 { |
| const ASTContext &Context; |
| |
| /// \brief 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; |
| |
| /// Brackets - The left and right array brackets. |
| SourceRange Brackets; |
| |
| DependentSizedArrayType(const ASTContext &Context, QualType et, QualType can, |
| Expr *e, ArraySizeModifier sm, unsigned tq, |
| SourceRange brackets); |
| |
| friend class ASTContext; // ASTContext creates these. |
| |
| public: |
| 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; |
| } |
| |
| friend class StmtIteratorBase; |
| |
| |
| 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); |
| }; |
| |
| /// DependentSizedExtVectorType - This type represent an extended vector type |
| /// where either the type or size is dependent. For example: |
| /// @code |
| /// template<typename T, int Size> |
| /// class vector { |
| /// typedef T __attribute__((ext_vector_type(Size))) type; |
| /// } |
| /// @endcode |
| class DependentSizedExtVectorType : public Type, public llvm::FoldingSetNode { |
| const ASTContext &Context; |
| Expr *SizeExpr; |
| /// ElementType - The element type of the array. |
| QualType ElementType; |
| SourceLocation loc; |
| |
| DependentSizedExtVectorType(const ASTContext &Context, QualType ElementType, |
| QualType can, Expr *SizeExpr, SourceLocation loc); |
| |
| friend class ASTContext; |
| |
| 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); |
| }; |
| |
| |
| /// VectorType - 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 { |
| GenericVector, // not a target-specific vector type |
| AltiVecVector, // is AltiVec vector |
| AltiVecPixel, // is AltiVec 'vector Pixel' |
| AltiVecBool, // is AltiVec 'vector bool ...' |
| NeonVector, // is ARM Neon vector |
| NeonPolyVector // is ARM Neon polynomial vector |
| }; |
| protected: |
| /// ElementType - 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); |
| |
| friend class ASTContext; // ASTContext creates these. |
| |
| 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; |
| } |
| }; |
| |
| /// 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, colors, and textures (modeled after OpenGL Shading Language). |
| class ExtVectorType : public VectorType { |
| ExtVectorType(QualType vecType, unsigned nElements, QualType canonType) : |
| VectorType(ExtVector, vecType, nElements, canonType, GenericVector) {} |
| friend class ASTContext; // ASTContext creates these. |
| public: |
| static int getPointAccessorIdx(char c) { |
| switch (c) { |
| default: return -1; |
| case 'x': return 0; |
| case 'y': return 1; |
| case 'z': return 2; |
| case 'w': 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) { |
| if (int idx = getPointAccessorIdx(c)+1) return idx-1; |
| return getNumericAccessorIdx(c); |
| } |
| |
| bool isAccessorWithinNumElements(char c) const { |
| if (int idx = getAccessorIdx(c)+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: |
| /// ExtInfo - 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 { |
| // Feel free to rearrange or add bits, but if you go over 9, |
| // you'll need to adjust both the Bits field below and |
| // Type::FunctionTypeBitfields. |
| |
| // | CC |noreturn|produces|regparm| |
| // |0 .. 3| 4 | 5 | 6 .. 8| |
| // |
| // regparm is either 0 (no regparm attribute) or the regparm value+1. |
| enum { CallConvMask = 0xF }; |
| enum { NoReturnMask = 0x10 }; |
| enum { ProducesResultMask = 0x20 }; |
| enum { RegParmMask = ~(CallConvMask | NoReturnMask | ProducesResultMask), |
| RegParmOffset = 6 }; // Assumed to be the last field |
| |
| uint16_t Bits; |
| |
| ExtInfo(unsigned Bits) : Bits(static_cast<uint16_t>(Bits)) {} |
| |
| friend class FunctionType; |
| |
| 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) { |
| assert((!hasRegParm || regParm < 7) && "Invalid regparm value"); |
| Bits = ((unsigned) cc) | |
| (noReturn ? NoReturnMask : 0) | |
| (producesResult ? ProducesResultMask : 0) | |
| (hasRegParm ? ((regParm + 1) << RegParmOffset) : 0); |
| } |
| |
| // Constructor with all defaults. Use when for example creating a |
| // function know to use defaults. |
| ExtInfo() : Bits(CC_C) { } |
| |
| // 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 getHasRegParm() const { return (Bits >> RegParmOffset) != 0; } |
| unsigned getRegParm() const { |
| unsigned RegParm = Bits >> 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 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); |
| } |
| }; |
| |
| protected: |
| FunctionType(TypeClass tc, QualType res, |
| unsigned typeQuals, 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; |
| FunctionTypeBits.TypeQuals = typeQuals; |
| } |
| unsigned getTypeQuals() const { return FunctionTypeBits.TypeQuals; } |
| |
| public: |
| QualType getReturnType() const { return ResultType; } |
| |
| bool getHasRegParm() const { return getExtInfo().getHasRegParm(); } |
| unsigned getRegParmType() const { return getExtInfo().getRegParm(); } |
| /// \brief 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); } |
| bool isConst() const { return getTypeQuals() & Qualifiers::Const; } |
| bool isVolatile() const { return getTypeQuals() & Qualifiers::Volatile; } |
| bool isRestrict() const { return getTypeQuals() & Qualifiers::Restrict; } |
| |
| /// \brief Determine the type of an expression that calls a function of |
| /// this type. |
| QualType getCallResultType(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; |
| } |
| }; |
| |
| /// FunctionNoProtoType - Represents a K&R-style 'int foo()' function, which has |
| /// no information available about its arguments. |
| class FunctionNoProtoType : public FunctionType, public llvm::FoldingSetNode { |
| FunctionNoProtoType(QualType Result, QualType Canonical, ExtInfo Info) |
| : FunctionType(FunctionNoProto, Result, 0, Canonical, |
| /*Dependent=*/false, /*InstantiationDependent=*/false, |
| Result->isVariablyModifiedType(), |
| /*ContainsUnexpandedParameterPack=*/false, Info) {} |
| |
| friend class ASTContext; // ASTContext creates these. |
| |
| 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; |
| } |
| }; |
| |
| /// FunctionProtoType - 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. |
| class FunctionProtoType : public FunctionType, public llvm::FoldingSetNode { |
| public: |
| /// ExtProtoInfo - Extra information about a function prototype. |
| struct ExtProtoInfo { |
| ExtProtoInfo() |
| : Variadic(false), HasTrailingReturn(false), TypeQuals(0), |
| ExceptionSpecType(EST_None), RefQualifier(RQ_None), NumExceptions(0), |
| Exceptions(0), NoexceptExpr(0), ExceptionSpecDecl(0), |
| ExceptionSpecTemplate(0), ConsumedParameters(0) {} |
| |
| ExtProtoInfo(CallingConv CC) |
| : ExtInfo(CC), Variadic(false), HasTrailingReturn(false), TypeQuals(0), |
| ExceptionSpecType(EST_None), RefQualifier(RQ_None), NumExceptions(0), |
| Exceptions(0), NoexceptExpr(0), ExceptionSpecDecl(0), |
| ExceptionSpecTemplate(0), ConsumedParameters(0) {} |
| |
| FunctionType::ExtInfo ExtInfo; |
| bool Variadic : 1; |
| bool HasTrailingReturn : 1; |
| unsigned char TypeQuals; |
| ExceptionSpecificationType ExceptionSpecType; |
| RefQualifierKind RefQualifier; |
| unsigned NumExceptions; |
| const QualType *Exceptions; |
| Expr *NoexceptExpr; |
| FunctionDecl *ExceptionSpecDecl; |
| FunctionDecl *ExceptionSpecTemplate; |
| const bool *ConsumedParameters; |
| }; |
| |
| private: |
| /// \brief 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 |