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.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@123817 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
John McCall 2011-01-19 10:06:00 +00:00
Родитель f4c7371fb1
Коммит 3b6575108a
7 изменённых файлов: 392 добавлений и 427 удалений

Просмотреть файл

@ -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);

Просмотреть файл

@ -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):
@ -1249,6 +1241,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

Просмотреть файл

@ -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);
// Apply qualifiers from the element type to the array.
QualType canon = getQualifiedType(QualType(canonTy,0),
canonElementType.second);
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);
}
// 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;
Types.push_back(New);
return QualType(New, 0);
// 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.

Просмотреть файл

@ -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;
}

Просмотреть файл

@ -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();

Просмотреть файл

@ -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;
}

Просмотреть файл

@ -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}}
}