Change the canonical representation of array types to store qualifiers on the

outermost array types and not on the element type.  Move the CanonicalType
member from Type to ExtQualsTypeCommonBase;  the canonical type on an ExtQuals
node includes the qualifiers on the ExtQuals.  Assorted optimizations enabled
by this change.

getQualifiers(), hasQualifiers(), etc. should all now implicitly look through
array types.

llvm-svn: 123817
This commit is contained in:
John McCall 2011-01-19 10:06:00 +00:00
parent e8231f41aa
commit 33ddac05bb
7 changed files with 392 additions and 427 deletions

View File

@ -1091,7 +1091,9 @@ public:
/// include typedefs, 'typeof' operators, etc. The returned type is guaranteed /// include typedefs, 'typeof' operators, etc. The returned type is guaranteed
/// to be free of any of these, allowing two canonical types to be compared /// to be free of any of these, allowing two canonical types to be compared
/// for exact equality with a simple pointer comparison. /// 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 { const Type *getCanonicalType(const Type *T) const {
return T->getCanonicalTypeInternal().getTypePtr(); return T->getCanonicalTypeInternal().getTypePtr();
@ -1125,13 +1127,8 @@ public:
/// \brief Determine whether the given types are equivalent after /// \brief Determine whether the given types are equivalent after
/// cvr-qualifiers have been removed. /// cvr-qualifiers have been removed.
bool hasSameUnqualifiedType(QualType T1, QualType T2) { bool hasSameUnqualifiedType(QualType T1, QualType T2) {
CanQualType CT1 = getCanonicalType(T1); return getCanonicalType(T1).getTypePtr() ==
CanQualType CT2 = getCanonicalType(T2); getCanonicalType(T2).getTypePtr();
Qualifiers Quals;
QualType UnqualT1 = getUnqualifiedArrayType(CT1, Quals);
QualType UnqualT2 = getUnqualifiedArrayType(CT2, Quals);
return UnqualT1 == UnqualT2;
} }
bool UnwrapSimilarPointerTypes(QualType &T1, QualType &T2); bool UnwrapSimilarPointerTypes(QualType &T1, QualType &T2);

View File

