diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index 9d6188e95e..3815eb5866 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -1091,7 +1091,9 @@ public: /// include typedefs, 'typeof' operators, etc. The returned type is guaranteed /// to be free of any of these, allowing two canonical types to be compared /// for exact equality with a simple pointer comparison. - CanQualType getCanonicalType(QualType T) const; + CanQualType getCanonicalType(QualType T) const { + return CanQualType::CreateUnsafe(T.getCanonicalType()); + } const Type *getCanonicalType(const Type *T) const { return T->getCanonicalTypeInternal().getTypePtr(); @@ -1125,13 +1127,8 @@ public: /// \brief Determine whether the given types are equivalent after /// cvr-qualifiers have been removed. bool hasSameUnqualifiedType(QualType T1, QualType T2) { - CanQualType CT1 = getCanonicalType(T1); - CanQualType CT2 = getCanonicalType(T2); - - Qualifiers Quals; - QualType UnqualT1 = getUnqualifiedArrayType(CT1, Quals); - QualType UnqualT2 = getUnqualifiedArrayType(CT2, Quals); - return UnqualT1 == UnqualT2; + return getCanonicalType(T1).getTypePtr() == + getCanonicalType(T2).getTypePtr(); } bool UnwrapSimilarPointerTypes(QualType &T1, QualType &T2); diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h index 08748057ea..95c5797e5b 100644 --- a/include/clang/AST/Type.h +++ b/include/clang/AST/Type.h @@ -94,6 +94,8 @@ namespace clang { class TemplateArgumentLoc; class TemplateArgumentListInfo; class ElaboratedType; + class ExtQuals; + class ExtQualsTypeCommonBase; struct PrintingPolicy; template <typename> class CanQual; @@ -345,85 +347,6 @@ private: static const uint32_t AddressSpaceShift = 5; }; -/// \brief Base class that is common to both the \c ExtQuals and \c Type -/// classes, which allows \c QualType to access the common fields between the -/// two. -/// -class ExtQualsTypeCommonBase { -protected: - ExtQualsTypeCommonBase(const Type *BaseType) : BaseType(BaseType) { } - - /// \brief The "base" type of an extended qualifiers type (\c ExtQuals) or - /// a self-referential pointer (for \c Type). - /// - /// This pointer allows an efficient mapping from a QualType to its - /// underlying type pointer. - const Type *BaseType; - - friend class QualType; -}; - -/// ExtQuals - We can encode up to four bits in the low bits of a -/// type pointer, but there are many more type qualifiers that we want -/// to be able to apply to an arbitrary type. Therefore we have this -/// struct, intended to be heap-allocated and used by QualType to -/// store qualifiers. -/// -/// The current design tags the 'const', 'restrict', and 'volatile' qualifiers -/// in three low bits on the QualType pointer; a fourth bit records whether -/// the pointer is an ExtQuals node. The extended qualifiers (address spaces, -/// Objective-C GC attributes) are much more rare. -class ExtQuals : public ExtQualsTypeCommonBase, public llvm::FoldingSetNode { - // NOTE: changing the fast qualifiers should be straightforward as - // long as you don't make 'const' non-fast. - // 1. Qualifiers: - // a) Modify the bitmasks (Qualifiers::TQ and DeclSpec::TQ). - // Fast qualifiers must occupy the low-order bits. - // b) Update Qualifiers::FastWidth and FastMask. - // 2. QualType: - // a) Update is{Volatile,Restrict}Qualified(), defined inline. - // b) Update remove{Volatile,Restrict}, defined near the end of - // this header. - // 3. ASTContext: - // a) Update get{Volatile,Restrict}Type. - - /// Quals - the immutable set of qualifiers applied by this - /// node; always contains extended qualifiers. - Qualifiers Quals; - -public: - ExtQuals(const Type *Base, Qualifiers Quals) - : ExtQualsTypeCommonBase(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 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; } - -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); - } -}; - /// CallingConv - Specifies the calling convention that a function uses. enum CallingConv { CC_Default, @@ -461,6 +384,14 @@ class QualType { return Value.getPointer().get<const Type*>(); } + const ExtQualsTypeCommonBase *getCommonPtr() const { + assert(!isNull() && "Cannot retrieve a NULL type pointer"); + uintptr_t CommonPtrVal + = reinterpret_cast<uintptr_t>(Value.getOpaqueValue()); + CommonPtrVal &= ~(uintptr_t)((1 << TypeAlignmentInBits) - 1); + return reinterpret_cast<ExtQualsTypeCommonBase*>(CommonPtrVal); + } + friend class QualifierCollector; public: QualType() {} @@ -479,36 +410,13 @@ public: /// /// This function requires that the type not be NULL. If the type might be /// NULL, use the (slightly less efficient) \c getTypePtrOrNull(). - const Type *getTypePtr() const { - assert(!isNull() && "Cannot retrieve a NULL type pointer"); - uintptr_t CommonPtrVal - = reinterpret_cast<uintptr_t>(Value.getOpaqueValue()); - CommonPtrVal &= ~(uintptr_t)((1 << TypeAlignmentInBits) - 1); - ExtQualsTypeCommonBase *CommonPtr - = reinterpret_cast<ExtQualsTypeCommonBase*>(CommonPtrVal); - return const_cast<Type *>(CommonPtr->BaseType); - } + const Type *getTypePtr() const; - const Type *getTypePtrOrNull() const { - uintptr_t TypePtrPtrVal - = reinterpret_cast<uintptr_t>(Value.getOpaqueValue()); - TypePtrPtrVal &= ~(uintptr_t)((1 << TypeAlignmentInBits) - 1); - Type **TypePtrPtr = reinterpret_cast<Type**>(TypePtrPtrVal); - return TypePtrPtr ? *TypePtrPtr : 0; - } + const Type *getTypePtrOrNull() const; /// Divides a QualType into its unqualified type and a set of local /// qualifiers. - SplitQualType split() const { - if (!hasLocalNonFastQualifiers()) - return SplitQualType(getTypePtrUnsafe(), - Qualifiers::fromFastMask(getLocalFastQualifiers())); - - const ExtQuals *eq = getExtQualsUnsafe(); - Qualifiers qs = eq->getQualifiers(); - qs.addFastQualifiers(getLocalFastQualifiers()); - return SplitQualType(eq->getBaseType(), qs); - } + SplitQualType split() const; void *getAsOpaquePtr() const { return Value.getOpaqueValue(); } static QualType getFromOpaquePtr(const void *Ptr) { @@ -583,13 +491,7 @@ public: /// \brief Retrieve the set of qualifiers local to this particular QualType /// instance, not including any qualifiers acquired through typedefs or /// other sugar. - Qualifiers getLocalQualifiers() const { - Qualifiers Quals; - if (hasLocalNonFastQualifiers()) - Quals = getExtQualsUnsafe()->getQualifiers(); - Quals.addFastQualifiers(getLocalFastQualifiers()); - return Quals; - } + Qualifiers getLocalQualifiers() const; /// \brief Retrieve the set of qualifiers applied to this type. Qualifiers getQualifiers() const; @@ -658,6 +560,8 @@ public: return T; } + QualType getCanonicalType() const; + /// \brief Return this type with all of the instance-specific qualifiers /// removed, but without removing any qualifiers that may have been applied /// through typedefs. @@ -831,6 +735,94 @@ public: namespace clang { +/// \brief Base class that is common to both the \c ExtQuals and \c Type +/// classes, which allows \c QualType to access the common fields between the +/// two. +/// +class ExtQualsTypeCommonBase { + ExtQualsTypeCommonBase(const Type *baseType, QualType canon) + : BaseType(baseType), CanonicalType(canon) {} + + /// \brief The "base" type of an extended qualifiers type (\c ExtQuals) or + /// a self-referential pointer (for \c Type). + /// + /// This pointer allows an efficient mapping from a QualType to its + /// underlying type pointer. + const Type *const BaseType; + + /// \brief The canonical type of this type. A QualType. + QualType CanonicalType; + + friend class QualType; + friend class Type; + friend class ExtQuals; +}; + +/// ExtQuals - We can encode up to four bits in the low bits of a +/// type pointer, but there are many more type qualifiers that we want +/// to be able to apply to an arbitrary type. Therefore we have this +/// struct, intended to be heap-allocated and used by QualType to +/// store qualifiers. +/// +/// The current design tags the 'const', 'restrict', and 'volatile' qualifiers +/// in three low bits on the QualType pointer; a fourth bit records whether +/// the pointer is an ExtQuals node. The extended qualifiers (address spaces, +/// Objective-C GC attributes) are much more rare. +class ExtQuals : public ExtQualsTypeCommonBase, public llvm::FoldingSetNode { + // NOTE: changing the fast qualifiers should be straightforward as + // long as you don't make 'const' non-fast. + // 1. Qualifiers: + // a) Modify the bitmasks (Qualifiers::TQ and DeclSpec::TQ). + // Fast qualifiers must occupy the low-order bits. + // b) Update Qualifiers::FastWidth and FastMask. + // 2. QualType: + // a) Update is{Volatile,Restrict}Qualified(), defined inline. + // b) Update remove{Volatile,Restrict}, defined near the end of + // this header. + // 3. ASTContext: + // a) Update get{Volatile,Restrict}Type. + + /// Quals - the immutable set of qualifiers applied by this + /// node; always contains extended qualifiers. + Qualifiers Quals; + + ExtQuals *this_() { return this; } + +public: + ExtQuals(const Type *baseType, QualType canon, Qualifiers quals) + : ExtQualsTypeCommonBase(baseType, + canon.isNull() ? QualType(this_(), 0) : canon), + Quals(quals) + { + assert(Quals.hasNonFastQualifiers() + && "ExtQuals created with no fast qualifiers"); + assert(!Quals.hasFastQualifiers() + && "ExtQuals created with fast qualifiers"); + } + + Qualifiers getQualifiers() const { return Quals; } + + bool hasObjCGCAttr() const { return Quals.hasObjCGCAttr(); } + Qualifiers::GC getObjCGCAttr() const { return Quals.getObjCGCAttr(); } + + bool hasAddressSpace() const { return Quals.hasAddressSpace(); } + unsigned getAddressSpace() const { return Quals.getAddressSpace(); } + + const Type *getBaseType() const { return BaseType; } + +public: + void Profile(llvm::FoldingSetNodeID &ID) const { + Profile(ID, getBaseType(), Quals); + } + static void Profile(llvm::FoldingSetNodeID &ID, + const Type *BaseType, + Qualifiers Quals) { + assert(!Quals.hasFastQualifiers() && "fast qualifiers in ExtQuals hash!"); + ID.AddPointer(BaseType); + Quals.Profile(ID); + } +}; + /// Type - This is the base class of the type hierarchy. A central concept /// with types is that each type always has a canonical type. A canonical type /// is the type with any typedef names stripped out of it or the types it @@ -870,8 +862,6 @@ private: Type(const Type&); // DO NOT IMPLEMENT. void operator=(const Type&); // DO NOT IMPLEMENT. - QualType CanonicalType; - /// Bitfields required by the Type class. class TypeBitfields { friend class Type; @@ -1060,10 +1050,10 @@ private: protected: // silence VC++ warning C4355: 'this' : used in base member initializer list Type *this_() { return this; } - Type(TypeClass tc, QualType Canonical, bool Dependent, bool VariablyModified, + Type(TypeClass tc, QualType canon, bool Dependent, bool VariablyModified, bool ContainsUnexpandedParameterPack) - : ExtQualsTypeCommonBase(this), - CanonicalType(Canonical.isNull() ? QualType(this_(), 0) : Canonical) { + : ExtQualsTypeCommonBase(this, + canon.isNull() ? QualType(this_(), 0) : canon) { TypeBits.TC = tc; TypeBits.Dependent = Dependent; TypeBits.VariablyModified = VariablyModified; @@ -1106,8 +1096,10 @@ public: return TypeBits.ContainsUnexpandedParameterPack; } + /// Determines if this type would be canonical if it had no further + /// qualification. bool isCanonicalUnqualified() const { - return CanonicalType.getTypePtr() == this; + return CanonicalType == QualType(this, 0); } /// Types are partitioned into 3 broad categories (C99 6.2.5p1): @@ -1248,6 +1240,10 @@ public: /// \brief Whether this type is a variably-modified type (C99 6.7.5). bool isVariablyModifiedType() const { return TypeBits.VariablyModified; } + + /// \brief Whether this type involves a variable-length array type + /// with a definite size. + bool hasSizedVLAType() const; /// \brief Whether this type is or contains a local or unnamed type. bool hasUnnamedOrLocalType() const; @@ -1310,6 +1306,10 @@ public: // immediately following this class. template <typename T> const T *getAs() const; + /// A variant of getAs<> for array types which silently discards + /// qualifiers from the outermost type. + const ArrayType *getAsArrayTypeUnsafe() const; + /// getArrayElementTypeNoTypeQual - If this is an array type, return the /// element type of the array, potentially with type qualifiers missing. /// This method should never be used when type qualifiers are meaningful. @@ -3795,15 +3795,16 @@ public: QualifierCollector(Qualifiers Qs = Qualifiers()) : Qualifiers(Qs) {} /// Collect any qualifiers on the given type and return an - /// unqualified type. - const Type *strip(QualType QT) { - addFastQualifiers(QT.getLocalFastQualifiers()); - if (QT.hasLocalNonFastQualifiers()) { - const ExtQuals *EQ = QT.getExtQualsUnsafe(); - addQualifiers(EQ->getQualifiers()); - return EQ->getBaseType(); - } - return QT.getTypePtrUnsafe(); + /// unqualified type. The qualifiers are assumed to be consistent + /// with those already in the type. + const Type *strip(QualType type) { + addFastQualifiers(type.getLocalFastQualifiers()); + if (!type.hasLocalNonFastQualifiers()) + return type.getTypePtrUnsafe(); + + const ExtQuals *extQuals = type.getExtQualsUnsafe(); + addConsistentQualifiers(extQuals->getQualifiers()); + return extQuals->getBaseType(); } /// Apply the collected qualifiers to the given type. @@ -3816,49 +3817,84 @@ public: // Inline function definitions. +inline const Type *QualType::getTypePtr() const { + return getCommonPtr()->BaseType; +} + +inline const Type *QualType::getTypePtrOrNull() const { + return (isNull() ? 0 : getCommonPtr()->BaseType); +} + +inline SplitQualType QualType::split() const { + if (!hasLocalNonFastQualifiers()) + return SplitQualType(getTypePtrUnsafe(), + Qualifiers::fromFastMask(getLocalFastQualifiers())); + + const ExtQuals *eq = getExtQualsUnsafe(); + Qualifiers qs = eq->getQualifiers(); + qs.addFastQualifiers(getLocalFastQualifiers()); + return SplitQualType(eq->getBaseType(), qs); +} + +inline Qualifiers QualType::getLocalQualifiers() const { + Qualifiers Quals; + if (hasLocalNonFastQualifiers()) + Quals = getExtQualsUnsafe()->getQualifiers(); + Quals.addFastQualifiers(getLocalFastQualifiers()); + return Quals; +} + +inline Qualifiers QualType::getQualifiers() const { + Qualifiers quals = getCommonPtr()->CanonicalType.getLocalQualifiers(); + quals.addFastQualifiers(getLocalFastQualifiers()); + return quals; +} + +inline unsigned QualType::getCVRQualifiers() const { + unsigned cvr = getCommonPtr()->CanonicalType.getLocalCVRQualifiers(); + cvr |= getLocalCVRQualifiers(); + return cvr; +} + +inline QualType QualType::getCanonicalType() const { + QualType canon = getCommonPtr()->CanonicalType; + return canon.withFastQualifiers(getLocalFastQualifiers()); +} + inline bool QualType::isCanonical() const { - const Type *T = getTypePtr(); - if (hasLocalQualifiers()) - return T->isCanonicalUnqualified() && !isa<ArrayType>(T); - return T->isCanonicalUnqualified(); + return getTypePtr()->isCanonicalUnqualified(); } inline bool QualType::isCanonicalAsParam() const { + if (!isCanonical()) return false; if (hasLocalQualifiers()) return false; const Type *T = getTypePtr(); - if ((*this)->isPointerType()) { - QualType BaseType = (*this)->getAs<PointerType>()->getPointeeType(); - if (isa<VariableArrayType>(BaseType)) { - const ArrayType *AT = dyn_cast<ArrayType>(BaseType); - const VariableArrayType *VAT = cast<VariableArrayType>(AT); - if (VAT->getSizeExpr()) - T = BaseType.getTypePtr(); - } - } - return T->isCanonicalUnqualified() && - !isa<FunctionType>(T) && !isa<ArrayType>(T); + if (T->isVariablyModifiedType() && T->hasSizedVLAType()) + return false; + + return !isa<FunctionType>(T) && !isa<ArrayType>(T); } inline bool QualType::isConstQualified() const { return isLocalConstQualified() || - getTypePtr()->getCanonicalTypeInternal().isLocalConstQualified(); + getCommonPtr()->CanonicalType.isLocalConstQualified(); } inline bool QualType::isRestrictQualified() const { return isLocalRestrictQualified() || - getTypePtr()->getCanonicalTypeInternal().isLocalRestrictQualified(); + getCommonPtr()->CanonicalType.isLocalRestrictQualified(); } inline bool QualType::isVolatileQualified() const { return isLocalVolatileQualified() || - getTypePtr()->getCanonicalTypeInternal().isLocalVolatileQualified(); + getCommonPtr()->CanonicalType.isLocalVolatileQualified(); } inline bool QualType::hasQualifiers() const { return hasLocalQualifiers() || - getTypePtr()->getCanonicalTypeInternal().hasLocalQualifiers(); + getCommonPtr()->CanonicalType.hasLocalQualifiers(); } inline QualType QualType::getUnqualifiedType() const { @@ -3875,33 +3911,6 @@ inline SplitQualType QualType::getSplitUnqualifiedType() const { return getSplitUnqualifiedTypeImpl(*this); } -inline Qualifiers QualType::getQualifiers() const { - // Split this type and collect the local qualifiers. - SplitQualType splitNonCanon = split(); - Qualifiers quals = splitNonCanon.second; - - // Now split the canonical type and collect the local qualifiers there. - SplitQualType splitCanon = splitNonCanon.first->getCanonicalTypeInternal().split(); - quals.addConsistentQualifiers(splitCanon.second); - - // If the canonical type is an array, recurse on its element type. - if (const ArrayType *array = dyn_cast<ArrayType>(splitCanon.first)) - quals.addConsistentQualifiers(array->getElementType().getQualifiers()); - - return quals; -} - -inline unsigned QualType::getCVRQualifiers() const { - // This is basically getQualifiers() but optimized to avoid split(); - // there should be exactly one conditional branch in this function. - unsigned cvr = getLocalCVRQualifiers(); - QualType type = getTypePtr()->getCanonicalTypeInternal(); - cvr |= type.getLocalCVRQualifiers(); - if (const ArrayType *array = dyn_cast<ArrayType>(type.getTypePtr())) - cvr |= array->getElementType().getCVRQualifiers(); - return cvr; -} - inline void QualType::removeLocalConst() { removeLocalFastQualifiers(Qualifiers::Const); } @@ -3924,42 +3933,12 @@ inline void QualType::removeLocalCVRQualifiers(unsigned Mask) { /// getAddressSpace - Return the address space of this type. inline unsigned QualType::getAddressSpace() const { - if (hasLocalNonFastQualifiers()) { - const ExtQuals *EQ = getExtQualsUnsafe(); - if (EQ->hasAddressSpace()) - return EQ->getAddressSpace(); - } - - QualType CT = getTypePtr()->getCanonicalTypeInternal(); - if (CT.hasLocalNonFastQualifiers()) { - const ExtQuals *EQ = CT.getExtQualsUnsafe(); - if (EQ->hasAddressSpace()) - return EQ->getAddressSpace(); - } - - if (const ArrayType *AT = dyn_cast<ArrayType>(CT)) - return AT->getElementType().getAddressSpace(); - return 0; + return getQualifiers().getAddressSpace(); } /// getObjCGCAttr - Return the gc attribute of this type. inline Qualifiers::GC QualType::getObjCGCAttr() const { - if (hasLocalNonFastQualifiers()) { - const ExtQuals *EQ = getExtQualsUnsafe(); - if (EQ->hasObjCGCAttr()) - return EQ->getObjCGCAttr(); - } - - QualType CT = getTypePtr()->getCanonicalTypeInternal(); - if (CT.hasLocalNonFastQualifiers()) { - const ExtQuals *EQ = CT.getExtQualsUnsafe(); - if (EQ->hasObjCGCAttr()) - return EQ->getObjCGCAttr(); - } - - if (const ArrayType *AT = dyn_cast<ArrayType>(CT)) - return AT->getElementType().getObjCGCAttr(); - return Qualifiers::GCNone; + return getQualifiers().getObjCGCAttr(); } inline FunctionType::ExtInfo getFunctionExtInfo(const Type &t) { @@ -4209,6 +4188,20 @@ template <typename T> const T *Type::getAs() const { return cast<T>(getUnqualifiedDesugaredType()); } +inline const ArrayType *Type::getAsArrayTypeUnsafe() const { + // If this is directly an array type, return it. + if (const ArrayType *arr = dyn_cast<ArrayType>(this)) + return arr; + + // If the canonical form of this type isn't the right kind, reject it. + if (!isa<ArrayType>(CanonicalType)) + return 0; + + // If this is a typedef for the type, strip the typedef off without + // losing all typedef information. + return cast<ArrayType>(getUnqualifiedDesugaredType()); +} + } // end namespace clang #endif diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index eaabf71e07..b1ecb2bc28 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -569,19 +569,20 @@ CharUnits ASTContext::getDeclAlign(const Decl *D, bool RefAsPointee) const { T = getPointerType(RT->getPointeeType()); } if (!T->isIncompleteType() && !T->isFunctionType()) { + // Adjust alignments of declarations with array type by the + // large-array alignment on the target. unsigned MinWidth = Target.getLargeArrayMinWidth(); - unsigned ArrayAlign = Target.getLargeArrayAlign(); - if (isa<VariableArrayType>(T) && MinWidth != 0) - Align = std::max(Align, ArrayAlign); - if (const ConstantArrayType *CT = dyn_cast<ConstantArrayType>(T)) { - unsigned Size = getTypeSize(CT); - if (MinWidth != 0 && MinWidth <= Size) - Align = std::max(Align, ArrayAlign); - } - // Incomplete or function types default to 1. - while (isa<VariableArrayType>(T) || isa<IncompleteArrayType>(T)) - T = cast<ArrayType>(T)->getElementType(); + const ArrayType *arrayType; + if (MinWidth && (arrayType = getAsArrayType(T))) { + if (isa<VariableArrayType>(arrayType)) + Align = std::max(Align, Target.getLargeArrayAlign()); + else if (isa<ConstantArrayType>(arrayType) && + MinWidth <= getTypeSize(cast<ConstantArrayType>(arrayType))) + Align = std::max(Align, Target.getLargeArrayAlign()); + // Walk through any array types while we're at it. + T = getBaseElementType(arrayType); + } Align = std::max(Align, getPreferredTypeAlign(T.getTypePtr())); } if (const FieldDecl *FD = dyn_cast<FieldDecl>(VD)) { @@ -1092,24 +1093,33 @@ ASTContext::getASTObjCImplementationLayout( //===----------------------------------------------------------------------===// QualType -ASTContext::getExtQualType(const Type *TypeNode, Qualifiers Quals) const { - unsigned Fast = Quals.getFastQualifiers(); - Quals.removeFastQualifiers(); +ASTContext::getExtQualType(const Type *baseType, Qualifiers quals) const { + unsigned fastQuals = quals.getFastQualifiers(); + quals.removeFastQualifiers(); // Check if we've already instantiated this type. llvm::FoldingSetNodeID ID; - ExtQuals::Profile(ID, TypeNode, Quals); - void *InsertPos = 0; - if (ExtQuals *EQ = ExtQualNodes.FindNodeOrInsertPos(ID, InsertPos)) { - assert(EQ->getQualifiers() == Quals); - QualType T = QualType(EQ, Fast); - return T; + ExtQuals::Profile(ID, baseType, quals); + void *insertPos = 0; + if (ExtQuals *eq = ExtQualNodes.FindNodeOrInsertPos(ID, insertPos)) { + assert(eq->getQualifiers() == quals); + return QualType(eq, fastQuals); } - ExtQuals *New = new (*this, TypeAlignment) ExtQuals(TypeNode, Quals); - ExtQualNodes.InsertNode(New, InsertPos); - QualType T = QualType(New, Fast); - return T; + // If the base type is not canonical, make the appropriate canonical type. + QualType canon; + if (!baseType->isCanonicalUnqualified()) { + SplitQualType canonSplit = baseType->getCanonicalTypeInternal().split(); + canonSplit.second.addConsistentQualifiers(quals); + canon = getExtQualType(canonSplit.first, canonSplit.second); + + // Re-find the insert position. + (void) ExtQualNodes.FindNodeOrInsertPos(ID, insertPos); + } + + ExtQuals *eq = new (*this, TypeAlignment) ExtQuals(baseType, canon, quals); + ExtQualNodes.InsertNode(eq, insertPos); + return QualType(eq, fastQuals); } QualType @@ -1395,12 +1405,15 @@ QualType ASTContext::getConstantArrayType(QualType EltTy, ConstantArrayTypes.FindNodeOrInsertPos(ID, InsertPos)) return QualType(ATP, 0); - // If the element type isn't canonical, this won't be a canonical type either, - // so fill in the canonical type field. - QualType Canonical; - if (!EltTy.isCanonical()) { - Canonical = getConstantArrayType(getCanonicalType(EltTy), ArySize, - ASM, EltTypeQuals); + // If the element type isn't canonical or has qualifiers, this won't + // be a canonical type either, so fill in the canonical type field. + QualType Canon; + if (!EltTy.isCanonical() || EltTy.hasLocalQualifiers()) { + SplitQualType canonSplit = getCanonicalType(EltTy).split(); + Canon = getConstantArrayType(QualType(canonSplit.first, 0), ArySize, + ASM, EltTypeQuals); + Canon = getQualifiedType(Canon, canonSplit.second); + // Get the new insert position for the node we care about. ConstantArrayType *NewIP = ConstantArrayTypes.FindNodeOrInsertPos(ID, InsertPos); @@ -1408,7 +1421,7 @@ QualType ASTContext::getConstantArrayType(QualType EltTy, } ConstantArrayType *New = new(*this,TypeAlignment) - ConstantArrayType(EltTy, Canonical, ArySize, ASM, EltTypeQuals); + ConstantArrayType(EltTy, Canon, ArySize, ASM, EltTypeQuals); ConstantArrayTypes.InsertNode(New, InsertPos); Types.push_back(New); return QualType(New, 0); @@ -1547,15 +1560,18 @@ QualType ASTContext::getVariableArrayType(QualType EltTy, SourceRange Brackets) const { // Since we don't unique expressions, it isn't possible to unique VLA's // that have an expression provided for their size. - QualType CanonType; + QualType Canon; - if (!EltTy.isCanonical()) { - CanonType = getVariableArrayType(getCanonicalType(EltTy), NumElts, ASM, - EltTypeQuals, Brackets); + // Be sure to pull qualifiers off the element type. + if (!EltTy.isCanonical() || EltTy.hasLocalQualifiers()) { + SplitQualType canonSplit = getCanonicalType(EltTy).split(); + Canon = getVariableArrayType(QualType(canonSplit.first, 0), NumElts, ASM, + EltTypeQuals, Brackets); + Canon = getQualifiedType(Canon, canonSplit.second); } VariableArrayType *New = new(*this, TypeAlignment) - VariableArrayType(EltTy, CanonType, NumElts, ASM, EltTypeQuals, Brackets); + VariableArrayType(EltTy, Canon, NumElts, ASM, EltTypeQuals, Brackets); VariableArrayTypes.push_back(New); Types.push_back(New); @@ -1565,106 +1581,114 @@ QualType ASTContext::getVariableArrayType(QualType EltTy, /// getDependentSizedArrayType - Returns a non-unique reference to /// the type for a dependently-sized array of the specified element /// type. -QualType ASTContext::getDependentSizedArrayType(QualType EltTy, - Expr *NumElts, +QualType ASTContext::getDependentSizedArrayType(QualType elementType, + Expr *numElements, ArrayType::ArraySizeModifier ASM, - unsigned EltTypeQuals, - SourceRange Brackets) const { - assert((!NumElts || NumElts->isTypeDependent() || - NumElts->isValueDependent()) && + unsigned elementTypeQuals, + SourceRange brackets) const { + assert((!numElements || numElements->isTypeDependent() || + numElements->isValueDependent()) && "Size must be type- or value-dependent!"); - void *InsertPos = 0; - DependentSizedArrayType *Canon = 0; + // Dependently-sized array types that do not have a specified number + // of elements will have their sizes deduced from a dependent + // initializer. We do no canonicalization here at all, which is okay + // because they can't be used in most locations. + if (!numElements) { + DependentSizedArrayType *newType + = new (*this, TypeAlignment) + DependentSizedArrayType(*this, elementType, QualType(), + numElements, ASM, elementTypeQuals, + brackets); + Types.push_back(newType); + return QualType(newType, 0); + } + + // Otherwise, we actually build a new type every time, but we + // also build a canonical type. + + SplitQualType canonElementType = getCanonicalType(elementType).split(); + + void *insertPos = 0; llvm::FoldingSetNodeID ID; + DependentSizedArrayType::Profile(ID, *this, + QualType(canonElementType.first, 0), + ASM, elementTypeQuals, numElements); - QualType CanonicalEltTy = getCanonicalType(EltTy); - if (NumElts) { - // Dependently-sized array types that do not have a specified - // number of elements will have their sizes deduced from an - // initializer. - DependentSizedArrayType::Profile(ID, *this, CanonicalEltTy, ASM, - EltTypeQuals, NumElts); + // Look for an existing type with these properties. + DependentSizedArrayType *canonTy = + DependentSizedArrayTypes.FindNodeOrInsertPos(ID, insertPos); - Canon = DependentSizedArrayTypes.FindNodeOrInsertPos(ID, InsertPos); + // If we don't have one, build one. + if (!canonTy) { + canonTy = new (*this, TypeAlignment) + DependentSizedArrayType(*this, QualType(canonElementType.first, 0), + QualType(), numElements, ASM, elementTypeQuals, + brackets); + DependentSizedArrayTypes.InsertNode(canonTy, insertPos); + Types.push_back(canonTy); } - DependentSizedArrayType *New; - if (Canon) { - // We already have a canonical version of this array type; use it as - // the canonical type for a newly-built type. - New = new (*this, TypeAlignment) - DependentSizedArrayType(*this, EltTy, QualType(Canon, 0), - NumElts, ASM, EltTypeQuals, Brackets); - } else if (CanonicalEltTy == EltTy) { - // This is a canonical type. Record it. - New = new (*this, TypeAlignment) - DependentSizedArrayType(*this, EltTy, QualType(), - NumElts, ASM, EltTypeQuals, Brackets); - - if (NumElts) { -#ifndef NDEBUG - DependentSizedArrayType *CanonCheck - = DependentSizedArrayTypes.FindNodeOrInsertPos(ID, InsertPos); - assert(!CanonCheck && "Dependent-sized canonical array type broken"); - (void)CanonCheck; -#endif - DependentSizedArrayTypes.InsertNode(New, InsertPos); - } - } else { - QualType Canon = getDependentSizedArrayType(CanonicalEltTy, NumElts, - ASM, EltTypeQuals, - SourceRange()); - New = new (*this, TypeAlignment) - DependentSizedArrayType(*this, EltTy, Canon, - NumElts, ASM, EltTypeQuals, Brackets); - } + // Apply qualifiers from the element type to the array. + QualType canon = getQualifiedType(QualType(canonTy,0), + canonElementType.second); - Types.push_back(New); - return QualType(New, 0); + // If we didn't need extra canonicalization for the element type, + // then just use that as our result. + if (QualType(canonElementType.first, 0) == elementType) + return canon; + + // Otherwise, we need to build a type which follows the spelling + // of the element type. + DependentSizedArrayType *sugaredType + = new (*this, TypeAlignment) + DependentSizedArrayType(*this, elementType, canon, numElements, + ASM, elementTypeQuals, brackets); + Types.push_back(sugaredType); + return QualType(sugaredType, 0); } -QualType ASTContext::getIncompleteArrayType(QualType EltTy, +QualType ASTContext::getIncompleteArrayType(QualType elementType, ArrayType::ArraySizeModifier ASM, - unsigned EltTypeQuals) const { + unsigned elementTypeQuals) const { llvm::FoldingSetNodeID ID; - IncompleteArrayType::Profile(ID, EltTy, ASM, EltTypeQuals); + IncompleteArrayType::Profile(ID, elementType, ASM, elementTypeQuals); - void *InsertPos = 0; - if (IncompleteArrayType *ATP = - IncompleteArrayTypes.FindNodeOrInsertPos(ID, InsertPos)) - return QualType(ATP, 0); + void *insertPos = 0; + if (IncompleteArrayType *iat = + IncompleteArrayTypes.FindNodeOrInsertPos(ID, insertPos)) + return QualType(iat, 0); // If the element type isn't canonical, this won't be a canonical type - // either, so fill in the canonical type field. - QualType Canonical; + // either, so fill in the canonical type field. We also have to pull + // qualifiers off the element type. + QualType canon; - if (!EltTy.isCanonical()) { - Canonical = getIncompleteArrayType(getCanonicalType(EltTy), - ASM, EltTypeQuals); + if (!elementType.isCanonical() || elementType.hasLocalQualifiers()) { + SplitQualType canonSplit = getCanonicalType(elementType).split(); + canon = getIncompleteArrayType(QualType(canonSplit.first, 0), + ASM, elementTypeQuals); + canon = getQualifiedType(canon, canonSplit.second); // Get the new insert position for the node we care about. - IncompleteArrayType *NewIP = - IncompleteArrayTypes.FindNodeOrInsertPos(ID, InsertPos); - assert(NewIP == 0 && "Shouldn't be in the map!"); (void)NewIP; + IncompleteArrayType *existing = + IncompleteArrayTypes.FindNodeOrInsertPos(ID, insertPos); + assert(!existing && "Shouldn't be in the map!"); (void) existing; } - IncompleteArrayType *New = new (*this, TypeAlignment) - IncompleteArrayType(EltTy, Canonical, ASM, EltTypeQuals); + IncompleteArrayType *newType = new (*this, TypeAlignment) + IncompleteArrayType(elementType, canon, ASM, elementTypeQuals); - IncompleteArrayTypes.InsertNode(New, InsertPos); - Types.push_back(New); - return QualType(New, 0); + IncompleteArrayTypes.InsertNode(newType, insertPos); + Types.push_back(newType); + return QualType(newType, 0); } /// getVectorType - Return the unique reference to a vector type of /// the specified element type and size. VectorType must be a built-in type. QualType ASTContext::getVectorType(QualType vecType, unsigned NumElts, VectorType::VectorKind VecKind) const { - const BuiltinType *BaseType; - - BaseType = dyn_cast<BuiltinType>(getCanonicalType(vecType).getTypePtr()); - assert(BaseType != 0 && "getVectorType(): Expecting a built-in type"); + assert(vecType->isBuiltinType()); // Check if we've already instantiated a vector of this type. llvm::FoldingSetNodeID ID; @@ -1695,10 +1719,7 @@ QualType ASTContext::getVectorType(QualType vecType, unsigned NumElts, /// the specified element type and size. VectorType must be a built-in type. QualType ASTContext::getExtVectorType(QualType vecType, unsigned NumElts) const { - const BuiltinType *baseType; - - baseType = dyn_cast<BuiltinType>(getCanonicalType(vecType).getTypePtr()); - assert(baseType != 0 && "getExtVectorType(): Expecting a built-in type"); + assert(vecType->isBuiltinType()); // Check if we've already instantiated a vector of this type. llvm::FoldingSetNodeID ID; @@ -2651,61 +2672,6 @@ CanQualType ASTContext::getCanonicalParamType(QualType T) const { return CanQualType::CreateUnsafe(Result); } -/// getCanonicalType - Return the canonical (structural) type corresponding to -/// the specified potentially non-canonical type. The non-canonical version -/// of a type may have many "decorated" versions of types. Decorators can -/// include typedefs, 'typeof' operators, etc. The returned type is guaranteed -/// 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) const { - 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 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. - const ArrayType *AT = dyn_cast<ArrayType>(CanType); - if (!AT) - 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 = getQualifiedType(AT->getElementType(), Quals); - NewEltTy = getCanonicalType(NewEltTy); - - if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(AT)) - return CanQualType::CreateUnsafe( - getConstantArrayType(NewEltTy, CAT->getSize(), - CAT->getSizeModifier(), - CAT->getIndexTypeCVRQualifiers())); - if (const IncompleteArrayType *IAT = dyn_cast<IncompleteArrayType>(AT)) - return CanQualType::CreateUnsafe( - getIncompleteArrayType(NewEltTy, IAT->getSizeModifier(), - IAT->getIndexTypeCVRQualifiers())); - - if (const DependentSizedArrayType *DSAT = dyn_cast<DependentSizedArrayType>(AT)) - return CanQualType::CreateUnsafe( - getDependentSizedArrayType(NewEltTy, - DSAT->getSizeExpr(), - DSAT->getSizeModifier(), - DSAT->getIndexTypeCVRQualifiers(), - DSAT->getBracketsRange())->getCanonicalTypeInternal()); - - const VariableArrayType *VAT = cast<VariableArrayType>(AT); - return CanQualType::CreateUnsafe(getVariableArrayType(NewEltTy, - VAT->getSizeExpr(), - VAT->getSizeModifier(), - VAT->getIndexTypeCVRQualifiers(), - VAT->getBracketsRange())); -} QualType ASTContext::getUnqualifiedArrayType(QualType type, Qualifiers &quals) { @@ -2960,7 +2926,8 @@ ASTContext::getCanonicalNestedNameSpecifier(NestedNameSpecifier *NNS) const { T = getCanonicalType(T); } - return NestedNameSpecifier::Create(*this, 0, false, T.getTypePtr()); + return NestedNameSpecifier::Create(*this, 0, false, + const_cast<Type*>(T.getTypePtr())); } case NestedNameSpecifier::Global: @@ -2982,8 +2949,7 @@ const ArrayType *ASTContext::getAsArrayType(QualType T) const { } // Handle the common negative case fast. - QualType CType = T->getCanonicalTypeInternal(); - if (!isa<ArrayType>(CType)) + if (!isa<ArrayType>(T.getCanonicalType())) return 0; // Apply any qualifiers from the array type to the element type. This @@ -2994,19 +2960,17 @@ const ArrayType *ASTContext::getAsArrayType(QualType T) const { // 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. - QualifierCollector Qs; - const Type *Ty = Qs.strip(T.getDesugaredType(*this)); + SplitQualType split = T.getSplitDesugaredType(); + Qualifiers qs = split.second; // If we have a simple case, just return now. - const ArrayType *ATy = dyn_cast<ArrayType>(Ty); - if (ATy == 0 || Qs.empty()) + const ArrayType *ATy = dyn_cast<ArrayType>(split.first); + 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 = getQualifiedType(ATy->getElementType(), Qs); + QualType NewEltTy = getQualifiedType(ATy->getElementType(), qs); if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(ATy)) return cast<ArrayType>(getConstantArrayType(NewEltTy, CAT->getSize(), @@ -3054,20 +3018,22 @@ QualType ASTContext::getArrayDecayedType(QualType Ty) const { return getQualifiedType(PtrTy, PrettyArrayType->getIndexTypeQualifiers()); } -QualType ASTContext::getBaseElementType(QualType QT) const { - QualifierCollector Qs; - while (const ArrayType *AT = getAsArrayType(QualType(Qs.strip(QT), 0))) - QT = AT->getElementType(); - return Qs.apply(*this, QT); +QualType ASTContext::getBaseElementType(const ArrayType *array) const { + return getBaseElementType(array->getElementType()); } -QualType ASTContext::getBaseElementType(const ArrayType *AT) const { - QualType ElemTy = AT->getElementType(); +QualType ASTContext::getBaseElementType(QualType type) const { + Qualifiers qs; + while (true) { + SplitQualType split = type.getSplitDesugaredType(); + const ArrayType *array = split.first->getAsArrayTypeUnsafe(); + if (!array) break; - if (const ArrayType *AT = getAsArrayType(ElemTy)) - return getBaseElementType(AT); + type = array->getElementType(); + qs.addConsistentQualifiers(split.second); + } - return ElemTy; + return getQualifiedType(type, qs); } /// getConstantArrayElementCount - Returns number of constant array elements. diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index f69c38f4ab..d8939cc123 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -1414,8 +1414,8 @@ public: // If this type is non-canonical, ask its canonical type for the // relevant information. - if (QualType(T, 0) != T->CanonicalType) { - const Type *CT = T->CanonicalType.getTypePtr(); + if (!T->isCanonicalUnqualified()) { + const Type *CT = T->getCanonicalTypeInternal().getTypePtr(); ensure(CT); T->TypeBits.CacheValidAndVisibility = CT->TypeBits.CacheValidAndVisibility; @@ -1556,3 +1556,21 @@ void Type::ClearLinkageCache() { if (QualType(this, 0) != CanonicalType) CanonicalType->TypeBits.CacheValidAndVisibility = 0; } + +bool Type::hasSizedVLAType() const { + if (!isVariablyModifiedType()) return false; + + if (const PointerType *ptr = getAs<PointerType>()) + return ptr->getPointeeType()->hasSizedVLAType(); + if (const ReferenceType *ref = getAs<ReferenceType>()) + return ref->getPointeeType()->hasSizedVLAType(); + if (const ArrayType *arr = getAsArrayTypeUnsafe()) { + if (isa<VariableArrayType>(arr) && + cast<VariableArrayType>(arr)->getSizeExpr()) + return true; + + return arr->getElementType()->hasSizedVLAType(); + } + + return false; +} diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index 06a34c22c5..a1b09d91f2 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -4461,17 +4461,17 @@ BuiltinCandidateTypeSet::AddTypesConvertedFrom(QualType Ty, if (const ReferenceType *RefTy = Ty->getAs<ReferenceType>()) Ty = RefTy->getPointeeType(); - // We don't care about qualifiers on the type. + // If we're dealing with an array type, decay to the pointer. + if (Ty->isArrayType()) + Ty = SemaRef.Context.getArrayDecayedType(Ty); + + // Otherwise, we don't care about qualifiers on the type. Ty = Ty.getLocalUnqualifiedType(); // Flag if we ever add a non-record type. const RecordType *TyRec = Ty->getAs<RecordType>(); HasNonRecordTypes = HasNonRecordTypes || !TyRec; - // If we're dealing with an array type, decay to the pointer. - if (Ty->isArrayType()) - Ty = SemaRef.Context.getArrayDecayedType(Ty); - // Flag if we encounter an arithmetic type. HasArithmeticOrEnumeralTypes = HasArithmeticOrEnumeralTypes || Ty->isArithmeticType(); diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index fbf5638f33..ebc34d0f35 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -3380,33 +3380,36 @@ TreeTransform<Derived>::TransformDependentSizedArrayType(TypeLocBuilder &TLB, // Array bounds are not potentially evaluated contexts EnterExpressionEvaluationContext Unevaluated(SemaRef, Sema::Unevaluated); - ExprResult SizeResult - = getDerived().TransformExpr(T->getSizeExpr()); - if (SizeResult.isInvalid()) + // Prefer the expression from the TypeLoc; the other may have been uniqued. + Expr *origSize = TL.getSizeExpr(); + if (!origSize) origSize = T->getSizeExpr(); + + ExprResult sizeResult + = getDerived().TransformExpr(origSize); + if (sizeResult.isInvalid()) return QualType(); - Expr *Size = static_cast<Expr*>(SizeResult.get()); + Expr *size = sizeResult.get(); QualType Result = TL.getType(); if (getDerived().AlwaysRebuild() || ElementType != T->getElementType() || - Size != T->getSizeExpr()) { + size != origSize) { Result = getDerived().RebuildDependentSizedArrayType(ElementType, T->getSizeModifier(), - Size, + size, T->getIndexTypeCVRQualifiers(), TL.getBracketsRange()); if (Result.isNull()) return QualType(); } - else SizeResult.take(); // We might have any sort of array type now, but fortunately they // all have the same location layout. ArrayTypeLoc NewTL = TLB.push<ArrayTypeLoc>(Result); NewTL.setLBracketLoc(TL.getLBracketLoc()); NewTL.setRBracketLoc(TL.getRBracketLoc()); - NewTL.setSizeExpr(Size); + NewTL.setSizeExpr(size); return Result; } diff --git a/test/Sema/typedef-retain.c b/test/Sema/typedef-retain.c index 5b963c48b2..a7173b7877 100644 --- a/test/Sema/typedef-retain.c +++ b/test/Sema/typedef-retain.c @@ -24,15 +24,3 @@ int test4(const a y) { y[0] = 10; // expected-error {{read-only variable is not assignable}} } -// PR2189 -int test5() { - const int s[5]; int t[5]; - return &s == &t; // expected-warning {{comparison of distinct pointer types}} -} - -int test6() { - const a s; - a t; - return &s == &t; // expected-warning {{comparison of distinct pointer types}} -} -