/// 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();
/// \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);
class TemplateArgumentLoc;
class TemplateArgumentListInfo;
class ElaboratedType;
+ class ExtQuals;
+ class ExtQualsTypeCommonBase;
struct PrintingPolicy;
template <typename> class CanQual;
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,
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() {}
///
/// 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) {
/// \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;
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.
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
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;
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;
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):
/// \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;
// 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.
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.
// 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 {
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);
}
/// 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) {
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
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);
+ 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);
}
- // Incomplete or function types default to 1.
- while (isa<VariableArrayType>(T) || isa<IncompleteArrayType>(T))
- T = cast<ArrayType>(T)->getElementType();
-
Align = std::max(Align, getPreferredTypeAlign(T.getTypePtr()));
}
if (const FieldDecl *FD = dyn_cast<FieldDecl>(VD)) {
//===----------------------------------------------------------------------===//
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
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);
}
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);
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);
/// 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;
- llvm::FoldingSetNodeID ID;
-
- 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);
-
- Canon = DependentSizedArrayTypes.FindNodeOrInsertPos(ID, InsertPos);
+ // 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);
}
- DependentSizedArrayType *New;
- if (Canon) {
- // We already have a canonical version of this array type; use it as
- // the canonical type for a newly-built type.
- New = new (*this, TypeAlignment)
- DependentSizedArrayType(*this, EltTy, QualType(Canon, 0),
- NumElts, ASM, EltTypeQuals, Brackets);
- } else if (CanonicalEltTy == EltTy) {
- // This is a canonical type. Record it.
- New = new (*this, TypeAlignment)
- DependentSizedArrayType(*this, EltTy, QualType(),
- NumElts, ASM, EltTypeQuals, Brackets);
-
- if (NumElts) {
-#ifndef NDEBUG
- DependentSizedArrayType *CanonCheck
- = DependentSizedArrayTypes.FindNodeOrInsertPos(ID, InsertPos);
- assert(!CanonCheck && "Dependent-sized canonical array type broken");
- (void)CanonCheck;
-#endif
- DependentSizedArrayTypes.InsertNode(New, InsertPos);
- }
- } else {
- QualType Canon = getDependentSizedArrayType(CanonicalEltTy, NumElts,
- ASM, EltTypeQuals,
- SourceRange());
- New = new (*this, TypeAlignment)
- DependentSizedArrayType(*this, EltTy, Canon,
- NumElts, ASM, EltTypeQuals, Brackets);
- }
+ // Otherwise, we actually build a new type every time, but we
+ // also build a canonical type.
- Types.push_back(New);
- return QualType(New, 0);
-}
+ SplitQualType canonElementType = getCanonicalType(elementType).split();
-QualType ASTContext::getIncompleteArrayType(QualType EltTy,
+ void *insertPos = 0;
+ llvm::FoldingSetNodeID ID;
+ DependentSizedArrayType::Profile(ID, *this,
+ QualType(canonElementType.first, 0),
+ ASM, elementTypeQuals, numElements);
+
+ // Look for an existing type with these properties.
+ DependentSizedArrayType *canonTy =
+ 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);
+ }
+
+ // Apply qualifiers from the element type to the array.
+ QualType canon = getQualifiedType(QualType(canonTy,0),
+ canonElementType.second);
+
+ // If we didn't need extra canonicalization for the element type,
+ // then just use that as our result.
+ if (QualType(canonElementType.first, 0) == elementType)
+ return canon;
+
+ // Otherwise, we need to build a type which follows the spelling
+ // of the element type.
+ DependentSizedArrayType *sugaredType
+ = new (*this, TypeAlignment)
+ DependentSizedArrayType(*this, elementType, canon, numElements,
+ ASM, elementTypeQuals, brackets);
+ Types.push_back(sugaredType);
+ return QualType(sugaredType, 0);
+}
+
+QualType ASTContext::getIncompleteArrayType(QualType 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;
/// 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;
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) {
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:
}
// 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
// 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(),
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.
// 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;
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;
+}
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();
// 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;
}
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}}
-}
-