Generalize some operations on qualifiers. QualType::getQualifiers() and
::getCVRQualifiers() now look through array types, like all the other
standard queries. Also, make a 'split' variant of getUnqualifiedType().
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@123751 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h
index e32676a..7e57af5 100644
--- a/include/clang/AST/Type.h
+++ b/include/clang/AST/Type.h
@@ -272,6 +272,25 @@
}
}
+ /// \brief Add the qualifiers from the given set to this set, given that
+ /// they don't conflict.
+ void addConsistentQualifiers(Qualifiers qs) {
+ assert(getAddressSpace() == qs.getAddressSpace() ||
+ !hasAddressSpace() || !qs.hasAddressSpace());
+ assert(getObjCGCAttr() == qs.getObjCGCAttr() ||
+ !hasObjCGCAttr() || !qs.hasObjCGCAttr());
+ Mask |= qs.Mask;
+ }
+
+ /// \brief Determines if these qualifiers compatibly include another set.
+ /// Generally this answers the question of whether an object with the other
+ /// qualifiers can be safely used as an object with these qualifiers.
+ bool compatiblyIncludes(Qualifiers other) const {
+ // Non-CVR qualifiers must match exactly. CVR qualifiers may subset.
+ return ((Mask & ~CVRMask) == (other.Mask & ~CVRMask)) &&
+ (((Mask & CVRMask) | (other.Mask & CVRMask)) == (Mask & CVRMask));
+ }
+
bool isSupersetOf(Qualifiers Other) const;
bool operator==(Qualifiers Other) const { return Mask == Other.Mask; }
@@ -442,8 +461,6 @@
return Value.getPointer().get<const Type*>();
}
- QualType getUnqualifiedTypeSlow() const;
-
friend class QualifierCollector;
public:
QualType() {}
@@ -588,11 +605,6 @@
/// applied to this type.
unsigned getCVRQualifiers() const;
- /// \brief Retrieve the set of CVR (const-volatile-restrict) qualifiers
- /// applied to this type, looking through any number of unqualified array
- /// types to their element types' qualifiers.
- unsigned getCVRQualifiersThroughArrayTypes() const;
-
bool isConstant(ASTContext& Ctx) const {
return QualType::isConstant(*this, Ctx);
}
@@ -651,15 +663,36 @@
/// through typedefs.
QualType getLocalUnqualifiedType() const { return QualType(getTypePtr(), 0); }
- /// \brief Return the unqualified form of the given type, which might be
- /// desugared to eliminate qualifiers introduced via typedefs.
- QualType getUnqualifiedType() const {
- QualType T = getLocalUnqualifiedType();
- if (!T.hasQualifiers())
- return T;
-
- return getUnqualifiedTypeSlow();
- }
+ /// \brief Retrieve the unqualified variant of the given type,
+ /// removing as little sugar as possible.
+ ///
+ /// This routine looks through various kinds of sugar to find the
+ /// least-desugared type that is unqualified. For example, given:
+ ///
+ /// \code
+ /// typedef int Integer;
+ /// typedef const Integer CInteger;
+ /// typedef CInteger DifferenceType;
+ /// \endcode
+ ///
+ /// Executing \c getUnqualifiedType() on the type \c DifferenceType will
+ /// desugar until we hit the type \c Integer, which has no qualifiers on it.
+ ///
+ /// The resulting type might still be qualified if it's an array
+ /// type. To strip qualifiers even from within an array type, use
+ /// ASTContext::getUnqualifiedArrayType.
+ inline QualType getUnqualifiedType() const;
+
+ /// getSplitUnqualifiedType - Retrieve the unqualified variant of the
+ /// given type, removing as little sugar as possible.
+ ///
+ /// Like getUnqualifiedType(), but also returns the set of
+ /// qualifiers that were built up.
+ ///
+ /// The resulting type might still be qualified if it's an array
+ /// type. To strip qualifiers even from within an array type, use
+ /// ASTContext::getUnqualifiedArrayType.
+ inline SplitQualType getSplitUnqualifiedType() const;
bool isMoreQualifiedThan(QualType Other) const;
bool isAtLeastAsQualifiedAs(QualType Other) const;
@@ -762,6 +795,7 @@
static bool isConstant(QualType T, ASTContext& Ctx);
static QualType getDesugaredType(QualType T, const ASTContext &Context);
static SplitQualType getSplitDesugaredType(QualType T);
+ static SplitQualType getSplitUnqualifiedTypeImpl(QualType type);
static QualType IgnoreParens(QualType T);
};
@@ -3826,30 +3860,46 @@
return hasLocalQualifiers() ||
getTypePtr()->getCanonicalTypeInternal().hasLocalQualifiers();
}
-
-inline Qualifiers QualType::getQualifiers() const {
- Qualifiers Quals = getLocalQualifiers();
- Quals.addQualifiers(
- getTypePtr()->getCanonicalTypeInternal().getLocalQualifiers());
- return Quals;
-}
-
-inline unsigned QualType::getCVRQualifiers() const {
- return getLocalCVRQualifiers() |
- getTypePtr()->getCanonicalTypeInternal().getLocalCVRQualifiers();
+
+inline QualType QualType::getUnqualifiedType() const {
+ if (!getTypePtr()->getCanonicalTypeInternal().hasLocalQualifiers())
+ return QualType(getTypePtr(), 0);
+
+ return QualType(getSplitUnqualifiedTypeImpl(*this).first, 0);
}
-/// getCVRQualifiersThroughArrayTypes - If there are CVR qualifiers for this
-/// type, returns them. Otherwise, if this is an array type, recurses
-/// on the element type until some qualifiers have been found or a non-array
-/// type reached.
-inline unsigned QualType::getCVRQualifiersThroughArrayTypes() const {
- if (unsigned Quals = getCVRQualifiers())
- return Quals;
- QualType CT = getTypePtr()->getCanonicalTypeInternal();
- if (const ArrayType *AT = dyn_cast<ArrayType>(CT))
- return AT->getElementType().getCVRQualifiersThroughArrayTypes();
- return 0;
+inline SplitQualType QualType::getSplitUnqualifiedType() const {
+ if (!getTypePtr()->getCanonicalTypeInternal().hasLocalQualifiers())
+ return split();
+
+ 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() {
@@ -3937,26 +3987,18 @@
/// is more qualified than "const int", "volatile int", and
/// "int". However, it is not more qualified than "const volatile
/// int".
-inline bool QualType::isMoreQualifiedThan(QualType Other) const {
- // FIXME: work on arbitrary qualifiers
- unsigned MyQuals = this->getCVRQualifiersThroughArrayTypes();
- unsigned OtherQuals = Other.getCVRQualifiersThroughArrayTypes();
- if (getAddressSpace() != Other.getAddressSpace())
- return false;
- return MyQuals != OtherQuals && (MyQuals | OtherQuals) == MyQuals;
+inline bool QualType::isMoreQualifiedThan(QualType other) const {
+ Qualifiers myQuals = getQualifiers();
+ Qualifiers otherQuals = other.getQualifiers();
+ return (myQuals != otherQuals && myQuals.compatiblyIncludes(otherQuals));
}
/// isAtLeastAsQualifiedAs - Determine whether this type is at last
/// as qualified as the Other type. For example, "const volatile
/// int" is at least as qualified as "const int", "volatile int",
/// "int", and "const volatile int".
-inline bool QualType::isAtLeastAsQualifiedAs(QualType Other) const {
- // FIXME: work on arbitrary qualifiers
- unsigned MyQuals = this->getCVRQualifiersThroughArrayTypes();
- unsigned OtherQuals = Other.getCVRQualifiersThroughArrayTypes();
- if (getAddressSpace() != Other.getAddressSpace())
- return false;
- return (MyQuals | OtherQuals) == MyQuals;
+inline bool QualType::isAtLeastAsQualifiedAs(QualType other) const {
+ return getQualifiers().compatiblyIncludes(other.getQualifiers());
}
/// getNonReferenceType - If Type is a reference type (e.g., const
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index 2e1a8c2..ec9de25 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -2626,30 +2626,50 @@
VAT->getBracketsRange()));
}
-QualType ASTContext::getUnqualifiedArrayType(QualType T,
- Qualifiers &Quals) {
- Quals = T.getQualifiers();
- const ArrayType *AT = getAsArrayType(T);
+QualType ASTContext::getUnqualifiedArrayType(QualType type,
+ Qualifiers &quals) {
+ SplitQualType splitType = type.getSplitUnqualifiedType();
+
+ // FIXME: getSplitUnqualifiedType() actually walks all the way to
+ // the unqualified desugared type and then drops it on the floor.
+ // We then have to strip that sugar back off with
+ // getUnqualifiedDesugaredType(), which is silly.
+ const ArrayType *AT =
+ dyn_cast<ArrayType>(splitType.first->getUnqualifiedDesugaredType());
+
+ // If we don't have an array, just use the results in splitType.
if (!AT) {
- return T.getUnqualifiedType();
+ quals = splitType.second;
+ return QualType(splitType.first, 0);
}
- QualType Elt = AT->getElementType();
- QualType UnqualElt = getUnqualifiedArrayType(Elt, Quals);
- if (Elt == UnqualElt)
- return T;
+ // Otherwise, recurse on the array's element type.
+ QualType elementType = AT->getElementType();
+ QualType unqualElementType = getUnqualifiedArrayType(elementType, quals);
+
+ // If that didn't change the element type, AT has no qualifiers, so we
+ // 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);
+ }
+
+ // Otherwise, add in the qualifiers from the outermost type, then
+ // build the type back up.
+ quals.addConsistentQualifiers(splitType.second);
if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(AT)) {
- return getConstantArrayType(UnqualElt, CAT->getSize(),
+ return getConstantArrayType(unqualElementType, CAT->getSize(),
CAT->getSizeModifier(), 0);
}
if (const IncompleteArrayType *IAT = dyn_cast<IncompleteArrayType>(AT)) {
- return getIncompleteArrayType(UnqualElt, IAT->getSizeModifier(), 0);
+ return getIncompleteArrayType(unqualElementType, IAT->getSizeModifier(), 0);
}
if (const VariableArrayType *VAT = dyn_cast<VariableArrayType>(AT)) {
- return getVariableArrayType(UnqualElt,
+ return getVariableArrayType(unqualElementType,
VAT->getSizeExpr(),
VAT->getSizeModifier(),
VAT->getIndexTypeCVRQualifiers(),
@@ -2657,7 +2677,7 @@
}
const DependentSizedArrayType *DSAT = cast<DependentSizedArrayType>(AT);
- return getDependentSizedArrayType(UnqualElt, DSAT->getSizeExpr(),
+ return getDependentSizedArrayType(unqualElementType, DSAT->getSizeExpr(),
DSAT->getSizeModifier(), 0,
SourceRange());
}
diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp
index 3882f49..f69c38f 100644
--- a/lib/AST/Type.cpp
+++ b/lib/AST/Type.cpp
@@ -150,44 +150,6 @@
->getElementType().getTypePtr();
}
-/// \brief Retrieve the unqualified variant of the given type, removing as
-/// little sugar as possible.
-///
-/// This routine looks through various kinds of sugar to find the
-/// least-desuraged type that is unqualified. For example, given:
-///
-/// \code
-/// typedef int Integer;
-/// typedef const Integer CInteger;
-/// typedef CInteger DifferenceType;
-/// \endcode
-///
-/// Executing \c getUnqualifiedTypeSlow() on the type \c DifferenceType will
-/// desugar until we hit the type \c Integer, which has no qualifiers on it.
-QualType QualType::getUnqualifiedTypeSlow() const {
- QualType Cur = *this;
- while (true) {
- if (!Cur.hasQualifiers())
- return Cur;
-
- const Type *CurTy = Cur.getTypePtr();
- switch (CurTy->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 Cur.getLocalUnqualifiedType(); \
- Cur = Ty->desugar(); \
- break; \
- }
-#include "clang/AST/TypeNodes.def"
- }
- }
-
- return Cur.getUnqualifiedType();
-}
-
/// getDesugaredType - Return the specified type with any "sugar" removed from
/// the type. This takes off typedefs, typeof's etc. If the outer level of
/// the type is already concrete, it returns it unmodified. This is similar
@@ -220,7 +182,47 @@
}
}
+SplitQualType QualType::getSplitUnqualifiedTypeImpl(QualType type) {
+ SplitQualType split = type.split();
+
+ // All the qualifiers we've seen so far.
+ Qualifiers quals = split.second;
+
+ // The last type node we saw with any nodes inside it.
+ const Type *lastTypeWithQuals = split.first;
+
+ while (true) {
+ QualType next;
+
+ // Do a single-step desugar, aborting the loop if the type isn't
+ // sugared.
+ switch (split.first->getTypeClass()) {
+#define ABSTRACT_TYPE(Class, Parent)
+#define TYPE(Class, Parent) \
+ case Type::Class: { \
+ const Class##Type *ty = cast<Class##Type>(split.first); \
+ if (!ty->isSugared()) goto done; \
+ next = ty->desugar(); \
+ break; \
+ }
+#include "clang/AST/TypeNodes.def"
+ }
+
+ // 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);
+ }
+ }
+
+ done:
+ return SplitQualType(lastTypeWithQuals, quals);
+}
+
QualType QualType::IgnoreParens(QualType T) {
+ // FIXME: this seems inherently un-qualifiers-safe.
while (const ParenType *PT = T->getAs<ParenType>())
T = PT->getInnerType();
return T;
diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp
index 0d074e0..812c633 100644
--- a/lib/Sema/SemaTemplateDeduction.cpp
+++ b/lib/Sema/SemaTemplateDeduction.cpp
@@ -476,6 +476,7 @@
case Type::DependentName:
case Type::Decltype:
case Type::UnresolvedUsing:
+ case Type::TemplateTypeParm:
return true;
case Type::ConstantArray:
@@ -876,7 +877,7 @@
Qualifiers Quals;
QualType UnqualParam = S.Context.getUnqualifiedArrayType(Param, Quals);
Quals.setCVRQualifiers(Quals.getCVRQualifiers() &
- Arg.getCVRQualifiersThroughArrayTypes());
+ Arg.getCVRQualifiers());
Param = S.Context.getQualifiedType(UnqualParam, Quals);
}
}