From 62c28c831bbf207cc36e683e7c321fc33bf8928c Mon Sep 17 00:00:00 2001 From: John McCall <rjmccall@apple.com> Date: Tue, 18 Jan 2011 07:41:22 +0000 Subject: [PATCH] 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 --- include/clang/AST/Type.h | 142 +++++++++++++++++++---------- lib/AST/ASTContext.cpp | 46 +++++++--- lib/AST/Type.cpp | 78 ++++++++-------- lib/Sema/SemaTemplateDeduction.cpp | 3 +- 4 files changed, 167 insertions(+), 102 deletions(-) diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h index e32676a3973..7e57af5c23a 100644 --- a/include/clang/AST/Type.h +++ b/include/clang/AST/Type.h @@ -272,6 +272,25 @@ public: } } + /// \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 @@ class QualType { return Value.getPointer().get<const Type*>(); } - QualType getUnqualifiedTypeSlow() const; - friend class QualifierCollector; public: QualType() {} @@ -588,11 +605,6 @@ public: /// 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 @@ public: /// 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 @@ private: 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 @@ inline bool QualType::hasQualifiers() const { return hasLocalQualifiers() || getTypePtr()->getCanonicalTypeInternal().hasLocalQualifiers(); } - -inline Qualifiers QualType::getQualifiers() const { - Qualifiers Quals = getLocalQualifiers(); - Quals.addQualifiers( - getTypePtr()->getCanonicalTypeInternal().getLocalQualifiers()); - return Quals; + +inline QualType QualType::getUnqualifiedType() const { + if (!getTypePtr()->getCanonicalTypeInternal().hasLocalQualifiers()) + return QualType(getTypePtr(), 0); + + return QualType(getSplitUnqualifiedTypeImpl(*this).first, 0); +} + +inline SplitQualType QualType::getSplitUnqualifiedType() const { + if (!getTypePtr()->getCanonicalTypeInternal().hasLocalQualifiers()) + return split(); + + return getSplitUnqualifiedTypeImpl(*this); } -inline unsigned QualType::getCVRQualifiers() const { - return getLocalCVRQualifiers() | - getTypePtr()->getCanonicalTypeInternal().getLocalCVRQualifiers(); +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; } -/// 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 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 @@ inline bool Qualifiers::isSupersetOf(Qualifiers Other) const { /// 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 2e1a8c2d4bb..ec9de250179 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -2626,30 +2626,50 @@ CanQualType ASTContext::getCanonicalType(QualType T) const { 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 @@ QualType ASTContext::getUnqualifiedArrayType(QualType T, } 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 3882f4960ac..f69c38f4ab8 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -150,44 +150,6 @@ const Type *Type::getArrayElementTypeNoTypeQual() const { ->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::getSplitDesugaredType(QualType T) { } } +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 0d074e03333..812c633c587 100644 --- a/lib/Sema/SemaTemplateDeduction.cpp +++ b/lib/Sema/SemaTemplateDeduction.cpp @@ -476,6 +476,7 @@ static bool IsPossiblyOpaquelyQualifiedType(QualType T) { case Type::DependentName: case Type::Decltype: case Type::UnresolvedUsing: + case Type::TemplateTypeParm: return true; case Type::ConstantArray: @@ -876,7 +877,7 @@ DeduceTemplateArguments(Sema &S, Qualifiers Quals; QualType UnqualParam = S.Context.getUnqualifiedArrayType(Param, Quals); Quals.setCVRQualifiers(Quals.getCVRQualifiers() & - Arg.getCVRQualifiersThroughArrayTypes()); + Arg.getCVRQualifiers()); Param = S.Context.getQualifiedType(UnqualParam, Quals); } } -- GitLab