@ -94,6 +94,8 @@ namespace clang {
class TemplateArgumentLoc; class TemplateArgumentLoc;
class TemplateArgumentListInfo; class TemplateArgumentListInfo;
class ElaboratedType; class ElaboratedType;
class ExtQuals;
class ExtQualsTypeCommonBase;
struct PrintingPolicy; struct PrintingPolicy;
template <typename> class CanQual; template <typename> class CanQual;
@ -345,85 +347,6 @@ private:
static const uint32_t AddressSpaceShift = 5; 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. /// CallingConv - Specifies the calling convention that a function uses.
enum CallingConv { enum CallingConv {
CC_Default, CC_Default,
@ -461,6 +384,14 @@ class QualType {
return Value.getPointer().get<const Type*>(); 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; friend class QualifierCollector;
public: public:
QualType() {} QualType() {}
@ -479,36 +410,13 @@ public:
/// ///
/// This function requires that the type not be NULL. If the type might be /// This function requires that the type not be NULL. If the type might be
/// NULL, use the (slightly less efficient) \c getTypePtrOrNull(). /// NULL, use the (slightly less efficient) \c getTypePtrOrNull().
const Type *getTypePtr() const { 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 *getTypePtrOrNull() 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;
}
/// Divides a QualType into its unqualified type and a set of local /// Divides a QualType into its unqualified type and a set of local
/// qualifiers. /// qualifiers.
SplitQualType split() const { 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);
}
void *getAsOpaquePtr() const { return Value.getOpaqueValue(); } void *getAsOpaquePtr() const { return Value.getOpaqueValue(); }
static QualType getFromOpaquePtr(const void *Ptr) { static QualType getFromOpaquePtr(const void *Ptr) {
@ -583,13 +491,7 @@ public:
/// \brief Retrieve the set of qualifiers local to this particular QualType /// \brief Retrieve the set of qualifiers local to this particular QualType
/// instance, not including any qualifiers acquired through typedefs or /// instance, not including any qualifiers acquired through typedefs or
/// other sugar. /// other sugar.
Qualifiers getLocalQualifiers() const { Qualifiers getLocalQualifiers() const;
Qualifiers Quals;
if (hasLocalNonFastQualifiers())
Quals = getExtQualsUnsafe()->getQualifiers();
Quals.addFastQualifiers(getLocalFastQualifiers());
return Quals;
}
/// \brief Retrieve the set of qualifiers applied to this type. /// \brief Retrieve the set of qualifiers applied to this type.
Qualifiers getQualifiers() const; Qualifiers getQualifiers() const;
@ -658,6 +560,8 @@ public:
return T; return T;
} }
QualType getCanonicalType() const;
/// \brief Return this type with all of the instance-specific qualifiers /// \brief Return this type with all of the instance-specific qualifiers
/// removed, but without removing any qualifiers that may have been applied /// removed, but without removing any qualifiers that may have been applied
/// through typedefs. /// through typedefs.
@ -831,6 +735,94 @@ public:
namespace clang { 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 /// 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 /// 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 /// 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. Type(const Type&); // DO NOT IMPLEMENT.
void operator=(const Type&); // DO NOT IMPLEMENT. void operator=(const Type&); // DO NOT IMPLEMENT.
QualType CanonicalType;
/// Bitfields required by the Type class. /// Bitfields required by the Type class.
class TypeBitfields { class TypeBitfields {
friend class Type; friend class Type;
@ -1060,10 +1050,10 @@ private:
protected: protected:
// silence VC++ warning C4355: 'this' : used in base member initializer list // silence VC++ warning C4355: 'this' : used in base member initializer list
Type *this_() { return this; } Type *this_() { return this; }
Type(TypeClass tc, QualType Canonical, bool Dependent, bool VariablyModified, Type(TypeClass tc, QualType canon, bool Dependent, bool VariablyModified,
bool ContainsUnexpandedParameterPack) bool ContainsUnexpandedParameterPack)
: ExtQualsTypeCommonBase(this), : ExtQualsTypeCommonBase(this,
CanonicalType(Canonical.isNull() ? QualType(this_(), 0) : Canonical) { canon.isNull() ? QualType(this_(), 0) : canon) {
TypeBits.TC = tc; TypeBits.TC = tc;
TypeBits.Dependent = Dependent; TypeBits.Dependent = Dependent;
TypeBits.VariablyModified = VariablyModified; TypeBits.VariablyModified = VariablyModified;
@ -1106,8 +1096,10 @@ public:
return TypeBits.ContainsUnexpandedParameterPack; return TypeBits.ContainsUnexpandedParameterPack;
} }
/// Determines if this type would be canonical if it had no further
/// qualification.
bool isCanonicalUnqualified() const { bool isCanonicalUnqualified() const {
return CanonicalType.getTypePtr() == this; return CanonicalType == QualType(this, 0);
} }
/// Types are partitioned into 3 broad categories (C99 6.2.5p1): /// Types are partitioned into 3 broad categories (C99 6.2.5p1):
@ -1249,6 +1241,10 @@ public:
/// \brief Whether this type is a variably-modified type (C99 6.7.5). /// \brief Whether this type is a variably-modified type (C99 6.7.5).
bool isVariablyModifiedType() const { return TypeBits.VariablyModified; } 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. /// \brief Whether this type is or contains a local or unnamed type.
bool hasUnnamedOrLocalType() const; bool hasUnnamedOrLocalType() const;
@ -1310,6 +1306,10 @@ public:
// immediately following this class. // immediately following this class.
template <typename T> const T *getAs() const; 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 /// getArrayElementTypeNoTypeQual - If this is an array type, return the
/// element type of the array, potentially with type qualifiers missing. /// element type of the array, potentially with type qualifiers missing.
/// This method should never be used when type qualifiers are meaningful. /// This method should never be used when type qualifiers are meaningful.
@ -3795,15 +3795,16 @@ public:
QualifierCollector(Qualifiers Qs = Qualifiers()) : Qualifiers(Qs) {} QualifierCollector(Qualifiers Qs = Qualifiers()) : Qualifiers(Qs) {}
/// Collect any qualifiers on the given type and return an /// Collect any qualifiers on the given type and return an
/// unqualified type. /// unqualified type. The qualifiers are assumed to be consistent
const Type *strip(QualType QT) { /// with those already in the type.
addFastQualifiers(QT.getLocalFastQualifiers()); const Type *strip(QualType type) {
if (QT.hasLocalNonFastQualifiers()) { addFastQualifiers(type.getLocalFastQualifiers());
const ExtQuals *EQ = QT.getExtQualsUnsafe(); if (!type.hasLocalNonFastQualifiers())
addQualifiers(EQ->getQualifiers()); return type.getTypePtrUnsafe();
return EQ->getBaseType();
} const ExtQuals *extQuals = type.getExtQualsUnsafe();
return QT.getTypePtrUnsafe(); addConsistentQualifiers(extQuals->getQualifiers());
return extQuals->getBaseType();
} }
/// Apply the collected qualifiers to the given type. /// Apply the collected qualifiers to the given type.
@ -3816,49 +3817,84 @@ public:
// Inline function definitions. // 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 { inline bool QualType::isCanonical() const {
const Type *T = getTypePtr(); return getTypePtr()->isCanonicalUnqualified();
if (hasLocalQualifiers())
return T->isCanonicalUnqualified() && !isa<ArrayType>(T);
return T->isCanonicalUnqualified();
} }
inline bool QualType::isCanonicalAsParam() const { inline bool QualType::isCanonicalAsParam() const {
if (!isCanonical()) return false;
if (hasLocalQualifiers()) return false; if (hasLocalQualifiers()) return false;
const Type *T = getTypePtr(); const Type *T = getTypePtr();
if ((*this)->isPointerType()) { if (T->isVariablyModifiedType() && T->hasSizedVLAType())
QualType BaseType = (*this)->getAs<PointerType>()->getPointeeType(); return false;
if (isa<VariableArrayType>(BaseType)) {
const ArrayType *AT = dyn_cast<ArrayType>(BaseType); return !isa<FunctionType>(T) && !isa<ArrayType>(T);
const VariableArrayType *VAT = cast<VariableArrayType>(AT);
if (VAT->getSizeExpr())
T = BaseType.getTypePtr();
}
}
return T->isCanonicalUnqualified() &&
!isa<FunctionType>(T) && !isa<ArrayType>(T);
} }
inline bool QualType::isConstQualified() const { inline bool QualType::isConstQualified() const {
return isLocalConstQualified() || return isLocalConstQualified() ||
getTypePtr()->getCanonicalTypeInternal().isLocalConstQualified(); getCommonPtr()->CanonicalType.isLocalConstQualified();
} }
inline bool QualType::isRestrictQualified() const { inline bool QualType::isRestrictQualified() const {
return isLocalRestrictQualified() || return isLocalRestrictQualified() ||
getTypePtr()->getCanonicalTypeInternal().isLocalRestrictQualified(); getCommonPtr()->CanonicalType.isLocalRestrictQualified();
} }
inline bool QualType::isVolatileQualified() const { inline bool QualType::isVolatileQualified() const {
return isLocalVolatileQualified() || return isLocalVolatileQualified() ||
getTypePtr()->getCanonicalTypeInternal().isLocalVolatileQualified(); getCommonPtr()->CanonicalType.isLocalVolatileQualified();
} }
inline bool QualType::hasQualifiers() const { inline bool QualType::hasQualifiers() const {
return hasLocalQualifiers() || return hasLocalQualifiers() ||
getTypePtr()->getCanonicalTypeInternal().hasLocalQualifiers(); getCommonPtr()->CanonicalType.hasLocalQualifiers();
} }
inline QualType QualType::getUnqualifiedType() const { inline QualType QualType::getUnqualifiedType() const {
@ -3875,33 +3911,6 @@ inline SplitQualType QualType::getSplitUnqualifiedType() const {
return getSplitUnqualifiedTypeImpl(*this); 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() { inline void QualType::removeLocalConst() {
removeLocalFastQualifiers(Qualifiers::Const); removeLocalFastQualifiers(Qualifiers::Const);
} }
@ -3924,42 +3933,12 @@ inline void QualType::removeLocalCVRQualifiers(unsigned Mask) {
/// getAddressSpace - Return the address space of this type. /// getAddressSpace - Return the address space of this type.
inline unsigned QualType::getAddressSpace() const { inline unsigned QualType::getAddressSpace() const {
if (hasLocalNonFastQualifiers()) { return getQualifiers().getAddressSpace();
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;
} }
/// getObjCGCAttr - Return the gc attribute of this type. /// getObjCGCAttr - Return the gc attribute of this type.
inline Qualifiers::GC QualType::getObjCGCAttr() const { inline Qualifiers::GC QualType::getObjCGCAttr() const {
if (hasLocalNonFastQualifiers()) { return getQualifiers().getObjCGCAttr();
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;
} }
inline FunctionType::ExtInfo getFunctionExtInfo(const Type &t) { inline FunctionType::ExtInfo getFunctionExtInfo(const Type &t) {
@ -4209,6 +4188,20 @@ template <typename T> const T *Type::getAs() const {
return cast<T>(getUnqualifiedDesugaredType()); 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 } // end namespace clang
#endif #endif

View File

@ -569,19 +569,20 @@ CharUnits ASTContext::getDeclAlign(const Decl *D, bool RefAsPointee) const {
T = getPointerType(RT->getPointeeType()); T = getPointerType(RT->getPointeeType());
} }
if (!T->isIncompleteType() && !T->isFunctionType()) { 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 MinWidth = Target.getLargeArrayMinWidth();
unsigned ArrayAlign = Target.getLargeArrayAlign(); const ArrayType *arrayType;
if (isa<VariableArrayType>(T) && MinWidth != 0) if (MinWidth && (arrayType = getAsArrayType(T))) {
Align = std::max(Align, ArrayAlign); if (isa<VariableArrayType>(arrayType))
if (const ConstantArrayType *CT = dyn_cast<ConstantArrayType>(T)) { Align = std::max(Align, Target.getLargeArrayAlign());
unsigned Size = getTypeSize(CT); else if (isa<ConstantArrayType>(arrayType) &&
if (MinWidth != 0 && MinWidth <= Size) MinWidth <= getTypeSize(cast<ConstantArrayType>(arrayType)))
Align = std::max(Align, ArrayAlign); Align = std::max(Align, Target.getLargeArrayAlign());
}
// Incomplete or function types default to 1.
while (isa<VariableArrayType>(T) || isa<IncompleteArrayType>(T))
T = cast<ArrayType>(T)->getElementType();
// Walk through any array types while we're at it.
T = getBaseElementType(arrayType);
}
Align = std::max(Align, getPreferredTypeAlign(T.getTypePtr())); Align = std::max(Align, getPreferredTypeAlign(T.getTypePtr()));
} }
if (const FieldDecl *FD = dyn_cast<FieldDecl>(VD)) { if (const FieldDecl *FD = dyn_cast<FieldDecl>(VD)) {
@ -1092,24 +1093,33 @@ ASTContext::getASTObjCImplementationLayout(
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
QualType QualType
ASTContext::getExtQualType(const Type *TypeNode, Qualifiers Quals) const { ASTContext::getExtQualType(const Type *baseType, Qualifiers quals) const {
unsigned Fast = Quals.getFastQualifiers(); unsigned fastQuals = quals.getFastQualifiers();
Quals.removeFastQualifiers(); quals.removeFastQualifiers();
// Check if we've already instantiated this type. // Check if we've already instantiated this type.
llvm::FoldingSetNodeID ID; llvm::FoldingSetNodeID ID;
ExtQuals::Profile(ID, TypeNode, Quals); ExtQuals::Profile(ID, baseType, quals);
void *InsertPos = 0; void *insertPos = 0;
if (ExtQuals *EQ = ExtQualNodes.FindNodeOrInsertPos(ID, InsertPos)) { if (ExtQuals *eq = ExtQualNodes.FindNodeOrInsertPos(ID, insertPos)) {
assert(EQ->getQualifiers() == Quals); assert(eq->getQualifiers() == quals);
QualType T = QualType(EQ, Fast); return QualType(eq, fastQuals);
return T;
} }
ExtQuals *New = new (*this, TypeAlignment) ExtQuals(TypeNode, Quals); // If the base type is not canonical, make the appropriate canonical type.
ExtQualNodes.InsertNode(New, InsertPos); QualType canon;
QualType T = QualType(New, Fast); if (!baseType->isCanonicalUnqualified()) {
return T; 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 QualType
@ -1395,12 +1405,15 @@ QualType ASTContext::getConstantArrayType(QualType EltTy,
ConstantArrayTypes.FindNodeOrInsertPos(ID, InsertPos)) ConstantArrayTypes.FindNodeOrInsertPos(ID, InsertPos))
return QualType(ATP, 0); return QualType(ATP, 0);
// If the element type isn't canonical, this won't be a canonical type either, // If the element type isn't canonical or has qualifiers, this won't
// so fill in the canonical type field. // be a canonical type either, so fill in the canonical type field.
QualType Canonical; QualType Canon;
if (!EltTy.isCanonical()) { if (!EltTy.isCanonical() || EltTy.hasLocalQualifiers()) {
Canonical = getConstantArrayType(getCanonicalType(EltTy), ArySize, SplitQualType canonSplit = getCanonicalType(EltTy).split();
ASM, EltTypeQuals); 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. // Get the new insert position for the node we care about.
ConstantArrayType *NewIP = ConstantArrayType *NewIP =
ConstantArrayTypes.FindNodeOrInsertPos(ID, InsertPos); ConstantArrayTypes.FindNodeOrInsertPos(ID, InsertPos);
@ -1408,7 +1421,7 @@ QualType ASTContext::getConstantArrayType(QualType EltTy,
} }
ConstantArrayType *New = new(*this,TypeAlignment) ConstantArrayType *New = new(*this,TypeAlignment)
ConstantArrayType(EltTy, Canonical, ArySize, ASM, EltTypeQuals); ConstantArrayType(EltTy, Canon, ArySize, ASM, EltTypeQuals);
ConstantArrayTypes.InsertNode(New, InsertPos); ConstantArrayTypes.InsertNode(New, InsertPos);
Types.push_back(New); Types.push_back(New);
return QualType(New, 0); return QualType(New, 0);
@ -1547,15 +1560,18 @@ QualType ASTContext::getVariableArrayType(QualType EltTy,
SourceRange Brackets) const { SourceRange Brackets) const {
// Since we don't unique expressions, it isn't possible to unique VLA's // Since we don't unique expressions, it isn't possible to unique VLA's
// that have an expression provided for their size. // that have an expression provided for their size.
QualType CanonType; QualType Canon;
if (!EltTy.isCanonical()) { // Be sure to pull qualifiers off the element type.
CanonType = getVariableArrayType(getCanonicalType(EltTy), NumElts, ASM, if (!EltTy.isCanonical() || EltTy.hasLocalQualifiers()) {
EltTypeQuals, Brackets); 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 *New = new(*this, TypeAlignment)
VariableArrayType(EltTy, CanonType, NumElts, ASM, EltTypeQuals, Brackets); VariableArrayType(EltTy, Canon, NumElts, ASM, EltTypeQuals, Brackets);
VariableArrayTypes.push_back(New); VariableArrayTypes.push_back(New);
Types.push_back(New); Types.push_back(New);
@ -1565,106 +1581,114 @@ QualType ASTContext::getVariableArrayType(QualType EltTy,
/// getDependentSizedArrayType - Returns a non-unique reference to /// getDependentSizedArrayType - Returns a non-unique reference to
/// the type for a dependently-sized array of the specified element /// the type for a dependently-sized array of the specified element
/// type. /// type.
QualType ASTContext::getDependentSizedArrayType(QualType EltTy, QualType ASTContext::getDependentSizedArrayType(QualType elementType,
Expr *NumElts, Expr *numElements,
ArrayType::ArraySizeModifier ASM, ArrayType::ArraySizeModifier ASM,
unsigned EltTypeQuals, unsigned elementTypeQuals,
SourceRange Brackets) const { SourceRange brackets) const {
assert((!NumElts || NumElts->isTypeDependent() || assert((!numElements || numElements->isTypeDependent() ||
NumElts->isValueDependent()) && numElements->isValueDependent()) &&
"Size must be type- or value-dependent!"); "Size must be type- or value-dependent!");
void *InsertPos = 0; // Dependently-sized array types that do not have a specified number
DependentSizedArrayType *Canon = 0; // 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; llvm::FoldingSetNodeID ID;
DependentSizedArrayType::Profile(ID, *this,
QualType(canonElementType.first, 0),
ASM, elementTypeQuals, numElements);
QualType CanonicalEltTy = getCanonicalType(EltTy); // Look for an existing type with these properties.
if (NumElts) { DependentSizedArrayType *canonTy =
// Dependently-sized array types that do not have a specified DependentSizedArrayTypes.FindNodeOrInsertPos(ID, insertPos);
// number of elements will have their sizes deduced from an
// initializer.
DependentSizedArrayType::Profile(ID, *this, CanonicalEltTy, ASM,
EltTypeQuals, NumElts);
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; // Apply qualifiers from the element type to the array.
if (Canon) { QualType canon = getQualifiedType(QualType(canonTy,0),
// We already have a canonical version of this array type; use it as canonElementType.second);
// 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) { // If we didn't need extra canonicalization for the element type,
#ifndef NDEBUG // then just use that as our result.
DependentSizedArrayType *CanonCheck if (QualType(canonElementType.first, 0) == elementType)
= DependentSizedArrayTypes.FindNodeOrInsertPos(ID, InsertPos); return canon;
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);
}
Types.push_back(New); // Otherwise, we need to build a type which follows the spelling
return QualType(New, 0); // 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, ArrayType::ArraySizeModifier ASM,
unsigned EltTypeQuals) const { unsigned elementTypeQuals) const {
llvm::FoldingSetNodeID ID; llvm::FoldingSetNodeID ID;
IncompleteArrayType::Profile(ID, EltTy, ASM, EltTypeQuals); IncompleteArrayType::Profile(ID, elementType, ASM, elementTypeQuals);
void *InsertPos = 0; void *insertPos = 0;
if (IncompleteArrayType *ATP = if (IncompleteArrayType *iat =
IncompleteArrayTypes.FindNodeOrInsertPos(ID, InsertPos)) IncompleteArrayTypes.FindNodeOrInsertPos(ID, insertPos))
return QualType(ATP, 0); return QualType(iat, 0);
// If the element type isn't canonical, this won't be a canonical type // If the element type isn't canonical, this won't be a canonical type
// either, so fill in the canonical type field. // either, so fill in the canonical type field. We also have to pull
QualType Canonical; // qualifiers off the element type.
QualType canon;
if (!EltTy.isCanonical()) { if (!elementType.isCanonical() || elementType.hasLocalQualifiers()) {
Canonical = getIncompleteArrayType(getCanonicalType(EltTy), SplitQualType canonSplit = getCanonicalType(elementType).split();
ASM, EltTypeQuals); canon = getIncompleteArrayType(QualType(canonSplit.first, 0),
ASM, elementTypeQuals);
canon = getQualifiedType(canon, canonSplit.second);
// Get the new insert position for the node we care about. // Get the new insert position for the node we care about.
IncompleteArrayType *NewIP = IncompleteArrayType *existing =
IncompleteArrayTypes.FindNodeOrInsertPos(ID, InsertPos); IncompleteArrayTypes.FindNodeOrInsertPos(ID, insertPos);
assert(NewIP == 0 && "Shouldn't be in the map!"); (void)NewIP; assert(!existing && "Shouldn't be in the map!"); (void) existing;
} }
IncompleteArrayType *New = new (*this, TypeAlignment) IncompleteArrayType *newType = new (*this, TypeAlignment)
IncompleteArrayType(EltTy, Canonical, ASM, EltTypeQuals); IncompleteArrayType(elementType, canon, ASM, elementTypeQuals);
IncompleteArrayTypes.InsertNode(New, InsertPos); IncompleteArrayTypes.InsertNode(newType, insertPos);
Types.push_back(New); Types.push_back(newType);
return QualType(New, 0); return QualType(newType, 0);
} }
/// getVectorType - Return the unique reference to a vector type of /// getVectorType - Return the unique reference to a vector type of
/// the specified element type and size. VectorType must be a built-in type. /// the specified element type and size. VectorType must be a built-in type.
QualType ASTContext::getVectorType(QualType vecType, unsigned NumElts, QualType ASTContext::getVectorType(QualType vecType, unsigned NumElts,
VectorType::VectorKind VecKind) const { VectorType::VectorKind VecKind) const {
const BuiltinType *BaseType; assert(vecType->isBuiltinType());
BaseType = dyn_cast<BuiltinType>(getCanonicalType(vecType).getTypePtr());
assert(BaseType != 0 && "getVectorType(): Expecting a built-in type");
// Check if we've already instantiated a vector of this type. // Check if we've already instantiated a vector of this type.
llvm::FoldingSetNodeID ID; 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. /// the specified element type and size. VectorType must be a built-in type.
QualType QualType
ASTContext::getExtVectorType(QualType vecType, unsigned NumElts) const { ASTContext::getExtVectorType(QualType vecType, unsigned NumElts) const {
const BuiltinType *baseType; assert(vecType->isBuiltinType());
baseType = dyn_cast<BuiltinType>(getCanonicalType(vecType).getTypePtr());
assert(baseType != 0 && "getExtVectorType(): Expecting a built-in type");
// Check if we've already instantiated a vector of this type. // Check if we've already instantiated a vector of this type.
llvm::FoldingSetNodeID ID; llvm::FoldingSetNodeID ID;
@ -2651,61 +2672,6 @@ CanQualType ASTContext::getCanonicalParamType(QualType T) const {
return CanQualType::CreateUnsafe(Result); 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, QualType ASTContext::getUnqualifiedArrayType(QualType type,
Qualifiers &quals) { Qualifiers &quals) {
@ -2960,7 +2926,8 @@ ASTContext::getCanonicalNestedNameSpecifier(NestedNameSpecifier *NNS) const {
T = getCanonicalType(T); 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: case NestedNameSpecifier::Global:
@ -2982,8 +2949,7 @@ const ArrayType *ASTContext::getAsArrayType(QualType T) const {
} }
// Handle the common negative case fast. // Handle the common negative case fast.
QualType CType = T->getCanonicalTypeInternal(); if (!isa<ArrayType>(T.getCanonicalType()))
if (!isa<ArrayType>(CType))
return 0; return 0;
// Apply any qualifiers from the array type to the element type. This // 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 // 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. // we must propagate them down into the element type.
QualifierCollector Qs; SplitQualType split = T.getSplitDesugaredType();
const Type *Ty = Qs.strip(T.getDesugaredType(*this)); Qualifiers qs = split.second;
// If we have a simple case, just return now. // If we have a simple case, just return now.
const ArrayType *ATy = dyn_cast<ArrayType>(Ty); const ArrayType *ATy = dyn_cast<ArrayType>(split.first);
if (ATy == 0 || Qs.empty()) if (ATy == 0 || qs.empty())
return ATy; return ATy;
// Otherwise, we have an array and we have qualifiers on it. Push the // 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. // 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. QualType NewEltTy = getQualifiedType(ATy->getElementType(), qs);
// This can recursively sink qualifiers through multiple levels of arrays.
QualType NewEltTy = getQualifiedType(ATy->getElementType(), Qs);
if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(ATy)) if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(ATy))
return cast<ArrayType>(getConstantArrayType(NewEltTy, CAT->getSize(), return cast<ArrayType>(getConstantArrayType(NewEltTy, CAT->getSize(),
@ -3054,20 +3018,22 @@ QualType ASTContext::getArrayDecayedType(QualType Ty) const {
return getQualifiedType(PtrTy, PrettyArrayType->getIndexTypeQualifiers()); return getQualifiedType(PtrTy, PrettyArrayType->getIndexTypeQualifiers());
} }
QualType ASTContext::getBaseElementType(QualType QT) const { QualType ASTContext::getBaseElementType(const ArrayType *array) const {
QualifierCollector Qs; return getBaseElementType(array->getElementType());
while (const ArrayType *AT = getAsArrayType(QualType(Qs.strip(QT), 0)))
QT = AT->getElementType();
return Qs.apply(*this, QT);
} }
QualType ASTContext::getBaseElementType(const ArrayType *AT) const { QualType ASTContext::getBaseElementType(QualType type) const {
QualType ElemTy = AT->getElementType(); Qualifiers qs;
while (true) {
SplitQualType split = type.getSplitDesugaredType();
const ArrayType *array = split.first->getAsArrayTypeUnsafe();
if (!array) break;
if (const ArrayType *AT = getAsArrayType(ElemTy)) type = array->getElementType();
return getBaseElementType(AT); qs.addConsistentQualifiers(split.second);
}
return ElemTy; return getQualifiedType(type, qs);
} }
/// getConstantArrayElementCount - Returns number of constant array elements. /// getConstantArrayElementCount - Returns number of constant array elements.

View File

@ -1414,8 +1414,8 @@ public:
// If this type is non-canonical, ask its canonical type for the // If this type is non-canonical, ask its canonical type for the
// relevant information. // relevant information.
if (QualType(T, 0) != T->CanonicalType) { if (!T->isCanonicalUnqualified()) {
const Type *CT = T->CanonicalType.getTypePtr(); const Type *CT = T->getCanonicalTypeInternal().getTypePtr();
ensure(CT); ensure(CT);
T->TypeBits.CacheValidAndVisibility = T->TypeBits.CacheValidAndVisibility =
CT->TypeBits.CacheValidAndVisibility; CT->TypeBits.CacheValidAndVisibility;
@ -1556,3 +1556,21 @@ void Type::ClearLinkageCache() {
if (QualType(this, 0) != CanonicalType) if (QualType(this, 0) != CanonicalType)
CanonicalType->TypeBits.CacheValidAndVisibility = 0; 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;
}

View File

@ -4461,17 +4461,17 @@ BuiltinCandidateTypeSet::AddTypesConvertedFrom(QualType Ty,
if (const ReferenceType *RefTy = Ty->getAs<ReferenceType>()) if (const ReferenceType *RefTy = Ty->getAs<ReferenceType>())
Ty = RefTy->getPointeeType(); 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(); Ty = Ty.getLocalUnqualifiedType();
// Flag if we ever add a non-record type. // Flag if we ever add a non-record type.
const RecordType *TyRec = Ty->getAs<RecordType>(); const RecordType *TyRec = Ty->getAs<RecordType>();
HasNonRecordTypes = HasNonRecordTypes || !TyRec; 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. // Flag if we encounter an arithmetic type.
HasArithmeticOrEnumeralTypes = HasArithmeticOrEnumeralTypes =
HasArithmeticOrEnumeralTypes || Ty->isArithmeticType(); HasArithmeticOrEnumeralTypes || Ty->isArithmeticType();

View File

@ -3380,33 +3380,36 @@ TreeTransform<Derived>::TransformDependentSizedArrayType(TypeLocBuilder &TLB,
// Array bounds are not potentially evaluated contexts // Array bounds are not potentially evaluated contexts
EnterExpressionEvaluationContext Unevaluated(SemaRef, Sema::Unevaluated); EnterExpressionEvaluationContext Unevaluated(SemaRef, Sema::Unevaluated);
ExprResult SizeResult // Prefer the expression from the TypeLoc; the other may have been uniqued.
= getDerived().TransformExpr(T->getSizeExpr()); Expr *origSize = TL.getSizeExpr();
if (SizeResult.isInvalid()) if (!origSize) origSize = T->getSizeExpr();
ExprResult sizeResult
= getDerived().TransformExpr(origSize);
if (sizeResult.isInvalid())
return QualType(); return QualType();
Expr *Size = static_cast<Expr*>(SizeResult.get()); Expr *size = sizeResult.get();
QualType Result = TL.getType(); QualType Result = TL.getType();
if (getDerived().AlwaysRebuild() || if (getDerived().AlwaysRebuild() ||
ElementType != T->getElementType() || ElementType != T->getElementType() ||
Size != T->getSizeExpr()) { size != origSize) {
Result = getDerived().RebuildDependentSizedArrayType(ElementType, Result = getDerived().RebuildDependentSizedArrayType(ElementType,
T->getSizeModifier(), T->getSizeModifier(),
Size, size,
T->getIndexTypeCVRQualifiers(), T->getIndexTypeCVRQualifiers(),
TL.getBracketsRange()); TL.getBracketsRange());
if (Result.isNull()) if (Result.isNull())
return QualType(); return QualType();
} }
else SizeResult.take();
// We might have any sort of array type now, but fortunately they // We might have any sort of array type now, but fortunately they
// all have the same location layout. // all have the same location layout.
ArrayTypeLoc NewTL = TLB.push<ArrayTypeLoc>(Result); ArrayTypeLoc NewTL = TLB.push<ArrayTypeLoc>(Result);
NewTL.setLBracketLoc(TL.getLBracketLoc()); NewTL.setLBracketLoc(TL.getLBracketLoc());
NewTL.setRBracketLoc(TL.getRBracketLoc()); NewTL.setRBracketLoc(TL.getRBracketLoc());
NewTL.setSizeExpr(Size); NewTL.setSizeExpr(size);
return Result; return Result;
} }

View File

@ -24,15 +24,3 @@ int test4(const a y) {
y[0] = 10; // expected-error {{read-only variable is not assignable}} 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}}
}