Index: test/Sema/address_spaces.c =================================================================== --- test/Sema/address_spaces.c (revision 82620) +++ test/Sema/address_spaces.c (working copy) @@ -33,6 +33,6 @@ struct _st { __attribute__((address_space(256))) void * * const base = 0; void * get_0(void) { return base[0]; // expected-error {{illegal implicit cast between two pointers with different address spaces}} \ - expected-warning {{returning 'void __attribute__((address_space(256)))*' discards qualifiers, expected 'void *'}} + expected-warning {{returning 'void __attribute__((address_space(256))) *' discards qualifiers, expected 'void *'}} } Index: include/clang/Frontend/PCHReader.h =================================================================== --- include/clang/Frontend/PCHReader.h (revision 82620) +++ include/clang/Frontend/PCHReader.h (working copy) @@ -206,7 +206,7 @@ private: /// /// When the pointer at index I is non-NULL, the type with /// ID = (I + 1) << 3 has already been loaded from the PCH file. - std::vector TypesLoaded; + std::vector TypesLoaded; /// \brief Offset of each declaration within the bitstream, indexed /// by the declaration ID (-1). Index: include/clang/Frontend/DocumentXML.h =================================================================== --- include/clang/Frontend/DocumentXML.h (revision 82620) +++ include/clang/Frontend/DocumentXML.h (working copy) @@ -132,6 +132,7 @@ private: // for addAttributeOptional: static bool isDefault(unsigned value) { return value == 0; } static bool isDefault(bool value) { return !value; } + static bool isDefault(Qualifiers::GC value) { return value == Qualifiers::GCNone; } static bool isDefault(const std::string& value) { return value.empty(); } }; Index: include/clang/Frontend/PCHWriter.h =================================================================== --- include/clang/Frontend/PCHWriter.h (revision 82620) +++ include/clang/Frontend/PCHWriter.h (working copy) @@ -40,6 +40,24 @@ class SourceManager; class SwitchCase; class TargetInfo; +/// A structure for putting "fast"-unqualified QualTypes into a +/// DenseMap. This uses the standard pointer hash function. +struct UnsafeQualTypeDenseMapInfo { + static inline bool isEqual(QualType A, QualType B) { return A == B; } + static inline bool isPod() { return true; } + static inline QualType getEmptyKey() { + return QualType::getFromOpaquePtr((void*) 1); + } + static inline QualType getTombstoneKey() { + return QualType::getFromOpaquePtr((void*) 2); + } + static inline unsigned getHashValue(QualType T) { + assert(!T.getFastQualifiers() && "hash invalid for types with fast quals"); + uintptr_t v = reinterpret_cast(T.getAsOpaquePtr()); + return (unsigned(v) >> 4) ^ (unsigned(v) >> 9); + } +}; + /// \brief Writes a precompiled header containing the contents of a /// translation unit. /// @@ -76,9 +94,11 @@ private: /// /// The ID numbers of types are consecutive (in order of discovery) /// and start at 1. 0 is reserved for NULL. When types are actually - /// stored in the stream, the ID number is shifted by 3 bits to - /// allow for the const/volatile/restrict qualifiers. - llvm::DenseMap TypeIDs; + /// stored in the stream, the ID number is shifted by 2 bits to + /// allow for the const/volatile qualifiers. + /// + /// Keys in the map never have const/volatile qualifiers. + llvm::DenseMap TypeIDs; /// \brief Offset of each type in the bitstream, indexed by /// the type's ID. @@ -89,7 +109,7 @@ private: /// \brief Queue containing the types that we still need to /// emit. - std::queue TypesToEmit; + std::queue TypesToEmit; /// \brief Map that provides the ID numbers of each identifier in /// the output stream. @@ -168,7 +188,7 @@ private: const char* isysroot); void WritePreprocessor(const Preprocessor &PP); void WriteComments(ASTContext &Context); - void WriteType(const Type *T); + void WriteType(QualType T); void WriteTypesBlock(ASTContext &Context); uint64_t WriteDeclContextLexicalBlock(ASTContext &Context, DeclContext *DC); uint64_t WriteDeclContextVisibleBlock(ASTContext &Context, DeclContext *DC); Index: include/clang/Frontend/TypeXML.def =================================================================== --- include/clang/Frontend/TypeXML.def (revision 82620) +++ include/clang/Frontend/TypeXML.def (working copy) @@ -68,17 +68,8 @@ NODE_XML(QualType, "CvQualifiedType") ATTRIBUTE_OPT_XML(isConstQualified(), "const") // boolean ATTRIBUTE_OPT_XML(isVolatileQualified(), "volatile") // boolean ATTRIBUTE_OPT_XML(isRestrictQualified(), "restrict") // boolean -END_NODE_XML - -NODE_XML(ExtQualType, "ExtQualType") - ID_ATTRIBUTE_XML - TYPE_ATTRIBUTE_XML(getBaseType()) - ATTRIBUTE_OPT_XML(getAddressSpace(), "adress_space") // unsigned: Address Space ID - The address space ID this type is qualified with. - ATTRIBUTE_ENUM_OPT_XML(getObjCGCAttr(), "objc_gc") // GC __weak/__strong attributes - ENUM_XML(QualType::GCNone, "") - ENUM_XML(QualType::Weak, "weak") - ENUM_XML(QualType::Strong, "strong") - END_ENUM_XML + ATTRIBUTE_OPT_XML(getObjCGCAttr(), "objc_gc") // Qualifiers::GC + ATTRIBUTE_OPT_XML(getAddressSpace(), "address_space") // unsigned END_NODE_XML NODE_XML(BuiltinType, "FundamentalType") @@ -175,7 +166,7 @@ NODE_XML(ConstantArrayType, "ArrayType") ENUM_XML(ArrayType::Static, "static") ENUM_XML(ArrayType::Star, "star") END_ENUM_XML - ATTRIBUTE_OPT_XML(getIndexTypeQualifier(), "index_type_qualifier") // unsigned + ATTRIBUTE_OPT_XML(getIndexTypeCVRQualifiers(), "index_type_qualifier") // unsigned END_NODE_XML NODE_XML(IncompleteArrayType, "IncompleteArrayType") Index: include/clang/AST/CanonicalType.h =================================================================== --- include/clang/AST/CanonicalType.h (revision 82620) +++ include/clang/AST/CanonicalType.h (working copy) @@ -103,20 +103,23 @@ public: /// proxy. CanProxy operator->() const; + /// \brief Retrieve all qualifiers. + Qualifiers getQualifiers() const { return Stored.getQualifiers(); } + /// \brief Retrieve the const/volatile/restrict qualifiers. unsigned getCVRQualifiers() const { return Stored.getCVRQualifiers(); } - /// \brief Set the const/volatile/restrict qualifiers - void setCVRQualifiers(unsigned Quals) { Stored.setCVRQualifiers(Quals); } + /// \brief Determines whether this type has any qualifiers + bool hasQualifiers() const { return Stored.hasQualifiers(); } bool isConstQualified() const { - return (getCVRQualifiers() & QualType::Const) ? true : false; + return Stored.isConstQualified(); } bool isVolatileQualified() const { - return (getCVRQualifiers() & QualType::Volatile) ? true : false; + return Stored.isVolatileQualified(); } bool isRestrictQualified() const { - return (getCVRQualifiers() & QualType::Restrict) ? true : false; + return Stored.isRestrictQualified(); } /// \brief Retrieve the unqualified form of this type. @@ -322,7 +325,7 @@ public: static inline clang::CanQual getFromVoidPointer(void *P) { return clang::CanQual::getFromOpaquePtr(P); } - // CVR qualifiers go in low bits. + // qualifier information is encoded in the low bits. enum { NumLowBitsAvailable = 0 }; }; @@ -426,13 +429,6 @@ public: }; template<> -struct CanProxyAdaptor : public CanProxyBase { - LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(Type*, getBaseType) - LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(QualType::GCAttrTypes, getObjCGCAttr) - LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(unsigned, getAddressSpace) -}; - -template<> struct CanProxyAdaptor : public CanProxyBase { LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getElementType) }; @@ -477,7 +473,7 @@ struct CanProxyAdaptor : publ LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getElementType) LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(ArrayType::ArraySizeModifier, getSizeModifier) - LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(unsigned, getIndexTypeQualifier) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(Qualifiers, getIndexTypeQualifiers) }; template<> @@ -486,7 +482,7 @@ struct CanProxyAdaptor @@ -529,7 +525,7 @@ struct CanProxyAdaptor inline CanQual CanQual::getUnqualifiedType() const { - if (CanQual EQ = getAs()) - return CanQual::CreateUnsafe(QualType(EQ->getBaseType(), 0)); - return CanQual::CreateUnsafe(QualType(Stored.getTypePtr(), 0)); + return CanQual::CreateUnsafe(Stored.getUnqualifiedType()); } template @@ -707,10 +701,6 @@ CanProxy CanQual::getAs() const { if (isa(Stored.getTypePtr())) return CanQual::CreateUnsafe(Stored); - if (const ExtQualType *EQ = Stored->getAs()) - return CanQual::CreateUnsafe(QualType(EQ->getBaseType(), 0)) - .template getAs(); - return CanProxy(); } Index: include/clang/AST/TypeNodes.def =================================================================== --- include/clang/AST/TypeNodes.def (revision 82620) +++ include/clang/AST/TypeNodes.def (working copy) @@ -51,7 +51,6 @@ # define DEPENDENT_TYPE(Class, Base) TYPE(Class, Base) #endif -TYPE(ExtQual, Type) TYPE(Builtin, Type) TYPE(FixedWidthInt, Type) TYPE(Complex, Type) Index: include/clang/AST/ASTContext.h =================================================================== --- include/clang/AST/ASTContext.h (revision 82620) +++ include/clang/AST/ASTContext.h (working copy) @@ -63,7 +63,7 @@ namespace clang { /// decls) that can be referred to throughout the semantic analysis of a file. class ASTContext { std::vector Types; - llvm::FoldingSet ExtQualTypes; + llvm::FoldingSet ExtQualNodes; llvm::FoldingSet ComplexTypes; llvm::FoldingSet PointerTypes; llvm::FoldingSet BlockPointerTypes; @@ -332,6 +332,11 @@ public: // Type Constructors //===--------------------------------------------------------------------===// +private: + /// getExtQualType - Return a type with extended qualifiers. + QualType getExtQualType(const Type *Base, Qualifiers Quals); + +public: /// getAddSpaceQualType - Return the uniqued reference to the type for an /// address space qualified type with the specified type and address space. /// The resulting type has a union of the qualifiers from T and the address @@ -342,7 +347,27 @@ public: /// getObjCGCQualType - Returns the uniqued reference to the type for an /// objc gc qualified type. The retulting type has a union of the qualifiers /// from T and the gc attribute. - QualType getObjCGCQualType(QualType T, QualType::GCAttrTypes gcAttr); + QualType getObjCGCQualType(QualType T, Qualifiers::GC gcAttr); + + /// getRestrictType - Returns the uniqued reference to the type for a + /// 'restrict' qualified type. The resulting type has a union of the + /// qualifiers from T and 'restrict'. + QualType getRestrictType(QualType T) { + return T.withFastQualifiers(Qualifiers::Restrict); + } + + /// getVolatileType - Returns the uniqued reference to the type for a + /// 'volatile' qualified type. The resulting type has a union of the + /// qualifiers from T and 'volatile'. + QualType getVolatileType(QualType T); + + /// getConstType - Returns the uniqued reference to the type for a + /// 'const' qualified type. The resulting type has a union of the + /// qualifiers from T and 'const'. + /// + /// It can be reasonably expected that this will always be + /// equivalent to calling T.withConst(). + QualType getConstType(QualType T) { return T.withConst(); } /// getNoReturnType - Add the noreturn attribute to the given type which must /// be a FunctionType or a pointer to an allowable type or a BlockPointer. @@ -636,6 +661,28 @@ public: QualType getFixedWidthIntType(unsigned Width, bool Signed); + /// getCVRQualifiedType - Returns a type with additional const, + /// volatile, or restrict qualifiers. + QualType getCVRQualifiedType(QualType T, unsigned CVR) { + return getQualifiedType(T, Qualifiers::fromCVRMask(CVR)); + } + + /// getQualifiedType - Returns a type with additional qualifiers. + QualType getQualifiedType(QualType T, Qualifiers Qs) { + if (!Qs.hasNonFastQualifiers()) + return T.withFastQualifiers(Qs.getFastQualifiers()); + QualifierCollector Qc(Qs); + const Type *Ptr = Qc.strip(T); + return getExtQualType(Ptr, Qc); + } + + /// getQualifiedType - Returns a type with additional qualifiers. + QualType getQualifiedType(const Type *T, Qualifiers Qs) { + if (!Qs.hasNonFastQualifiers()) + return QualType(T, Qs.getFastQualifiers()); + return getExtQualType(T, Qs); + } + TemplateName getQualifiedTemplateName(NestedNameSpecifier *NNS, bool TemplateKeyword, TemplateDecl *Template); @@ -666,7 +713,7 @@ public: /// getObjCGCAttr - Returns one of GCNone, Weak or Strong objc's /// garbage collection attribute. /// - QualType::GCAttrTypes getObjCGCAttrKind(const QualType &Ty) const; + Qualifiers::GC getObjCGCAttrKind(const QualType &Ty) const; /// isObjCNSObjectType - Return true if this is an NSObject object with /// its NSObject attribute set. Index: include/clang/AST/Type.h =================================================================== --- include/clang/AST/Type.h (revision 82620) +++ include/clang/AST/Type.h (working copy) @@ -30,7 +30,7 @@ using llvm::cast; using llvm::cast_or_null; using llvm::dyn_cast; using llvm::dyn_cast_or_null; -namespace clang { class Type; } +namespace clang { class Type; class ExtQuals; } namespace llvm { template @@ -44,6 +44,15 @@ namespace llvm { } enum { NumLowBitsAvailable = 3 }; }; + 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 = 3 }; + }; } namespace clang { @@ -73,43 +82,345 @@ namespace clang { #define TYPE(Class, Base) class Class##Type; #include "clang/AST/TypeNodes.def" -/// QualType - For efficiency, we don't store CVR-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 three 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. -class QualType { - llvm::PointerIntPair Value; +/// 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. + enum TQ { // NOTE: These flags must be kept in sync with DeclSpec::TQ. Const = 0x1, Restrict = 0x2, Volatile = 0x4, - CVRFlags = Const|Restrict|Volatile + CVRMask = Const | Volatile | Restrict }; - enum GCAttrTypes { + enum GC { GCNone = 0, Weak, Strong }; - // 24 bits should be enough for anyone. - static const unsigned MaxAddressSpace = 0xffffffu; + enum { + /// The maximum supported address space number. + /// 24 bits should be enough for anyone. + MaxAddressSpace = 0xffffffu, + + /// The width of the "fast" qualifier mask. + FastWidth = 2, + + /// The fast qualifier mask. + FastMask = (1 << FastWidth) - 1 + }; + + Qualifiers() : Mask(0) {} + + 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); + } + + 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()); + } + } + + bool operator==(Qualifiers Other) const { return Mask == Other.Mask; } + bool operator!=(Qualifiers Other) const { return Mask != Other.Mask; } + + 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; + } + + std::string getAsString() const; + std::string getAsString(const PrintingPolicy &Policy) const { + std::string Buffer; + getAsStringInternal(Buffer, Policy); + return Buffer; + } + void getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const; + + void Profile(llvm::FoldingSetNodeID &ID) const { + ID.AddInteger(Mask); + } + +private: + + // bits: |0 1 2|3 .. 4|5 .. 31| + // |C R V|GCAttr|AddrSpace| + uint32_t Mask; + + static const uint32_t GCAttrMask = 0x18; + static const uint32_t GCAttrShift = 3; + static const uint32_t AddressSpaceMask = ~(CVRMask | GCAttrMask); + static const uint32_t AddressSpaceShift = 5; +}; + + +/// ExtQuals - We can encode up to three 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' and 'restrict' qualifiers in +/// two low bits on the QualType pointer; a third bit records whether +/// the pointer is an ExtQuals node. 'const' was chosen because it is +/// orders of magnitude more common than the other two qualifiers, in +/// both library and user code. It's relatively rare to see +/// 'restrict' in user code, but many standard C headers are saturated +/// with 'restrict' declarations, so that representing them efficiently +/// is a critical goal of this representation. +class ExtQuals : 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. + + /// Context - the context to which this set belongs. We save this + /// here so that QualifierCollector can use it to reapply extended + /// qualifiers to an arbitrary type without requiring a context to + /// be pushed through every single API dealing with qualifiers. + ASTContext& Context; + + /// BaseType - the underlying type that this qualifies + const Type *BaseType; + + /// Quals - the immutable set of qualifiers applied by this + /// node; always contains extended qualifiers. + Qualifiers Quals; + +public: + ExtQuals(ASTContext& Context, const Type *Base, Qualifiers Quals) + : Context(Context), BaseType(Base), 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 hasVolatile() const { return Quals.hasVolatile(); } + + bool hasObjCGCAttr() const { return Quals.hasObjCGCAttr(); } + Qualifiers::GC getObjCGCAttr() const { return Quals.getObjCGCAttr(); } + + bool hasAddressSpace() const { return Quals.hasAddressSpace(); } + unsigned getAddressSpace() const { return Quals.getAddressSpace(); } + + const Type *getBaseType() const { return BaseType; } + + ASTContext &getContext() const { return Context; } + +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); + } +}; + + +/// 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, + Qualifiers::FastWidth> Value; + + bool hasExtQuals() const { + return Value.getPointer().is(); + } + + const ExtQuals *getExtQualsUnsafe() const { + return Value.getPointer().get(); + } + const Type *getTypePtrUnsafe() const { + return Value.getPointer().get(); + } + + friend class QualifierCollector; +public: QualType() {} QualType(const Type *Ptr, unsigned Quals) - : Value(const_cast(Ptr), Quals) {} - - unsigned getCVRQualifiers() const { return Value.getInt(); } - void setCVRQualifiers(unsigned Quals) { Value.setInt(Quals); } - Type *getTypePtr() const { return Value.getPointer(); } + : Value(Ptr, Quals) {} + QualType(const ExtQuals *Ptr, unsigned Quals) + : Value(Ptr, Quals) {} + + unsigned getFastQualifiers() const { return Value.getInt(); } + void setFastQualifiers(unsigned Quals) { Value.setInt(Quals); } + + /// Retrieves a pointer to the underlying (unqualified) type. + /// This should really return a const Type, but it's not worth + /// changing all the users right now. + Type *getTypePtr() const { + if (hasNonFastQualifiers()) + return const_cast(getExtQualsUnsafe()->getBaseType()); + return const_cast(getTypePtrUnsafe()); + } void *getAsOpaquePtr() const { return Value.getOpaqueValue(); } static QualType getFromOpaquePtr(void *Ptr) { @@ -128,43 +439,97 @@ public: /// isNull - Return true if this QualType doesn't point to a type yet. bool isNull() const { - return getTypePtr() == 0; + return Value.getPointer().isNull(); } bool isConstQualified() const { - return (getCVRQualifiers() & Const) ? true : false; + return (getFastQualifiers() & Qualifiers::Const); + } + bool isRestrictQualified() const { + return (getFastQualifiers() & Qualifiers::Restrict); } bool isVolatileQualified() const { - return (getCVRQualifiers() & Volatile) ? true : false; + return (hasNonFastQualifiers() && getExtQualsUnsafe()->hasVolatile()); } - bool isRestrictQualified() const { - return (getCVRQualifiers() & Restrict) ? true : false; + + // Determines whether this type has any direct qualifiers. + bool hasQualifiers() const { + return getFastQualifiers() || hasNonFastQualifiers(); + } + + bool hasNonFastQualifiers() const { + return hasExtQuals(); + } + + // Retrieves the set of qualifiers belonging to this type. + Qualifiers getQualifiers() const { + Qualifiers Quals; + if (hasNonFastQualifiers()) + Quals = getExtQualsUnsafe()->getQualifiers(); + Quals.addFastQualifiers(getFastQualifiers()); + return Quals; + } + + // Retrieves the CVR qualifiers of this type. + unsigned getCVRQualifiers() const { + unsigned CVR = getFastQualifiers(); + if (isVolatileQualified()) CVR |= Qualifiers::Volatile; + return CVR; } bool isConstant(ASTContext& Ctx) const; - /// addConst/addVolatile/addRestrict - add the specified type qual to this - /// QualType. - void addConst() { Value.setInt(Value.getInt() | Const); } - void addVolatile() { Value.setInt(Value.getInt() | Volatile); } - void addRestrict() { Value.setInt(Value.getInt() | Restrict); } + // Don't promise in the API that anything besides 'const' can be + // easily added. - void removeConst() { Value.setInt(Value.getInt() & ~Const); } - void removeVolatile() { Value.setInt(Value.getInt() & ~Volatile); } - void removeRestrict() { Value.setInt(Value.getInt() & ~Restrict); } + /// addConst - add the specified type qualifier to this QualType. + void addConst() { + addFastQualifiers(Qualifiers::Const); + } + QualType withConst() const { + return withFastQualifiers(Qualifiers::Const); + } + + void addFastQualifiers(unsigned TQs) { + assert(!(TQs & ~Qualifiers::FastMask) + && "non-fast qualifier bits set in mask!"); + Value.setInt(Value.getInt() | TQs); + } + + void removeConst(); + void removeVolatile(); + void removeRestrict(); + void removeCVRQualifiers(unsigned Mask); + + void removeFastQualifiers() { Value.setInt(0); } + void removeFastQualifiers(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; + } - QualType getQualifiedType(unsigned TQs) const { - return QualType(getTypePtr(), TQs); + // Creates a type with exactly the given fast qualifiers, removing + // any existing fast qualifiers. + QualType withExactFastQualifiers(unsigned TQs) const { + return withoutFastQualifiers().withFastQualifiers(TQs); } - QualType getWithAdditionalQualifiers(unsigned TQs) const { - return QualType(getTypePtr(), TQs|getCVRQualifiers()); + + // Removes fast qualifiers, but leaves any extended qualifiers in place. + QualType withoutFastQualifiers() const { + QualType T = *this; + T.removeFastQualifiers(); + return T; } - QualType withConst() const { return getWithAdditionalQualifiers(Const); } - QualType withVolatile() const { return getWithAdditionalQualifiers(Volatile);} - QualType withRestrict() const { return getWithAdditionalQualifiers(Restrict);} + QualType getUnqualifiedType() const { return QualType(getTypePtr(), 0); } - QualType getUnqualifiedType() const; bool isMoreQualifiedThan(QualType Other) const; bool isAtLeastAsQualifiedAs(QualType Other) const; QualType getNonReferenceType() const; @@ -175,6 +540,8 @@ public: /// 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(bool ForDisplay = false) const; /// operator==/!= - Indicate whether the specified types and qualifiers are @@ -202,22 +569,20 @@ public: ID.AddPointer(getAsOpaquePtr()); } -public: - /// getAddressSpace - Return the address space of this type. inline unsigned getAddressSpace() const; /// GCAttrTypesAttr - Returns gc attribute of this type. - inline QualType::GCAttrTypes getObjCGCAttr() const; + inline Qualifiers::GC getObjCGCAttr() const; /// isObjCGCWeak true when Type is objc's weak. bool isObjCGCWeak() const { - return getObjCGCAttr() == Weak; + return getObjCGCAttr() == Qualifiers::Weak; } /// isObjCGCStrong true when Type is objc's strong. bool isObjCGCStrong() const { - return getObjCGCAttr() == Strong; + return getObjCGCAttr() == Qualifiers::Strong; } /// getNoReturnAttr - Returns true if the type has the noreturn attribute, @@ -249,7 +614,7 @@ public: static inline clang::QualType getFromVoidPointer(void *P) { return clang::QualType::getFromOpaquePtr(P); } - // CVR qualifiers go in low bits. + // Various qualifiers go in low bits. enum { NumLowBitsAvailable = 0 }; }; @@ -519,151 +884,11 @@ template <> inline const TypedefType *Ty #define TYPE(Class, Base) #define LEAF_TYPE(Class) \ template <> inline const Class##Type *Type::getAs() const { \ - return dyn_cast(CanonicalType.getUnqualifiedType()); \ + return dyn_cast(CanonicalType); \ } #include "clang/AST/TypeNodes.def" -/// ExtQualType - TR18037 (C embedded extensions) 6.2.5p26 -/// This supports all kinds of type attributes; including, -/// address space qualified types, objective-c's __weak and -/// __strong attributes. -/// -class ExtQualType : public Type, public llvm::FoldingSetNode { - /// BaseType - This is the underlying type that this qualifies. All CVR - /// qualifiers are stored on the QualType that references this type, so we - /// can't have any here. - Type *BaseType; - - /// Address Space ID - The address space ID this type is qualified with. - unsigned AddressSpace; - /// GC __weak/__strong attributes - QualType::GCAttrTypes GCAttrType; - - ExtQualType(Type *Base, QualType CanonicalPtr, unsigned AddrSpace, - QualType::GCAttrTypes gcAttr) : - Type(ExtQual, CanonicalPtr, Base->isDependentType()), BaseType(Base), - AddressSpace(AddrSpace), GCAttrType(gcAttr) { - assert(!isa(BaseType) && - "Cannot have ExtQualType of ExtQualType"); - } - friend class ASTContext; // ASTContext creates these. -public: - Type *getBaseType() const { return BaseType; } - QualType::GCAttrTypes getObjCGCAttr() const { return GCAttrType; } - unsigned getAddressSpace() const { return AddressSpace; } - - virtual void getAsStringInternal(std::string &InnerString, - const PrintingPolicy &Policy) const; - - void Profile(llvm::FoldingSetNodeID &ID) { - Profile(ID, getBaseType(), AddressSpace, GCAttrType); - } - static void Profile(llvm::FoldingSetNodeID &ID, Type *Base, - unsigned AddrSpace, QualType::GCAttrTypes gcAttr) { - ID.AddPointer(Base); - ID.AddInteger(AddrSpace); - ID.AddInteger(gcAttr); - } - - static bool classof(const Type *T) { return T->getTypeClass() == ExtQual; } - static bool classof(const ExtQualType *) { return true; } -}; - - -/// QualifierSet - This class is used to collect qualifiers. -/// 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 QualifierSet { -public: - QualifierSet() : Mask(0) {} - - void removeConst() { removeCVR(QualType::Const); } - void removeVolatile() { removeCVR(QualType::Volatile); } - void removeRestrict() { removeCVR(QualType::Restrict); } - void removeCVR(unsigned mask) { Mask &= ~mask; } - void removeAddressSpace() { setAddressSpace(0); } - void removeObjCGCAttrType() { setGCAttrType(QualType::GCNone); } - - void addConst() { addCVR(QualType::Const); } - void addVolatile() { addCVR(QualType::Volatile); } - void addRestrict() { addCVR(QualType::Restrict); } - void addCVR(unsigned mask) { Mask |= mask; } - void addAddressSpace(unsigned space) { - assert(space); - setAddressSpace(space); - } - void addObjCGCAttrType(QualType::GCAttrTypes type) { - assert(type); - setGCAttrType(type); - } - - bool hasConst() const { return Mask & QualType::Const; } - bool hasVolatile() const { return Mask & QualType::Volatile; } - bool hasRestrict() const { return Mask & QualType::Restrict; } - unsigned getCVRMask() const { return Mask & CVRMask; } - - bool hasObjCGCAttrType() const { return Mask & GCAttrMask; } - QualType::GCAttrTypes getObjCGCAttrType() const { - return QualType::GCAttrTypes((Mask & GCAttrMask) >> GCAttrShift); - } - - bool hasAddressSpace() const { return Mask & AddressSpaceMask; } - unsigned getAddressSpace() const { return Mask >> AddressSpaceShift; } - - /// empty() - Return true if there are no qualifiers collected - /// in this set. - bool empty() { - return (Mask == 0); - } - - /// Collect any qualifiers on the given type and return an - /// unqualified type. - const Type *strip(QualType QT) { - Mask |= QT.getCVRQualifiers(); - return strip(QT.getTypePtr()); - } - - /// Collect any qualifiers on the given type and return an - /// unqualified type. - const Type *strip(const Type* T); - - /// Apply the collected qualifiers to the given type. - QualType apply(QualType QT, ASTContext& C); - - /// Apply the collected qualifiers to the given type. - QualType apply(const Type* T, ASTContext& C) { - return apply(QualType(T, 0), C); - } - - bool operator==(QualifierSet& Other) { return Mask == Other.Mask; } - -private: - void setAddressSpace(unsigned space) { - assert(space <= MaxAddressSpace); - Mask = (Mask & ~AddressSpaceMask) - | (((uint32_t) space) << AddressSpaceShift); - } - - void setGCAttrType(QualType::GCAttrTypes type) { - Mask = (Mask & ~GCAttrMask) | (type << GCAttrShift); - } - - // bits: |0 1 2|3 .. 4|5 .. 31| - // |C R V|GCAttr|AddrSpace| - uint32_t Mask; - - static const uint32_t CVRMask = 0x07; - static const uint32_t GCAttrMask = 0x18; - static const uint32_t GCAttrShift = 3; - static const uint32_t AddressSpaceMask = ~(CVRMask | GCAttrMask); - static const uint32_t AddressSpaceShift = 5; - static const unsigned MaxAddressSpace = QualType::MaxAddressSpace; -}; - - /// 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 { @@ -967,7 +1192,10 @@ public: ArraySizeModifier getSizeModifier() const { return ArraySizeModifier(SizeModifier); } - unsigned getIndexTypeQualifier() const { return IndexTypeQuals; } + Qualifiers getIndexTypeQualifiers() const { + return Qualifiers::fromCVRMask(IndexTypeQuals); + } + unsigned getIndexTypeCVRQualifiers() const { return IndexTypeQuals; } static bool classof(const Type *T) { return T->getTypeClass() == ConstantArray || @@ -1003,7 +1231,7 @@ public: void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, getElementType(), getSize(), - getSizeModifier(), getIndexTypeQualifier()); + getSizeModifier(), getIndexTypeCVRQualifiers()); } static void Profile(llvm::FoldingSetNodeID &ID, QualType ET, const llvm::APInt &ArraySize, ArraySizeModifier SizeMod, @@ -1109,7 +1337,8 @@ public: friend class StmtIteratorBase; void Profile(llvm::FoldingSetNodeID &ID) { - Profile(ID, getElementType(), getSizeModifier(), getIndexTypeQualifier()); + Profile(ID, getElementType(), getSizeModifier(), + getIndexTypeCVRQualifiers()); } static void Profile(llvm::FoldingSetNodeID &ID, QualType ET, @@ -1226,7 +1455,7 @@ public: void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, Context, getElementType(), - getSizeModifier(), getIndexTypeQualifier(), getSizeExpr()); + getSizeModifier(), getIndexTypeCVRQualifiers(), getSizeExpr()); } static void Profile(llvm::FoldingSetNodeID &ID, ASTContext &Context, @@ -1709,7 +1938,7 @@ public: /// @brief Determines whether this type is in the process of being /// defined. bool isBeingDefined() const { return decl.getInt(); } - void setBeingDefined(bool Def) { decl.setInt(Def? 1 : 0); } + void setBeingDefined(bool Def) const { decl.setInt(Def? 1 : 0); } virtual void getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const; @@ -2206,41 +2435,119 @@ public: static bool classof(const ObjCObjectPointerType *) { return true; } }; +/// A qualifier set is used to build a set of qualifiers. +class QualifierCollector : public Qualifiers { + ASTContext *Context; + +public: + QualifierCollector(Qualifiers Qs = Qualifiers()) + : Qualifiers(Qs), Context(0) {} + QualifierCollector(ASTContext &Context, Qualifiers Qs = Qualifiers()) + : Qualifiers(Qs), Context(&Context) {} + + void setContext(ASTContext &C) { Context = &C; } + + /// Collect any qualifiers on the given type and return an + /// unqualified type. + const Type *strip(QualType QT) { + addFastQualifiers(QT.getFastQualifiers()); + if (QT.hasNonFastQualifiers()) { + const ExtQuals *EQ = QT.getExtQualsUnsafe(); + Context = &EQ->getContext(); + addQualifiers(EQ->getQualifiers()); + return EQ->getBaseType(); + } + return QT.getTypePtrUnsafe(); + } + + /// Apply the collected qualifiers to the given type. + QualType apply(QualType QT) const; + + /// Apply the collected qualifiers to the given type. + QualType apply(const Type* T) const; + +}; + + // Inline function definitions. -/// getUnqualifiedType - Return the type without any qualifiers. -inline QualType QualType::getUnqualifiedType() const { - Type *TP = getTypePtr(); - if (const ExtQualType *EXTQT = dyn_cast(TP)) - TP = EXTQT->getBaseType(); - return QualType(TP, 0); +inline void QualType::removeConst() { + removeFastQualifiers(Qualifiers::Const); +} + +inline void QualType::removeRestrict() { + removeFastQualifiers(Qualifiers::Restrict); +} + +inline void QualType::removeVolatile() { + QualifierCollector Qc; + const Type *Ty = Qc.strip(*this); + if (Qc.hasVolatile()) { + Qc.removeVolatile(); + *this = Qc.apply(Ty); + } +} + +inline void QualType::removeCVRQualifiers(unsigned Mask) { + assert(!(Mask & ~Qualifiers::CVRMask) && "mask has non-fast qualifiers"); + + // Fast path: we don't need to touch the slow qualifiers. + if (!(Mask & ~Qualifiers::FastMask)) { + removeFastQualifiers(Mask); + return; + } + + QualifierCollector Qc; + const Type *Ty = Qc.strip(*this); + Qc.removeCVRQualifiers(Mask); + *this = Qc.apply(Ty); } /// getAddressSpace - Return the address space of this type. inline unsigned QualType::getAddressSpace() const { + if (hasNonFastQualifiers()) { + const ExtQuals *EQ = getExtQualsUnsafe(); + if (EQ->hasAddressSpace()) + return EQ->getAddressSpace(); + } + QualType CT = getTypePtr()->getCanonicalTypeInternal(); + if (CT.hasNonFastQualifiers()) { + const ExtQuals *EQ = CT.getExtQualsUnsafe(); + if (EQ->hasAddressSpace()) + return EQ->getAddressSpace(); + } + if (const ArrayType *AT = dyn_cast(CT)) return AT->getElementType().getAddressSpace(); if (const RecordType *RT = dyn_cast(CT)) return RT->getAddressSpace(); - if (const ExtQualType *EXTQT = dyn_cast(CT)) - return EXTQT->getAddressSpace(); return 0; } /// getObjCGCAttr - Return the gc attribute of this type. -inline QualType::GCAttrTypes QualType::getObjCGCAttr() const { +inline Qualifiers::GC QualType::getObjCGCAttr() const { + if (hasNonFastQualifiers()) { + const ExtQuals *EQ = getExtQualsUnsafe(); + if (EQ->hasObjCGCAttr()) + return EQ->getObjCGCAttr(); + } + QualType CT = getTypePtr()->getCanonicalTypeInternal(); + if (CT.hasNonFastQualifiers()) { + const ExtQuals *EQ = CT.getExtQualsUnsafe(); + if (EQ->hasObjCGCAttr()) + return EQ->getObjCGCAttr(); + } + if (const ArrayType *AT = dyn_cast(CT)) return AT->getElementType().getObjCGCAttr(); - if (const ExtQualType *EXTQT = dyn_cast(CT)) - return EXTQT->getObjCGCAttr(); if (const ObjCObjectPointerType *PT = CT->getAs()) return PT->getPointeeType().getObjCGCAttr(); // We most look at all pointer types, not just pointer to interface types. if (const PointerType *PT = CT->getAs()) return PT->getPointeeType().getObjCGCAttr(); - return GCNone; + return Qualifiers::GCNone; } /// getNoReturnAttr - Returns true if the type has the noreturn attribute, @@ -2262,6 +2569,7 @@ inline bool QualType::getNoReturnAttr() /// "int". However, it is not more qualified than "const volatile /// int". inline bool QualType::isMoreQualifiedThan(QualType Other) const { + // FIXME: work on arbitrary qualifiers unsigned MyQuals = this->getCVRQualifiers(); unsigned OtherQuals = Other.getCVRQualifiers(); if (getAddressSpace() != Other.getAddressSpace()) @@ -2274,6 +2582,7 @@ inline bool QualType::isMoreQualifiedTha /// int" is at least as qualified as "const int", "volatile int", /// "int", and "const volatile int". inline bool QualType::isAtLeastAsQualifiedAs(QualType Other) const { + // FIXME: work on arbitrary qualifiers unsigned MyQuals = this->getCVRQualifiers(); unsigned OtherQuals = Other.getCVRQualifiers(); if (getAddressSpace() != Other.getAddressSpace()) @@ -2441,14 +2750,10 @@ template const T *Type::get return Ty; // If the canonical form of this type isn't the right kind, reject it. - if (!isa(CanonicalType)) { - // Look through type qualifiers - if (isa(CanonicalType.getUnqualifiedType())) - return CanonicalType.getUnqualifiedType()->getAs(); + if (!isa(CanonicalType)) return 0; - } - // If this is a typedef for a pointer type, strip the typedef off without + // If this is a typedef for the type, strip the typedef off without // losing all typedef information. return cast(getDesugaredType()); } Index: include/clang/Parse/DeclSpec.h =================================================================== --- include/clang/Parse/DeclSpec.h (revision 82620) +++ include/clang/Parse/DeclSpec.h (working copy) @@ -90,7 +90,7 @@ public: }; // type-qualifiers - enum TQ { // NOTE: These flags must be kept in sync with QualType::TQ. + enum TQ { // NOTE: These flags must be kept in sync with Qualifiers::TQ. TQ_unspecified = 0, TQ_const = 1, TQ_restrict = 2, Index: lib/Frontend/PCHWriter.cpp =================================================================== --- lib/Frontend/PCHWriter.cpp (revision 82620) +++ lib/Frontend/PCHWriter.cpp (working copy) @@ -64,13 +64,6 @@ namespace { }; } -void PCHTypeWriter::VisitExtQualType(const ExtQualType *T) { - Writer.AddTypeRef(QualType(T->getBaseType(), 0), Record); - Record.push_back(T->getObjCGCAttr()); // FIXME: use stable values - Record.push_back(T->getAddressSpace()); - Code = pch::TYPE_EXT_QUAL; -} - void PCHTypeWriter::VisitBuiltinType(const BuiltinType *T) { assert(false && "Built-in types are never serialized"); } @@ -115,7 +108,7 @@ void PCHTypeWriter::VisitMemberPointerTy void PCHTypeWriter::VisitArrayType(const ArrayType *T) { Writer.AddTypeRef(T->getElementType(), Record); Record.push_back(T->getSizeModifier()); // FIXME: stable values - Record.push_back(T->getIndexTypeQualifier()); // FIXME: stable values + Record.push_back(T->getIndexTypeCVRQualifiers()); // FIXME: stable values } void PCHTypeWriter::VisitConstantArrayType(const ConstantArrayType *T) { @@ -1087,7 +1080,7 @@ void PCHWriter::WriteComments(ASTContext //===----------------------------------------------------------------------===// /// \brief Write the representation of a type to the PCH stream. -void PCHWriter::WriteType(const Type *T) { +void PCHWriter::WriteType(QualType T) { pch::TypeID &ID = TypeIDs[T]; if (ID == 0) // we haven't seen this type before. ID = NextTypeID++; @@ -1104,22 +1097,30 @@ void PCHWriter::WriteType(const Type *T) // Emit the type's representation. PCHTypeWriter W(*this, Record); - switch (T->getTypeClass()) { - // For all of the concrete, non-dependent types, call the - // appropriate visitor function. + + if (T.hasNonFastQualifiers()) { + Qualifiers Qs = T.getQualifiers(); + AddTypeRef(T.getUnqualifiedType(), Record); + Record.push_back(Qs.getAsOpaqueValue()); + W.Code = pch::TYPE_EXT_QUAL; + } else { + switch (T->getTypeClass()) { + // For all of the concrete, non-dependent types, call the + // appropriate visitor function. #define TYPE(Class, Base) \ - case Type::Class: W.Visit##Class##Type(cast(T)); break; + case Type::Class: W.Visit##Class##Type(cast(T)); break; #define ABSTRACT_TYPE(Class, Base) #define DEPENDENT_TYPE(Class, Base) #include "clang/AST/TypeNodes.def" - // For all of the dependent type nodes (which only occur in C++ - // templates), produce an error. + // For all of the dependent type nodes (which only occur in C++ + // templates), produce an error. #define TYPE(Class, Base) #define DEPENDENT_TYPE(Class, Base) case Type::Class: #include "clang/AST/TypeNodes.def" - assert(false && "Cannot serialize dependent type nodes"); - break; + assert(false && "Cannot serialize dependent type nodes"); + break; + } } // Emit the serialized record. @@ -1136,9 +1137,8 @@ void PCHWriter::WriteTypesBlock(ASTConte // Emit all of the types that need to be emitted (so far). while (!TypesToEmit.empty()) { - const Type *T = TypesToEmit.front(); + QualType T = TypesToEmit.front(); TypesToEmit.pop(); - assert(!isa(T) && "Built-in types are not serialized"); WriteType(T); } @@ -1975,6 +1975,26 @@ void PCHWriter::AddTypeRef(QualType T, R return; } + unsigned FastQuals = T.getFastQualifiers(); + T.removeFastQualifiers(); + + if (T.hasNonFastQualifiers()) { + pch::TypeID &ID = TypeIDs[T]; + if (ID == 0) { + // We haven't seen these qualifiers applied to this type before. + // Assign it a new ID. This is the only time we enqueue a + // qualified type, and it has no CV qualifiers. + ID = NextTypeID++; + TypesToEmit.push(T); + } + + // Encode the type qualifiers in the type reference. + Record.push_back((ID << Qualifiers::FastWidth) | FastQuals); + return; + } + + assert(!T.hasQualifiers()); + if (const BuiltinType *BT = dyn_cast(T.getTypePtr())) { pch::TypeID ID = 0; switch (BT->getKind()) { @@ -2010,20 +2030,20 @@ void PCHWriter::AddTypeRef(QualType T, R break; } - Record.push_back((ID << 3) | T.getCVRQualifiers()); + Record.push_back((ID << Qualifiers::FastWidth) | FastQuals); return; } - pch::TypeID &ID = TypeIDs[T.getTypePtr()]; + pch::TypeID &ID = TypeIDs[T]; if (ID == 0) { // We haven't seen this type before. Assign it a new ID and put it - // into the queu of types to emit. + // into the queue of types to emit. ID = NextTypeID++; - TypesToEmit.push(T.getTypePtr()); + TypesToEmit.push(T); } // Encode the type qualifiers in the type reference. - Record.push_back((ID << 3) | T.getCVRQualifiers()); + Record.push_back((ID << Qualifiers::FastWidth) | FastQuals); } void PCHWriter::AddDeclRef(const Decl *D, RecordData &Record) { Index: lib/Frontend/DocumentXML.cpp =================================================================== --- lib/Frontend/DocumentXML.cpp (revision 82620) +++ lib/Frontend/DocumentXML.cpp (working copy) @@ -135,7 +135,7 @@ void DocumentXML::finalize() { for (XML::IdMap::iterator i = Types.begin(), e = Types.end(); i != e; ++i) { - if (i->first.getCVRQualifiers() != 0) { + if (i->first.hasQualifiers()) { writeTypeToXML(i->first); addAttribute("id", getPrefixedId(i->second, ID_NORMAL)); toParent(); @@ -205,7 +205,7 @@ void DocumentXML::addTypeRecursively(con { addTypeRecursively(pType.getTypePtr()); // beautifier: a non-qualified type shall be transparent - if (pType.getCVRQualifiers() == 0) + if (!pType.hasQualifiers()) { Types[pType] = BasicTypes[pType.getTypePtr()]; } Index: lib/Frontend/RewriteObjC.cpp =================================================================== --- lib/Frontend/RewriteObjC.cpp (revision 82620) +++ lib/Frontend/RewriteObjC.cpp (working copy) @@ -1937,8 +1937,7 @@ void RewriteObjC::RewriteObjCQualifiedIn void RewriteObjC::SynthSelGetUidFunctionDecl() { IdentifierInfo *SelGetUidIdent = &Context->Idents.get("sel_registerName"); llvm::SmallVector ArgTys; - ArgTys.push_back(Context->getPointerType( - Context->CharTy.getQualifiedType(QualType::Const))); + ArgTys.push_back(Context->getPointerType(Context->CharTy.withConst())); QualType getFuncType = Context->getFunctionType(Context->getObjCSelType(), &ArgTys[0], ArgTys.size(), false /*isVariadic*/, 0); @@ -2084,8 +2083,7 @@ void RewriteObjC::SynthMsgSendFpretFunct void RewriteObjC::SynthGetClassFunctionDecl() { IdentifierInfo *getClassIdent = &Context->Idents.get("objc_getClass"); llvm::SmallVector ArgTys; - ArgTys.push_back(Context->getPointerType( - Context->CharTy.getQualifiedType(QualType::Const))); + ArgTys.push_back(Context->getPointerType(Context->CharTy.withConst())); QualType getClassType = Context->getFunctionType(Context->getObjCIdType(), &ArgTys[0], ArgTys.size(), false /*isVariadic*/, 0); @@ -2099,8 +2097,7 @@ void RewriteObjC::SynthGetClassFunctionD void RewriteObjC::SynthGetMetaClassFunctionDecl() { IdentifierInfo *getClassIdent = &Context->Idents.get("objc_getMetaClass"); llvm::SmallVector ArgTys; - ArgTys.push_back(Context->getPointerType( - Context->CharTy.getQualifiedType(QualType::Const))); + ArgTys.push_back(Context->getPointerType(Context->CharTy.withConst())); QualType getClassType = Context->getFunctionType(Context->getObjCIdType(), &ArgTys[0], ArgTys.size(), false /*isVariadic*/, 0); Index: lib/Frontend/PCHReader.cpp =================================================================== --- lib/Frontend/PCHReader.cpp (revision 82620) +++ lib/Frontend/PCHReader.cpp (working copy) @@ -1764,18 +1764,11 @@ QualType PCHReader::ReadTypeRecord(uint6 unsigned Code = Stream.ReadCode(); switch ((pch::TypeCode)Stream.ReadRecord(Code, Record)) { case pch::TYPE_EXT_QUAL: { - assert(Record.size() == 3 && + assert(Record.size() == 2 && "Incorrect encoding of extended qualifier type"); QualType Base = GetType(Record[0]); - QualType::GCAttrTypes GCAttr = (QualType::GCAttrTypes)Record[1]; - unsigned AddressSpace = Record[2]; - - QualType T = Base; - if (GCAttr != QualType::GCNone) - T = Context->getObjCGCQualType(T, GCAttr); - if (AddressSpace) - T = Context->getAddrSpaceQualType(T, AddressSpace); - return T; + Qualifiers Quals = Qualifiers::fromOpaqueValue(Record[1]); + return Context->getQualifiedType(Base, Quals); } case pch::TYPE_FIXED_WIDTH_INT: { @@ -1984,8 +1977,8 @@ QualType PCHReader::ReadTypeRecord(uint6 QualType PCHReader::GetType(pch::TypeID ID) { - unsigned Quals = ID & 0x07; - unsigned Index = ID >> 3; + unsigned FastQuals = ID & Qualifiers::FastMask; + unsigned Index = ID >> Qualifiers::FastWidth; if (Index < pch::NUM_PREDEF_TYPE_IDS) { QualType T; @@ -2026,15 +2019,15 @@ QualType PCHReader::GetType(pch::TypeID } assert(!T.isNull() && "Unknown predefined type"); - return T.getQualifiedType(Quals); + return T.withFastQualifiers(FastQuals); } Index -= pch::NUM_PREDEF_TYPE_IDS; //assert(Index < TypesLoaded.size() && "Type index out-of-range"); - if (!TypesLoaded[Index]) - TypesLoaded[Index] = ReadTypeRecord(TypeOffsets[Index]).getTypePtr(); + if (TypesLoaded[Index].isNull()) + TypesLoaded[Index] = ReadTypeRecord(TypeOffsets[Index]); - return QualType(TypesLoaded[Index], Quals); + return TypesLoaded[Index].withFastQualifiers(FastQuals); } Decl *PCHReader::GetDecl(pch::DeclID ID) { @@ -2155,7 +2148,7 @@ void PCHReader::PrintStats() { unsigned NumTypesLoaded = TypesLoaded.size() - std::count(TypesLoaded.begin(), TypesLoaded.end(), - (Type *)0); + QualType()); unsigned NumDeclsLoaded = DeclsLoaded.size() - std::count(DeclsLoaded.begin(), DeclsLoaded.end(), (Decl *)0); Index: lib/CodeGen/CGObjCMac.cpp =================================================================== --- lib/CodeGen/CGObjCMac.cpp (revision 82620) +++ lib/CodeGen/CGObjCMac.cpp (working copy) @@ -112,6 +112,9 @@ LValue CGObjCRuntime::EmitValueForIvarAt V = CGF.Builder.CreateGEP(V, Offset, "add.ptr"); V = CGF.Builder.CreateBitCast(V, llvm::PointerType::getUnqual(LTy)); + Qualifiers Quals = CGF.MakeQualifiers(IvarTy); + Quals.addCVRQualifiers(CVRQualifiers); + if (Ivar->isBitField()) { // We need to compute the bit offset for the bit-field, the offset // is to the byte. Note, there is a subtle invariant here: we can @@ -124,11 +127,11 @@ LValue CGObjCRuntime::EmitValueForIvarAt Ivar->getBitWidth()->EvaluateAsInt(CGF.getContext()).getZExtValue(); return LValue::MakeBitfield(V, BitOffset, BitFieldSize, IvarTy->isSignedIntegerType(), - IvarTy.getCVRQualifiers()|CVRQualifiers); + Quals.getCVRQualifiers()); } - LValue LV = LValue::MakeAddr(V, IvarTy.getCVRQualifiers()|CVRQualifiers, - CGF.CGM.getContext().getObjCGCAttrKind(IvarTy)); + + LValue LV = LValue::MakeAddr(V, Quals); return LV; } @@ -2992,21 +2995,20 @@ llvm::Constant *CGObjCCommonMac::GetIvar return llvm::Constant::getNullValue(ObjCTypes.Int8PtrTy); } -static QualType::GCAttrTypes GetGCAttrTypeForType(ASTContext &Ctx, - QualType FQT) { +static Qualifiers::GC GetGCAttrTypeForType(ASTContext &Ctx, QualType FQT) { if (FQT.isObjCGCStrong()) - return QualType::Strong; + return Qualifiers::Strong; if (FQT.isObjCGCWeak()) - return QualType::Weak; + return Qualifiers::Weak; if (FQT->isObjCObjectPointerType() || FQT->isBlockPointerType()) - return QualType::Strong; + return Qualifiers::Strong; if (const PointerType *PT = FQT->getAs()) return GetGCAttrTypeForType(Ctx, PT->getPointeeType()); - return QualType::GCNone; + return Qualifiers::GCNone; } void CGObjCCommonMac::BuildAggrIvarRecordLayout(const RecordType *RT, @@ -3123,11 +3125,11 @@ void CGObjCCommonMac::BuildAggrIvarLayou } // At this point, we are done with Record/Union and array there of. // For other arrays we are down to its element type. - QualType::GCAttrTypes GCAttr = GetGCAttrTypeForType(CGM.getContext(), FQT); + Qualifiers::GC GCAttr = GetGCAttrTypeForType(CGM.getContext(), FQT); unsigned FieldSize = CGM.getContext().getTypeSize(Field->getType()); - if ((ForStrongLayout && GCAttr == QualType::Strong) - || (!ForStrongLayout && GCAttr == QualType::Weak)) { + if ((ForStrongLayout && GCAttr == Qualifiers::Strong) + || (!ForStrongLayout && GCAttr == Qualifiers::Weak)) { if (IsUnion) { uint64_t UnionIvarSize = FieldSize / WordSizeInBits; if (UnionIvarSize > MaxUnionIvarSize) { @@ -3140,8 +3142,8 @@ void CGObjCCommonMac::BuildAggrIvarLayou FieldSize / WordSizeInBits)); } } else if ((ForStrongLayout && - (GCAttr == QualType::GCNone || GCAttr == QualType::Weak)) - || (!ForStrongLayout && GCAttr != QualType::Weak)) { + (GCAttr == Qualifiers::GCNone || GCAttr == Qualifiers::Weak)) + || (!ForStrongLayout && GCAttr != Qualifiers::Weak)) { if (IsUnion) { // FIXME: Why the asymmetry? We divide by word size in bits on other // side. Index: lib/CodeGen/CGCXX.cpp =================================================================== --- lib/CodeGen/CGCXX.cpp (revision 82620) +++ lib/CodeGen/CGCXX.cpp (working copy) @@ -1686,8 +1686,8 @@ void CodeGenFunction::EmitCtorPrologue(c // FIXME: This is really ugly; should be refactored somehow unsigned idx = CGM.getTypes().getLLVMFieldNo(Field); llvm::Value *V = Builder.CreateStructGEP(LoadOfThis, idx, "tmp"); - LHS = LValue::MakeAddr(V, FieldType.getCVRQualifiers(), - QualType::GCNone, FieldType.getAddressSpace()); + assert(!FieldType.getObjCGCAttr() && "fields cannot have GC attrs"); + LHS = LValue::MakeAddr(V, MakeQualifiers(FieldType)); } else { LHS = EmitLValueForField(LoadOfThis, Field, false, 0); } Index: lib/CodeGen/CGExprScalar.cpp =================================================================== --- lib/CodeGen/CGExprScalar.cpp (revision 82620) +++ lib/CodeGen/CGExprScalar.cpp (working copy) @@ -791,8 +791,7 @@ Value *ScalarExprEmitter::VisitPrePostIn NextVal = Builder.CreateGEP(InVal, Inc, "add.ptr"); llvm::Value *lhs = LV.getAddress(); lhs = Builder.CreateBitCast(lhs, llvm::PointerType::getUnqual(i8Ty)); - LV = LValue::MakeAddr(lhs, ValTy.getCVRQualifiers(), - CGF.getContext().getObjCGCAttrKind(ValTy)); + LV = LValue::MakeAddr(lhs, CGF.MakeQualifiers(ValTy)); } else NextVal = Builder.CreateInBoundsGEP(InVal, Inc, "ptrincdec"); } else { Index: lib/CodeGen/CGExpr.cpp =================================================================== --- lib/CodeGen/CGExpr.cpp (revision 82620) +++ lib/CodeGen/CGExpr.cpp (working copy) @@ -166,9 +166,7 @@ LValue CodeGenFunction::EmitUnsupportedL ErrorUnsupported(E, Name); llvm::Type *Ty = llvm::PointerType::getUnqual(ConvertType(E->getType())); return LValue::MakeAddr(llvm::UndefValue::get(Ty), - E->getType().getCVRQualifiers(), - getContext().getObjCGCAttrKind(E->getType()), - E->getType().getAddressSpace()); + MakeQualifiers(E->getType())); } /// EmitLValue - Emit code to compute a designator that specifies the location @@ -746,17 +744,16 @@ LValue CodeGenFunction::EmitDeclRefLValu llvm::Value *V = CGM.GetAddrOfGlobalVar(VD); if (VD->getType()->isReferenceType()) V = Builder.CreateLoad(V, "tmp"); - LV = LValue::MakeAddr(V, E->getType().getCVRQualifiers(), - getContext().getObjCGCAttrKind(E->getType()), - E->getType().getAddressSpace()); + LV = LValue::MakeAddr(V, MakeQualifiers(E->getType())); } else { llvm::Value *V = LocalDeclMap[VD]; assert(V && "DeclRefExpr not entered in LocalDeclMap?"); + + Qualifiers Quals = MakeQualifiers(E->getType()); // local variables do not get their gc attribute set. - QualType::GCAttrTypes attr = QualType::GCNone; // local static? - if (!NonGCable) - attr = getContext().getObjCGCAttrKind(E->getType()); + if (NonGCable) Quals.removeObjCGCAttr(); + if (VD->hasAttr()) { V = Builder.CreateStructGEP(V, 1, "forwarding"); V = Builder.CreateLoad(V, false); @@ -765,8 +762,7 @@ LValue CodeGenFunction::EmitDeclRefLValu } if (VD->getType()->isReferenceType()) V = Builder.CreateLoad(V, "tmp"); - LV = LValue::MakeAddr(V, E->getType().getCVRQualifiers(), attr, - E->getType().getAddressSpace()); + LV = LValue::MakeAddr(V, Quals); } LValue::SetObjCNonGC(LV, NonGCable); setObjCGCLValueClass(getContext(), E, LV); @@ -775,9 +771,7 @@ LValue CodeGenFunction::EmitDeclRefLValu llvm::Value *V = CGM.GetAddrOfGlobalVar(VD); if (VD->getType()->isReferenceType()) V = Builder.CreateLoad(V, "tmp"); - LValue LV = LValue::MakeAddr(V, E->getType().getCVRQualifiers(), - getContext().getObjCGCAttrKind(E->getType()), - E->getType().getAddressSpace()); + LValue LV = LValue::MakeAddr(V, MakeQualifiers(E->getType())); setObjCGCLValueClass(getContext(), E, LV); return LV; } else if (const FunctionDecl *FD = dyn_cast(E->getDecl())) { @@ -794,16 +788,12 @@ LValue CodeGenFunction::EmitDeclRefLValu V = Builder.CreateBitCast(V, ConvertType(NoProtoType), "tmp"); } } - return LValue::MakeAddr(V, E->getType().getCVRQualifiers(), - getContext().getObjCGCAttrKind(E->getType()), - E->getType().getAddressSpace()); + return LValue::MakeAddr(V, MakeQualifiers(E->getType())); } else if (const ImplicitParamDecl *IPD = dyn_cast(E->getDecl())) { llvm::Value *V = LocalDeclMap[IPD]; assert(V && "BlockVarDecl not entered in LocalDeclMap?"); - return LValue::MakeAddr(V, E->getType().getCVRQualifiers(), - getContext().getObjCGCAttrKind(E->getType()), - E->getType().getAddressSpace()); + return LValue::MakeAddr(V, MakeQualifiers(E->getType())); } assert(0 && "Unimp declref"); //an invalid LValue, but the assert will @@ -812,10 +802,7 @@ LValue CodeGenFunction::EmitDeclRefLValu } LValue CodeGenFunction::EmitBlockDeclRefLValue(const BlockDeclRefExpr *E) { - return LValue::MakeAddr(GetAddrOfBlockDecl(E), - E->getType().getCVRQualifiers(), - getContext().getObjCGCAttrKind(E->getType()), - E->getType().getAddressSpace()); + return LValue::MakeAddr(GetAddrOfBlockDecl(E), MakeQualifiers(E->getType())); } LValue CodeGenFunction::EmitUnaryOpLValue(const UnaryOperator *E) { @@ -831,10 +818,10 @@ LValue CodeGenFunction::EmitUnaryOpLValu QualType T = E->getSubExpr()->getType()->getPointeeType(); assert(!T.isNull() && "CodeGenFunction::EmitUnaryOpLValue: Illegal type"); - LValue LV = LValue::MakeAddr(EmitScalarExpr(E->getSubExpr()), - T.getCVRQualifiers(), - getContext().getObjCGCAttrKind(T), - ExprTy.getAddressSpace()); + Qualifiers Quals = MakeQualifiers(T); + Quals.setAddressSpace(ExprTy.getAddressSpace()); + + LValue LV = LValue::MakeAddr(EmitScalarExpr(E->getSubExpr()), Quals); // We should not generate __weak write barrier on indirect reference // of a pointer to object; as in void foo (__weak id *param); *param = 0; // But, we continue to generate __strong write barrier on indirect write @@ -851,18 +838,18 @@ LValue CodeGenFunction::EmitUnaryOpLValu unsigned Idx = E->getOpcode() == UnaryOperator::Imag; return LValue::MakeAddr(Builder.CreateStructGEP(LV.getAddress(), Idx, "idx"), - ExprTy.getCVRQualifiers(), - QualType::GCNone, - ExprTy.getAddressSpace()); + MakeQualifiers(ExprTy)); } } LValue CodeGenFunction::EmitStringLiteralLValue(const StringLiteral *E) { - return LValue::MakeAddr(CGM.GetAddrOfConstantStringFromLiteral(E), 0); + return LValue::MakeAddr(CGM.GetAddrOfConstantStringFromLiteral(E), + Qualifiers()); } LValue CodeGenFunction::EmitObjCEncodeExprLValue(const ObjCEncodeExpr *E) { - return LValue::MakeAddr(CGM.GetAddrOfConstantStringFromObjCEncode(E), 0); + return LValue::MakeAddr(CGM.GetAddrOfConstantStringFromObjCEncode(E), + Qualifiers()); } @@ -894,7 +881,7 @@ LValue CodeGenFunction::EmitPredefinedFu llvm::Constant *C = CGM.GetAddrOfConstantCString(FunctionName, GlobalVarName.c_str()); - return LValue::MakeAddr(C, 0); + return LValue::MakeAddr(C, Qualifiers()); } LValue CodeGenFunction::EmitPredefinedLValue(const PredefinedExpr *E) { @@ -923,7 +910,7 @@ LValue CodeGenFunction::EmitArraySubscri Idx = Builder.CreateIntCast(Idx, llvm::Type::getInt32Ty(VMContext), IdxSigned, "vidx"); return LValue::MakeVectorElt(LHS.getAddress(), Idx, - E->getBase()->getType().getCVRQualifiers()); + E->getBase()->getType().getCVRQualifiers()); } // The base must be a pointer, which is not an aggregate. Emit it. @@ -973,10 +960,10 @@ LValue CodeGenFunction::EmitArraySubscri assert(!T.isNull() && "CodeGenFunction::EmitArraySubscriptExpr(): Illegal base type"); - LValue LV = LValue::MakeAddr(Address, - T.getCVRQualifiers(), - getContext().getObjCGCAttrKind(T), - E->getBase()->getType().getAddressSpace()); + Qualifiers Quals = MakeQualifiers(T); + Quals.setAddressSpace(E->getBase()->getType().getAddressSpace()); + + LValue LV = LValue::MakeAddr(Address, Quals); if (getContext().getLangOptions().ObjC1 && getContext().getLangOptions().getGCMode() != LangOptions::NonGC) { LValue::SetObjCNonGC(LV, !E->isOBJCGCCandidate(getContext())); @@ -1009,9 +996,9 @@ EmitExtVectorElementExpr(const ExtVector } else { const PointerType *PT = E->getBase()->getType()->getAs(); llvm::Value *Ptr = EmitScalarExpr(E->getBase()); - Base = LValue::MakeAddr(Ptr, PT->getPointeeType().getCVRQualifiers(), - QualType::GCNone, - PT->getPointeeType().getAddressSpace()); + Qualifiers Quals = MakeQualifiers(PT->getPointeeType()); + Quals.removeObjCGCAttr(); + Base = LValue::MakeAddr(Ptr, Quals); } // Encode the element access list into a vector of unsigned indices. @@ -1021,7 +1008,7 @@ EmitExtVectorElementExpr(const ExtVector if (Base.isSimple()) { llvm::Constant *CV = GenerateConstantVector(VMContext, Indices); return LValue::MakeExtVectorElt(Base.getAddress(), CV, - Base.getQualifiers()); + Base.getVRQualifiers()); } assert(Base.isExtVectorElt() && "Can only subscript lvalue vec elts here!"); @@ -1037,7 +1024,7 @@ EmitExtVectorElementExpr(const ExtVector } llvm::Constant *CV = llvm::ConstantVector::get(&CElts[0], CElts.size()); return LValue::MakeExtVectorElt(Base.getExtVectorAddr(), CV, - Base.getQualifiers()); + Base.getVRQualifiers()); } LValue CodeGenFunction::EmitMemberExpr(const MemberExpr *E) { @@ -1045,7 +1032,7 @@ LValue CodeGenFunction::EmitMemberExpr(c bool isNonGC = false; Expr *BaseExpr = E->getBase(); llvm::Value *BaseValue = NULL; - unsigned CVRQualifiers=0; + Qualifiers BaseQuals; // If this is s.x, emit s as an lvalue. If it is s->x, emit s as a scalar. if (E->isArrow()) { @@ -1054,7 +1041,7 @@ LValue CodeGenFunction::EmitMemberExpr(c BaseExpr->getType()->getAs(); if (PTy->getPointeeType()->isUnionType()) isUnion = true; - CVRQualifiers = PTy->getPointeeType().getCVRQualifiers(); + BaseQuals = PTy->getPointeeType().getQualifiers(); } else if (isa(BaseExpr->IgnoreParens()) || isa( BaseExpr->IgnoreParens())) { @@ -1062,7 +1049,7 @@ LValue CodeGenFunction::EmitMemberExpr(c BaseValue = RV.getAggregateAddr(); if (BaseExpr->getType()->isUnionType()) isUnion = true; - CVRQualifiers = BaseExpr->getType().getCVRQualifiers(); + BaseQuals = BaseExpr->getType().getQualifiers(); } else { LValue BaseLV = EmitLValue(BaseExpr); if (BaseLV.isNonGC()) @@ -1072,14 +1059,14 @@ LValue CodeGenFunction::EmitMemberExpr(c QualType BaseTy = BaseExpr->getType(); if (BaseTy->isUnionType()) isUnion = true; - CVRQualifiers = BaseTy.getCVRQualifiers(); + BaseQuals = BaseTy.getQualifiers(); } FieldDecl *Field = dyn_cast(E->getMemberDecl()); // FIXME: Handle non-field member expressions assert(Field && "No code generation for non-field member references"); LValue MemExpLV = EmitLValueForField(BaseValue, Field, isUnion, - CVRQualifiers); + BaseQuals.getCVRQualifiers()); LValue::SetObjCNonGC(MemExpLV, isNonGC); setObjCGCLValueClass(getContext(), E, MemExpLV); return MemExpLV; @@ -1133,17 +1120,14 @@ LValue CodeGenFunction::EmitLValueForFie } if (Field->getType()->isReferenceType()) V = Builder.CreateLoad(V, "tmp"); - QualType::GCAttrTypes attr = getContext().getObjCGCAttrKind(Field->getType()); + + Qualifiers Quals = MakeQualifiers(Field->getType()); + Quals.addCVRQualifiers(CVRQualifiers); // __weak attribute on a field is ignored. - if (attr == QualType::Weak) - attr = QualType::GCNone; + if (Quals.getObjCGCAttr() == Qualifiers::Weak) + Quals.removeObjCGCAttr(); - LValue LV = - LValue::MakeAddr(V, - Field->getType().getCVRQualifiers()|CVRQualifiers, - attr, - Field->getType().getAddressSpace()); - return LV; + return LValue::MakeAddr(V, Quals); } LValue CodeGenFunction::EmitCompoundLiteralLValue(const CompoundLiteralExpr* E){ @@ -1151,9 +1135,7 @@ LValue CodeGenFunction::EmitCompoundLite llvm::Value *DeclPtr = CreateTempAlloca(LTy, ".compoundliteral"); const Expr* InitExpr = E->getInitializer(); - LValue Result = LValue::MakeAddr(DeclPtr, E->getType().getCVRQualifiers(), - QualType::GCNone, - E->getType().getAddressSpace()); + LValue Result = LValue::MakeAddr(DeclPtr, MakeQualifiers(E->getType())); if (E->getType()->isComplexType()) { EmitComplexExprIntoAddr(InitExpr, DeclPtr, false); @@ -1199,9 +1181,7 @@ CodeGenFunction::EmitConditionalOperator EmitBlock(ContBlock); Temp = Builder.CreateLoad(Temp, "lv"); - return LValue::MakeAddr(Temp, E->getType().getCVRQualifiers(), - getContext().getObjCGCAttrKind(E->getType()), - E->getType().getAddressSpace()); + return LValue::MakeAddr(Temp, MakeQualifiers(E->getType())); } // ?: here should be an aggregate. @@ -1212,9 +1192,7 @@ CodeGenFunction::EmitConditionalOperator llvm::Value *Temp = CreateTempAlloca(ConvertType(E->getType())); EmitAggExpr(E, Temp, false); - return LValue::MakeAddr(Temp, E->getType().getCVRQualifiers(), - getContext().getObjCGCAttrKind(E->getType()), - E->getType().getAddressSpace()); + return LValue::MakeAddr(Temp, MakeQualifiers(E->getType())); } /// EmitCastLValue - Casts are never lvalues. If a cast is needed by the code @@ -1254,18 +1232,14 @@ LValue CodeGenFunction::EmitCastLValue(c GetAddressCXXOfBaseClass(LV.getAddress(), DerivedClassDecl, BaseClassDecl, /*NullCheckValue=*/false); - return LValue::MakeAddr(Base, E->getType().getCVRQualifiers(), - getContext().getObjCGCAttrKind(E->getType()), - E->getType().getAddressSpace()); + return LValue::MakeAddr(Base, MakeQualifiers(E->getType())); } case CastExpr::CK_ToUnion: { llvm::Value *Temp = CreateTempAlloca(ConvertType(E->getType())); EmitAnyExpr(E->getSubExpr(), Temp, false); - return LValue::MakeAddr(Temp, E->getType().getCVRQualifiers(), - getContext().getObjCGCAttrKind(E->getType()), - E->getType().getAddressSpace()); + return LValue::MakeAddr(Temp, MakeQualifiers(E->getType())); } } } @@ -1327,9 +1301,7 @@ LValue CodeGenFunction::EmitBinaryOperat llvm::Value *Temp = CreateTempAlloca(ConvertType(E->getType())); EmitAggExpr(E, Temp, false); // FIXME: Are these qualifiers correct? - return LValue::MakeAddr(Temp, E->getType().getCVRQualifiers(), - getContext().getObjCGCAttrKind(E->getType()), - E->getType().getAddressSpace()); + return LValue::MakeAddr(Temp, MakeQualifiers(E->getType())); } LValue CodeGenFunction::EmitCallExprLValue(const CallExpr *E) { @@ -1340,23 +1312,17 @@ LValue CodeGenFunction::EmitCallExprLVal "Can't have a scalar return unless the return type is a " "reference type!"); - return LValue::MakeAddr(RV.getScalarVal(), E->getType().getCVRQualifiers(), - getContext().getObjCGCAttrKind(E->getType()), - E->getType().getAddressSpace()); + return LValue::MakeAddr(RV.getScalarVal(), MakeQualifiers(E->getType())); } - return LValue::MakeAddr(RV.getAggregateAddr(), - E->getType().getCVRQualifiers(), - getContext().getObjCGCAttrKind(E->getType()), - E->getType().getAddressSpace()); + return LValue::MakeAddr(RV.getAggregateAddr(), MakeQualifiers(E->getType())); } LValue CodeGenFunction::EmitVAArgExprLValue(const VAArgExpr *E) { // FIXME: This shouldn't require another copy. llvm::Value *Temp = CreateTempAlloca(ConvertType(E->getType())); EmitAggExpr(E, Temp, false); - return LValue::MakeAddr(Temp, E->getType().getCVRQualifiers(), - QualType::GCNone, E->getType().getAddressSpace()); + return LValue::MakeAddr(Temp, MakeQualifiers(E->getType())); } LValue @@ -1368,8 +1334,7 @@ CodeGenFunction::EmitCXXConditionDeclLVa LValue CodeGenFunction::EmitCXXConstructLValue(const CXXConstructExpr *E) { llvm::Value *Temp = CreateTempAlloca(ConvertTypeForMem(E->getType()), "tmp"); EmitCXXConstructExpr(Temp, E); - return LValue::MakeAddr(Temp, E->getType().getCVRQualifiers(), - QualType::GCNone, E->getType().getAddressSpace()); + return LValue::MakeAddr(Temp, MakeQualifiers(E->getType())); } LValue @@ -1385,10 +1350,7 @@ LValue CodeGenFunction::EmitObjCMessageE // Can only get l-value for message expression returning aggregate type RValue RV = EmitObjCMessageExpr(E); // FIXME: can this be volatile? - return LValue::MakeAddr(RV.getAggregateAddr(), - E->getType().getCVRQualifiers(), - getContext().getObjCGCAttrKind(E->getType()), - E->getType().getAddressSpace()); + return LValue::MakeAddr(RV.getAggregateAddr(), MakeQualifiers(E->getType())); } llvm::Value *CodeGenFunction::EmitIvarOffset(const ObjCInterfaceDecl *Interface, @@ -1408,22 +1370,23 @@ LValue CodeGenFunction::EmitObjCIvarRefL // FIXME: A lot of the code below could be shared with EmitMemberExpr. llvm::Value *BaseValue = 0; const Expr *BaseExpr = E->getBase(); - unsigned CVRQualifiers = 0; + Qualifiers BaseQuals; QualType ObjectTy; if (E->isArrow()) { BaseValue = EmitScalarExpr(BaseExpr); ObjectTy = BaseExpr->getType()->getPointeeType(); - CVRQualifiers = ObjectTy.getCVRQualifiers(); + BaseQuals = ObjectTy.getQualifiers(); } else { LValue BaseLV = EmitLValue(BaseExpr); // FIXME: this isn't right for bitfields. BaseValue = BaseLV.getAddress(); ObjectTy = BaseExpr->getType(); - CVRQualifiers = ObjectTy.getCVRQualifiers(); + BaseQuals = ObjectTy.getQualifiers(); } LValue LV = - EmitLValueForIvar(ObjectTy, BaseValue, E->getDecl(), CVRQualifiers); + EmitLValueForIvar(ObjectTy, BaseValue, E->getDecl(), + BaseQuals.getCVRQualifiers()); setObjCGCLValueClass(getContext(), E, LV); return LV; } @@ -1453,10 +1416,7 @@ LValue CodeGenFunction::EmitStmtExprLVal // Can only get l-value for message expression returning aggregate type RValue RV = EmitAnyExprToTemp(E); // FIXME: can this be volatile? - return LValue::MakeAddr(RV.getAggregateAddr(), - E->getType().getCVRQualifiers(), - getContext().getObjCGCAttrKind(E->getType()), - E->getType().getAddressSpace()); + return LValue::MakeAddr(RV.getAggregateAddr(), MakeQualifiers(E->getType())); } Index: lib/CodeGen/CodeGenTypes.cpp =================================================================== --- lib/CodeGen/CodeGenTypes.cpp (revision 82620) +++ lib/CodeGen/CodeGenTypes.cpp (working copy) @@ -267,7 +267,7 @@ const llvm::Type *CodeGenTypes::ConvertN case Type::VariableArray: { const VariableArrayType &A = cast(Ty); - assert(A.getIndexTypeQualifier() == 0 && + assert(A.getIndexTypeCVRQualifiers() == 0 && "FIXME: We only handle trivial array types so far!"); // VLAs resolve to the innermost element type; this matches // the return of alloca, and there isn't any obviously better choice. @@ -275,7 +275,7 @@ const llvm::Type *CodeGenTypes::ConvertN } case Type::IncompleteArray: { const IncompleteArrayType &A = cast(Ty); - assert(A.getIndexTypeQualifier() == 0 && + assert(A.getIndexTypeCVRQualifiers() == 0 && "FIXME: We only handle trivial array types so far!"); // int X[] -> [0 x int] return llvm::ArrayType::get(ConvertTypeForMemRecursive(A.getElementType()), 0); @@ -312,10 +312,6 @@ const llvm::Type *CodeGenTypes::ConvertN return GetFunctionType(getFunctionInfo(FNPT), true); } - case Type::ExtQual: - return - ConvertTypeRecursive(QualType(cast(Ty).getBaseType(), 0)); - case Type::ObjCInterface: { // Objective-C interfaces are always opaque (outside of the // runtime, which can do whatever it likes); we never refine Index: lib/CodeGen/Mangle.cpp =================================================================== --- lib/CodeGen/Mangle.cpp (revision 82620) +++ lib/CodeGen/Mangle.cpp (working copy) @@ -84,7 +84,7 @@ namespace { void manglePrefix(const DeclContext *DC); void mangleTemplatePrefix(const NamedDecl *ND); void mangleOperatorName(OverloadedOperatorKind OO, unsigned Arity); - void mangleCVQualifiers(unsigned Quals); + void mangleQualifiers(Qualifiers Quals); void mangleType(QualType T); // Declare manglers for every type class. @@ -459,7 +459,7 @@ void CXXNameMangler::mangleNestedName(co // FIXME: no class template support Out << 'N'; if (const CXXMethodDecl *Method = dyn_cast(ND)) - mangleCVQualifiers(Method->getTypeQualifiers()); + mangleQualifiers(Qualifiers::fromCVRMask(Method->getTypeQualifiers())); // Check if we have a template. const TemplateArgumentList *TemplateArgs = 0; @@ -637,14 +637,16 @@ CXXNameMangler::mangleOperatorName(Overl } } -void CXXNameMangler::mangleCVQualifiers(unsigned Quals) { +void CXXNameMangler::mangleQualifiers(Qualifiers Quals) { // ::= [r] [V] [K] # restrict (C99), volatile, const - if (Quals & QualType::Restrict) + if (Quals.hasRestrict()) Out << 'r'; - if (Quals & QualType::Volatile) + if (Quals.hasVolatile()) Out << 'V'; - if (Quals & QualType::Const) + if (Quals.hasConst()) Out << 'K'; + + // FIXME: For now, just drop all extension qualifiers on the floor. } void CXXNameMangler::mangleType(QualType T) { @@ -655,10 +657,10 @@ void CXXNameMangler::mangleType(QualType if (IsSubstitutable && mangleSubstitution(T)) return; - if (unsigned CVRQualifiers = T.getCVRQualifiers()) { - // ::= - mangleCVQualifiers(CVRQualifiers); - + if (Qualifiers Quals = T.getQualifiers()) { + mangleQualifiers(Quals); + // Recurse: even if the qualified type isn't yet substitutable, + // the unqualified type might be. mangleType(T.getUnqualifiedType()); } else { switch (T->getTypeClass()) { @@ -669,7 +671,7 @@ void CXXNameMangler::mangleType(QualType return; #define TYPE(CLASS, PARENT) \ case Type::CLASS: \ - mangleType(static_cast(T.getTypePtr())); \ + mangleType(static_cast(T.getTypePtr())); \ break; #include "clang/AST/TypeNodes.def" } @@ -830,7 +832,7 @@ void CXXNameMangler::mangleType(const Me mangleType(QualType(T->getClass(), 0)); QualType PointeeType = T->getPointeeType(); if (const FunctionProtoType *FPT = dyn_cast(PointeeType)) { - mangleCVQualifiers(FPT->getTypeQuals()); + mangleQualifiers(Qualifiers::fromCVRMask(FPT->getTypeQuals())); mangleType(FPT); } else mangleType(PointeeType); @@ -912,11 +914,6 @@ void CXXNameMangler::mangleType(const Ty assert(false && "can't mangle dependent typenames yet"); } -// FIXME: For now, just drop all extension qualifiers on the floor. -void CXXNameMangler::mangleType(const ExtQualType *T) { - mangleType(QualType(T->getBaseType(), 0)); -} - void CXXNameMangler::mangleExpression(const Expr *E) { // ::= // ::= Index: lib/CodeGen/CGExprAgg.cpp =================================================================== --- lib/CodeGen/CGExprAgg.cpp (revision 82620) +++ lib/CodeGen/CGExprAgg.cpp (working copy) @@ -181,7 +181,7 @@ void AggExprEmitter::VisitCastExpr(CastE llvm::Value *CastPtr = Builder.CreateBitCast(DestPtr, CGF.ConvertType(PtrTy)); EmitInitializationToLValue(E->getSubExpr(), - LValue::MakeAddr(CastPtr, 0)); + LValue::MakeAddr(CastPtr, Qualifiers())); return; } @@ -316,7 +316,7 @@ void AggExprEmitter::VisitVAArgExpr(VAAr return; } - EmitFinalDestCopy(VE, LValue::MakeAddr(ArgPtr, 0)); + EmitFinalDestCopy(VE, LValue::MakeAddr(ArgPtr, Qualifiers())); } void AggExprEmitter::VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E) { @@ -429,15 +429,16 @@ void AggExprEmitter::VisitInitListExpr(I QualType ElementType = CGF.getContext().getCanonicalType(E->getType()); ElementType = CGF.getContext().getAsArrayType(ElementType)->getElementType(); - unsigned CVRqualifier = ElementType.getCVRQualifiers(); + // FIXME: were we intentionally ignoring address spaces and GC attributes? + Qualifiers Quals = CGF.MakeQualifiers(ElementType); for (uint64_t i = 0; i != NumArrayElements; ++i) { llvm::Value *NextVal = Builder.CreateStructGEP(DestPtr, i, ".array"); if (i < NumInitElements) EmitInitializationToLValue(E->getInit(i), - LValue::MakeAddr(NextVal, CVRqualifier)); + LValue::MakeAddr(NextVal, Quals)); else - EmitNullInitializationToLValue(LValue::MakeAddr(NextVal, CVRqualifier), + EmitNullInitializationToLValue(LValue::MakeAddr(NextVal, Quals), ElementType); } return; Index: lib/CodeGen/CGDebugInfo.cpp =================================================================== --- lib/CodeGen/CGDebugInfo.cpp (revision 82620) +++ lib/CodeGen/CGDebugInfo.cpp (working copy) @@ -788,7 +788,6 @@ llvm::DIType CGDebugInfo::CreateTypeNode case Type::RValueReference: case Type::Vector: case Type::ExtVector: - case Type::ExtQual: case Type::FixedWidthInt: case Type::MemberPointer: case Type::TemplateSpecialization: Index: lib/CodeGen/CodeGenFunction.h =================================================================== --- lib/CodeGen/CodeGenFunction.h (revision 82620) +++ lib/CodeGen/CodeGenFunction.h (working copy) @@ -496,6 +496,12 @@ public: // Helpers //===--------------------------------------------------------------------===// + Qualifiers MakeQualifiers(QualType T) { + Qualifiers Quals = T.getQualifiers(); + Quals.setObjCGCAttr(getContext().getObjCGCAttrKind(T)); + return Quals; + } + /// CreateTempAlloca - This creates a alloca and inserts it into the entry /// block. llvm::AllocaInst *CreateTempAlloca(const llvm::Type *Ty, Index: lib/CodeGen/CGCall.cpp =================================================================== --- lib/CodeGen/CGCall.cpp (revision 82620) +++ lib/CodeGen/CGCall.cpp (working copy) @@ -629,7 +629,7 @@ void CodeGenFunction::EmitFunctionProlog (Name + ".addr").c_str()); // FIXME: What are the right qualifiers here? llvm::Function::arg_iterator End = - ExpandTypeFromArgs(Ty, LValue::MakeAddr(Temp,0), AI); + ExpandTypeFromArgs(Ty, LValue::MakeAddr(Temp, Qualifiers()), AI); EmitParmDecl(*Arg, Temp); // Name the arguments used in expansion and increment AI. Index: lib/CodeGen/CGValue.h =================================================================== --- lib/CodeGen/CGValue.h (revision 82620) +++ lib/CodeGen/CGValue.h (working copy) @@ -118,12 +118,6 @@ class LValue { // use getKVCRefExpr } LVType; - enum ObjCType { - None = 0, // object with no gc attribute. - Weak, // __weak object expression - Strong // __strong object expression - }; - llvm::Value *V; union { @@ -146,9 +140,8 @@ class LValue { const ObjCImplicitSetterGetterRefExpr *KVCRefExpr; }; - bool Volatile:1; - // FIXME: set but never used, what effect should it have? - bool Restrict:1; + // 'const' is unused here + Qualifiers Quals; // objective-c's ivar bool Ivar:1; @@ -163,20 +156,13 @@ class LValue { // Lvalue is a global reference of an objective-c object bool GlobalObjCRef : 1; - // objective-c's gc attributes - unsigned ObjCType : 2; - - // address space - unsigned AddressSpace; - private: - static void SetQualifiers(unsigned Qualifiers, LValue& R) { - R.Volatile = (Qualifiers&QualType::Volatile)!=0; - R.Restrict = (Qualifiers&QualType::Restrict)!=0; + void SetQualifiers(Qualifiers Quals) { + this->Quals = Quals; + // FIXME: Convenient place to set objc flags to 0. This should really be // done in a user-defined constructor instead. - R.ObjCType = None; - R.Ivar = R.ObjIsArray = R.NonGC = R.GlobalObjCRef = false; + this->Ivar = this->ObjIsArray = this->NonGC = this->GlobalObjCRef = false; } public: @@ -187,21 +173,18 @@ public: bool isPropertyRef() const { return LVType == PropertyRef; } bool isKVCRef() const { return LVType == KVCRef; } - bool isVolatileQualified() const { return Volatile; } - bool isRestrictQualified() const { return Restrict; } - unsigned getQualifiers() const { - return (Volatile ? QualType::Volatile : 0) | - (Restrict ? QualType::Restrict : 0); - } + bool isVolatileQualified() const { return Quals.hasVolatile(); } + bool isRestrictQualified() const { return Quals.hasRestrict(); } + unsigned getVRQualifiers() const { return Quals.getCVRQualifiers(); } bool isObjCIvar() const { return Ivar; } bool isObjCArray() const { return ObjIsArray; } bool isNonGC () const { return NonGC; } bool isGlobalObjCRef() const { return GlobalObjCRef; } - bool isObjCWeak() const { return ObjCType == Weak; } - bool isObjCStrong() const { return ObjCType == Strong; } + bool isObjCWeak() const { return Quals.getObjCGCAttr() == Qualifiers::Weak; } + bool isObjCStrong() const { return Quals.getObjCGCAttr() == Qualifiers::Strong; } - unsigned getAddressSpace() const { return AddressSpace; } + unsigned getAddressSpace() const { return Quals.getAddressSpace(); } static void SetObjCIvar(LValue& R, bool iValue) { R.Ivar = iValue; @@ -216,14 +199,6 @@ public: static void SetObjCNonGC(LValue& R, bool iValue) { R.NonGC = iValue; } - static void SetObjCType(QualType::GCAttrTypes GCAttrs, LValue& R) { - if (GCAttrs == QualType::Weak) - R.ObjCType = Weak; - else if (GCAttrs == QualType::Strong) - R.ObjCType = Strong; - else - R.ObjCType = None; - } // simple lvalue llvm::Value *getAddress() const { assert(isSimple()); return V; } @@ -262,48 +237,44 @@ public: return KVCRefExpr; } - static LValue MakeAddr(llvm::Value *V, unsigned Qualifiers, - QualType::GCAttrTypes GCAttrs = QualType::GCNone, - unsigned AddressSpace = 0) { + static LValue MakeAddr(llvm::Value *V, Qualifiers Quals) { LValue R; R.LVType = Simple; R.V = V; - SetQualifiers(Qualifiers,R); - R.AddressSpace = AddressSpace; - SetObjCType(GCAttrs, R); + R.SetQualifiers(Quals); return R; } static LValue MakeVectorElt(llvm::Value *Vec, llvm::Value *Idx, - unsigned Qualifiers) { + unsigned CVR) { LValue R; R.LVType = VectorElt; R.V = Vec; R.VectorIdx = Idx; - SetQualifiers(Qualifiers,R); + R.SetQualifiers(Qualifiers::fromCVRMask(CVR)); return R; } static LValue MakeExtVectorElt(llvm::Value *Vec, llvm::Constant *Elts, - unsigned Qualifiers) { + unsigned CVR) { LValue R; R.LVType = ExtVectorElt; R.V = Vec; R.VectorElts = Elts; - SetQualifiers(Qualifiers,R); + R.SetQualifiers(Qualifiers::fromCVRMask(CVR)); return R; } static LValue MakeBitfield(llvm::Value *V, unsigned short StartBit, unsigned short Size, bool IsSigned, - unsigned Qualifiers) { + unsigned CVR) { LValue R; R.LVType = BitField; R.V = V; R.BitfieldData.StartBit = StartBit; R.BitfieldData.Size = Size; R.BitfieldData.IsSigned = IsSigned; - SetQualifiers(Qualifiers,R); + R.SetQualifiers(Qualifiers::fromCVRMask(CVR)); return R; } @@ -311,20 +282,20 @@ public: // the lvalue. However, this complicates the code a bit, and I haven't figured // out how to make it go wrong yet. static LValue MakePropertyRef(const ObjCPropertyRefExpr *E, - unsigned Qualifiers) { + unsigned CVR) { LValue R; R.LVType = PropertyRef; R.PropertyRefExpr = E; - SetQualifiers(Qualifiers,R); + R.SetQualifiers(Qualifiers::fromCVRMask(CVR)); return R; } static LValue MakeKVCRef(const ObjCImplicitSetterGetterRefExpr *E, - unsigned Qualifiers) { + unsigned CVR) { LValue R; R.LVType = KVCRef; R.KVCRefExpr = E; - SetQualifiers(Qualifiers,R); + R.SetQualifiers(Qualifiers::fromCVRMask(CVR)); return R; } }; Index: lib/Sema/SemaDeclCXX.cpp =================================================================== --- lib/Sema/SemaDeclCXX.cpp (revision 82620) +++ lib/Sema/SemaDeclCXX.cpp (working copy) @@ -2046,13 +2046,13 @@ QualType Sema::CheckConstructorDeclarato DeclaratorChunk::FunctionTypeInfo &FTI = D.getTypeObject(0).Fun; if (FTI.TypeQuals != 0) { - if (FTI.TypeQuals & QualType::Const) + if (FTI.TypeQuals & Qualifiers::Const) Diag(D.getIdentifierLoc(), diag::err_invalid_qualified_constructor) << "const" << SourceRange(D.getIdentifierLoc()); - if (FTI.TypeQuals & QualType::Volatile) + if (FTI.TypeQuals & Qualifiers::Volatile) Diag(D.getIdentifierLoc(), diag::err_invalid_qualified_constructor) << "volatile" << SourceRange(D.getIdentifierLoc()); - if (FTI.TypeQuals & QualType::Restrict) + if (FTI.TypeQuals & Qualifiers::Restrict) Diag(D.getIdentifierLoc(), diag::err_invalid_qualified_constructor) << "restrict" << SourceRange(D.getIdentifierLoc()); } @@ -2159,13 +2159,13 @@ QualType Sema::CheckDestructorDeclarator DeclaratorChunk::FunctionTypeInfo &FTI = D.getTypeObject(0).Fun; if (FTI.TypeQuals != 0 && !D.isInvalidType()) { - if (FTI.TypeQuals & QualType::Const) + if (FTI.TypeQuals & Qualifiers::Const) Diag(D.getIdentifierLoc(), diag::err_invalid_qualified_destructor) << "const" << SourceRange(D.getIdentifierLoc()); - if (FTI.TypeQuals & QualType::Volatile) + if (FTI.TypeQuals & Qualifiers::Volatile) Diag(D.getIdentifierLoc(), diag::err_invalid_qualified_destructor) << "volatile" << SourceRange(D.getIdentifierLoc()); - if (FTI.TypeQuals & QualType::Restrict) + if (FTI.TypeQuals & Qualifiers::Restrict) Diag(D.getIdentifierLoc(), diag::err_invalid_qualified_destructor) << "restrict" << SourceRange(D.getIdentifierLoc()); D.setInvalidType(); @@ -2844,10 +2844,8 @@ Sema::getAssignOperatorMethod(ParmVarDec // If class's assignment operator argument is const/volatile qualified, // look for operator = (const/volatile B&). Otherwise, look for // operator = (B&). - if (ParmDecl->getType().isConstQualified()) - RHSType.addConst(); - if (ParmDecl->getType().isVolatileQualified()) - RHSType.addVolatile(); + RHSType = Context.getCVRQualifiedType(RHSType, + ParmDecl->getType().getCVRQualifiers()); ExprOwningPtr LHS(this, new (Context) DeclRefExpr(ParmDecl, LHSType, SourceLocation())); @@ -3571,7 +3569,7 @@ Sema::CheckReferenceInit(Expr *&Init, Qu // -- Otherwise, the reference shall be to a non-volatile const // type (i.e., cv1 shall be const), or the reference shall be an // rvalue reference and the initializer expression shall be an rvalue. - if (!isRValRef && T1.getCVRQualifiers() != QualType::Const) { + if (!isRValRef && T1.getCVRQualifiers() != Qualifiers::Const) { if (!ICS) Diag(Init->getSourceRange().getBegin(), diag::err_not_reference_to_const_init) Index: lib/Sema/TreeTransform.h =================================================================== --- lib/Sema/TreeTransform.h (revision 82620) +++ lib/Sema/TreeTransform.h (working copy) @@ -188,7 +188,7 @@ public: /// not permitted (e.g., qualifiers on reference or function types). This /// is the right thing for template instantiation, but probably not for /// other clients. - QualType AddTypeQualifiers(QualType T, unsigned CVRQualifiers); + QualType AddTypeQualifiers(QualType T, Qualifiers Qs); /// \brief Transform the given statement. /// @@ -1935,13 +1935,16 @@ QualType TreeTransform::Transfo if (getDerived().AlreadyTransformed(T)) return T; + QualifierCollector Qs; + const Type *Ty = Qs.strip(T); + QualType Result; - switch (T->getTypeClass()) { + switch (Ty->getTypeClass()) { #define ABSTRACT_TYPE(CLASS, PARENT) #define TYPE(CLASS, PARENT) \ case Type::CLASS: \ Result = getDerived().Transform##CLASS##Type( \ - static_cast(T.getTypePtr())); \ + static_cast(Ty)); \ break; #include "clang/AST/TypeNodes.def" } @@ -1949,25 +1952,19 @@ QualType TreeTransform::Transfo if (Result.isNull() || T == Result) return Result; - return getDerived().AddTypeQualifiers(Result, T.getCVRQualifiers()); + return getDerived().AddTypeQualifiers(Result, Qs); } template QualType -TreeTransform::AddTypeQualifiers(QualType T, unsigned CVRQualifiers) { - if (CVRQualifiers && !T->isFunctionType() && !T->isReferenceType()) - return T.getWithAdditionalQualifiers(CVRQualifiers); +TreeTransform::AddTypeQualifiers(QualType T, Qualifiers Quals) { + if (!Quals.empty() && !T->isFunctionType() && !T->isReferenceType()) + return SemaRef.Context.getQualifiedType(T, Quals); return T; } template -QualType TreeTransform::TransformExtQualType(const ExtQualType *T) { - // FIXME: Implement - return QualType(T, 0); -} - -template QualType TreeTransform::TransformBuiltinType(const BuiltinType *T) { // Nothing to do return QualType(T, 0); @@ -2076,7 +2073,7 @@ TreeTransform::TransformConstan return getDerived().RebuildConstantArrayType(ElementType, T->getSizeModifier(), T->getSize(), - T->getIndexTypeQualifier()); + T->getIndexTypeCVRQualifiers()); } template @@ -2103,7 +2100,7 @@ TreeTransform::TransformConstan T->getSizeModifier(), T->getSize(), Size.takeAs(), - T->getIndexTypeQualifier(), + T->getIndexTypeCVRQualifiers(), T->getBracketsRange()); } @@ -2122,7 +2119,7 @@ TreeTransform::TransformConstan return getDerived().RebuildConstantArrayWithoutExprType(ElementType, T->getSizeModifier(), T->getSize(), - T->getIndexTypeQualifier()); + T->getIndexTypeCVRQualifiers()); } template @@ -2138,7 +2135,7 @@ QualType TreeTransform::Transfo return getDerived().RebuildIncompleteArrayType(ElementType, T->getSizeModifier(), - T->getIndexTypeQualifier()); + T->getIndexTypeCVRQualifiers()); } template @@ -2165,7 +2162,7 @@ QualType TreeTransform::Transfo return getDerived().RebuildVariableArrayType(ElementType, T->getSizeModifier(), move(Size), - T->getIndexTypeQualifier(), + T->getIndexTypeCVRQualifiers(), T->getBracketsRange()); } @@ -2193,7 +2190,7 @@ QualType TreeTransform::Transfo return getDerived().RebuildDependentSizedArrayType(ElementType, T->getSizeModifier(), move(Size), - T->getIndexTypeQualifier(), + T->getIndexTypeCVRQualifiers(), T->getBracketsRange()); } @@ -4462,14 +4459,14 @@ TreeTransform::TransformBlockDe template QualType TreeTransform::RebuildPointerType(QualType PointeeType) { - return SemaRef.BuildPointerType(PointeeType, 0, + return SemaRef.BuildPointerType(PointeeType, Qualifiers(), getDerived().getBaseLocation(), getDerived().getBaseEntity()); } template QualType TreeTransform::RebuildBlockPointerType(QualType PointeeType) { - return SemaRef.BuildBlockPointerType(PointeeType, 0, + return SemaRef.BuildBlockPointerType(PointeeType, Qualifiers(), getDerived().getBaseLocation(), getDerived().getBaseEntity()); } @@ -4477,7 +4474,7 @@ QualType TreeTransform::Rebuild template QualType TreeTransform::RebuildLValueReferenceType(QualType ReferentType) { - return SemaRef.BuildReferenceType(ReferentType, true, 0, + return SemaRef.BuildReferenceType(ReferentType, true, Qualifiers(), getDerived().getBaseLocation(), getDerived().getBaseEntity()); } @@ -4485,7 +4482,7 @@ TreeTransform::RebuildLValueRef template QualType TreeTransform::RebuildRValueReferenceType(QualType ReferentType) { - return SemaRef.BuildReferenceType(ReferentType, false, 0, + return SemaRef.BuildReferenceType(ReferentType, false, Qualifiers(), getDerived().getBaseLocation(), getDerived().getBaseEntity()); } @@ -4493,7 +4490,7 @@ TreeTransform::RebuildRValueRef template QualType TreeTransform::RebuildMemberPointerType(QualType PointeeType, QualType ClassType) { - return SemaRef.BuildMemberPointerType(PointeeType, ClassType, 0, + return SemaRef.BuildMemberPointerType(PointeeType, ClassType, Qualifiers(), getDerived().getBaseLocation(), getDerived().getBaseEntity()); } @@ -4700,7 +4697,7 @@ TreeTransform::RebuildNestedNam QualType T) { if (T->isDependentType() || T->isRecordType() || (SemaRef.getLangOptions().CPlusPlus0x && T->isEnumeralType())) { - assert(T.getCVRQualifiers() == 0 && "Can't get cv-qualifiers here"); + assert(!T.hasQualifiers() && "Can't get cv-qualifiers here"); return NestedNameSpecifier::Create(SemaRef.Context, Prefix, TemplateKW, T.getTypePtr()); } Index: lib/Sema/SemaExprCXX.cpp =================================================================== --- lib/Sema/SemaExprCXX.cpp (revision 82620) +++ lib/Sema/SemaExprCXX.cpp (working copy) @@ -972,7 +972,7 @@ Sema::IsStringLiteralToNonConstPointerCo = ToPtrType->getPointeeType()->getAs()) { // This conversion is considered only when there is an // explicit appropriate pointer target type (C++ 4.2p2). - if (ToPtrType->getPointeeType().getCVRQualifiers() == 0 && + if (!ToPtrType->getPointeeType().hasQualifiers() && ((StrLit->isWide() && ToPointeeType->isWideCharType()) || (!StrLit->isWide() && (ToPointeeType->getKind() == BuiltinType::Char_U || @@ -1307,10 +1307,7 @@ QualType Sema::CheckPointerToMemberOpera // argument. // We probably need a "MemberFunctionClosureType" or something like that. QualType Result = MemPtr->getPointeeType(); - if (LType.isConstQualified()) - Result.addConst(); - if (LType.isVolatileQualified()) - Result.addVolatile(); + Result = Context.getCVRQualifiedType(Result, LType.getCVRQualifiers()); return Result; } @@ -1656,8 +1653,10 @@ QualType Sema::CXXCheckConditionalOperan Context.getCanonicalType(RPointee).getUnqualifiedType()) { // Second, we take the greater of the two cv qualifications. If neither // is greater than the other, the conversion is not possible. - unsigned Q = LPointee.getCVRQualifiers() | RPointee.getCVRQualifiers(); - if (Q == LPointee.getCVRQualifiers() || Q == RPointee.getCVRQualifiers()){ + unsigned CVR_L = LPointee.getCVRQualifiers(); + unsigned CVR_R = RPointee.getCVRQualifiers(); + unsigned CVR = CVR_L | CVR_R; + if (CVR == CVR_L || CVR == CVR_R) { // Third, we check if either of the container classes is derived from // the other. QualType LContainer(LMemPtr->getClass(), 0); @@ -1675,8 +1674,10 @@ QualType Sema::CXXCheckConditionalOperan // The type 'Q Pointee (MoreDerived::*)' is the common type. // We don't use ImpCastExprToType here because this could still fail // for ambiguous or inaccessible conversions. - QualType Common = Context.getMemberPointerType( - LPointee.getQualifiedType(Q), MoreDerived.getTypePtr()); + LPointee + = Context.getQualifiedType(LPointee, Qualifiers::fromCVRMask(CVR)); + QualType Common + = Context.getMemberPointerType(LPointee, MoreDerived.getTypePtr()); if (PerformImplicitConversion(LHS, Common, "converting")) return QualType(); if (PerformImplicitConversion(RHS, Common, "converting")) @@ -1778,16 +1779,21 @@ QualType Sema::FindCompositePointerType( I = QualifierUnion.begin(), E = QualifierUnion.end(); I != E; (void)++I, ++MOC) { + Qualifiers Quals = Qualifiers::fromCVRMask(*I); if (MOC->first && MOC->second) { // Rebuild member pointer type - Composite1 = Context.getMemberPointerType(Composite1.getQualifiedType(*I), - MOC->first); - Composite2 = Context.getMemberPointerType(Composite2.getQualifiedType(*I), - MOC->second); + Composite1 = Context.getMemberPointerType( + Context.getQualifiedType(Composite1, Quals), + MOC->first); + Composite2 = Context.getMemberPointerType( + Context.getQualifiedType(Composite2, Quals), + MOC->second); } else { // Rebuild pointer type - Composite1 = Context.getPointerType(Composite1.getQualifiedType(*I)); - Composite2 = Context.getPointerType(Composite2.getQualifiedType(*I)); + Composite1 + = Context.getPointerType(Context.getQualifiedType(Composite1, Quals)); + Composite2 + = Context.getPointerType(Context.getQualifiedType(Composite2, Quals)); } } Index: lib/Sema/SemaInherit.cpp =================================================================== --- lib/Sema/SemaInherit.cpp (revision 82620) +++ lib/Sema/SemaInherit.cpp (working copy) @@ -59,7 +59,7 @@ BasePaths::decl_iterator BasePaths::foun /// an unqualified, canonical class type. bool BasePaths::isAmbiguous(QualType BaseType) { assert(BaseType->isCanonical() && "Base type must be the canonical type"); - assert(BaseType.getCVRQualifiers() == 0 && "Base type must be unqualified"); + assert(BaseType.hasQualifiers() == 0 && "Base type must be unqualified"); std::pair& Subobjects = ClassSubobjects[BaseType]; return Subobjects.second + (Subobjects.first? 1 : 0) > 1; } Index: lib/Sema/SemaDecl.cpp =================================================================== --- lib/Sema/SemaDecl.cpp (revision 82620) +++ lib/Sema/SemaDecl.cpp (working copy) @@ -1814,14 +1814,16 @@ static QualType TryToFixInvalidVariablyM // constant expression folding, like struct {char x[(int)(char*)2];} SizeIsNegative = false; - if (const PointerType* PTy = dyn_cast(T)) { + QualifierCollector Qs; + const Type *Ty = Qs.strip(T); + + if (const PointerType* PTy = dyn_cast(Ty)) { QualType Pointee = PTy->getPointeeType(); QualType FixedType = TryToFixInvalidVariablyModifiedType(Pointee, Context, SizeIsNegative); if (FixedType.isNull()) return FixedType; FixedType = Context.getPointerType(FixedType); - FixedType.setCVRQualifiers(T.getCVRQualifiers()); - return FixedType; + return Qs.apply(FixedType); } const VariableArrayType* VLATy = dyn_cast(T); @@ -2968,7 +2970,7 @@ void Sema::CheckMain(FunctionDecl* FD) { // char const * const * // char * const * - QualifierSet qs; + QualifierCollector qs; const PointerType* PT; if ((PT = qs.strip(AT)->getAs()) && (PT = qs.strip(PT->getPointeeType())->getAs()) && Index: lib/Sema/SemaTemplateDeduction.cpp =================================================================== --- lib/Sema/SemaTemplateDeduction.cpp (revision 82620) +++ lib/Sema/SemaTemplateDeduction.cpp (working copy) @@ -300,28 +300,30 @@ DeduceTemplateArguments(ASTContext &Cont } /// \brief Returns a completely-unqualified array type, capturing the -/// qualifiers in CVRQuals. +/// qualifiers in Quals. /// /// \param Context the AST context in which the array type was built. /// /// \param T a canonical type that may be an array type. /// -/// \param CVRQuals will receive the set of const/volatile/restrict qualifiers -/// that were applied to the element type of the array. +/// \param Quals will receive the full set of qualifiers that were +/// applied to the element type of the array. /// /// \returns if \p T is an array type, the completely unqualified array type /// that corresponds to T. Otherwise, returns T. static QualType getUnqualifiedArrayType(ASTContext &Context, QualType T, - unsigned &CVRQuals) { + Qualifiers &Quals) { assert(T->isCanonical() && "Only operates on canonical types"); if (!isa(T)) { - CVRQuals = T.getCVRQualifiers(); + Quals = T.getQualifiers(); return T.getUnqualifiedType(); } + assert(!T.hasQualifiers() && "canonical array type has qualifiers!"); + if (const ConstantArrayType *CAT = dyn_cast(T)) { QualType Elt = getUnqualifiedArrayType(Context, CAT->getElementType(), - CVRQuals); + Quals); if (Elt == CAT->getElementType()) return T; @@ -331,7 +333,7 @@ static QualType getUnqualifiedArrayType( if (const IncompleteArrayType *IAT = dyn_cast(T)) { QualType Elt = getUnqualifiedArrayType(Context, IAT->getElementType(), - CVRQuals); + Quals); if (Elt == IAT->getElementType()) return T; @@ -340,7 +342,7 @@ static QualType getUnqualifiedArrayType( const DependentSizedArrayType *DSAT = cast(T); QualType Elt = getUnqualifiedArrayType(Context, DSAT->getElementType(), - CVRQuals); + Quals); if (Elt == DSAT->getElementType()) return T; @@ -387,9 +389,9 @@ DeduceTemplateArguments(ASTContext &Cont // referred to by the reference) can be more cv-qualified than the // transformed A. if (TDF & TDF_ParamWithReferenceType) { - unsigned ExtraQualsOnParam - = Param.getCVRQualifiers() & ~Arg.getCVRQualifiers(); - Param.setCVRQualifiers(Param.getCVRQualifiers() & ~ExtraQualsOnParam); + Qualifiers Quals = Param.getQualifiers(); + Quals.setCVRQualifiers(Quals.getCVRQualifiers() & Arg.getCVRQualifiers()); + Param = Context.getQualifiedType(Param.getUnqualifiedType(), Quals); } // If the parameter type is not dependent, there is nothing to deduce. @@ -418,10 +420,10 @@ DeduceTemplateArguments(ASTContext &Cont // top level, so they can be matched with the qualifiers on the parameter. // FIXME: address spaces, ObjC GC qualifiers if (isa(Arg)) { - unsigned CVRQuals = 0; - Arg = getUnqualifiedArrayType(Context, Arg, CVRQuals); - if (CVRQuals) { - Arg = Arg.getWithAdditionalQualifiers(CVRQuals); + Qualifiers Quals; + Arg = getUnqualifiedArrayType(Context, Arg, Quals); + if (Quals) { + Arg = Context.getQualifiedType(Arg, Quals); RecanonicalizeArg = true; } } @@ -437,8 +439,8 @@ DeduceTemplateArguments(ASTContext &Cont assert(TemplateTypeParm->getDepth() == 0 && "Can't deduce with depth > 0"); - unsigned Quals = Arg.getCVRQualifiers() & ~Param.getCVRQualifiers(); - QualType DeducedType = Arg.getQualifiedType(Quals); + QualType DeducedType = Arg; + DeducedType.removeCVRQualifiers(Param.getCVRQualifiers()); if (RecanonicalizeArg) DeducedType = Context.getCanonicalType(DeducedType); @@ -2022,13 +2024,6 @@ MarkUsedTemplateParameters(Sema &SemaRef T = SemaRef.Context.getCanonicalType(T); switch (T->getTypeClass()) { - case Type::ExtQual: - MarkUsedTemplateParameters(SemaRef, - QualType(cast(T)->getBaseType(), 0), - OnlyDeduced, - Used); - break; - case Type::Pointer: MarkUsedTemplateParameters(SemaRef, cast(T)->getPointeeType(), Index: lib/Sema/SemaOverload.cpp =================================================================== --- lib/Sema/SemaOverload.cpp (revision 82620) +++ lib/Sema/SemaOverload.cpp (working copy) @@ -856,12 +856,12 @@ BuildSimilarlyQualifiedPointerType(const ASTContext &Context) { QualType CanonFromPointee = Context.getCanonicalType(FromPtr->getPointeeType()); QualType CanonToPointee = Context.getCanonicalType(ToPointee); - unsigned Quals = CanonFromPointee.getCVRQualifiers(); + Qualifiers Quals = CanonFromPointee.getQualifiers(); // Exact qualifier match -> return the pointer type we're converting to. - if (CanonToPointee.getCVRQualifiers() == Quals) { + if (CanonToPointee.getQualifiers() == Quals) { // ToType is exactly what we need. Return it. - if (ToType.getTypePtr()) + if (!ToType.isNull()) return ToType; // Build a pointer to ToPointee. It has the right qualifiers @@ -870,7 +870,8 @@ BuildSimilarlyQualifiedPointerType(const } // Just build a canonical type that has the right qualifiers. - return Context.getPointerType(CanonToPointee.getQualifiedType(Quals)); + return Context.getPointerType( + Context.getQualifiedType(CanonToPointee.getUnqualifiedType(), Quals)); } static bool isNullPointerConstantForConversion(Expr *Expr, @@ -2020,8 +2021,8 @@ bool Sema::PerformCopyInitialization(Exp ImplicitConversionSequence Sema::TryObjectArgumentInitialization(Expr *From, CXXMethodDecl *Method) { QualType ClassType = Context.getTypeDeclType(Method->getParent()); - unsigned MethodQuals = Method->getTypeQualifiers(); - QualType ImplicitParamType = ClassType.getQualifiedType(MethodQuals); + QualType ImplicitParamType + = Context.getCVRQualifiedType(ClassType, Method->getTypeQualifiers()); // Set up the conversion sequence as a "bad" conversion, to allow us // to exit early. @@ -2830,25 +2831,23 @@ public: /// false otherwise. bool BuiltinCandidateTypeSet::AddPointerWithMoreQualifiedTypeVariants(QualType Ty) { + // Insert this type. if (!PointerTypes.insert(Ty)) return false; - if (const PointerType *PointerTy = Ty->getAs()) { - QualType PointeeTy = PointerTy->getPointeeType(); - // FIXME: Optimize this so that we don't keep trying to add the same types. + const PointerType *PointerTy = Ty->getAs(); + assert(PointerTy && "type was not a pointer type!"); - // FIXME: Do we have to add CVR qualifiers at *all* levels to deal with all - // pointer conversions that don't cast away constness? - if (!PointeeTy.isConstQualified()) - AddPointerWithMoreQualifiedTypeVariants - (Context.getPointerType(PointeeTy.withConst())); - if (!PointeeTy.isVolatileQualified()) - AddPointerWithMoreQualifiedTypeVariants - (Context.getPointerType(PointeeTy.withVolatile())); - if (!PointeeTy.isRestrictQualified()) - AddPointerWithMoreQualifiedTypeVariants - (Context.getPointerType(PointeeTy.withRestrict())); + QualType PointeeTy = PointerTy->getPointeeType(); + unsigned BaseCVR = PointeeTy.getCVRQualifiers(); + + // Iterate through all strict supersets of BaseCVR. + for (unsigned CVR = BaseCVR+1; CVR <= Qualifiers::CVRMask; ++CVR) { + if ((CVR | BaseCVR) != CVR) continue; + + QualType QPointeeTy = Context.getCVRQualifiedType(PointeeTy, CVR); + PointerTypes.insert(Context.getPointerType(QPointeeTy)); } return true; @@ -2868,20 +2867,20 @@ BuiltinCandidateTypeSet::AddMemberPointe if (!MemberPointerTypes.insert(Ty)) return false; - if (const MemberPointerType *PointerTy = Ty->getAs()) { - QualType PointeeTy = PointerTy->getPointeeType(); - const Type *ClassTy = PointerTy->getClass(); - // FIXME: Optimize this so that we don't keep trying to add the same types. + const MemberPointerType *PointerTy = Ty->getAs(); + assert(PointerTy && "type was not a member pointer type!"); + + QualType PointeeTy = PointerTy->getPointeeType(); + const Type *ClassTy = PointerTy->getClass(); - if (!PointeeTy.isConstQualified()) - AddMemberPointerWithMoreQualifiedTypeVariants - (Context.getMemberPointerType(PointeeTy.withConst(), ClassTy)); - if (!PointeeTy.isVolatileQualified()) - AddMemberPointerWithMoreQualifiedTypeVariants - (Context.getMemberPointerType(PointeeTy.withVolatile(), ClassTy)); - if (!PointeeTy.isRestrictQualified()) - AddMemberPointerWithMoreQualifiedTypeVariants - (Context.getMemberPointerType(PointeeTy.withRestrict(), ClassTy)); + // Iterate through all strict supersets of the pointee type's CVR + // qualifiers. + unsigned BaseCVR = PointeeTy.getCVRQualifiers(); + for (unsigned CVR = BaseCVR+1; CVR <= Qualifiers::CVRMask; ++CVR) { + if ((CVR | BaseCVR) != CVR) continue; + + QualType QPointeeTy = Context.getCVRQualifiedType(PointeeTy, CVR); + MemberPointerTypes.insert(Context.getMemberPointerType(QPointeeTy, ClassTy)); } return true; @@ -2921,7 +2920,8 @@ BuiltinCandidateTypeSet::AddTypesConvert // Add 'cv void*' to our set of types. if (!Ty->isVoidType()) { QualType QualVoid - = Context.VoidTy.getQualifiedType(PointeeTy.getCVRQualifiers()); + = Context.getCVRQualifiedType(Context.VoidTy, + PointeeTy.getCVRQualifiers()); AddPointerWithMoreQualifiedTypeVariants(Context.getPointerType(QualVoid)); } @@ -2933,7 +2933,8 @@ BuiltinCandidateTypeSet::AddTypesConvert for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(); Base != ClassDecl->bases_end(); ++Base) { QualType BaseTy = Context.getCanonicalType(Base->getType()); - BaseTy = BaseTy.getQualifiedType(PointeeTy.getCVRQualifiers()); + BaseTy = Context.getCVRQualifiedType(BaseTy.getUnqualifiedType(), + PointeeTy.getCVRQualifiers()); // Add the pointer type, recursively, so that we get all of // the indirect base classes, too. @@ -2994,7 +2995,8 @@ static void AddBuiltinAssignmentOperator if (!S.Context.getCanonicalType(T).isVolatileQualified()) { // volatile T& operator=(volatile T&, T) - ParamTypes[0] = S.Context.getLValueReferenceType(T.withVolatile()); + ParamTypes[0] + = S.Context.getLValueReferenceType(S.Context.getVolatileType(T)); ParamTypes[1] = T; S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet, /*IsAssignmentOperator=*/true); @@ -3116,7 +3118,8 @@ Sema::AddBuiltinOperatorCandidates(Overl AddBuiltinCandidate(ArithTy, ParamTypes, Args, 2, CandidateSet); // Volatile version - ParamTypes[0] = Context.getLValueReferenceType(ArithTy.withVolatile()); + ParamTypes[0] + = Context.getLValueReferenceType(Context.getVolatileType(ArithTy)); if (NumArgs == 1) AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 1, CandidateSet); else @@ -3151,7 +3154,8 @@ Sema::AddBuiltinOperatorCandidates(Overl if (!Context.getCanonicalType(*Ptr).isVolatileQualified()) { // With volatile - ParamTypes[0] = Context.getLValueReferenceType((*Ptr).withVolatile()); + ParamTypes[0] + = Context.getLValueReferenceType(Context.getVolatileType(*Ptr)); if (NumArgs == 1) AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 1, CandidateSet); else @@ -3462,7 +3466,8 @@ Sema::AddBuiltinOperatorCandidates(Overl if (!Context.getCanonicalType(*Ptr).isVolatileQualified()) { // volatile version - ParamTypes[0] = Context.getLValueReferenceType((*Ptr).withVolatile()); + ParamTypes[0] + = Context.getLValueReferenceType(Context.getVolatileType(*Ptr)); AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet, /*IsAssigmentOperator=*/Op == OO_Equal); } @@ -3495,7 +3500,7 @@ Sema::AddBuiltinOperatorCandidates(Overl /*IsAssigmentOperator=*/Op == OO_Equal); // Add this built-in operator as a candidate (VQ is 'volatile'). - ParamTypes[0] = ArithmeticTypes[Left].withVolatile(); + ParamTypes[0] = Context.getVolatileType(ArithmeticTypes[Left]); ParamTypes[0] = Context.getLValueReferenceType(ParamTypes[0]); AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet, /*IsAssigmentOperator=*/Op == OO_Equal); @@ -3533,7 +3538,7 @@ Sema::AddBuiltinOperatorCandidates(Overl // Add this built-in operator as a candidate (VQ is 'volatile'). ParamTypes[0] = ArithmeticTypes[Left]; - ParamTypes[0].addVolatile(); + ParamTypes[0] = Context.getVolatileType(ParamTypes[0]); ParamTypes[0] = Context.getLValueReferenceType(ParamTypes[0]); AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet); } Index: lib/Sema/SemaType.cpp =================================================================== --- lib/Sema/SemaType.cpp (revision 82620) +++ lib/Sema/SemaType.cpp (working copy) @@ -312,7 +312,7 @@ QualType Sema::ConvertDeclSpecToType(con // Enforce C99 6.7.3p2: "Types other than pointer types derived from object // or incomplete types shall not be restrict-qualified." C++ also allows // restrict-qualified references. - if (TypeQuals & QualType::Restrict) { + if (TypeQuals & DeclSpec::TQ_restrict) { if (Result->isPointerType() || Result->isReferenceType()) { QualType EltTy = Result->isPointerType() ? Result->getAs()->getPointeeType() : @@ -324,13 +324,13 @@ QualType Sema::ConvertDeclSpecToType(con Diag(DS.getRestrictSpecLoc(), diag::err_typecheck_invalid_restrict_invalid_pointee) << EltTy << DS.getSourceRange(); - TypeQuals &= ~QualType::Restrict; // Remove the restrict qualifier. + TypeQuals &= ~DeclSpec::TQ_restrict; // Remove the restrict qualifier. } } else { Diag(DS.getRestrictSpecLoc(), diag::err_typecheck_invalid_restrict_not_pointer) << Result << DS.getSourceRange(); - TypeQuals &= ~QualType::Restrict; // Remove the restrict qualifier. + TypeQuals &= ~DeclSpec::TQ_restrict; // Remove the restrict qualifier. } } @@ -340,12 +340,14 @@ QualType Sema::ConvertDeclSpecToType(con if (Result->isFunctionType() && TypeQuals) { // Get some location to point at, either the C or V location. SourceLocation Loc; - if (TypeQuals & QualType::Const) + if (TypeQuals & DeclSpec::TQ_const) Loc = DS.getConstSpecLoc(); - else { - assert((TypeQuals & QualType::Volatile) && - "Has CV quals but not C or V?"); + else if (TypeQuals & DeclSpec::TQ_volatile) Loc = DS.getVolatileSpecLoc(); + else { + assert((TypeQuals & DeclSpec::TQ_restrict) && + "Has CVR quals but not C, V, or R?"); + Loc = DS.getRestrictSpecLoc(); } Diag(Loc, diag::warn_typecheck_function_qualifiers) << Result << DS.getSourceRange(); @@ -359,12 +361,14 @@ QualType Sema::ConvertDeclSpecToType(con // FIXME: Shouldn't we be checking SCS_typedef here? if (DS.getTypeSpecType() == DeclSpec::TST_typename && TypeQuals && Result->isReferenceType()) { - TypeQuals &= ~QualType::Const; - TypeQuals &= ~QualType::Volatile; + TypeQuals &= ~DeclSpec::TQ_const; + TypeQuals &= ~DeclSpec::TQ_volatile; } - Result = Result.getQualifiedType(TypeQuals); + Qualifiers Quals = Qualifiers::fromCVRMask(TypeQuals); + Result = Context.getQualifiedType(Result, Quals); } + return Result; } @@ -399,23 +403,25 @@ QualType Sema::BuildPointerType(QualType return QualType(); } + Qualifiers Qs = Qualifiers::fromCVRMask(Quals); + // Enforce C99 6.7.3p2: "Types other than pointer types derived from // object or incomplete types shall not be restrict-qualified." - if ((Quals & QualType::Restrict) && !T->isIncompleteOrObjectType()) { + if (Qs.hasRestrict() && !T->isIncompleteOrObjectType()) { Diag(Loc, diag::err_typecheck_invalid_restrict_invalid_pointee) << T; - Quals &= ~QualType::Restrict; + Qs.removeRestrict(); } // Build the pointer type. - return Context.getPointerType(T).getQualifiedType(Quals); + return Context.getQualifiedType(Context.getPointerType(T), Qs); } /// \brief Build a reference type. /// /// \param T The type to which we'll be building a reference. /// -/// \param Quals The cvr-qualifiers to be applied to the reference type. +/// \param CVR The cvr-qualifiers to be applied to the reference type. /// /// \param Loc The location of the entity whose type involves this /// reference type or, if there is no such entity, the location of the @@ -426,8 +432,9 @@ QualType Sema::BuildPointerType(QualType /// /// \returns A suitable reference type, if there are no /// errors. Otherwise, returns a NULL type. -QualType Sema::BuildReferenceType(QualType T, bool LValueRef, unsigned Quals, +QualType Sema::BuildReferenceType(QualType T, bool LValueRef, unsigned CVR, SourceLocation Loc, DeclarationName Entity) { + Qualifiers Quals = Qualifiers::fromCVRMask(CVR); if (LValueRef) { if (const RValueReferenceType *R = T->getAs()) { // C++0x [dcl.typedef]p9: If a typedef TD names a type that is a @@ -435,8 +442,8 @@ QualType Sema::BuildReferenceType(QualTy // reference to cv TD" creates the type "lvalue reference to T". // We use the qualifiers (restrict or none) of the original reference, // not the new ones. This is consistent with GCC. - return Context.getLValueReferenceType(R->getPointeeType()). - getQualifiedType(T.getCVRQualifiers()); + QualType LVRT = Context.getLValueReferenceType(R->getPointeeType()); + return Context.getQualifiedType(LVRT, T.getQualifiers()); } } if (T->isReferenceType()) { @@ -449,7 +456,7 @@ QualType Sema::BuildReferenceType(QualTy // typedef int& intref; // typedef intref& intref2; // - // Parser::ParserDeclaratorInternal diagnoses the case where + // Parser::ParseDeclaratorInternal diagnoses the case where // references are written directly; here, we handle the // collapsing of references-to-references as described in C++ // DR 106 and amended by C++ DR 540. @@ -466,10 +473,10 @@ QualType Sema::BuildReferenceType(QualTy // Enforce C99 6.7.3p2: "Types other than pointer types derived from // object or incomplete types shall not be restrict-qualified." - if ((Quals & QualType::Restrict) && !T->isIncompleteOrObjectType()) { + if (Quals.hasRestrict() && !T->isIncompleteOrObjectType()) { Diag(Loc, diag::err_typecheck_invalid_restrict_invalid_pointee) << T; - Quals &= ~QualType::Restrict; + Quals.removeRestrict(); } // C++ [dcl.ref]p1: @@ -481,13 +488,13 @@ QualType Sema::BuildReferenceType(QualTy // We diagnose extraneous cv-qualifiers for the non-typedef, // non-template type argument case within the parser. Here, we just // ignore any extraneous cv-qualifiers. - Quals &= ~QualType::Const; - Quals &= ~QualType::Volatile; + Quals.removeConst(); + Quals.removeVolatile(); // Handle restrict on references. if (LValueRef) - return Context.getLValueReferenceType(T).getQualifiedType(Quals); - return Context.getRValueReferenceType(T).getQualifiedType(Quals); + return Context.getQualifiedType(Context.getLValueReferenceType(T), Quals); + return Context.getQualifiedType(Context.getRValueReferenceType(T), Quals); } /// \brief Build an array type. @@ -513,6 +520,7 @@ QualType Sema::BuildReferenceType(QualTy QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM, Expr *ArraySize, unsigned Quals, SourceRange Brackets, DeclarationName Entity) { + SourceLocation Loc = Brackets.getBegin(); // C99 6.7.5.2p1: If the element type is an incomplete or function type, // reject it (e.g. void ary[7], struct foo ary[7], void ary[7]()) @@ -706,15 +714,17 @@ QualType Sema::BuildFunctionType(QualTyp /// /// \param T the type to which the member pointer refers. /// \param Class the class type into which the member pointer points. -/// \param Quals Qualifiers applied to the member pointer type +/// \param CVR Qualifiers applied to the member pointer type /// \param Loc the location where this type begins /// \param Entity the name of the entity that will have this member pointer type /// /// \returns a member pointer type, if successful, or a NULL type if there was /// an error. QualType Sema::BuildMemberPointerType(QualType T, QualType Class, - unsigned Quals, SourceLocation Loc, + unsigned CVR, SourceLocation Loc, DeclarationName Entity) { + Qualifiers Quals = Qualifiers::fromCVRMask(CVR); + // Verify that we're not building a pointer to pointer to function with // exception specification. if (CheckDistantExceptionSpec(T)) { @@ -744,13 +754,13 @@ QualType Sema::BuildMemberPointerType(Qu // Enforce C99 6.7.3p2: "Types other than pointer types derived from // object or incomplete types shall not be restrict-qualified." - if ((Quals & QualType::Restrict) && !T->isIncompleteOrObjectType()) { + if (Quals.hasRestrict() && !T->isIncompleteOrObjectType()) { Diag(Loc, diag::err_typecheck_invalid_restrict_invalid_pointee) << T; // FIXME: If we're doing this as part of template instantiation, // we should return immediately. - Quals &= ~QualType::Restrict; + Quals.removeRestrict(); } if (!Class->isDependentType() && !Class->isRecordType()) { @@ -758,15 +768,15 @@ QualType Sema::BuildMemberPointerType(Qu return QualType(); } - return Context.getMemberPointerType(T, Class.getTypePtr()) - .getQualifiedType(Quals); + return Context.getQualifiedType( + Context.getMemberPointerType(T, Class.getTypePtr()), Quals); } /// \brief Build a block pointer type. /// /// \param T The type to which we'll be building a block pointer. /// -/// \param Quals The cvr-qualifiers to be applied to the block pointer type. +/// \param CVR The cvr-qualifiers to be applied to the block pointer type. /// /// \param Loc The location of the entity whose type involves this /// block pointer type or, if there is no such entity, the location of the @@ -777,15 +787,16 @@ QualType Sema::BuildMemberPointerType(Qu /// /// \returns A suitable block pointer type, if there are no /// errors. Otherwise, returns a NULL type. -QualType Sema::BuildBlockPointerType(QualType T, unsigned Quals, +QualType Sema::BuildBlockPointerType(QualType T, unsigned CVR, SourceLocation Loc, DeclarationName Entity) { - if (!T.getTypePtr()->isFunctionType()) { + if (!T->isFunctionType()) { Diag(Loc, diag::err_nonfunction_block_type); return QualType(); } - return Context.getBlockPointerType(T).getQualifiedType(Quals); + Qualifiers Quals = Qualifiers::fromCVRMask(CVR); + return Context.getQualifiedType(Context.getBlockPointerType(T), Quals); } QualType Sema::GetTypeFromParser(TypeTy *Ty, DeclaratorInfo **DInfo) { @@ -921,8 +932,9 @@ QualType Sema::GetTypeForDeclarator(Decl case DeclaratorChunk::BlockPointer: if (ShouldBuildInfo) { if (SourceTy->isFunctionType()) - SourceTy = Context.getBlockPointerType(SourceTy) - .getQualifiedType(DeclType.Cls.TypeQuals); + SourceTy + = Context.getQualifiedType(Context.getBlockPointerType(SourceTy), + Qualifiers::fromCVRMask(DeclType.Cls.TypeQuals)); else // If not function type Context::getBlockPointerType asserts, // so just give up. @@ -939,8 +951,8 @@ QualType Sema::GetTypeForDeclarator(Decl case DeclaratorChunk::Pointer: //FIXME: Use ObjCObjectPointer for info when appropriate. if (ShouldBuildInfo) - SourceTy = Context.getPointerType(SourceTy) - .getQualifiedType(DeclType.Ptr.TypeQuals); + SourceTy = Context.getQualifiedType(Context.getPointerType(SourceTy), + Qualifiers::fromCVRMask(DeclType.Ptr.TypeQuals)); // Verify that we're not building a pointer to pointer to function with // exception specification. if (getLangOptions().CPlusPlus && CheckDistantExceptionSpec(T)) { @@ -957,14 +969,16 @@ QualType Sema::GetTypeForDeclarator(Decl } T = BuildPointerType(T, DeclType.Ptr.TypeQuals, DeclType.Loc, Name); break; - case DeclaratorChunk::Reference: + case DeclaratorChunk::Reference: { + Qualifiers Quals; + if (DeclType.Ref.HasRestrict) Quals.addRestrict(); + if (ShouldBuildInfo) { if (DeclType.Ref.LValueRef) SourceTy = Context.getLValueReferenceType(SourceTy); else SourceTy = Context.getRValueReferenceType(SourceTy); - unsigned Quals = DeclType.Ref.HasRestrict ? QualType::Restrict : 0; - SourceTy = SourceTy.getQualifiedType(Quals); + SourceTy = Context.getQualifiedType(SourceTy, Quals); } // Verify that we're not building a reference to pointer to function with @@ -974,15 +988,15 @@ QualType Sema::GetTypeForDeclarator(Decl D.setInvalidType(true); // Build the type anyway. } - T = BuildReferenceType(T, DeclType.Ref.LValueRef, - DeclType.Ref.HasRestrict ? QualType::Restrict : 0, + T = BuildReferenceType(T, DeclType.Ref.LValueRef, Quals, DeclType.Loc, Name); break; + } case DeclaratorChunk::Array: { if (ShouldBuildInfo) // We just need to get an array type, the exact type doesn't matter. SourceTy = Context.getIncompleteArrayType(SourceTy, ArrayType::Normal, - DeclType.Arr.TypeQuals); + DeclType.Arr.TypeQuals); // Verify that we're not building an array of pointers to function with // exception specification. @@ -1009,7 +1023,8 @@ QualType Sema::GetTypeForDeclarator(Decl ASM = ArrayType::Normal; D.setInvalidType(true); } - T = BuildArrayType(T, ASM, ArraySize, ATI.TypeQuals, + T = BuildArrayType(T, ASM, ArraySize, + Qualifiers::fromCVRMask(ATI.TypeQuals), SourceRange(DeclType.Loc, DeclType.EndLoc), Name); break; } @@ -1028,7 +1043,8 @@ QualType Sema::GetTypeForDeclarator(Decl } SourceTy = Context.getFunctionType(SourceTy, ArgTys.data(), ArgTys.size(), - FTI.isVariadic, FTI.TypeQuals); + FTI.isVariadic, + FTI.TypeQuals); } // If the function declarator has a prototype (i.e. it is not () and @@ -1132,7 +1148,7 @@ QualType Sema::GetTypeForDeclarator(Decl Param->setType(ArgTy); } else { // Reject, but continue to parse 'float(const void)'. - if (ArgTy.getCVRQualifiers()) + if (ArgTy.hasQualifiers()) Diag(DeclType.Loc, diag::err_void_param_qualified); // Do not add 'void' to the ArgTys list. @@ -1198,8 +1214,9 @@ QualType Sema::GetTypeForDeclarator(Decl if (ShouldBuildInfo) { QualType cls = !ClsType.isNull() ? ClsType : Context.IntTy; - SourceTy = Context.getMemberPointerType(SourceTy, cls.getTypePtr()) - .getQualifiedType(DeclType.Mem.TypeQuals); + SourceTy = Context.getQualifiedType( + Context.getMemberPointerType(SourceTy, cls.getTypePtr()), + Qualifiers::fromCVRMask(DeclType.Mem.TypeQuals)); } if (!ClsType.isNull()) @@ -1479,7 +1496,7 @@ bool Sema::CheckExceptionSpecSubset(unsi SubIsPointer = true; } bool SubIsClass = CanonicalSubT->isRecordType(); - CanonicalSubT.setCVRQualifiers(0); + CanonicalSubT = CanonicalSubT.getUnqualifiedType(); BasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true, /*DetectVirtual=*/false); @@ -1501,7 +1518,7 @@ bool Sema::CheckExceptionSpecSubset(unsi continue; } } - CanonicalSuperT.setCVRQualifiers(0); + CanonicalSuperT = CanonicalSuperT.getUnqualifiedType(); // If the types are the same, move on to the next type in the subset. if (CanonicalSubT == CanonicalSuperT) { Contained = true; @@ -1633,6 +1650,7 @@ Sema::TypeResult Sema::ActOnTypeName(Sco /// space for the type. static void HandleAddressSpaceTypeAttribute(QualType &Type, const AttributeList &Attr, Sema &S){ + // If this type is already address space qualified, reject it. // Clause 6.7.3 - Type qualifiers: "No type shall be qualified by qualifiers // for two or more different address spaces." @@ -1664,10 +1682,10 @@ static void HandleAddressSpaceTypeAttrib addrSpace.setIsSigned(false); } llvm::APSInt max(addrSpace.getBitWidth()); - max = QualType::MaxAddressSpace; + max = Qualifiers::MaxAddressSpace; if (addrSpace > max) { S.Diag(Attr.getLoc(), diag::err_attribute_address_space_too_high) - << QualType::MaxAddressSpace << ASArgExpr->getSourceRange(); + << Qualifiers::MaxAddressSpace << ASArgExpr->getSourceRange(); return; } @@ -1679,7 +1697,7 @@ static void HandleAddressSpaceTypeAttrib /// specified type. The attribute contains 1 argument, weak or strong. static void HandleObjCGCTypeAttribute(QualType &Type, const AttributeList &Attr, Sema &S) { - if (Type.getObjCGCAttr() != QualType::GCNone) { + if (Type.getObjCGCAttr() != Qualifiers::GCNone) { S.Diag(Attr.getLoc(), diag::err_attribute_multiple_objc_gc); return; } @@ -1690,15 +1708,15 @@ static void HandleObjCGCTypeAttribute(Qu << "objc_gc" << 1; return; } - QualType::GCAttrTypes GCAttr; + Qualifiers::GC GCAttr; if (Attr.getNumArgs() != 0) { S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1; return; } if (Attr.getParameterName()->isStr("weak")) - GCAttr = QualType::Weak; + GCAttr = Qualifiers::Weak; else if (Attr.getParameterName()->isStr("strong")) - GCAttr = QualType::Strong; + GCAttr = Qualifiers::Strong; else { S.Diag(Attr.getLoc(), diag::warn_attribute_type_not_supported) << "objc_gc" << Attr.getParameterName(); Index: lib/Sema/SemaStmt.cpp =================================================================== --- lib/Sema/SemaStmt.cpp (revision 82620) +++ lib/Sema/SemaStmt.cpp (working copy) @@ -1295,22 +1295,19 @@ public: TypeWithHandler(const QualType &type, CXXCatchStmt *statement) : t(type), stmt(statement) {} + // An arbitrary order is fine as long as it places identical + // types next to each other. bool operator<(const TypeWithHandler &y) const { - if (t.getTypePtr() < y.t.getTypePtr()) + if (t.getAsOpaquePtr() < y.t.getAsOpaquePtr()) return true; - else if (t.getTypePtr() > y.t.getTypePtr()) - return false; - else if (t.getCVRQualifiers() < y.t.getCVRQualifiers()) - return true; - else if (t.getCVRQualifiers() < y.t.getCVRQualifiers()) + if (t.getAsOpaquePtr() > y.t.getAsOpaquePtr()) return false; else return getTypeSpecStartLoc() < y.getTypeSpecStartLoc(); } bool operator==(const TypeWithHandler& other) const { - return t.getTypePtr() == other.t.getTypePtr() - && t.getCVRQualifiers() == other.t.getCVRQualifiers(); + return t == other.t; } QualType getQualType() const { return t; } Index: lib/Sema/SemaCXXCast.cpp =================================================================== --- lib/Sema/SemaCXXCast.cpp (revision 82620) +++ lib/Sema/SemaCXXCast.cpp (working copy) @@ -186,12 +186,12 @@ CastsAwayConstness(Sema &Self, QualType "Destination type is not pointer or pointer to member."); QualType UnwrappedSrcType = SrcType, UnwrappedDestType = DestType; - llvm::SmallVector cv1, cv2; + llvm::SmallVector cv1, cv2; // Find the qualifications. while (Self.UnwrapSimilarPointerTypes(UnwrappedSrcType, UnwrappedDestType)) { - cv1.push_back(UnwrappedSrcType.getCVRQualifiers()); - cv2.push_back(UnwrappedDestType.getCVRQualifiers()); + cv1.push_back(UnwrappedSrcType.getQualifiers()); + cv2.push_back(UnwrappedDestType.getQualifiers()); } assert(cv1.size() > 0 && "Must have at least one pointer level."); @@ -199,13 +199,14 @@ CastsAwayConstness(Sema &Self, QualType // unwrapping, of course). QualType SrcConstruct = Self.Context.VoidTy; QualType DestConstruct = Self.Context.VoidTy; - for (llvm::SmallVector::reverse_iterator i1 = cv1.rbegin(), - i2 = cv2.rbegin(); + ASTContext &Context = Self.Context; + for (llvm::SmallVector::reverse_iterator i1 = cv1.rbegin(), + i2 = cv2.rbegin(); i1 != cv1.rend(); ++i1, ++i2) { - SrcConstruct = Self.Context.getPointerType( - SrcConstruct.getQualifiedType(*i1)); - DestConstruct = Self.Context.getPointerType( - DestConstruct.getQualifiedType(*i2)); + SrcConstruct + = Context.getPointerType(Context.getQualifiedType(SrcConstruct, *i1)); + DestConstruct + = Context.getPointerType(Context.getQualifiedType(DestConstruct, *i2)); } // Test if they're compatible. Index: lib/Sema/SemaExpr.cpp =================================================================== --- lib/Sema/SemaExpr.cpp (revision 82620) +++ lib/Sema/SemaExpr.cpp (working copy) @@ -566,7 +566,7 @@ Sema::BuildAnonymousStructUnionMemberRef // of the anonymous union objects and, eventually, the field we // found via name lookup. bool BaseObjectIsPointer = false; - unsigned ExtraQuals = 0; + Qualifiers BaseQuals; if (BaseObject) { // BaseObject is an anonymous struct/union variable (and is, // therefore, not part of another non-anonymous record). @@ -574,8 +574,8 @@ Sema::BuildAnonymousStructUnionMemberRef MarkDeclarationReferenced(Loc, BaseObject); BaseObjectExpr = new (Context) DeclRefExpr(BaseObject,BaseObject->getType(), SourceLocation()); - ExtraQuals - = Context.getCanonicalType(BaseObject->getType()).getCVRQualifiers(); + BaseQuals + = Context.getCanonicalType(BaseObject->getType()).getQualifiers(); } else if (BaseObjectExpr) { // The caller provided the base object expression. Determine // whether its a pointer and whether it adds any qualifiers to the @@ -585,7 +585,8 @@ Sema::BuildAnonymousStructUnionMemberRef BaseObjectIsPointer = true; ObjectType = ObjectPtr->getPointeeType(); } - ExtraQuals = Context.getCanonicalType(ObjectType).getCVRQualifiers(); + BaseQuals + = Context.getCanonicalType(ObjectType).getQualifiers(); } else { // We've found a member of an anonymous struct/union that is // inside a non-anonymous struct/union, so in a well-formed @@ -608,7 +609,7 @@ Sema::BuildAnonymousStructUnionMemberRef return ExprError(Diag(Loc,diag::err_invalid_member_use_in_static_method) << Field->getDeclName()); } - ExtraQuals = MD->getTypeQualifiers(); + BaseQuals = Qualifiers::fromCVRMask(MD->getTypeQualifiers()); } if (!BaseObjectExpr) @@ -619,24 +620,35 @@ Sema::BuildAnonymousStructUnionMemberRef // Build the implicit member references to the field of the // anonymous struct/union. Expr *Result = BaseObjectExpr; - unsigned BaseAddrSpace = BaseObjectExpr->getType().getAddressSpace(); + Qualifiers ResultQuals = BaseQuals; for (llvm::SmallVector::reverse_iterator FI = AnonFields.rbegin(), FIEnd = AnonFields.rend(); FI != FIEnd; ++FI) { QualType MemberType = (*FI)->getType(); - if (!(*FI)->isMutable()) { - unsigned combinedQualifiers - = MemberType.getCVRQualifiers() | ExtraQuals; - MemberType = MemberType.getQualifiedType(combinedQualifiers); - } - if (BaseAddrSpace != MemberType.getAddressSpace()) - MemberType = Context.getAddrSpaceQualType(MemberType, BaseAddrSpace); + Qualifiers MemberTypeQuals = + Context.getCanonicalType(MemberType).getQualifiers(); + + // CVR attributes from the base are picked up by members, + // except that 'mutable' members don't pick up 'const'. + if ((*FI)->isMutable()) + ResultQuals.removeConst(); + + // GC attributes are never picked up by members. + ResultQuals.removeObjCGCAttr(); + + // TR 18037 does not allow fields to be declared with address spaces. + assert(!MemberTypeQuals.hasAddressSpace()); + + Qualifiers NewQuals = ResultQuals + MemberTypeQuals; + if (NewQuals != MemberTypeQuals) + MemberType = Context.getQualifiedType(MemberType, NewQuals); + MarkDeclarationReferenced(Loc, *FI); // FIXME: Might this end up being a qualified name? Result = new (Context) MemberExpr(Result, BaseObjectIsPointer, *FI, OpLoc, MemberType); BaseObjectIsPointer = false; - ExtraQuals = Context.getCanonicalType(MemberType).getCVRQualifiers(); + ResultQuals = NewQuals; } return Owned(Result); @@ -948,11 +960,10 @@ Sema::BuildDeclarationNameExpr(SourceLoc if (const ReferenceType *RefType = MemberType->getAs()) MemberType = RefType->getPointeeType(); - else if (!FD->isMutable()) { - unsigned combinedQualifiers - = MemberType.getCVRQualifiers() | MD->getTypeQualifiers(); - MemberType = MemberType.getQualifiedType(combinedQualifiers); - } + else if (!FD->isMutable()) + MemberType + = Context.getQualifiedType(MemberType, + Qualifiers::fromCVRMask(MD->getTypeQualifiers())); } else if (CXXMethodDecl *Method = dyn_cast(D)) { if (!Method->isStatic()) { Ctx = Method->getParent(); @@ -1135,7 +1146,7 @@ Sema::BuildDeclarationNameExpr(SourceLoc // - a constant with integral or enumeration type and is // initialized with an expression that is value-dependent else if (const VarDecl *Dcl = dyn_cast(VD)) { - if (Dcl->getType().getCVRQualifiers() == QualType::Const && + if (Dcl->getType().getCVRQualifiers() == Qualifiers::Const && Dcl->getInit()) { ValueDependent = Dcl->getInit()->isValueDependent(); } @@ -1174,7 +1185,7 @@ Sema::OwningExprResult Sema::ActOnPredef PredefinedExpr::ComputeName(Context, IT, currentDecl).length(); llvm::APInt LengthI(32, Length + 1); - ResTy = Context.CharTy.getQualifiedType(QualType::Const); + ResTy = Context.CharTy.withConst(); ResTy = Context.getConstantArrayType(ResTy, LengthI, ArrayType::Normal, 0); } return Owned(new (Context) PredefinedExpr(Loc, ResTy, IT)); @@ -2235,14 +2246,16 @@ Sema::BuildMemberReferenceExpr(Scope *S, if (const ReferenceType *Ref = MemberType->getAs()) MemberType = Ref->getPointeeType(); else { - unsigned BaseAddrSpace = BaseType.getAddressSpace(); - unsigned combinedQualifiers = - MemberType.getCVRQualifiers() | BaseType.getCVRQualifiers(); - if (FD->isMutable()) - combinedQualifiers &= ~QualType::Const; - MemberType = MemberType.getQualifiedType(combinedQualifiers); - if (BaseAddrSpace != MemberType.getAddressSpace()) - MemberType = Context.getAddrSpaceQualType(MemberType, BaseAddrSpace); + Qualifiers BaseQuals = BaseType.getQualifiers(); + BaseQuals.removeObjCGCAttr(); + if (FD->isMutable()) BaseQuals.removeConst(); + + Qualifiers MemberQuals + = Context.getCanonicalType(MemberType).getQualifiers(); + + Qualifiers Combined = BaseQuals + MemberQuals; + if (Combined != MemberQuals) + MemberType = Context.getQualifiedType(MemberType, Combined); } MarkDeclarationReferenced(MemberLoc, FD); @@ -3510,7 +3523,8 @@ QualType Sema::CheckConditionalOperands( if (LHSTy->isVoidPointerType() && RHSTy->isObjCObjectPointerType()) { QualType lhptee = LHSTy->getAs()->getPointeeType(); QualType rhptee = RHSTy->getAs()->getPointeeType(); - QualType destPointee = lhptee.getQualifiedType(rhptee.getCVRQualifiers()); + QualType destPointee + = Context.getQualifiedType(lhptee, rhptee.getQualifiers()); QualType destType = Context.getPointerType(destPointee); ImpCastExprToType(LHS, destType); // add qualifiers if necessary ImpCastExprToType(RHS, destType); // promote to void* @@ -3519,7 +3533,8 @@ QualType Sema::CheckConditionalOperands( if (LHSTy->isObjCObjectPointerType() && RHSTy->isVoidPointerType()) { QualType lhptee = LHSTy->getAs()->getPointeeType(); QualType rhptee = RHSTy->getAs()->getPointeeType(); - QualType destPointee = rhptee.getQualifiedType(lhptee.getCVRQualifiers()); + QualType destPointee + = Context.getQualifiedType(rhptee, lhptee.getQualifiers()); QualType destType = Context.getPointerType(destPointee); ImpCastExprToType(RHS, destType); // add qualifiers if necessary ImpCastExprToType(LHS, destType); // promote to void* @@ -3534,14 +3549,16 @@ QualType Sema::CheckConditionalOperands( // ignore qualifiers on void (C99 6.5.15p3, clause 6) if (lhptee->isVoidType() && rhptee->isIncompleteOrObjectType()) { // Figure out necessary qualifiers (C99 6.5.15p6) - QualType destPointee=lhptee.getQualifiedType(rhptee.getCVRQualifiers()); + QualType destPointee + = Context.getQualifiedType(lhptee, rhptee.getQualifiers()); QualType destType = Context.getPointerType(destPointee); ImpCastExprToType(LHS, destType); // add qualifiers if necessary ImpCastExprToType(RHS, destType); // promote to void* return destType; } if (rhptee->isVoidType() && lhptee->isIncompleteOrObjectType()) { - QualType destPointee=rhptee.getQualifiedType(lhptee.getCVRQualifiers()); + QualType destPointee + = Context.getQualifiedType(rhptee, lhptee.getQualifiers()); QualType destType = Context.getPointerType(destPointee); ImpCastExprToType(LHS, destType); // add qualifiers if necessary ImpCastExprToType(RHS, destType); // promote to void* Index: lib/Sema/SemaTemplateInstantiate.cpp =================================================================== --- lib/Sema/SemaTemplateInstantiate.cpp (revision 82620) +++ lib/Sema/SemaTemplateInstantiate.cpp (working copy) @@ -496,7 +496,7 @@ TemplateInstantiator::TransformPredefine PredefinedExpr::ComputeName(getSema().Context, IT, currentDecl).length(); llvm::APInt LengthI(32, Length + 1); - QualType ResTy = getSema().Context.CharTy.getQualifiedType(QualType::Const); + QualType ResTy = getSema().Context.CharTy.withConst(); ResTy = getSema().Context.getConstantArrayType(ResTy, LengthI, ArrayType::Normal, 0); PredefinedExpr *PE = Index: lib/Sema/Sema.cpp =================================================================== --- lib/Sema/Sema.cpp (revision 82620) +++ lib/Sema/Sema.cpp (working copy) @@ -44,9 +44,7 @@ static void ConvertArgToStringFn(Diagnos // If this is a sugared type (like a typedef, typeof, etc), then unwrap one // level of the sugar so that the type is more obvious to the user. - QualType DesugaredTy = Ty->getDesugaredType(true); - DesugaredTy.setCVRQualifiers(DesugaredTy.getCVRQualifiers() | - Ty.getCVRQualifiers()); + QualType DesugaredTy = Ty.getDesugaredType(true); if (Ty != DesugaredTy && // If the desugared type is a vector type, we don't want to expand it, Index: lib/AST/StmtDumper.cpp =================================================================== --- lib/AST/StmtDumper.cpp (revision 82620) +++ lib/AST/StmtDumper.cpp (working copy) @@ -87,13 +87,10 @@ namespace { fprintf(F, "'%s'", T.getAsString().c_str()); if (!T.isNull()) { - // If the type is directly a typedef, strip off typedefness to give at - // least one level of concreteness. - if (TypedefType *TDT = dyn_cast(T)) { - QualType Simplified = - TDT->LookThroughTypedefs().getQualifiedType(T.getCVRQualifiers()); + // If the type is sugared, also dump a (shallow) desugared type. + QualType Simplified = T.getDesugaredType(); + if (Simplified != T) fprintf(F, ":'%s'", Simplified.getAsString().c_str()); - } } } void DumpStmt(const Stmt *Node) { Index: lib/AST/Expr.cpp =================================================================== --- lib/AST/Expr.cpp (revision 82620) +++ lib/AST/Expr.cpp (working copy) @@ -825,7 +825,7 @@ Expr::isLvalueResult Expr::isLvalue(ASTC return LV_NotObjectType; // Allow qualified void which is an incomplete type other than void (yuck). - if (TR->isVoidType() && !Ctx.getCanonicalType(TR).getCVRQualifiers()) + if (TR->isVoidType() && !Ctx.getCanonicalType(TR).hasQualifiers()) return LV_IncompleteVoidType; return LV_Valid; @@ -1120,7 +1120,7 @@ bool Expr::isOBJCGCCandidate(ASTContext // dereferencing to a pointer is always a gc'able candidate, // unless it is __weak. return T->isPointerType() && - (Ctx.getObjCGCAttrKind(T) != QualType::Weak); + (Ctx.getObjCGCAttrKind(T) != Qualifiers::Weak); } return false; } @@ -1397,7 +1397,7 @@ static ICEDiag CheckICE(const Expr* E, A if (isa(cast(E)->getDecl())) return NoDiag(); if (Ctx.getLangOptions().CPlusPlus && - E->getType().getCVRQualifiers() == QualType::Const) { + E->getType().getCVRQualifiers() == Qualifiers::Const) { // C++ 7.1.5.1p2 // A variable of non-volatile const-qualified integral or enumeration // type initialized by an ICE can be used in ICEs. @@ -1635,7 +1635,7 @@ bool Expr::isNullPointerConstant(ASTCont // Check that it is a cast to void*. if (const PointerType *PT = CE->getType()->getAs()) { QualType Pointee = PT->getPointeeType(); - if (Pointee.getCVRQualifiers() == 0 && + if (!Pointee.hasQualifiers() && Pointee->isVoidType() && // to void* CE->getSubExpr()->getType()->isIntegerType()) // from int. return CE->getSubExpr()->isNullPointerConstant(Ctx); Index: lib/AST/Type.cpp =================================================================== --- lib/AST/Type.cpp (revision 82620) +++ lib/AST/Type.cpp (working copy) @@ -101,12 +101,8 @@ const Type *Type::getArrayElementTypeNoT return ATy->getElementType().getTypePtr(); // If the canonical form of this type isn't the right kind, reject it. - if (!isa(CanonicalType)) { - // Look through type qualifiers - if (ArrayType *AT = dyn_cast(CanonicalType.getUnqualifiedType())) - return AT->getElementType().getTypePtr(); + if (!isa(CanonicalType)) return 0; - } // If this is a typedef for an array type, strip the typedef off without // losing all typedef information. @@ -125,8 +121,8 @@ const Type *Type::getArrayElementTypeNoT /// decide whether it is worth providing a desugared form of the type /// or not. QualType QualType::getDesugaredType(bool ForDisplay) const { - return getTypePtr()->getDesugaredType(ForDisplay) - .getWithAdditionalQualifiers(getCVRQualifiers()); + QualifierCollector Qs; + return Qs.apply(Qs.strip(*this)->getDesugaredType(ForDisplay)); } /// getDesugaredType - Return the specified type with any "sugar" removed from @@ -181,8 +177,6 @@ QualType Type::getDesugaredType(bool For bool Type::isVoidType() const { if (const BuiltinType *BT = dyn_cast(CanonicalType)) return BT->getKind() == BuiltinType::Void; - if (const ExtQualType *AS = dyn_cast(CanonicalType)) - return AS->getBaseType()->isVoidType(); return false; } @@ -190,15 +184,11 @@ bool Type::isObjectType() const { if (isa(CanonicalType) || isa(CanonicalType) || isa(CanonicalType) || isVoidType()) return false; - if (const ExtQualType *AS = dyn_cast(CanonicalType)) - return AS->getBaseType()->isObjectType(); return true; } bool Type::isDerivedType() const { switch (CanonicalType->getTypeClass()) { - case ExtQual: - return cast(CanonicalType)->getBaseType()->isDerivedType(); case Pointer: case VariableArray: case ConstantArray: @@ -241,39 +231,19 @@ bool Type::isUnionType() const { bool Type::isComplexType() const { if (const ComplexType *CT = dyn_cast(CanonicalType)) return CT->getElementType()->isFloatingType(); - if (const ExtQualType *AS = dyn_cast(CanonicalType)) - return AS->getBaseType()->isComplexType(); return false; } bool Type::isComplexIntegerType() const { // Check for GCC complex integer extension. - if (const ComplexType *CT = dyn_cast(CanonicalType)) - return CT->getElementType()->isIntegerType(); - if (const ExtQualType *AS = dyn_cast(CanonicalType)) - return AS->getBaseType()->isComplexIntegerType(); - return false; + return getAsComplexIntegerType(); } const ComplexType *Type::getAsComplexIntegerType() const { - // Are we directly a complex type? - if (const ComplexType *CTy = dyn_cast(this)) { - if (CTy->getElementType()->isIntegerType()) - return CTy; - return 0; - } - - // If the canonical form of this type isn't what we want, reject it. - if (!isa(CanonicalType)) { - // Look through type qualifiers (e.g. ExtQualType's). - if (isa(CanonicalType.getUnqualifiedType())) - return CanonicalType.getUnqualifiedType()->getAsComplexIntegerType(); - return 0; - } - - // If this is a typedef for a complex type, strip the typedef off without - // losing all typedef information. - return cast(getDesugaredType()); + if (const ComplexType *Complex = getAs()) + if (Complex->getElementType()->isIntegerType()) + return Complex; + return 0; } QualType Type::getPointeeType() const { @@ -335,9 +305,6 @@ const RecordType *Type::getAsStructureTy // losing all typedef information. return cast(getDesugaredType()); } - // Look through type qualifiers - if (isa(CanonicalType.getUnqualifiedType())) - return CanonicalType.getUnqualifiedType()->getAsStructureType(); return 0; } @@ -358,9 +325,6 @@ const RecordType *Type::getAsUnionType() return cast(getDesugaredType()); } - // Look through type qualifiers - if (isa(CanonicalType.getUnqualifiedType())) - return CanonicalType.getUnqualifiedType()->getAsUnionType(); return 0; } @@ -416,8 +380,6 @@ bool Type::isIntegerType() const { return true; if (const VectorType *VT = dyn_cast(CanonicalType)) return VT->getElementType()->isIntegerType(); - if (const ExtQualType *EXTQT = dyn_cast(CanonicalType)) - return EXTQT->getBaseType()->isIntegerType(); return false; } @@ -431,24 +393,18 @@ bool Type::isIntegralType() const { // FIXME: In C++, enum types are never integral. if (isa(CanonicalType)) return true; - if (const ExtQualType *EXTQT = dyn_cast(CanonicalType)) - return EXTQT->getBaseType()->isIntegralType(); return false; } bool Type::isEnumeralType() const { if (const TagType *TT = dyn_cast(CanonicalType)) return TT->getDecl()->isEnum(); - if (const ExtQualType *EXTQT = dyn_cast(CanonicalType)) - return EXTQT->getBaseType()->isEnumeralType(); return false; } bool Type::isBooleanType() const { if (const BuiltinType *BT = dyn_cast(CanonicalType)) return BT->getKind() == BuiltinType::Bool; - if (const ExtQualType *EXTQT = dyn_cast(CanonicalType)) - return EXTQT->getBaseType()->isBooleanType(); return false; } @@ -458,16 +414,12 @@ bool Type::isCharType() const { BT->getKind() == BuiltinType::UChar || BT->getKind() == BuiltinType::Char_S || BT->getKind() == BuiltinType::SChar; - if (const ExtQualType *EXTQT = dyn_cast(CanonicalType)) - return EXTQT->getBaseType()->isCharType(); return false; } bool Type::isWideCharType() const { if (const BuiltinType *BT = dyn_cast(CanonicalType)) return BT->getKind() == BuiltinType::WChar; - if (const ExtQualType *EXTQT = dyn_cast(CanonicalType)) - return EXTQT->getBaseType()->isWideCharType(); return false; } @@ -490,8 +442,6 @@ bool Type::isSignedIntegerType() const { if (const VectorType *VT = dyn_cast(CanonicalType)) return VT->getElementType()->isSignedIntegerType(); - if (const ExtQualType *EXTQT = dyn_cast(CanonicalType)) - return EXTQT->getBaseType()->isSignedIntegerType(); return false; } @@ -514,8 +464,6 @@ bool Type::isUnsignedIntegerType() const if (const VectorType *VT = dyn_cast(CanonicalType)) return VT->getElementType()->isUnsignedIntegerType(); - if (const ExtQualType *EXTQT = dyn_cast(CanonicalType)) - return EXTQT->getBaseType()->isUnsignedIntegerType(); return false; } @@ -527,8 +475,6 @@ bool Type::isFloatingType() const { return CT->getElementType()->isFloatingType(); if (const VectorType *VT = dyn_cast(CanonicalType)) return VT->getElementType()->isFloatingType(); - if (const ExtQualType *EXTQT = dyn_cast(CanonicalType)) - return EXTQT->getBaseType()->isFloatingType(); return false; } @@ -538,8 +484,6 @@ bool Type::isRealFloatingType() const { BT->getKind() <= BuiltinType::LongDouble; if (const VectorType *VT = dyn_cast(CanonicalType)) return VT->getElementType()->isRealFloatingType(); - if (const ExtQualType *EXTQT = dyn_cast(CanonicalType)) - return EXTQT->getBaseType()->isRealFloatingType(); return false; } @@ -553,8 +497,6 @@ bool Type::isRealType() const { return true; if (const VectorType *VT = dyn_cast(CanonicalType)) return VT->getElementType()->isRealType(); - if (const ExtQualType *EXTQT = dyn_cast(CanonicalType)) - return EXTQT->getBaseType()->isRealType(); return false; } @@ -568,8 +510,6 @@ bool Type::isArithmeticType() const { return ET->getDecl()->isDefinition(); if (isa(CanonicalType)) return true; - if (const ExtQualType *EXTQT = dyn_cast(CanonicalType)) - return EXTQT->getBaseType()->isArithmeticType(); return isa(CanonicalType) || isa(CanonicalType); } @@ -583,8 +523,6 @@ bool Type::isScalarType() const { return true; return false; } - if (const ExtQualType *EXTQT = dyn_cast(CanonicalType)) - return EXTQT->getBaseType()->isScalarType(); if (isa(CanonicalType)) return true; return isa(CanonicalType) || @@ -611,8 +549,6 @@ bool Type::isAggregateType() const { return true; } - if (const ExtQualType *EXTQT = dyn_cast(CanonicalType)) - return EXTQT->getBaseType()->isAggregateType(); return isa(CanonicalType); } @@ -620,8 +556,6 @@ bool Type::isAggregateType() const { /// according to the rules of C99 6.7.5p3. It is not legal to call this on /// incomplete types or dependent types. bool Type::isConstantSizeType() const { - if (const ExtQualType *EXTQT = dyn_cast(CanonicalType)) - return EXTQT->getBaseType()->isConstantSizeType(); assert(!isIncompleteType() && "This doesn't make sense for incomplete types"); assert(!isDependentType() && "This doesn't make sense for dependent types"); // The VAT must have a size, as it is known to be complete. @@ -634,8 +568,6 @@ bool Type::isConstantSizeType() const { bool Type::isIncompleteType() const { switch (CanonicalType->getTypeClass()) { default: return false; - case ExtQual: - return cast(CanonicalType)->getBaseType()->isIncompleteType(); case Builtin: // Void is the only incomplete builtin type. Per C99 6.2.5p19, it can never // be completed. @@ -664,8 +596,6 @@ bool Type::isPODType() const { switch (CanonicalType->getTypeClass()) { // Everything not explicitly mentioned is not POD. default: return false; - case ExtQual: - return cast(CanonicalType)->getBaseType()->isPODType(); case VariableArray: case ConstantArray: // IncompleteArray is caught by isIncompleteType() above. @@ -827,21 +757,16 @@ QualType TypedefType::LookThroughTypedef return FirstType; // Otherwise, do the fully general loop. - unsigned TypeQuals = 0; - const TypedefType *TDT = this; - while (1) { - QualType CurType = TDT->getDecl()->getUnderlyingType(); + QualifierCollector Qs; + QualType CurType; + const TypedefType *TDT = this; + do { + CurType = TDT->getDecl()->getUnderlyingType(); + TDT = dyn_cast(Qs.strip(CurType)); + } while (TDT); - /// FIXME: - /// FIXME: This is incorrect for ExtQuals! - /// FIXME: - TypeQuals |= CurType.getCVRQualifiers(); - - TDT = dyn_cast(CurType); - if (TDT == 0) - return QualType(CurType.getTypePtr(), TypeQuals); - } + return Qs.apply(CurType); } TypeOfExprType::TypeOfExprType(Expr *E, QualType can) @@ -961,27 +886,20 @@ TemplateSpecializationType::Profile(llvm Args[Idx].Profile(ID, Context); } -const Type *QualifierSet::strip(const Type* T) { - QualType DT = T->getDesugaredType(); - addCVR(DT.getCVRQualifiers()); - - if (const ExtQualType* EQT = dyn_cast(DT)) { - if (EQT->getAddressSpace()) - addAddressSpace(EQT->getAddressSpace()); - if (EQT->getObjCGCAttr()) - addObjCGCAttrType(EQT->getObjCGCAttr()); - return EQT->getBaseType(); - } else { - // Use the sugared type unless desugaring found extra qualifiers. - return (DT.getCVRQualifiers() ? DT.getTypePtr() : T); - } +QualType QualifierCollector::apply(QualType QT) const { + if (!hasNonFastQualifiers()) + return QT.withFastQualifiers(getFastQualifiers()); + + assert(Context && "extended qualifiers but no context!"); + return Context->getQualifiedType(QT, *this); } -QualType QualifierSet::apply(QualType QT, ASTContext& C) { - QT = QT.getWithAdditionalQualifiers(getCVRMask()); - if (hasObjCGCAttrType()) QT = C.getObjCGCQualType(QT, getObjCGCAttrType()); - if (hasAddressSpace()) QT = C.getAddrSpaceQualType(QT, getAddressSpace()); - return QT; +QualType QualifierCollector::apply(const Type *T) const { + if (!hasNonFastQualifiers()) + return QualType(T, getFastQualifiers()); + + assert(Context && "extended qualifiers but no context!"); + return Context->getQualifiedType(T, *this); } @@ -1012,14 +930,46 @@ void Type::dump() const { static void AppendTypeQualList(std::string &S, unsigned TypeQuals) { - // Note: funkiness to ensure we get a space only between quals. - bool NonePrinted = true; - if (TypeQuals & QualType::Const) - S += "const", NonePrinted = false; - if (TypeQuals & QualType::Volatile) - S += (NonePrinted+" volatile"), NonePrinted = false; - if (TypeQuals & QualType::Restrict) - S += (NonePrinted+" restrict"), NonePrinted = false; + if (TypeQuals & Qualifiers::Const) { + if (!S.empty()) S += ' '; + S += "const"; + } + if (TypeQuals & Qualifiers::Volatile) { + if (!S.empty()) S += ' '; + S += "volatile"; + } + if (TypeQuals & Qualifiers::Restrict) { + if (!S.empty()) S += ' '; + S += "restrict"; + } +} + +std::string Qualifiers::getAsString() const { + LangOptions LO; + return getAsString(PrintingPolicy(LO)); +} + +// Appends qualifiers to the given string, separated by spaces. Will +// prefix a space if the string is non-empty. Will not append a final +// space. +void Qualifiers::getAsStringInternal(std::string &S, + const PrintingPolicy&) const { + AppendTypeQualList(S, getCVRQualifiers()); + if (unsigned AddressSpace = getAddressSpace()) { + if (!S.empty()) S += ' '; + S += "__attribute__((address_space("; + S += llvm::utostr_32(AddressSpace); + S += ")))"; + } + if (Qualifiers::GC GCAttrType = getObjCGCAttr()) { + if (!S.empty()) S += ' '; + S += "__attribute__((objc_gc("; + if (GCAttrType == Qualifiers::Weak) + S += "weak"; + else + S += "strong"; + S += ")))"; + } } std::string QualType::getAsString() const { @@ -1041,13 +991,16 @@ QualType::getAsStringInternal(std::strin return; // Print qualifiers as appropriate. - if (unsigned Tq = getCVRQualifiers()) { + Qualifiers Quals = getQualifiers(); + if (!Quals.empty()) { std::string TQS; - AppendTypeQualList(TQS, Tq); - if (!S.empty()) - S = TQS + ' ' + S; - else - S = TQS; + Quals.getAsStringInternal(TQS, Policy); + + if (!S.empty()) { + TQS += ' '; + TQS += S; + } + std::swap(S, TQS); } getTypePtr()->getAsStringInternal(S, Policy); @@ -1084,25 +1037,6 @@ void ComplexType::getAsStringInternal(st S = "_Complex " + S; } -void ExtQualType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const { - bool NeedsSpace = false; - if (AddressSpace) { - S = "__attribute__((address_space("+llvm::utostr_32(AddressSpace)+")))" + S; - NeedsSpace = true; - } - if (GCAttrType != QualType::GCNone) { - if (NeedsSpace) - S += ' '; - S += "__attribute__((objc_gc("; - if (GCAttrType == QualType::Weak) - S += "weak"; - else - S += "strong"; - S += ")))"; - } - BaseType->getAsStringInternal(S, Policy); -} - void PointerType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const { S = '*' + S; @@ -1195,8 +1129,8 @@ void IncompleteArrayType::getAsStringInt void VariableArrayType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const { S += '['; - if (getIndexTypeQualifier()) { - AppendTypeQualList(S, getIndexTypeQualifier()); + if (getIndexTypeQualifiers().hasQualifiers()) { + AppendTypeQualList(S, getIndexTypeCVRQualifiers()); S += ' '; } @@ -1219,8 +1153,8 @@ void VariableArrayType::getAsStringInter void DependentSizedArrayType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const { S += '['; - if (getIndexTypeQualifier()) { - AppendTypeQualList(S, getIndexTypeQualifier()); + if (getIndexTypeQualifiers().hasQualifiers()) { + AppendTypeQualList(S, getIndexTypeCVRQualifiers()); S += ' '; } @@ -1536,6 +1470,9 @@ void ObjCObjectPointerType::getAsStringI } ObjCQIString += '>'; } + + PointeeType.getQualifiers().getAsStringInternal(ObjCQIString, Policy); + if (!isObjCIdType() && !isObjCQualifiedIdType()) ObjCQIString += " *"; // Don't forget the implicit pointer. else if (!InnerString.empty()) // Prefix the basic type, e.g. 'typedefname X'. Index: lib/AST/DeclarationName.cpp =================================================================== --- lib/AST/DeclarationName.cpp (revision 82620) +++ lib/AST/DeclarationName.cpp (working copy) @@ -309,11 +309,11 @@ DeclarationNameTable::getCXXSpecialName( switch (Kind) { case DeclarationName::CXXConstructorName: EKind = DeclarationNameExtra::CXXConstructor; - assert(Ty.getCVRQualifiers() == 0 &&"Constructor type must be unqualified"); + assert(!Ty.hasQualifiers() &&"Constructor type must be unqualified"); break; case DeclarationName::CXXDestructorName: EKind = DeclarationNameExtra::CXXDestructor; - assert(Ty.getCVRQualifiers() == 0 && "Destructor type must be unqualified"); + assert(!Ty.hasQualifiers() && "Destructor type must be unqualified"); break; case DeclarationName::CXXConversionFunctionName: EKind = DeclarationNameExtra::CXXConversionFunction; Index: lib/AST/ExprConstant.cpp =================================================================== --- lib/AST/ExprConstant.cpp (revision 82620) +++ lib/AST/ExprConstant.cpp (working copy) @@ -783,7 +783,7 @@ bool IntExprEvaluator::VisitDeclRefExpr( // In C++, const, non-volatile integers initialized with ICEs are ICEs. // In C, they can also be folded, although they are not ICEs. - if (E->getType().getCVRQualifiers() == QualType::Const) { + if (E->getType().getCVRQualifiers() == Qualifiers::Const) { if (const VarDecl *D = dyn_cast(E->getDecl())) { if (APValue *V = D->getEvaluatedValue()) return Success(V->getInt(), E); Index: lib/AST/DeclCXX.cpp =================================================================== --- lib/AST/DeclCXX.cpp (revision 82620) +++ lib/AST/DeclCXX.cpp (working copy) @@ -146,7 +146,7 @@ CXXRecordDecl::setBases(ASTContext &C, } bool CXXRecordDecl::hasConstCopyConstructor(ASTContext &Context) const { - return getCopyConstructor(Context, QualType::Const) != 0; + return getCopyConstructor(Context, Qualifiers::Const) != 0; } CXXConstructorDecl *CXXRecordDecl::getCopyConstructor(ASTContext &Context, @@ -167,8 +167,8 @@ CXXConstructorDecl *CXXRecordDecl::getCo if (cast(*Con)->isCopyConstructor(Context, FoundTQs)) { - if (((TypeQuals & QualType::Const) == (FoundTQs & QualType::Const)) || - (!(TypeQuals & QualType::Const) && (FoundTQs & QualType::Const))) + if (((TypeQuals & Qualifiers::Const) == (FoundTQs & Qualifiers::Const)) || + (!(TypeQuals & Qualifiers::Const) && (FoundTQs & Qualifiers::Const))) return cast(*Con); } @@ -508,7 +508,8 @@ QualType CXXMethodDecl::getThisType(ASTC ClassTy = TD->getInjectedClassNameType(C); else ClassTy = C.getTagDeclType(getParent()); - ClassTy = ClassTy.getWithAdditionalQualifiers(getTypeQualifiers()); + ClassTy = C.getQualifiedType(ClassTy, + Qualifiers::fromCVRMask(getTypeQualifiers())); return C.getPointerType(ClassTy); } @@ -600,6 +601,8 @@ CXXConstructorDecl::isCopyConstructor(AS if (PointeeType.getUnqualifiedType() != ClassTy) return false; + // FIXME: other qualifiers? + // We have a copy constructor. TypeQuals = PointeeType.getCVRQualifiers(); return true; Index: lib/AST/ASTContext.cpp =================================================================== --- lib/AST/ASTContext.cpp (revision 82620) +++ lib/AST/ASTContext.cpp (working copy) @@ -59,6 +59,13 @@ ASTContext::~ASTContext() { } { + llvm::FoldingSet::iterator + I = ExtQualNodes.begin(), E = ExtQualNodes.end(); + while (I != E) + Deallocate(&*I++); + } + + { llvm::DenseMap::iterator I = ASTRecordLayouts.begin(), E = ASTRecordLayouts.end(); while (I != E) { @@ -525,6 +532,10 @@ unsigned ASTContext::getDeclAlignInBytes /// getTypeSize - Return the size of the specified type, in bits. This method /// does not work on incomplete types. +/// +/// FIXME: Pointers into different addr spaces could have different sizes and +/// alignment requirements: getPointerInfo should take an AddrSpace, this +/// should take a QualType, &c. std::pair ASTContext::getTypeInfo(const Type *T) { uint64_t Width=0; @@ -656,10 +667,6 @@ ASTContext::getTypeInfo(const Type *T) { Width = std::max(llvm::NextPowerOf2(Width - 1), (uint64_t)8); Align = Width; break; - case Type::ExtQual: - // FIXME: Pointers into different addr spaces could have different sizes and - // alignment requirements: getPointerInfo should take an AddrSpace. - return getTypeInfo(QualType(cast(T)->getBaseType(), 0)); case Type::ObjCObjectPointer: Width = Target.getPointerWidth(0); Align = Target.getPointerAlign(0); @@ -1002,52 +1009,58 @@ const ASTRecordLayout &ASTContext::getAS // Type creation/memoization methods //===----------------------------------------------------------------------===// -QualType ASTContext::getAddrSpaceQualType(QualType T, unsigned AddressSpace) { - QualType CanT = getCanonicalType(T); - if (CanT.getAddressSpace() == AddressSpace) - return T; - - // If we are composing extended qualifiers together, merge together into one - // ExtQualType node. - unsigned CVRQuals = T.getCVRQualifiers(); - QualType::GCAttrTypes GCAttr = QualType::GCNone; - Type *TypeNode = T.getTypePtr(); - - if (ExtQualType *EQT = dyn_cast(TypeNode)) { - // If this type already has an address space specified, it cannot get - // another one. - assert(EQT->getAddressSpace() == 0 && - "Type cannot be in multiple addr spaces!"); - GCAttr = EQT->getObjCGCAttr(); - TypeNode = EQT->getBaseType(); - } +QualType ASTContext::getExtQualType(const Type *TypeNode, Qualifiers Quals) { + unsigned Fast = Quals.getFastQualifiers(); + Quals.removeFastQualifiers(); // Check if we've already instantiated this type. llvm::FoldingSetNodeID ID; - ExtQualType::Profile(ID, TypeNode, AddressSpace, GCAttr); + ExtQuals::Profile(ID, TypeNode, Quals); void *InsertPos = 0; - if (ExtQualType *EXTQy = ExtQualTypes.FindNodeOrInsertPos(ID, InsertPos)) - return QualType(EXTQy, CVRQuals); + if (ExtQuals *EQ = ExtQualNodes.FindNodeOrInsertPos(ID, InsertPos)) { + assert(EQ->getQualifiers() == Quals); + QualType T = QualType(EQ, Fast); + return T; + } - // If the base type isn't canonical, this won't be a canonical type either, - // so fill in the canonical type field. - QualType Canonical; - if (!TypeNode->isCanonical()) { - Canonical = getAddrSpaceQualType(CanT, AddressSpace); + ExtQuals *New = new (*this, 8) ExtQuals(*this, TypeNode, Quals); + ExtQualNodes.InsertNode(New, InsertPos); + QualType T = QualType(New, Fast); + return T; +} - // Update InsertPos, the previous call could have invalidated it. - ExtQualType *NewIP = ExtQualTypes.FindNodeOrInsertPos(ID, InsertPos); - assert(NewIP == 0 && "Shouldn't be in the map!"); NewIP = NewIP; - } - ExtQualType *New = - new (*this, 8) ExtQualType(TypeNode, Canonical, AddressSpace, GCAttr); - ExtQualTypes.InsertNode(New, InsertPos); - Types.push_back(New); - return QualType(New, CVRQuals); +QualType ASTContext::getVolatileType(QualType T) { + QualType CanT = getCanonicalType(T); + if (CanT.isVolatileQualified()) return T; + + QualifierCollector Quals; + const Type *TypeNode = Quals.strip(T); + Quals.addVolatile(); + + return getExtQualType(TypeNode, Quals); +} + +QualType ASTContext::getAddrSpaceQualType(QualType T, unsigned AddressSpace) { + QualType CanT = getCanonicalType(T); + if (CanT.getAddressSpace() == AddressSpace) + return T; + + // If we are composing extended qualifiers together, merge together + // into one ExtQuals node. + QualifierCollector Quals; + const Type *TypeNode = Quals.strip(T); + + // If this type already has an address space specified, it cannot get + // another one. + assert(!Quals.hasAddressSpace() && + "Type cannot be in multiple addr spaces!"); + Quals.addAddressSpace(AddressSpace); + + return getExtQualType(TypeNode, Quals); } QualType ASTContext::getObjCGCQualType(QualType T, - QualType::GCAttrTypes GCAttr) { + Qualifiers::GC GCAttr) { QualType CanT = getCanonicalType(T); if (CanT.getObjCGCAttr() == GCAttr) return T; @@ -1059,75 +1072,48 @@ QualType ASTContext::getObjCGCQualType(Q return getPointerType(ResultType); } } - // If we are composing extended qualifiers together, merge together into one - // ExtQualType node. - unsigned CVRQuals = T.getCVRQualifiers(); - Type *TypeNode = T.getTypePtr(); - unsigned AddressSpace = 0; - - if (ExtQualType *EQT = dyn_cast(TypeNode)) { - // If this type already has an ObjCGC specified, it cannot get - // another one. - assert(EQT->getObjCGCAttr() == QualType::GCNone && - "Type cannot have multiple ObjCGCs!"); - AddressSpace = EQT->getAddressSpace(); - TypeNode = EQT->getBaseType(); - } - // Check if we've already instantiated an gc qual'd type of this type. - llvm::FoldingSetNodeID ID; - ExtQualType::Profile(ID, TypeNode, AddressSpace, GCAttr); - void *InsertPos = 0; - if (ExtQualType *EXTQy = ExtQualTypes.FindNodeOrInsertPos(ID, InsertPos)) - return QualType(EXTQy, CVRQuals); - - // If the base type isn't canonical, this won't be a canonical type either, - // so fill in the canonical type field. - // FIXME: Isn't this also not canonical if the base type is a array - // or pointer type? I can't find any documentation for objc_gc, though... - QualType Canonical; - if (!T->isCanonical()) { - Canonical = getObjCGCQualType(CanT, GCAttr); + // If we are composing extended qualifiers together, merge together + // into one ExtQuals node. + QualifierCollector Quals; + const Type *TypeNode = Quals.strip(T); + + // If this type already has an ObjCGC specified, it cannot get + // another one. + assert(!Quals.hasObjCGCAttr() && + "Type cannot have multiple ObjCGCs!"); + Quals.addObjCGCAttr(GCAttr); - // Update InsertPos, the previous call could have invalidated it. - ExtQualType *NewIP = ExtQualTypes.FindNodeOrInsertPos(ID, InsertPos); - assert(NewIP == 0 && "Shouldn't be in the map!"); NewIP = NewIP; - } - ExtQualType *New = - new (*this, 8) ExtQualType(TypeNode, Canonical, AddressSpace, GCAttr); - ExtQualTypes.InsertNode(New, InsertPos); - Types.push_back(New); - return QualType(New, CVRQuals); + return getExtQualType(TypeNode, Quals); } QualType ASTContext::getNoReturnType(QualType T) { - QualifierSet qs; - qs.strip(T); + QualType ResultType; if (T->isPointerType()) { QualType Pointee = T->getAs()->getPointeeType(); - QualType ResultType = getNoReturnType(Pointee); + ResultType = getNoReturnType(Pointee); ResultType = getPointerType(ResultType); - ResultType.setCVRQualifiers(T.getCVRQualifiers()); - return qs.apply(ResultType, *this); - } - if (T->isBlockPointerType()) { + } else if (T->isBlockPointerType()) { QualType Pointee = T->getAs()->getPointeeType(); - QualType ResultType = getNoReturnType(Pointee); + ResultType = getNoReturnType(Pointee); ResultType = getBlockPointerType(ResultType); - ResultType.setCVRQualifiers(T.getCVRQualifiers()); - return qs.apply(ResultType, *this); - } - if (!T->isFunctionType()) - assert(0 && "can't noreturn qualify non-pointer to function or block type"); + } else { + assert (T->isFunctionType() + && "can't noreturn qualify non-pointer to function or block type"); - if (const FunctionNoProtoType *F = T->getAs()) { - return getFunctionNoProtoType(F->getResultType(), true); + if (const FunctionNoProtoType *F = T->getAs()) { + ResultType = getFunctionNoProtoType(F->getResultType(), true); + } else { + const FunctionProtoType *F = T->getAs(); + ResultType + = getFunctionType(F->getResultType(), F->arg_type_begin(), + F->getNumArgs(), F->isVariadic(), F->getTypeQuals(), + F->hasExceptionSpec(), F->hasAnyExceptionSpec(), + F->getNumExceptions(), F->exception_begin(), true); + } } - const FunctionProtoType *F = T->getAs(); - return getFunctionType(F->getResultType(), F->arg_type_begin(), - F->getNumArgs(), F->isVariadic(), F->getTypeQuals(), - F->hasExceptionSpec(), F->hasAnyExceptionSpec(), - F->getNumExceptions(), F->exception_begin(), true); + + return getQualifiedType(ResultType, T.getQualifiers()); } /// getComplexType - Return the uniqued reference to the type for a complex @@ -1645,8 +1631,8 @@ QualType ASTContext::getFunctionType(Qua const QualType *ExArray, bool NoReturn) { if (LangOpts.CPlusPlus) { for (unsigned i = 0; i != NumArgs; ++i) - assert(!ArgArray[i].getCVRQualifiers() && - "C++ arguments can't have toplevel CVR qualifiers!"); + assert(!ArgArray[i].hasQualifiers() && + "C++ arguments can't have toplevel qualifiers!"); } // Unique functions, to guarantee there is only one function of a particular @@ -2157,33 +2143,38 @@ QualType ASTContext::getPointerDiffType( /// to be free of any of these, allowing two canonical types to be compared /// for exact equality with a simple pointer comparison. CanQualType ASTContext::getCanonicalType(QualType T) { - QualType CanType = T.getTypePtr()->getCanonicalTypeInternal(); + QualifierCollector Quals; + const Type *Ptr = Quals.strip(T); + QualType CanType = Ptr->getCanonicalTypeInternal(); + + // The canonical internal type will be the canonical type *except* + // that we push type qualifiers down through array types. - // If the result has type qualifiers, make sure to canonicalize them as well. - unsigned TypeQuals = T.getCVRQualifiers() | CanType.getCVRQualifiers(); - if (TypeQuals == 0) + // If there are no new qualifiers to push down, stop here. + if (!Quals.hasQualifiers()) return CanQualType::CreateUnsafe(CanType); - // If the type qualifiers are on an array type, get the canonical type of the - // array with the qualifiers applied to the element type. + // If the type qualifiers are on an array type, get the canonical + // type of the array with the qualifiers applied to the element + // type. ArrayType *AT = dyn_cast(CanType); if (!AT) - return CanQualType::CreateUnsafe(CanType.getQualifiedType(TypeQuals)); + return CanQualType::CreateUnsafe(getQualifiedType(CanType, Quals)); // Get the canonical version of the element with the extra qualifiers on it. // This can recursively sink qualifiers through multiple levels of arrays. - QualType NewEltTy=AT->getElementType().getWithAdditionalQualifiers(TypeQuals); + QualType NewEltTy = getQualifiedType(AT->getElementType(), Quals); NewEltTy = getCanonicalType(NewEltTy); if (ConstantArrayType *CAT = dyn_cast(AT)) return CanQualType::CreateUnsafe( getConstantArrayType(NewEltTy, CAT->getSize(), CAT->getSizeModifier(), - CAT->getIndexTypeQualifier())); + CAT->getIndexTypeCVRQualifiers())); if (IncompleteArrayType *IAT = dyn_cast(AT)) return CanQualType::CreateUnsafe( getIncompleteArrayType(NewEltTy, IAT->getSizeModifier(), - IAT->getIndexTypeQualifier())); + IAT->getIndexTypeCVRQualifiers())); if (DependentSizedArrayType *DSAT = dyn_cast(AT)) return CanQualType::CreateUnsafe( @@ -2191,7 +2182,7 @@ CanQualType ASTContext::getCanonicalType DSAT->getSizeExpr() ? DSAT->getSizeExpr()->Retain() : 0, DSAT->getSizeModifier(), - DSAT->getIndexTypeQualifier(), + DSAT->getIndexTypeCVRQualifiers(), DSAT->getBracketsRange())); VariableArrayType *VAT = cast(AT); @@ -2199,7 +2190,7 @@ CanQualType ASTContext::getCanonicalType VAT->getSizeExpr() ? VAT->getSizeExpr()->Retain() : 0, VAT->getSizeModifier(), - VAT->getIndexTypeQualifier(), + VAT->getIndexTypeCVRQualifiers(), VAT->getBracketsRange())); } @@ -2316,68 +2307,47 @@ ASTContext::getCanonicalNestedNameSpecif const ArrayType *ASTContext::getAsArrayType(QualType T) { // Handle the non-qualified case efficiently. - if (T.getCVRQualifiers() == 0) { + if (!T.hasQualifiers()) { // Handle the common positive case fast. if (const ArrayType *AT = dyn_cast(T)) return AT; } - // Handle the common negative case fast, ignoring CVR qualifiers. + // Handle the common negative case fast. QualType CType = T->getCanonicalTypeInternal(); - - // Make sure to look through type qualifiers (like ExtQuals) for the negative - // test. - if (!isa(CType) && - !isa(CType.getUnqualifiedType())) + if (!isa(CType)) return 0; - // Apply any CVR qualifiers from the array type to the element type. This + // Apply any qualifiers from the array type to the element type. This // implements C99 6.7.3p8: "If the specification of an array type includes // any type qualifiers, the element type is so qualified, not the array type." // If we get here, we either have type qualifiers on the type, or we have // sugar such as a typedef in the way. If we have type qualifiers on the type // we must propagate them down into the element type. - unsigned CVRQuals = T.getCVRQualifiers(); - unsigned AddrSpace = 0; - Type *Ty = T.getTypePtr(); - - // Rip through ExtQualType's and typedefs to get to a concrete type. - while (1) { - if (const ExtQualType *EXTQT = dyn_cast(Ty)) { - AddrSpace = EXTQT->getAddressSpace(); - Ty = EXTQT->getBaseType(); - } else { - T = Ty->getDesugaredType(); - if (T.getTypePtr() == Ty && T.getCVRQualifiers() == 0) - break; - CVRQuals |= T.getCVRQualifiers(); - Ty = T.getTypePtr(); - } - } + + QualifierCollector Qs; + const Type *Ty = Qs.strip(T.getDesugaredType()); // If we have a simple case, just return now. const ArrayType *ATy = dyn_cast(Ty); - if (ATy == 0 || (AddrSpace == 0 && CVRQuals == 0)) + if (ATy == 0 || Qs.empty()) return ATy; // Otherwise, we have an array and we have qualifiers on it. Push the // qualifiers into the array element type and return a new array type. // Get the canonical version of the element with the extra qualifiers on it. // This can recursively sink qualifiers through multiple levels of arrays. - QualType NewEltTy = ATy->getElementType(); - if (AddrSpace) - NewEltTy = getAddrSpaceQualType(NewEltTy, AddrSpace); - NewEltTy = NewEltTy.getWithAdditionalQualifiers(CVRQuals); + QualType NewEltTy = getQualifiedType(ATy->getElementType(), Qs); if (const ConstantArrayType *CAT = dyn_cast(ATy)) return cast(getConstantArrayType(NewEltTy, CAT->getSize(), CAT->getSizeModifier(), - CAT->getIndexTypeQualifier())); + CAT->getIndexTypeCVRQualifiers())); if (const IncompleteArrayType *IAT = dyn_cast(ATy)) return cast(getIncompleteArrayType(NewEltTy, IAT->getSizeModifier(), - IAT->getIndexTypeQualifier())); + IAT->getIndexTypeCVRQualifiers())); if (const DependentSizedArrayType *DSAT = dyn_cast(ATy)) @@ -2386,15 +2356,15 @@ const ArrayType *ASTContext::getAsArrayT DSAT->getSizeExpr() ? DSAT->getSizeExpr()->Retain() : 0, DSAT->getSizeModifier(), - DSAT->getIndexTypeQualifier(), + DSAT->getIndexTypeCVRQualifiers(), DSAT->getBracketsRange())); const VariableArrayType *VAT = cast(ATy); return cast(getVariableArrayType(NewEltTy, VAT->getSizeExpr() ? - VAT->getSizeExpr()->Retain() : 0, + VAT->getSizeExpr()->Retain() : 0, VAT->getSizeModifier(), - VAT->getIndexTypeQualifier(), + VAT->getIndexTypeCVRQualifiers(), VAT->getBracketsRange())); } @@ -2415,18 +2385,21 @@ QualType ASTContext::getArrayDecayedType QualType PtrTy = getPointerType(PrettyArrayType->getElementType()); + llvm::errs() << "array type decaying from " << Ty.getAsString() << " to " << PtrTy.getAsString() << "\n"; + llvm::errs() << "element type is " << PrettyArrayType->getElementType().getAsString() << "\n"; + // int x[restrict 4] -> int *restrict - return PtrTy.getQualifiedType(PrettyArrayType->getIndexTypeQualifier()); + return getQualifiedType(PtrTy, PrettyArrayType->getIndexTypeQualifiers()); } QualType ASTContext::getBaseElementType(QualType QT) { - QualifierSet qualifiers; + QualifierCollector Qs; while (true) { - const Type *UT = qualifiers.strip(QT); + const Type *UT = Qs.strip(QT); if (const ArrayType *AT = getAsArrayType(QualType(UT,0))) { QT = AT->getElementType(); } else { - return qualifiers.apply(QT, *this); + return Qs.apply(QT); } } } @@ -2651,11 +2624,11 @@ QualType ASTContext::getCFConstantString QualType FieldTypes[4]; // const int *isa; - FieldTypes[0] = getPointerType(IntTy.getQualifiedType(QualType::Const)); + FieldTypes[0] = getPointerType(IntTy.withConst()); // int flags; FieldTypes[1] = IntTy; // const char *str; - FieldTypes[2] = getPointerType(CharTy.getQualifiedType(QualType::Const)); + FieldTypes[2] = getPointerType(CharTy.withConst()); // long length; FieldTypes[3] = LongTy; @@ -3139,9 +3112,9 @@ void ASTContext::getObjCEncodingForTypeI return; } - if (T->isObjCInterfaceType()) { + if (const ObjCInterfaceType *OIT = T->getAs()) { // @encode(class_name) - ObjCInterfaceDecl *OI = T->getAs()->getDecl(); + ObjCInterfaceDecl *OI = OIT->getDecl(); S += '{'; const IdentifierInfo *II = OI->getIdentifier(); S += II->getName(); @@ -3388,24 +3361,24 @@ bool ASTContext::isObjCNSObjectType(Qual /// getObjCGCAttr - Returns one of GCNone, Weak or Strong objc's /// garbage collection attribute. /// -QualType::GCAttrTypes ASTContext::getObjCGCAttrKind(const QualType &Ty) const { - QualType::GCAttrTypes GCAttrs = QualType::GCNone; +Qualifiers::GC ASTContext::getObjCGCAttrKind(const QualType &Ty) const { + Qualifiers::GC GCAttrs = Qualifiers::GCNone; if (getLangOptions().ObjC1 && getLangOptions().getGCMode() != LangOptions::NonGC) { GCAttrs = Ty.getObjCGCAttr(); // Default behavious under objective-c's gc is for objective-c pointers // (or pointers to them) be treated as though they were declared // as __strong. - if (GCAttrs == QualType::GCNone) { + if (GCAttrs == Qualifiers::GCNone) { if (Ty->isObjCObjectPointerType() || Ty->isBlockPointerType()) - GCAttrs = QualType::Strong; + GCAttrs = Qualifiers::Strong; else if (Ty->isPointerType()) return getObjCGCAttrKind(Ty->getAs()->getPointeeType()); } // Non-pointers have none gc'able attribute regardless of the attribute // set on them. else if (!Ty->isAnyPointerType() && !Ty->isBlockPointerType()) - return QualType::GCNone; + return Qualifiers::GCNone; } return GCAttrs; } @@ -3766,11 +3739,38 @@ QualType ASTContext::mergeTypes(QualType if (LHSCan == RHSCan) return LHS; - // If the qualifiers are different, the types aren't compatible - // Note that we handle extended qualifiers later, in the - // case for ExtQualType. - if (LHSCan.getCVRQualifiers() != RHSCan.getCVRQualifiers()) + // If the qualifiers are different, the types aren't compatible... mostly. + Qualifiers LQuals = LHSCan.getQualifiers(); + Qualifiers RQuals = RHSCan.getQualifiers(); + if (LQuals != RQuals) { + // If any of these qualifiers are different, we have a type + // mismatch. + if (LQuals.getCVRQualifiers() != RQuals.getCVRQualifiers() || + LQuals.getAddressSpace() != RQuals.getAddressSpace()) + return QualType(); + + // Exactly one GC qualifier difference is allowed: __strong is + // okay if the other type has no GC qualifier but is an Objective + // C object pointer (i.e. implicitly strong by default). We fix + // this by pretending that the unqualified type was actually + // qualified __strong. + Qualifiers::GC GC_L = LQuals.getObjCGCAttr(); + Qualifiers::GC GC_R = RQuals.getObjCGCAttr(); + assert((GC_L != GC_R) && "unequal qualifier sets had only equal elements"); + + if (GC_L == Qualifiers::Weak || GC_R == Qualifiers::Weak) + return QualType(); + + if (GC_L == Qualifiers::Strong && RHSCan->isObjCObjectPointerType()) { + return mergeTypes(LHS, getObjCGCQualType(RHS, Qualifiers::Strong)); + } + if (GC_R == Qualifiers::Strong && LHSCan->isObjCObjectPointerType()) { + return mergeTypes(getObjCGCQualType(LHS, Qualifiers::Strong), RHS); + } return QualType(); + } + + // Okay, qualifiers are equal. Type::TypeClass LHSClass = LHSCan->getTypeClass(); Type::TypeClass RHSClass = RHSCan->getTypeClass(); @@ -3780,59 +3780,6 @@ QualType ASTContext::mergeTypes(QualType if (LHSClass == Type::FunctionProto) LHSClass = Type::FunctionNoProto; if (RHSClass == Type::FunctionProto) RHSClass = Type::FunctionNoProto; - // Strip off objc_gc attributes off the top level so they can be merged. - // This is a complete mess, but the attribute itself doesn't make much sense. - if (RHSClass == Type::ExtQual) { - QualType::GCAttrTypes GCAttr = RHSCan.getObjCGCAttr(); - if (GCAttr != QualType::GCNone) { - QualType::GCAttrTypes GCLHSAttr = LHSCan.getObjCGCAttr(); - // __weak attribute must appear on both declarations. - // __strong attribue is redundant if other decl is an objective-c - // object pointer (or decorated with __strong attribute); otherwise - // issue error. - if ((GCAttr == QualType::Weak && GCLHSAttr != GCAttr) || - (GCAttr == QualType::Strong && GCLHSAttr != GCAttr && - !LHSCan->isObjCObjectPointerType())) - return QualType(); - - RHS = QualType(cast(RHS.getDesugaredType())->getBaseType(), - RHS.getCVRQualifiers()); - QualType Result = mergeTypes(LHS, RHS); - if (!Result.isNull()) { - if (Result.getObjCGCAttr() == QualType::GCNone) - Result = getObjCGCQualType(Result, GCAttr); - else if (Result.getObjCGCAttr() != GCAttr) - Result = QualType(); - } - return Result; - } - } - if (LHSClass == Type::ExtQual) { - QualType::GCAttrTypes GCAttr = LHSCan.getObjCGCAttr(); - if (GCAttr != QualType::GCNone) { - QualType::GCAttrTypes GCRHSAttr = RHSCan.getObjCGCAttr(); - // __weak attribute must appear on both declarations. __strong - // __strong attribue is redundant if other decl is an objective-c - // object pointer (or decorated with __strong attribute); otherwise - // issue error. - if ((GCAttr == QualType::Weak && GCRHSAttr != GCAttr) || - (GCAttr == QualType::Strong && GCRHSAttr != GCAttr && - !RHSCan->isObjCObjectPointerType())) - return QualType(); - - LHS = QualType(cast(LHS.getDesugaredType())->getBaseType(), - LHS.getCVRQualifiers()); - QualType Result = mergeTypes(LHS, RHS); - if (!Result.isNull()) { - if (Result.getObjCGCAttr() == QualType::GCNone) - Result = getObjCGCQualType(Result, GCAttr); - else if (Result.getObjCGCAttr() != GCAttr) - Result = QualType(); - } - return Result; - } - } - // Same as above for arrays if (LHSClass == Type::VariableArray || LHSClass == Type::IncompleteArray) LHSClass = Type::ConstantArray; @@ -3988,34 +3935,6 @@ QualType ASTContext::mergeTypes(QualType case Type::FixedWidthInt: // Distinct fixed-width integers are not compatible. return QualType(); - case Type::ExtQual: - // FIXME: ExtQual types can be compatible even if they're not - // identical! - return QualType(); - // First attempt at an implementation, but I'm not really sure it's - // right... -#if 0 - ExtQualType* LQual = cast(LHSCan); - ExtQualType* RQual = cast(RHSCan); - if (LQual->getAddressSpace() != RQual->getAddressSpace() || - LQual->getObjCGCAttr() != RQual->getObjCGCAttr()) - return QualType(); - QualType LHSBase, RHSBase, ResultType, ResCanUnqual; - LHSBase = QualType(LQual->getBaseType(), 0); - RHSBase = QualType(RQual->getBaseType(), 0); - ResultType = mergeTypes(LHSBase, RHSBase); - if (ResultType.isNull()) return QualType(); - ResCanUnqual = getCanonicalType(ResultType).getUnqualifiedType(); - if (LHSCan.getUnqualifiedType() == ResCanUnqual) - return LHS; - if (RHSCan.getUnqualifiedType() == ResCanUnqual) - return RHS; - ResultType = getAddrSpaceQualType(ResultType, LQual->getAddressSpace()); - ResultType = getObjCGCQualType(ResultType, LQual->getObjCGCAttr()); - ResultType.setCVRQualifiers(LHSCan.getCVRQualifiers()); - return ResultType; -#endif - case Type::TemplateSpecialization: assert(false && "Dependent types have no size"); break; @@ -4231,7 +4150,7 @@ static QualType DecodeTypeFromStr(const break; // FIXME: There's no way to have a built-in with an rvalue ref arg. case 'C': - Type = Type.getQualifiedType(QualType::Const); + Type = Type.withConst(); break; } }