Refactor the representation of qualifiers to bring ExtQualType out of the
Type hierarchy. Demote 'volatile' to extended-qualifier status. Audit our
use of qualifiers and fix a few places that weren't dealing with qualifiers
quite right; many more remain.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@82705 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index 8fe5852..a2a88af 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -59,6 +59,13 @@
}
{
+ llvm::FoldingSet<ExtQuals>::iterator
+ I = ExtQualNodes.begin(), E = ExtQualNodes.end();
+ while (I != E)
+ Deallocate(&*I++);
+ }
+
+ {
llvm::DenseMap<const RecordDecl*, const ASTRecordLayout*>::iterator
I = ASTRecordLayouts.begin(), E = ASTRecordLayouts.end();
while (I != E) {
@@ -525,6 +532,10 @@
/// getTypeSize - Return the size of the specified type, in bits. This method
/// does not work on incomplete types.
+///
+/// FIXME: Pointers into different addr spaces could have different sizes and
+/// alignment requirements: getPointerInfo should take an AddrSpace, this
+/// should take a QualType, &c.
std::pair<uint64_t, unsigned>
ASTContext::getTypeInfo(const Type *T) {
uint64_t Width=0;
@@ -656,10 +667,6 @@
Width = std::max(llvm::NextPowerOf2(Width - 1), (uint64_t)8);
Align = Width;
break;
- case Type::ExtQual:
- // FIXME: Pointers into different addr spaces could have different sizes and
- // alignment requirements: getPointerInfo should take an AddrSpace.
- return getTypeInfo(QualType(cast<ExtQualType>(T)->getBaseType(), 0));
case Type::ObjCObjectPointer:
Width = Target.getPointerWidth(0);
Align = Target.getPointerAlign(0);
@@ -1002,52 +1009,58 @@
// Type creation/memoization methods
//===----------------------------------------------------------------------===//
+QualType ASTContext::getExtQualType(const Type *TypeNode, Qualifiers Quals) {
+ unsigned Fast = Quals.getFastQualifiers();
+ Quals.removeFastQualifiers();
+
+ // Check if we've already instantiated this type.
+ llvm::FoldingSetNodeID ID;
+ 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 *New = new (*this, 8) ExtQuals(*this, TypeNode, Quals);
+ ExtQualNodes.InsertNode(New, InsertPos);
+ QualType T = QualType(New, Fast);
+ return T;
+}
+
+QualType ASTContext::getVolatileType(QualType T) {
+ QualType CanT = getCanonicalType(T);
+ if (CanT.isVolatileQualified()) return T;
+
+ QualifierCollector Quals;
+ const Type *TypeNode = Quals.strip(T);
+ Quals.addVolatile();
+
+ return getExtQualType(TypeNode, Quals);
+}
+
QualType ASTContext::getAddrSpaceQualType(QualType T, unsigned AddressSpace) {
QualType CanT = getCanonicalType(T);
if (CanT.getAddressSpace() == AddressSpace)
return T;
- // If we are composing extended qualifiers together, merge together into one
- // ExtQualType node.
- unsigned CVRQuals = T.getCVRQualifiers();
- QualType::GCAttrTypes GCAttr = QualType::GCNone;
- Type *TypeNode = T.getTypePtr();
+ // If we are composing extended qualifiers together, merge together
+ // into one ExtQuals node.
+ QualifierCollector Quals;
+ const Type *TypeNode = Quals.strip(T);
- if (ExtQualType *EQT = dyn_cast<ExtQualType>(TypeNode)) {
- // If this type already has an address space specified, it cannot get
- // another one.
- assert(EQT->getAddressSpace() == 0 &&
- "Type cannot be in multiple addr spaces!");
- GCAttr = EQT->getObjCGCAttr();
- TypeNode = EQT->getBaseType();
- }
+ // If this type already has an address space specified, it cannot get
+ // another one.
+ assert(!Quals.hasAddressSpace() &&
+ "Type cannot be in multiple addr spaces!");
+ Quals.addAddressSpace(AddressSpace);
- // Check if we've already instantiated this type.
- llvm::FoldingSetNodeID ID;
- ExtQualType::Profile(ID, TypeNode, AddressSpace, GCAttr);
- void *InsertPos = 0;
- if (ExtQualType *EXTQy = ExtQualTypes.FindNodeOrInsertPos(ID, InsertPos))
- return QualType(EXTQy, CVRQuals);
-
- // If the base type isn't canonical, this won't be a canonical type either,
- // so fill in the canonical type field.
- QualType Canonical;
- if (!TypeNode->isCanonical()) {
- Canonical = getAddrSpaceQualType(CanT, AddressSpace);
-
- // Update InsertPos, the previous call could have invalidated it.
- ExtQualType *NewIP = ExtQualTypes.FindNodeOrInsertPos(ID, InsertPos);
- assert(NewIP == 0 && "Shouldn't be in the map!"); NewIP = NewIP;
- }
- ExtQualType *New =
- new (*this, 8) ExtQualType(TypeNode, Canonical, AddressSpace, GCAttr);
- ExtQualTypes.InsertNode(New, InsertPos);
- Types.push_back(New);
- return QualType(New, CVRQuals);
+ return getExtQualType(TypeNode, Quals);
}
QualType ASTContext::getObjCGCQualType(QualType T,
- QualType::GCAttrTypes GCAttr) {
+ Qualifiers::GC GCAttr) {
QualType CanT = getCanonicalType(T);
if (CanT.getObjCGCAttr() == GCAttr)
return T;
@@ -1059,75 +1072,48 @@
return getPointerType(ResultType);
}
}
- // If we are composing extended qualifiers together, merge together into one
- // ExtQualType node.
- unsigned CVRQuals = T.getCVRQualifiers();
- Type *TypeNode = T.getTypePtr();
- unsigned AddressSpace = 0;
- if (ExtQualType *EQT = dyn_cast<ExtQualType>(TypeNode)) {
- // If this type already has an ObjCGC specified, it cannot get
- // another one.
- assert(EQT->getObjCGCAttr() == QualType::GCNone &&
- "Type cannot have multiple ObjCGCs!");
- AddressSpace = EQT->getAddressSpace();
- TypeNode = EQT->getBaseType();
- }
+ // If we are composing extended qualifiers together, merge together
+ // into one ExtQuals node.
+ QualifierCollector Quals;
+ const Type *TypeNode = Quals.strip(T);
- // Check if we've already instantiated an gc qual'd type of this type.
- llvm::FoldingSetNodeID ID;
- ExtQualType::Profile(ID, TypeNode, AddressSpace, GCAttr);
- void *InsertPos = 0;
- if (ExtQualType *EXTQy = ExtQualTypes.FindNodeOrInsertPos(ID, InsertPos))
- return QualType(EXTQy, CVRQuals);
+ // If this type already has an ObjCGC specified, it cannot get
+ // another one.
+ assert(!Quals.hasObjCGCAttr() &&
+ "Type cannot have multiple ObjCGCs!");
+ Quals.addObjCGCAttr(GCAttr);
- // If the base type isn't canonical, this won't be a canonical type either,
- // so fill in the canonical type field.
- // FIXME: Isn't this also not canonical if the base type is a array
- // or pointer type? I can't find any documentation for objc_gc, though...
- QualType Canonical;
- if (!T->isCanonical()) {
- Canonical = getObjCGCQualType(CanT, GCAttr);
-
- // Update InsertPos, the previous call could have invalidated it.
- ExtQualType *NewIP = ExtQualTypes.FindNodeOrInsertPos(ID, InsertPos);
- assert(NewIP == 0 && "Shouldn't be in the map!"); NewIP = NewIP;
- }
- ExtQualType *New =
- new (*this, 8) ExtQualType(TypeNode, Canonical, AddressSpace, GCAttr);
- ExtQualTypes.InsertNode(New, InsertPos);
- Types.push_back(New);
- return QualType(New, CVRQuals);
+ return getExtQualType(TypeNode, Quals);
}
QualType ASTContext::getNoReturnType(QualType T) {
- QualifierSet qs;
- qs.strip(T);
+ QualType ResultType;
if (T->isPointerType()) {
QualType Pointee = T->getAs<PointerType>()->getPointeeType();
- QualType ResultType = getNoReturnType(Pointee);
+ ResultType = getNoReturnType(Pointee);
ResultType = getPointerType(ResultType);
- ResultType.setCVRQualifiers(T.getCVRQualifiers());
- return qs.apply(ResultType, *this);
- }
- if (T->isBlockPointerType()) {
+ } else if (T->isBlockPointerType()) {
QualType Pointee = T->getAs<BlockPointerType>()->getPointeeType();
- QualType ResultType = getNoReturnType(Pointee);
+ ResultType = getNoReturnType(Pointee);
ResultType = getBlockPointerType(ResultType);
- ResultType.setCVRQualifiers(T.getCVRQualifiers());
- return qs.apply(ResultType, *this);
- }
- if (!T->isFunctionType())
- assert(0 && "can't noreturn qualify non-pointer to function or block type");
+ } else {
+ assert (T->isFunctionType()
+ && "can't noreturn qualify non-pointer to function or block type");
- if (const FunctionNoProtoType *F = T->getAs<FunctionNoProtoType>()) {
- return getFunctionNoProtoType(F->getResultType(), true);
+ if (const FunctionNoProtoType *F = T->getAs<FunctionNoProtoType>()) {
+ ResultType = getFunctionNoProtoType(F->getResultType(), true);
+ } else {
+ const FunctionProtoType *F = T->getAs<FunctionProtoType>();
+ ResultType
+ = getFunctionType(F->getResultType(), F->arg_type_begin(),
+ F->getNumArgs(), F->isVariadic(), F->getTypeQuals(),
+ F->hasExceptionSpec(), F->hasAnyExceptionSpec(),
+ F->getNumExceptions(), F->exception_begin(), true);
+ }
}
- const FunctionProtoType *F = T->getAs<FunctionProtoType>();
- return getFunctionType(F->getResultType(), F->arg_type_begin(),
- F->getNumArgs(), F->isVariadic(), F->getTypeQuals(),
- F->hasExceptionSpec(), F->hasAnyExceptionSpec(),
- F->getNumExceptions(), F->exception_begin(), true);
+
+ return getQualifiedType(ResultType, T.getQualifiers());
}
/// getComplexType - Return the uniqued reference to the type for a complex
@@ -1645,8 +1631,8 @@
const QualType *ExArray, bool NoReturn) {
if (LangOpts.CPlusPlus) {
for (unsigned i = 0; i != NumArgs; ++i)
- assert(!ArgArray[i].getCVRQualifiers() &&
- "C++ arguments can't have toplevel CVR qualifiers!");
+ assert(!ArgArray[i].hasQualifiers() &&
+ "C++ arguments can't have toplevel qualifiers!");
}
// Unique functions, to guarantee there is only one function of a particular
@@ -2157,33 +2143,38 @@
/// to be free of any of these, allowing two canonical types to be compared
/// for exact equality with a simple pointer comparison.
CanQualType ASTContext::getCanonicalType(QualType T) {
- QualType CanType = T.getTypePtr()->getCanonicalTypeInternal();
+ QualifierCollector Quals;
+ const Type *Ptr = Quals.strip(T);
+ QualType CanType = Ptr->getCanonicalTypeInternal();
- // If the result has type qualifiers, make sure to canonicalize them as well.
- unsigned TypeQuals = T.getCVRQualifiers() | CanType.getCVRQualifiers();
- if (TypeQuals == 0)
+ // 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.
+ // If the type qualifiers are on an array type, get the canonical
+ // type of the array with the qualifiers applied to the element
+ // type.
ArrayType *AT = dyn_cast<ArrayType>(CanType);
if (!AT)
- return CanQualType::CreateUnsafe(CanType.getQualifiedType(TypeQuals));
+ return CanQualType::CreateUnsafe(getQualifiedType(CanType, Quals));
// Get the canonical version of the element with the extra qualifiers on it.
// This can recursively sink qualifiers through multiple levels of arrays.
- QualType NewEltTy=AT->getElementType().getWithAdditionalQualifiers(TypeQuals);
+ QualType NewEltTy = getQualifiedType(AT->getElementType(), Quals);
NewEltTy = getCanonicalType(NewEltTy);
if (ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(AT))
return CanQualType::CreateUnsafe(
getConstantArrayType(NewEltTy, CAT->getSize(),
CAT->getSizeModifier(),
- CAT->getIndexTypeQualifier()));
+ CAT->getIndexTypeCVRQualifiers()));
if (IncompleteArrayType *IAT = dyn_cast<IncompleteArrayType>(AT))
return CanQualType::CreateUnsafe(
getIncompleteArrayType(NewEltTy, IAT->getSizeModifier(),
- IAT->getIndexTypeQualifier()));
+ IAT->getIndexTypeCVRQualifiers()));
if (DependentSizedArrayType *DSAT = dyn_cast<DependentSizedArrayType>(AT))
return CanQualType::CreateUnsafe(
@@ -2191,7 +2182,7 @@
DSAT->getSizeExpr() ?
DSAT->getSizeExpr()->Retain() : 0,
DSAT->getSizeModifier(),
- DSAT->getIndexTypeQualifier(),
+ DSAT->getIndexTypeCVRQualifiers(),
DSAT->getBracketsRange()));
VariableArrayType *VAT = cast<VariableArrayType>(AT);
@@ -2199,7 +2190,7 @@
VAT->getSizeExpr() ?
VAT->getSizeExpr()->Retain() : 0,
VAT->getSizeModifier(),
- VAT->getIndexTypeQualifier(),
+ VAT->getIndexTypeCVRQualifiers(),
VAT->getBracketsRange()));
}
@@ -2316,68 +2307,47 @@
const ArrayType *ASTContext::getAsArrayType(QualType T) {
// Handle the non-qualified case efficiently.
- if (T.getCVRQualifiers() == 0) {
+ if (!T.hasQualifiers()) {
// Handle the common positive case fast.
if (const ArrayType *AT = dyn_cast<ArrayType>(T))
return AT;
}
- // Handle the common negative case fast, ignoring CVR qualifiers.
+ // Handle the common negative case fast.
QualType CType = T->getCanonicalTypeInternal();
-
- // Make sure to look through type qualifiers (like ExtQuals) for the negative
- // test.
- if (!isa<ArrayType>(CType) &&
- !isa<ArrayType>(CType.getUnqualifiedType()))
+ if (!isa<ArrayType>(CType))
return 0;
- // Apply any CVR qualifiers from the array type to the element type. This
+ // Apply any qualifiers from the array type to the element type. This
// implements C99 6.7.3p8: "If the specification of an array type includes
// any type qualifiers, the element type is so qualified, not the array type."
// If we get here, we either have type qualifiers on the type, or we have
// sugar such as a typedef in the way. If we have type qualifiers on the type
// we must propagate them down into the element type.
- unsigned CVRQuals = T.getCVRQualifiers();
- unsigned AddrSpace = 0;
- Type *Ty = T.getTypePtr();
- // Rip through ExtQualType's and typedefs to get to a concrete type.
- while (1) {
- if (const ExtQualType *EXTQT = dyn_cast<ExtQualType>(Ty)) {
- AddrSpace = EXTQT->getAddressSpace();
- Ty = EXTQT->getBaseType();
- } else {
- T = Ty->getDesugaredType();
- if (T.getTypePtr() == Ty && T.getCVRQualifiers() == 0)
- break;
- CVRQuals |= T.getCVRQualifiers();
- Ty = T.getTypePtr();
- }
- }
+ QualifierCollector Qs;
+ const Type *Ty = Qs.strip(T.getDesugaredType());
// If we have a simple case, just return now.
const ArrayType *ATy = dyn_cast<ArrayType>(Ty);
- if (ATy == 0 || (AddrSpace == 0 && CVRQuals == 0))
+ if (ATy == 0 || Qs.empty())
return ATy;
// Otherwise, we have an array and we have qualifiers on it. Push the
// qualifiers into the array element type and return a new array type.
// Get the canonical version of the element with the extra qualifiers on it.
// This can recursively sink qualifiers through multiple levels of arrays.
- QualType NewEltTy = ATy->getElementType();
- if (AddrSpace)
- NewEltTy = getAddrSpaceQualType(NewEltTy, AddrSpace);
- NewEltTy = NewEltTy.getWithAdditionalQualifiers(CVRQuals);
+ QualType NewEltTy = getQualifiedType(ATy->getElementType(), Qs);
if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(ATy))
return cast<ArrayType>(getConstantArrayType(NewEltTy, CAT->getSize(),
CAT->getSizeModifier(),
- CAT->getIndexTypeQualifier()));
+ CAT->getIndexTypeCVRQualifiers()));
if (const IncompleteArrayType *IAT = dyn_cast<IncompleteArrayType>(ATy))
return cast<ArrayType>(getIncompleteArrayType(NewEltTy,
IAT->getSizeModifier(),
- IAT->getIndexTypeQualifier()));
+ IAT->getIndexTypeCVRQualifiers()));
if (const DependentSizedArrayType *DSAT
= dyn_cast<DependentSizedArrayType>(ATy))
@@ -2386,15 +2356,15 @@
DSAT->getSizeExpr() ?
DSAT->getSizeExpr()->Retain() : 0,
DSAT->getSizeModifier(),
- DSAT->getIndexTypeQualifier(),
+ DSAT->getIndexTypeCVRQualifiers(),
DSAT->getBracketsRange()));
const VariableArrayType *VAT = cast<VariableArrayType>(ATy);
return cast<ArrayType>(getVariableArrayType(NewEltTy,
VAT->getSizeExpr() ?
- VAT->getSizeExpr()->Retain() : 0,
+ VAT->getSizeExpr()->Retain() : 0,
VAT->getSizeModifier(),
- VAT->getIndexTypeQualifier(),
+ VAT->getIndexTypeCVRQualifiers(),
VAT->getBracketsRange()));
}
@@ -2416,17 +2386,17 @@
QualType PtrTy = getPointerType(PrettyArrayType->getElementType());
// int x[restrict 4] -> int *restrict
- return PtrTy.getQualifiedType(PrettyArrayType->getIndexTypeQualifier());
+ return getQualifiedType(PtrTy, PrettyArrayType->getIndexTypeQualifiers());
}
QualType ASTContext::getBaseElementType(QualType QT) {
- QualifierSet qualifiers;
+ QualifierCollector Qs;
while (true) {
- const Type *UT = qualifiers.strip(QT);
+ const Type *UT = Qs.strip(QT);
if (const ArrayType *AT = getAsArrayType(QualType(UT,0))) {
QT = AT->getElementType();
} else {
- return qualifiers.apply(QT, *this);
+ return Qs.apply(QT);
}
}
}
@@ -2651,11 +2621,11 @@
QualType FieldTypes[4];
// const int *isa;
- FieldTypes[0] = getPointerType(IntTy.getQualifiedType(QualType::Const));
+ FieldTypes[0] = getPointerType(IntTy.withConst());
// int flags;
FieldTypes[1] = IntTy;
// const char *str;
- FieldTypes[2] = getPointerType(CharTy.getQualifiedType(QualType::Const));
+ FieldTypes[2] = getPointerType(CharTy.withConst());
// long length;
FieldTypes[3] = LongTy;
@@ -3139,9 +3109,9 @@
return;
}
- if (T->isObjCInterfaceType()) {
+ if (const ObjCInterfaceType *OIT = T->getAs<ObjCInterfaceType>()) {
// @encode(class_name)
- ObjCInterfaceDecl *OI = T->getAs<ObjCInterfaceType>()->getDecl();
+ ObjCInterfaceDecl *OI = OIT->getDecl();
S += '{';
const IdentifierInfo *II = OI->getIdentifier();
S += II->getName();
@@ -3388,24 +3358,24 @@
/// getObjCGCAttr - Returns one of GCNone, Weak or Strong objc's
/// garbage collection attribute.
///
-QualType::GCAttrTypes ASTContext::getObjCGCAttrKind(const QualType &Ty) const {
- QualType::GCAttrTypes GCAttrs = QualType::GCNone;
+Qualifiers::GC ASTContext::getObjCGCAttrKind(const QualType &Ty) const {
+ Qualifiers::GC GCAttrs = Qualifiers::GCNone;
if (getLangOptions().ObjC1 &&
getLangOptions().getGCMode() != LangOptions::NonGC) {
GCAttrs = Ty.getObjCGCAttr();
// Default behavious under objective-c's gc is for objective-c pointers
// (or pointers to them) be treated as though they were declared
// as __strong.
- if (GCAttrs == QualType::GCNone) {
+ if (GCAttrs == Qualifiers::GCNone) {
if (Ty->isObjCObjectPointerType() || Ty->isBlockPointerType())
- GCAttrs = QualType::Strong;
+ GCAttrs = Qualifiers::Strong;
else if (Ty->isPointerType())
return getObjCGCAttrKind(Ty->getAs<PointerType>()->getPointeeType());
}
// Non-pointers have none gc'able attribute regardless of the attribute
// set on them.
else if (!Ty->isAnyPointerType() && !Ty->isBlockPointerType())
- return QualType::GCNone;
+ return Qualifiers::GCNone;
}
return GCAttrs;
}
@@ -3766,11 +3736,38 @@
if (LHSCan == RHSCan)
return LHS;
- // If the qualifiers are different, the types aren't compatible
- // Note that we handle extended qualifiers later, in the
- // case for ExtQualType.
- if (LHSCan.getCVRQualifiers() != RHSCan.getCVRQualifiers())
+ // If the qualifiers are different, the types aren't compatible... mostly.
+ Qualifiers LQuals = LHSCan.getQualifiers();
+ Qualifiers RQuals = RHSCan.getQualifiers();
+ if (LQuals != RQuals) {
+ // If any of these qualifiers are different, we have a type
+ // mismatch.
+ if (LQuals.getCVRQualifiers() != RQuals.getCVRQualifiers() ||
+ LQuals.getAddressSpace() != RQuals.getAddressSpace())
+ return QualType();
+
+ // Exactly one GC qualifier difference is allowed: __strong is
+ // okay if the other type has no GC qualifier but is an Objective
+ // C object pointer (i.e. implicitly strong by default). We fix
+ // this by pretending that the unqualified type was actually
+ // qualified __strong.
+ Qualifiers::GC GC_L = LQuals.getObjCGCAttr();
+ Qualifiers::GC GC_R = RQuals.getObjCGCAttr();
+ assert((GC_L != GC_R) && "unequal qualifier sets had only equal elements");
+
+ if (GC_L == Qualifiers::Weak || GC_R == Qualifiers::Weak)
+ return QualType();
+
+ if (GC_L == Qualifiers::Strong && RHSCan->isObjCObjectPointerType()) {
+ return mergeTypes(LHS, getObjCGCQualType(RHS, Qualifiers::Strong));
+ }
+ if (GC_R == Qualifiers::Strong && LHSCan->isObjCObjectPointerType()) {
+ return mergeTypes(getObjCGCQualType(LHS, Qualifiers::Strong), RHS);
+ }
return QualType();
+ }
+
+ // Okay, qualifiers are equal.
Type::TypeClass LHSClass = LHSCan->getTypeClass();
Type::TypeClass RHSClass = RHSCan->getTypeClass();
@@ -3780,59 +3777,6 @@
if (LHSClass == Type::FunctionProto) LHSClass = Type::FunctionNoProto;
if (RHSClass == Type::FunctionProto) RHSClass = Type::FunctionNoProto;
- // Strip off objc_gc attributes off the top level so they can be merged.
- // This is a complete mess, but the attribute itself doesn't make much sense.
- if (RHSClass == Type::ExtQual) {
- QualType::GCAttrTypes GCAttr = RHSCan.getObjCGCAttr();
- if (GCAttr != QualType::GCNone) {
- QualType::GCAttrTypes GCLHSAttr = LHSCan.getObjCGCAttr();
- // __weak attribute must appear on both declarations.
- // __strong attribue is redundant if other decl is an objective-c
- // object pointer (or decorated with __strong attribute); otherwise
- // issue error.
- if ((GCAttr == QualType::Weak && GCLHSAttr != GCAttr) ||
- (GCAttr == QualType::Strong && GCLHSAttr != GCAttr &&
- !LHSCan->isObjCObjectPointerType()))
- return QualType();
-
- RHS = QualType(cast<ExtQualType>(RHS.getDesugaredType())->getBaseType(),
- RHS.getCVRQualifiers());
- QualType Result = mergeTypes(LHS, RHS);
- if (!Result.isNull()) {
- if (Result.getObjCGCAttr() == QualType::GCNone)
- Result = getObjCGCQualType(Result, GCAttr);
- else if (Result.getObjCGCAttr() != GCAttr)
- Result = QualType();
- }
- return Result;
- }
- }
- if (LHSClass == Type::ExtQual) {
- QualType::GCAttrTypes GCAttr = LHSCan.getObjCGCAttr();
- if (GCAttr != QualType::GCNone) {
- QualType::GCAttrTypes GCRHSAttr = RHSCan.getObjCGCAttr();
- // __weak attribute must appear on both declarations. __strong
- // __strong attribue is redundant if other decl is an objective-c
- // object pointer (or decorated with __strong attribute); otherwise
- // issue error.
- if ((GCAttr == QualType::Weak && GCRHSAttr != GCAttr) ||
- (GCAttr == QualType::Strong && GCRHSAttr != GCAttr &&
- !RHSCan->isObjCObjectPointerType()))
- return QualType();
-
- LHS = QualType(cast<ExtQualType>(LHS.getDesugaredType())->getBaseType(),
- LHS.getCVRQualifiers());
- QualType Result = mergeTypes(LHS, RHS);
- if (!Result.isNull()) {
- if (Result.getObjCGCAttr() == QualType::GCNone)
- Result = getObjCGCQualType(Result, GCAttr);
- else if (Result.getObjCGCAttr() != GCAttr)
- Result = QualType();
- }
- return Result;
- }
- }
-
// Same as above for arrays
if (LHSClass == Type::VariableArray || LHSClass == Type::IncompleteArray)
LHSClass = Type::ConstantArray;
@@ -3988,34 +3932,6 @@
case Type::FixedWidthInt:
// Distinct fixed-width integers are not compatible.
return QualType();
- case Type::ExtQual:
- // FIXME: ExtQual types can be compatible even if they're not
- // identical!
- return QualType();
- // First attempt at an implementation, but I'm not really sure it's
- // right...
-#if 0
- ExtQualType* LQual = cast<ExtQualType>(LHSCan);
- ExtQualType* RQual = cast<ExtQualType>(RHSCan);
- if (LQual->getAddressSpace() != RQual->getAddressSpace() ||
- LQual->getObjCGCAttr() != RQual->getObjCGCAttr())
- return QualType();
- QualType LHSBase, RHSBase, ResultType, ResCanUnqual;
- LHSBase = QualType(LQual->getBaseType(), 0);
- RHSBase = QualType(RQual->getBaseType(), 0);
- ResultType = mergeTypes(LHSBase, RHSBase);
- if (ResultType.isNull()) return QualType();
- ResCanUnqual = getCanonicalType(ResultType).getUnqualifiedType();
- if (LHSCan.getUnqualifiedType() == ResCanUnqual)
- return LHS;
- if (RHSCan.getUnqualifiedType() == ResCanUnqual)
- return RHS;
- ResultType = getAddrSpaceQualType(ResultType, LQual->getAddressSpace());
- ResultType = getObjCGCQualType(ResultType, LQual->getObjCGCAttr());
- ResultType.setCVRQualifiers(LHSCan.getCVRQualifiers());
- return ResultType;
-#endif
-
case Type::TemplateSpecialization:
assert(false && "Dependent types have no size");
break;
@@ -4231,7 +4147,7 @@
break;
// FIXME: There's no way to have a built-in with an rvalue ref arg.
case 'C':
- Type = Type.getQualifiedType(QualType::Const);
+ Type = Type.withConst();
break;
}
}
diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp
index f3ea043..fc04ed4 100644
--- a/lib/AST/DeclCXX.cpp
+++ b/lib/AST/DeclCXX.cpp
@@ -146,7 +146,7 @@
}
bool CXXRecordDecl::hasConstCopyConstructor(ASTContext &Context) const {
- return getCopyConstructor(Context, QualType::Const) != 0;
+ return getCopyConstructor(Context, Qualifiers::Const) != 0;
}
CXXConstructorDecl *CXXRecordDecl::getCopyConstructor(ASTContext &Context,
@@ -167,8 +167,8 @@
if (cast<CXXConstructorDecl>(*Con)->isCopyConstructor(Context,
FoundTQs)) {
- if (((TypeQuals & QualType::Const) == (FoundTQs & QualType::Const)) ||
- (!(TypeQuals & QualType::Const) && (FoundTQs & QualType::Const)))
+ if (((TypeQuals & Qualifiers::Const) == (FoundTQs & Qualifiers::Const)) ||
+ (!(TypeQuals & Qualifiers::Const) && (FoundTQs & Qualifiers::Const)))
return cast<CXXConstructorDecl>(*Con);
}
@@ -508,7 +508,8 @@
ClassTy = TD->getInjectedClassNameType(C);
else
ClassTy = C.getTagDeclType(getParent());
- ClassTy = ClassTy.getWithAdditionalQualifiers(getTypeQualifiers());
+ ClassTy = C.getQualifiedType(ClassTy,
+ Qualifiers::fromCVRMask(getTypeQualifiers()));
return C.getPointerType(ClassTy);
}
@@ -600,6 +601,8 @@
if (PointeeType.getUnqualifiedType() != ClassTy)
return false;
+ // FIXME: other qualifiers?
+
// We have a copy constructor.
TypeQuals = PointeeType.getCVRQualifiers();
return true;
diff --git a/lib/AST/DeclarationName.cpp b/lib/AST/DeclarationName.cpp
index a01a892..101ddd2 100644
--- a/lib/AST/DeclarationName.cpp
+++ b/lib/AST/DeclarationName.cpp
@@ -309,11 +309,11 @@
switch (Kind) {
case DeclarationName::CXXConstructorName:
EKind = DeclarationNameExtra::CXXConstructor;
- assert(Ty.getCVRQualifiers() == 0 &&"Constructor type must be unqualified");
+ assert(!Ty.hasQualifiers() &&"Constructor type must be unqualified");
break;
case DeclarationName::CXXDestructorName:
EKind = DeclarationNameExtra::CXXDestructor;
- assert(Ty.getCVRQualifiers() == 0 && "Destructor type must be unqualified");
+ assert(!Ty.hasQualifiers() && "Destructor type must be unqualified");
break;
case DeclarationName::CXXConversionFunctionName:
EKind = DeclarationNameExtra::CXXConversionFunction;
diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp
index 9d2d46f..dc9cee1 100644
--- a/lib/AST/Expr.cpp
+++ b/lib/AST/Expr.cpp
@@ -825,7 +825,7 @@
return LV_NotObjectType;
// Allow qualified void which is an incomplete type other than void (yuck).
- if (TR->isVoidType() && !Ctx.getCanonicalType(TR).getCVRQualifiers())
+ if (TR->isVoidType() && !Ctx.getCanonicalType(TR).hasQualifiers())
return LV_IncompleteVoidType;
return LV_Valid;
@@ -1120,7 +1120,7 @@
// dereferencing to a pointer is always a gc'able candidate,
// unless it is __weak.
return T->isPointerType() &&
- (Ctx.getObjCGCAttrKind(T) != QualType::Weak);
+ (Ctx.getObjCGCAttrKind(T) != Qualifiers::Weak);
}
return false;
}
@@ -1397,7 +1397,7 @@
if (isa<EnumConstantDecl>(cast<DeclRefExpr>(E)->getDecl()))
return NoDiag();
if (Ctx.getLangOptions().CPlusPlus &&
- E->getType().getCVRQualifiers() == QualType::Const) {
+ E->getType().getCVRQualifiers() == Qualifiers::Const) {
// C++ 7.1.5.1p2
// A variable of non-volatile const-qualified integral or enumeration
// type initialized by an ICE can be used in ICEs.
@@ -1635,7 +1635,7 @@
// Check that it is a cast to void*.
if (const PointerType *PT = CE->getType()->getAs<PointerType>()) {
QualType Pointee = PT->getPointeeType();
- if (Pointee.getCVRQualifiers() == 0 &&
+ if (!Pointee.hasQualifiers() &&
Pointee->isVoidType() && // to void*
CE->getSubExpr()->getType()->isIntegerType()) // from int.
return CE->getSubExpr()->isNullPointerConstant(Ctx);
diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp
index 5123aaa..2aefae6 100644
--- a/lib/AST/ExprConstant.cpp
+++ b/lib/AST/ExprConstant.cpp
@@ -783,7 +783,7 @@
// In C++, const, non-volatile integers initialized with ICEs are ICEs.
// In C, they can also be folded, although they are not ICEs.
- if (E->getType().getCVRQualifiers() == QualType::Const) {
+ if (E->getType().getCVRQualifiers() == Qualifiers::Const) {
if (const VarDecl *D = dyn_cast<VarDecl>(E->getDecl())) {
if (APValue *V = D->getEvaluatedValue())
return Success(V->getInt(), E);
diff --git a/lib/AST/StmtDumper.cpp b/lib/AST/StmtDumper.cpp
index ed92da3..0465999 100644
--- a/lib/AST/StmtDumper.cpp
+++ b/lib/AST/StmtDumper.cpp
@@ -87,13 +87,10 @@
fprintf(F, "'%s'", T.getAsString().c_str());
if (!T.isNull()) {
- // If the type is directly a typedef, strip off typedefness to give at
- // least one level of concreteness.
- if (TypedefType *TDT = dyn_cast<TypedefType>(T)) {
- QualType Simplified =
- TDT->LookThroughTypedefs().getQualifiedType(T.getCVRQualifiers());
+ // If the type is sugared, also dump a (shallow) desugared type.
+ QualType Simplified = T.getDesugaredType();
+ if (Simplified != T)
fprintf(F, ":'%s'", Simplified.getAsString().c_str());
- }
}
}
void DumpStmt(const Stmt *Node) {
diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp
index 2783211..bda06ac 100644
--- a/lib/AST/Type.cpp
+++ b/lib/AST/Type.cpp
@@ -101,12 +101,8 @@
return ATy->getElementType().getTypePtr();
// If the canonical form of this type isn't the right kind, reject it.
- if (!isa<ArrayType>(CanonicalType)) {
- // Look through type qualifiers
- if (ArrayType *AT = dyn_cast<ArrayType>(CanonicalType.getUnqualifiedType()))
- return AT->getElementType().getTypePtr();
+ if (!isa<ArrayType>(CanonicalType))
return 0;
- }
// If this is a typedef for an array type, strip the typedef off without
// losing all typedef information.
@@ -125,8 +121,8 @@
/// decide whether it is worth providing a desugared form of the type
/// or not.
QualType QualType::getDesugaredType(bool ForDisplay) const {
- return getTypePtr()->getDesugaredType(ForDisplay)
- .getWithAdditionalQualifiers(getCVRQualifiers());
+ QualifierCollector Qs;
+ return Qs.apply(Qs.strip(*this)->getDesugaredType(ForDisplay));
}
/// getDesugaredType - Return the specified type with any "sugar" removed from
@@ -181,8 +177,6 @@
bool Type::isVoidType() const {
if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType))
return BT->getKind() == BuiltinType::Void;
- if (const ExtQualType *AS = dyn_cast<ExtQualType>(CanonicalType))
- return AS->getBaseType()->isVoidType();
return false;
}
@@ -190,15 +184,11 @@
if (isa<FunctionType>(CanonicalType) || isa<ReferenceType>(CanonicalType) ||
isa<IncompleteArrayType>(CanonicalType) || isVoidType())
return false;
- if (const ExtQualType *AS = dyn_cast<ExtQualType>(CanonicalType))
- return AS->getBaseType()->isObjectType();
return true;
}
bool Type::isDerivedType() const {
switch (CanonicalType->getTypeClass()) {
- case ExtQual:
- return cast<ExtQualType>(CanonicalType)->getBaseType()->isDerivedType();
case Pointer:
case VariableArray:
case ConstantArray:
@@ -241,39 +231,19 @@
bool Type::isComplexType() const {
if (const ComplexType *CT = dyn_cast<ComplexType>(CanonicalType))
return CT->getElementType()->isFloatingType();
- if (const ExtQualType *AS = dyn_cast<ExtQualType>(CanonicalType))
- return AS->getBaseType()->isComplexType();
return false;
}
bool Type::isComplexIntegerType() const {
// Check for GCC complex integer extension.
- if (const ComplexType *CT = dyn_cast<ComplexType>(CanonicalType))
- return CT->getElementType()->isIntegerType();
- if (const ExtQualType *AS = dyn_cast<ExtQualType>(CanonicalType))
- return AS->getBaseType()->isComplexIntegerType();
- return false;
+ return getAsComplexIntegerType();
}
const ComplexType *Type::getAsComplexIntegerType() const {
- // Are we directly a complex type?
- if (const ComplexType *CTy = dyn_cast<ComplexType>(this)) {
- if (CTy->getElementType()->isIntegerType())
- return CTy;
- return 0;
- }
-
- // If the canonical form of this type isn't what we want, reject it.
- if (!isa<ComplexType>(CanonicalType)) {
- // Look through type qualifiers (e.g. ExtQualType's).
- if (isa<ComplexType>(CanonicalType.getUnqualifiedType()))
- return CanonicalType.getUnqualifiedType()->getAsComplexIntegerType();
- return 0;
- }
-
- // If this is a typedef for a complex type, strip the typedef off without
- // losing all typedef information.
- return cast<ComplexType>(getDesugaredType());
+ if (const ComplexType *Complex = getAs<ComplexType>())
+ if (Complex->getElementType()->isIntegerType())
+ return Complex;
+ return 0;
}
QualType Type::getPointeeType() const {
@@ -335,9 +305,6 @@
// losing all typedef information.
return cast<RecordType>(getDesugaredType());
}
- // Look through type qualifiers
- if (isa<RecordType>(CanonicalType.getUnqualifiedType()))
- return CanonicalType.getUnqualifiedType()->getAsStructureType();
return 0;
}
@@ -358,9 +325,6 @@
return cast<RecordType>(getDesugaredType());
}
- // Look through type qualifiers
- if (isa<RecordType>(CanonicalType.getUnqualifiedType()))
- return CanonicalType.getUnqualifiedType()->getAsUnionType();
return 0;
}
@@ -416,8 +380,6 @@
return true;
if (const VectorType *VT = dyn_cast<VectorType>(CanonicalType))
return VT->getElementType()->isIntegerType();
- if (const ExtQualType *EXTQT = dyn_cast<ExtQualType>(CanonicalType))
- return EXTQT->getBaseType()->isIntegerType();
return false;
}
@@ -431,24 +393,18 @@
// FIXME: In C++, enum types are never integral.
if (isa<FixedWidthIntType>(CanonicalType))
return true;
- if (const ExtQualType *EXTQT = dyn_cast<ExtQualType>(CanonicalType))
- return EXTQT->getBaseType()->isIntegralType();
return false;
}
bool Type::isEnumeralType() const {
if (const TagType *TT = dyn_cast<TagType>(CanonicalType))
return TT->getDecl()->isEnum();
- if (const ExtQualType *EXTQT = dyn_cast<ExtQualType>(CanonicalType))
- return EXTQT->getBaseType()->isEnumeralType();
return false;
}
bool Type::isBooleanType() const {
if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType))
return BT->getKind() == BuiltinType::Bool;
- if (const ExtQualType *EXTQT = dyn_cast<ExtQualType>(CanonicalType))
- return EXTQT->getBaseType()->isBooleanType();
return false;
}
@@ -458,16 +414,12 @@
BT->getKind() == BuiltinType::UChar ||
BT->getKind() == BuiltinType::Char_S ||
BT->getKind() == BuiltinType::SChar;
- if (const ExtQualType *EXTQT = dyn_cast<ExtQualType>(CanonicalType))
- return EXTQT->getBaseType()->isCharType();
return false;
}
bool Type::isWideCharType() const {
if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType))
return BT->getKind() == BuiltinType::WChar;
- if (const ExtQualType *EXTQT = dyn_cast<ExtQualType>(CanonicalType))
- return EXTQT->getBaseType()->isWideCharType();
return false;
}
@@ -490,8 +442,6 @@
if (const VectorType *VT = dyn_cast<VectorType>(CanonicalType))
return VT->getElementType()->isSignedIntegerType();
- if (const ExtQualType *EXTQT = dyn_cast<ExtQualType>(CanonicalType))
- return EXTQT->getBaseType()->isSignedIntegerType();
return false;
}
@@ -514,8 +464,6 @@
if (const VectorType *VT = dyn_cast<VectorType>(CanonicalType))
return VT->getElementType()->isUnsignedIntegerType();
- if (const ExtQualType *EXTQT = dyn_cast<ExtQualType>(CanonicalType))
- return EXTQT->getBaseType()->isUnsignedIntegerType();
return false;
}
@@ -527,8 +475,6 @@
return CT->getElementType()->isFloatingType();
if (const VectorType *VT = dyn_cast<VectorType>(CanonicalType))
return VT->getElementType()->isFloatingType();
- if (const ExtQualType *EXTQT = dyn_cast<ExtQualType>(CanonicalType))
- return EXTQT->getBaseType()->isFloatingType();
return false;
}
@@ -538,8 +484,6 @@
BT->getKind() <= BuiltinType::LongDouble;
if (const VectorType *VT = dyn_cast<VectorType>(CanonicalType))
return VT->getElementType()->isRealFloatingType();
- if (const ExtQualType *EXTQT = dyn_cast<ExtQualType>(CanonicalType))
- return EXTQT->getBaseType()->isRealFloatingType();
return false;
}
@@ -553,8 +497,6 @@
return true;
if (const VectorType *VT = dyn_cast<VectorType>(CanonicalType))
return VT->getElementType()->isRealType();
- if (const ExtQualType *EXTQT = dyn_cast<ExtQualType>(CanonicalType))
- return EXTQT->getBaseType()->isRealType();
return false;
}
@@ -568,8 +510,6 @@
return ET->getDecl()->isDefinition();
if (isa<FixedWidthIntType>(CanonicalType))
return true;
- if (const ExtQualType *EXTQT = dyn_cast<ExtQualType>(CanonicalType))
- return EXTQT->getBaseType()->isArithmeticType();
return isa<ComplexType>(CanonicalType) || isa<VectorType>(CanonicalType);
}
@@ -583,8 +523,6 @@
return true;
return false;
}
- if (const ExtQualType *EXTQT = dyn_cast<ExtQualType>(CanonicalType))
- return EXTQT->getBaseType()->isScalarType();
if (isa<FixedWidthIntType>(CanonicalType))
return true;
return isa<PointerType>(CanonicalType) ||
@@ -611,8 +549,6 @@
return true;
}
- if (const ExtQualType *EXTQT = dyn_cast<ExtQualType>(CanonicalType))
- return EXTQT->getBaseType()->isAggregateType();
return isa<ArrayType>(CanonicalType);
}
@@ -620,8 +556,6 @@
/// according to the rules of C99 6.7.5p3. It is not legal to call this on
/// incomplete types or dependent types.
bool Type::isConstantSizeType() const {
- if (const ExtQualType *EXTQT = dyn_cast<ExtQualType>(CanonicalType))
- return EXTQT->getBaseType()->isConstantSizeType();
assert(!isIncompleteType() && "This doesn't make sense for incomplete types");
assert(!isDependentType() && "This doesn't make sense for dependent types");
// The VAT must have a size, as it is known to be complete.
@@ -634,8 +568,6 @@
bool Type::isIncompleteType() const {
switch (CanonicalType->getTypeClass()) {
default: return false;
- case ExtQual:
- return cast<ExtQualType>(CanonicalType)->getBaseType()->isIncompleteType();
case Builtin:
// Void is the only incomplete builtin type. Per C99 6.2.5p19, it can never
// be completed.
@@ -664,8 +596,6 @@
switch (CanonicalType->getTypeClass()) {
// Everything not explicitly mentioned is not POD.
default: return false;
- case ExtQual:
- return cast<ExtQualType>(CanonicalType)->getBaseType()->isPODType();
case VariableArray:
case ConstantArray:
// IncompleteArray is caught by isIncompleteType() above.
@@ -827,21 +757,16 @@
return FirstType;
// Otherwise, do the fully general loop.
- unsigned TypeQuals = 0;
+ QualifierCollector Qs;
+
+ QualType CurType;
const TypedefType *TDT = this;
- while (1) {
- QualType CurType = TDT->getDecl()->getUnderlyingType();
+ do {
+ CurType = TDT->getDecl()->getUnderlyingType();
+ TDT = dyn_cast<TypedefType>(Qs.strip(CurType));
+ } while (TDT);
-
- /// FIXME:
- /// FIXME: This is incorrect for ExtQuals!
- /// FIXME:
- TypeQuals |= CurType.getCVRQualifiers();
-
- TDT = dyn_cast<TypedefType>(CurType);
- if (TDT == 0)
- return QualType(CurType.getTypePtr(), TypeQuals);
- }
+ return Qs.apply(CurType);
}
TypeOfExprType::TypeOfExprType(Expr *E, QualType can)
@@ -961,27 +886,20 @@
Args[Idx].Profile(ID, Context);
}
-const Type *QualifierSet::strip(const Type* T) {
- QualType DT = T->getDesugaredType();
- addCVR(DT.getCVRQualifiers());
+QualType QualifierCollector::apply(QualType QT) const {
+ if (!hasNonFastQualifiers())
+ return QT.withFastQualifiers(getFastQualifiers());
- if (const ExtQualType* EQT = dyn_cast<ExtQualType>(DT)) {
- if (EQT->getAddressSpace())
- addAddressSpace(EQT->getAddressSpace());
- if (EQT->getObjCGCAttr())
- addObjCGCAttrType(EQT->getObjCGCAttr());
- return EQT->getBaseType();
- } else {
- // Use the sugared type unless desugaring found extra qualifiers.
- return (DT.getCVRQualifiers() ? DT.getTypePtr() : T);
- }
+ assert(Context && "extended qualifiers but no context!");
+ return Context->getQualifiedType(QT, *this);
}
-QualType QualifierSet::apply(QualType QT, ASTContext& C) {
- QT = QT.getWithAdditionalQualifiers(getCVRMask());
- if (hasObjCGCAttrType()) QT = C.getObjCGCQualType(QT, getObjCGCAttrType());
- if (hasAddressSpace()) QT = C.getAddrSpaceQualType(QT, getAddressSpace());
- return QT;
+QualType QualifierCollector::apply(const Type *T) const {
+ if (!hasNonFastQualifiers())
+ return QualType(T, getFastQualifiers());
+
+ assert(Context && "extended qualifiers but no context!");
+ return Context->getQualifiedType(T, *this);
}
@@ -1012,14 +930,46 @@
static void AppendTypeQualList(std::string &S, unsigned TypeQuals) {
- // Note: funkiness to ensure we get a space only between quals.
- bool NonePrinted = true;
- if (TypeQuals & QualType::Const)
- S += "const", NonePrinted = false;
- if (TypeQuals & QualType::Volatile)
- S += (NonePrinted+" volatile"), NonePrinted = false;
- if (TypeQuals & QualType::Restrict)
- S += (NonePrinted+" restrict"), NonePrinted = false;
+ if (TypeQuals & Qualifiers::Const) {
+ if (!S.empty()) S += ' ';
+ S += "const";
+ }
+ if (TypeQuals & Qualifiers::Volatile) {
+ if (!S.empty()) S += ' ';
+ S += "volatile";
+ }
+ if (TypeQuals & Qualifiers::Restrict) {
+ if (!S.empty()) S += ' ';
+ S += "restrict";
+ }
+}
+
+std::string Qualifiers::getAsString() const {
+ LangOptions LO;
+ return getAsString(PrintingPolicy(LO));
+}
+
+// Appends qualifiers to the given string, separated by spaces. Will
+// prefix a space if the string is non-empty. Will not append a final
+// space.
+void Qualifiers::getAsStringInternal(std::string &S,
+ const PrintingPolicy&) const {
+ AppendTypeQualList(S, getCVRQualifiers());
+ if (unsigned AddressSpace = getAddressSpace()) {
+ if (!S.empty()) S += ' ';
+ S += "__attribute__((address_space(";
+ S += llvm::utostr_32(AddressSpace);
+ S += ")))";
+ }
+ if (Qualifiers::GC GCAttrType = getObjCGCAttr()) {
+ if (!S.empty()) S += ' ';
+ S += "__attribute__((objc_gc(";
+ if (GCAttrType == Qualifiers::Weak)
+ S += "weak";
+ else
+ S += "strong";
+ S += ")))";
+ }
}
std::string QualType::getAsString() const {
@@ -1041,13 +991,16 @@
return;
// Print qualifiers as appropriate.
- if (unsigned Tq = getCVRQualifiers()) {
+ Qualifiers Quals = getQualifiers();
+ if (!Quals.empty()) {
std::string TQS;
- AppendTypeQualList(TQS, Tq);
- if (!S.empty())
- S = TQS + ' ' + S;
- else
- S = TQS;
+ Quals.getAsStringInternal(TQS, Policy);
+
+ if (!S.empty()) {
+ TQS += ' ';
+ TQS += S;
+ }
+ std::swap(S, TQS);
}
getTypePtr()->getAsStringInternal(S, Policy);
@@ -1084,25 +1037,6 @@
S = "_Complex " + S;
}
-void ExtQualType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const {
- bool NeedsSpace = false;
- if (AddressSpace) {
- S = "__attribute__((address_space("+llvm::utostr_32(AddressSpace)+")))" + S;
- NeedsSpace = true;
- }
- if (GCAttrType != QualType::GCNone) {
- if (NeedsSpace)
- S += ' ';
- S += "__attribute__((objc_gc(";
- if (GCAttrType == QualType::Weak)
- S += "weak";
- else
- S += "strong";
- S += ")))";
- }
- BaseType->getAsStringInternal(S, Policy);
-}
-
void PointerType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const {
S = '*' + S;
@@ -1195,8 +1129,8 @@
void VariableArrayType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const {
S += '[';
- if (getIndexTypeQualifier()) {
- AppendTypeQualList(S, getIndexTypeQualifier());
+ if (getIndexTypeQualifiers().hasQualifiers()) {
+ AppendTypeQualList(S, getIndexTypeCVRQualifiers());
S += ' ';
}
@@ -1219,8 +1153,8 @@
void DependentSizedArrayType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const {
S += '[';
- if (getIndexTypeQualifier()) {
- AppendTypeQualList(S, getIndexTypeQualifier());
+ if (getIndexTypeQualifiers().hasQualifiers()) {
+ AppendTypeQualList(S, getIndexTypeCVRQualifiers());
S += ' ';
}
@@ -1536,6 +1470,9 @@
}
ObjCQIString += '>';
}
+
+ PointeeType.getQualifiers().getAsStringInternal(ObjCQIString, Policy);
+
if (!isObjCIdType() && !isObjCQualifiedIdType())
ObjCQIString += " *"; // Don't forget the implicit pointer.
else if (!InnerString.empty()) // Prefix the basic type, e.g. 'typedefname X'.