Revise the SplitQualType interface to make it its own thing instead of

a typedef of std::pair.  This slightly improves type-safety, but mostly
makes code using it clearer to read as well as making it possible to add
methods to the type.

Add such a method for efficiently single-step desugaring a split type.
Add a method to single-step desugaring a locally-unqualified type.
Implement both the SplitQualType and QualType methods in terms of that.

Also, fix a typo ("ObjCGLifetime").

llvm-svn: 150028
This commit is contained in:
John McCall 2012-02-08 00:46:36 +00:00
parent 9716914b2d
commit 18ce25e1ec
10 changed files with 109 additions and 61 deletions

View File

@ -1134,6 +1134,11 @@ public:
return getQualifiedType(T, Qualifiers::fromCVRMask(CVR));
}
/// getQualifiedType - Un-split a SplitQualType.
QualType getQualifiedType(SplitQualType split) const {
return getQualifiedType(split.Ty, split.Quals);
}
/// getQualifiedType - Returns a type with additional qualifiers.
QualType getQualifiedType(QualType T, Qualifiers Qs) const {
if (!Qs.hasNonFastQualifiers())

View File

@ -236,7 +236,7 @@ public:
qs.removeObjCGCAttr();
return qs;
}
Qualifiers withoutObjCGLifetime() const {
Qualifiers withoutObjCLifetime() const {
Qualifiers qs = *this;
qs.removeObjCLifetime();
return qs;
@ -252,7 +252,8 @@ public:
void removeObjCLifetime() { setObjCLifetime(OCL_None); }
void addObjCLifetime(ObjCLifetime type) {
assert(type);
setObjCLifetime(type);
assert(!hasObjCLifetime());
Mask |= (type << LifetimeShift);
}
/// True if the lifetime is neither None or ExplicitNone.
@ -447,7 +448,32 @@ enum CallingConv {
CC_AAPCS_VFP // __attribute__((pcs("aapcs-vfp")))
};
typedef std::pair<const Type*, Qualifiers> SplitQualType;
/// A std::pair-like structure for storing a qualified type split
/// into its local qualifiers and its locally-unqualified type.
struct SplitQualType {
/// The locally-unqualified type.
const Type *Ty;
/// The local qualifiers.
Qualifiers Quals;
SplitQualType() : Ty(0), Quals() {}
SplitQualType(const Type *ty, Qualifiers qs) : Ty(ty), Quals(qs) {}
SplitQualType getSingleStepDesugaredType() const; // end of this file
// Make llvm::tie work.
operator std::pair<const Type *,Qualifiers>() const {
return std::pair<const Type *,Qualifiers>(Ty, Quals);
}
friend bool operator==(SplitQualType a, SplitQualType b) {
return a.Ty == b.Ty && a.Quals == b.Quals;
}
friend bool operator!=(SplitQualType a, SplitQualType b) {
return a.Ty != b.Ty || a.Quals != b.Quals;
}
};
/// QualType - For efficiency, we don't store CV-qualified types as nodes on
/// their own: instead each reference to a type stores the qualifiers. This
@ -769,7 +795,9 @@ public:
///
/// This routine takes off the first typedef, typeof, etc. If the outer level
/// of the type is already concrete, it returns it unmodified.
QualType getSingleStepDesugaredType(const ASTContext &Context) const;
QualType getSingleStepDesugaredType(const ASTContext &Context) const {
return getSingleStepDesugaredTypeImpl(*this, Context);
}
/// IgnoreParens - Returns the specified type after dropping any
/// outer-level parentheses.
@ -791,7 +819,7 @@ public:
return getAsString(split());
}
static std::string getAsString(SplitQualType split) {
return getAsString(split.first, split.second);
return getAsString(split.Ty, split.Quals);
}
static std::string getAsString(const Type *ty, Qualifiers qs);
@ -806,7 +834,7 @@ public:
}
static void getAsStringInternal(SplitQualType split, std::string &out,
const PrintingPolicy &policy) {
return getAsStringInternal(split.first, split.second, out, policy);
return getAsStringInternal(split.Ty, split.Quals, out, policy);
}
static void getAsStringInternal(const Type *ty, Qualifiers qs,
std::string &out,
@ -887,6 +915,8 @@ private:
static QualType getDesugaredType(QualType T, const ASTContext &Context);
static SplitQualType getSplitDesugaredType(QualType T);
static SplitQualType getSplitUnqualifiedTypeImpl(QualType type);
static QualType getSingleStepDesugaredTypeImpl(QualType type,
const ASTContext &C);
static QualType IgnoreParens(QualType T);
static DestructionKind isDestructedTypeImpl(QualType type);
};
@ -1333,6 +1363,11 @@ public:
return CanonicalType == QualType(this, 0);
}
/// Pull a single level of sugar off of this locally-unqualified type.
/// Users should generally prefer SplitQualType::getSingleStepDesugaredType()
/// or QualType::getSingleStepDesugaredType(const ASTContext&).
QualType getLocallyUnqualifiedSingleStepDesugaredType() const;
/// Types are partitioned into 3 broad categories (C99 6.2.5p1):
/// object types, function types, and incomplete types.
@ -4406,6 +4441,13 @@ public:
// Inline function definitions.
inline SplitQualType SplitQualType::getSingleStepDesugaredType() const {
SplitQualType desugar =
Ty->getLocallyUnqualifiedSingleStepDesugaredType().split();
desugar.Quals.addConsistentQualifiers(Quals);
return desugar;
}
inline const Type *QualType::getTypePtr() const {
return getCommonPtr()->BaseType;
}
@ -4490,7 +4532,7 @@ inline QualType QualType::getUnqualifiedType() const {
if (!getTypePtr()->getCanonicalTypeInternal().hasLocalQualifiers())
return QualType(getTypePtr(), 0);
return QualType(getSplitUnqualifiedTypeImpl(*this).first, 0);
return QualType(getSplitUnqualifiedTypeImpl(*this).Ty, 0);
}
inline SplitQualType QualType::getSplitUnqualifiedType() const {

View File

@ -1526,7 +1526,7 @@ def err_arg_with_address_space : Error<
def err_attr_objc_ownership_bad_type : Error<
"the type %0 cannot be retained">;
def err_attr_objc_ownership_redundant : Error<
"the type %0 already has retainment attributes set on it">;
"the type %0 is already explicitly ownership-qualified">;
def err_attribute_not_string : Error<
"argument to %0 attribute was not a string literal">;
def err_only_annotate_after_access_spec : Error<

View File

@ -1387,8 +1387,8 @@ ASTContext::getExtQualType(const Type *baseType, Qualifiers quals) const {
QualType canon;
if (!baseType->isCanonicalUnqualified()) {
SplitQualType canonSplit = baseType->getCanonicalTypeInternal().split();
canonSplit.second.addConsistentQualifiers(quals);
canon = getExtQualType(canonSplit.first, canonSplit.second);
canonSplit.Quals.addConsistentQualifiers(quals);
canon = getExtQualType(canonSplit.Ty, canonSplit.Quals);
// Re-find the insert position.
(void) ExtQualNodes.FindNodeOrInsertPos(ID, insertPos);
@ -1690,9 +1690,9 @@ QualType ASTContext::getConstantArrayType(QualType EltTy,
QualType Canon;
if (!EltTy.isCanonical() || EltTy.hasLocalQualifiers()) {
SplitQualType canonSplit = getCanonicalType(EltTy).split();
Canon = getConstantArrayType(QualType(canonSplit.first, 0), ArySize,
Canon = getConstantArrayType(QualType(canonSplit.Ty, 0), ArySize,
ASM, IndexTypeQuals);
Canon = getQualifiedType(Canon, canonSplit.second);
Canon = getQualifiedType(Canon, canonSplit.Quals);
// Get the new insert position for the node we care about.
ConstantArrayType *NewIP =
@ -1717,7 +1717,7 @@ QualType ASTContext::getVariableArrayDecayedType(QualType type) const {
QualType result;
SplitQualType split = type.getSplitDesugaredType();
const Type *ty = split.first;
const Type *ty = split.Ty;
switch (ty->getTypeClass()) {
#define TYPE(Class, Base)
#define ABSTRACT_TYPE(Class, Base)
@ -1836,7 +1836,7 @@ QualType ASTContext::getVariableArrayDecayedType(QualType type) const {
}
// Apply the top-level qualifiers from the original.
return getQualifiedType(result, split.second);
return getQualifiedType(result, split.Quals);
}
/// getVariableArrayType - Returns a non-unique reference to the type for a
@ -1853,9 +1853,9 @@ QualType ASTContext::getVariableArrayType(QualType EltTy,
// 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,
Canon = getVariableArrayType(QualType(canonSplit.Ty, 0), NumElts, ASM,
IndexTypeQuals, Brackets);
Canon = getQualifiedType(Canon, canonSplit.second);
Canon = getQualifiedType(Canon, canonSplit.Quals);
}
VariableArrayType *New = new(*this, TypeAlignment)
@ -1900,7 +1900,7 @@ QualType ASTContext::getDependentSizedArrayType(QualType elementType,
void *insertPos = 0;
llvm::FoldingSetNodeID ID;
DependentSizedArrayType::Profile(ID, *this,
QualType(canonElementType.first, 0),
QualType(canonElementType.Ty, 0),
ASM, elementTypeQuals, numElements);
// Look for an existing type with these properties.
@ -1910,7 +1910,7 @@ QualType ASTContext::getDependentSizedArrayType(QualType elementType,
// If we don't have one, build one.
if (!canonTy) {
canonTy = new (*this, TypeAlignment)
DependentSizedArrayType(*this, QualType(canonElementType.first, 0),
DependentSizedArrayType(*this, QualType(canonElementType.Ty, 0),
QualType(), numElements, ASM, elementTypeQuals,
brackets);
DependentSizedArrayTypes.InsertNode(canonTy, insertPos);
@ -1919,11 +1919,11 @@ QualType ASTContext::getDependentSizedArrayType(QualType elementType,
// Apply qualifiers from the element type to the array.
QualType canon = getQualifiedType(QualType(canonTy,0),
canonElementType.second);
canonElementType.Quals);
// If we didn't need extra canonicalization for the element type,
// then just use that as our result.
if (QualType(canonElementType.first, 0) == elementType)
if (QualType(canonElementType.Ty, 0) == elementType)
return canon;
// Otherwise, we need to build a type which follows the spelling
@ -1954,9 +1954,9 @@ QualType ASTContext::getIncompleteArrayType(QualType elementType,
if (!elementType.isCanonical() || elementType.hasLocalQualifiers()) {
SplitQualType canonSplit = getCanonicalType(elementType).split();
canon = getIncompleteArrayType(QualType(canonSplit.first, 0),
canon = getIncompleteArrayType(QualType(canonSplit.Ty, 0),
ASM, elementTypeQuals);
canon = getQualifiedType(canon, canonSplit.second);
canon = getQualifiedType(canon, canonSplit.Quals);
// Get the new insert position for the node we care about.
IncompleteArrayType *existing =
@ -3134,12 +3134,12 @@ QualType ASTContext::getUnqualifiedArrayType(QualType type,
// We then have to strip that sugar back off with
// getUnqualifiedDesugaredType(), which is silly.
const ArrayType *AT =
dyn_cast<ArrayType>(splitType.first->getUnqualifiedDesugaredType());
dyn_cast<ArrayType>(splitType.Ty->getUnqualifiedDesugaredType());
// If we don't have an array, just use the results in splitType.
if (!AT) {
quals = splitType.second;
return QualType(splitType.first, 0);
quals = splitType.Quals;
return QualType(splitType.Ty, 0);
}
// Otherwise, recurse on the array's element type.
@ -3150,13 +3150,13 @@ QualType ASTContext::getUnqualifiedArrayType(QualType type,
// can just use the results in splitType.
if (elementType == unqualElementType) {
assert(quals.empty()); // from the recursive call
quals = splitType.second;
return QualType(splitType.first, 0);
quals = splitType.Quals;
return QualType(splitType.Ty, 0);
}
// Otherwise, add in the qualifiers from the outermost type, then
// build the type back up.
quals.addConsistentQualifiers(splitType.second);
quals.addConsistentQualifiers(splitType.Quals);
if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(AT)) {
return getConstantArrayType(unqualElementType, CAT->getSize(),
@ -3458,10 +3458,10 @@ const ArrayType *ASTContext::getAsArrayType(QualType T) const {
// we must propagate them down into the element type.
SplitQualType split = T.getSplitDesugaredType();
Qualifiers qs = split.second;
Qualifiers qs = split.Quals;
// If we have a simple case, just return now.
const ArrayType *ATy = dyn_cast<ArrayType>(split.first);
const ArrayType *ATy = dyn_cast<ArrayType>(split.Ty);
if (ATy == 0 || qs.empty())
return ATy;
@ -3548,11 +3548,11 @@ QualType ASTContext::getBaseElementType(QualType type) const {
Qualifiers qs;
while (true) {
SplitQualType split = type.getSplitDesugaredType();
const ArrayType *array = split.first->getAsArrayTypeUnsafe();
const ArrayType *array = split.Ty->getAsArrayTypeUnsafe();
if (!array) break;
type = array->getElementType();
qs.addConsistentQualifiers(split.second);
qs.addConsistentQualifiers(split.Quals);
}
return getQualifiedType(type, qs);

View File

@ -1655,8 +1655,8 @@ void CXXNameMangler::mangleType(QualType T) {
} while (true);
}
SplitQualType split = T.split();
Qualifiers quals = split.second;
const Type *ty = split.first;
Qualifiers quals = split.Quals;
const Type *ty = split.Ty;
bool isSubstitutable = quals || !isa<BuiltinType>(T);
if (isSubstitutable && mangleSubstitution(T))

View File

@ -197,27 +197,28 @@ const Type *Type::getArrayElementTypeNoTypeQual() const {
/// concrete.
QualType QualType::getDesugaredType(QualType T, const ASTContext &Context) {
SplitQualType split = getSplitDesugaredType(T);
return Context.getQualifiedType(split.first, split.second);
return Context.getQualifiedType(split.Ty, split.Quals);
}
QualType QualType::getSingleStepDesugaredType(const ASTContext &Context) const {
QualifierCollector Qs;
const Type *CurTy = Qs.strip(*this);
switch (CurTy->getTypeClass()) {
QualType QualType::getSingleStepDesugaredTypeImpl(QualType type,
const ASTContext &Context) {
SplitQualType split = type.split();
QualType desugar = split.Ty->getLocallyUnqualifiedSingleStepDesugaredType();
return Context.getQualifiedType(desugar, split.Quals);
}
QualType Type::getLocallyUnqualifiedSingleStepDesugaredType() const {
switch (getTypeClass()) {
#define ABSTRACT_TYPE(Class, Parent)
#define TYPE(Class, Parent) \
case Type::Class: { \
const Class##Type *Ty = cast<Class##Type>(CurTy); \
if (!Ty->isSugared()) \
return *this; \
return Context.getQualifiedType(Ty->desugar(), Qs); \
break; \
const Class##Type *ty = cast<Class##Type>(this); \
if (!ty->isSugared()) return QualType(ty, 0); \
return ty->desugar(); \
}
#include "clang/AST/TypeNodes.def"
}
return *this;
llvm_unreachable("bad type kind!");
}
SplitQualType QualType::getSplitDesugaredType(QualType T) {
@ -245,21 +246,21 @@ SplitQualType QualType::getSplitUnqualifiedTypeImpl(QualType type) {
SplitQualType split = type.split();
// All the qualifiers we've seen so far.
Qualifiers quals = split.second;
Qualifiers quals = split.Quals;
// The last type node we saw with any nodes inside it.
const Type *lastTypeWithQuals = split.first;
const Type *lastTypeWithQuals = split.Ty;
while (true) {
QualType next;
// Do a single-step desugar, aborting the loop if the type isn't
// sugared.
switch (split.first->getTypeClass()) {
switch (split.Ty->getTypeClass()) {
#define ABSTRACT_TYPE(Class, Parent)
#define TYPE(Class, Parent) \
case Type::Class: { \
const Class##Type *ty = cast<Class##Type>(split.first); \
const Class##Type *ty = cast<Class##Type>(split.Ty); \
if (!ty->isSugared()) goto done; \
next = ty->desugar(); \
break; \
@ -270,9 +271,9 @@ SplitQualType QualType::getSplitUnqualifiedTypeImpl(QualType type) {
// Otherwise, split the underlying type. If that yields qualifiers,
// update the information.
split = next.split();
if (!split.second.empty()) {
lastTypeWithQuals = split.first;
quals.addConsistentQualifiers(split.second);
if (!split.Quals.empty()) {
lastTypeWithQuals = split.Ty;
quals.addConsistentQualifiers(split.Quals);
}
}

View File

@ -75,7 +75,7 @@ static void AppendTypeQualList(std::string &S, unsigned TypeQuals) {
void TypePrinter::print(QualType t, std::string &buffer) {
SplitQualType split = t.split();
print(split.first, split.second, buffer);
print(split.Ty, split.Quals, buffer);
}
void TypePrinter::print(const Type *T, Qualifiers Quals, std::string &buffer) {

View File

@ -4982,9 +4982,9 @@ checkPointerTypesForAssignment(Sema &S, QualType LHSType, QualType RHSType) {
// It's okay to add or remove GC or lifetime qualifiers when converting to
// and from void*.
else if (lhq.withoutObjCGCAttr().withoutObjCGLifetime()
else if (lhq.withoutObjCGCAttr().withoutObjCLifetime()
.compatiblyIncludes(
rhq.withoutObjCGCAttr().withoutObjCGLifetime())
rhq.withoutObjCGCAttr().withoutObjCLifetime())
&& (lhptee->isVoidType() || rhptee->isVoidType()))
; // keep old

View File

@ -2211,7 +2211,7 @@ bool Sema::isObjCWritebackConversion(QualType FromType, QualType ToType,
Qualifiers ToQuals = ToPointee.getQualifiers();
if (!ToPointee->isObjCLifetimeType() ||
ToQuals.getObjCLifetime() != Qualifiers::OCL_Autoreleasing ||
!ToQuals.withoutObjCGLifetime().empty())
!ToQuals.withoutObjCLifetime().empty())
return false;
// Argument must be a pointer to __strong to __weak.

View File

@ -3497,9 +3497,9 @@ namespace {
SplitQualType SplitOld = Old.split();
// As a special case, tail-recurse if there are no qualifiers.
if (SplitOld.second.empty())
return wrap(C, SplitOld.first, I);
return C.getQualifiedType(wrap(C, SplitOld.first, I), SplitOld.second);
if (SplitOld.Quals.empty())
return wrap(C, SplitOld.Ty, I);
return C.getQualifiedType(wrap(C, SplitOld.Ty, I), SplitOld.Quals);
}
QualType wrap(ASTContext &C, const Type *Old, unsigned I) {