forked from OSchip/llvm-project
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:
parent
9716914b2d
commit
18ce25e1ec
|
@ -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())
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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<
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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) {
|
||||
|
|
Loading…
Reference in New Issue