diff options
author | John McCall <rjmccall@apple.com> | 2012-02-08 00:46:36 +0000 |
---|---|---|
committer | John McCall <rjmccall@apple.com> | 2012-02-08 00:46:36 +0000 |
commit | 200fa53fd420aa8369586f569dbece04930ad6a3 (patch) | |
tree | 8cba3653f5d0a0caa25a13f020c1ec027e9c420c | |
parent | 531b1a91fbbf75dc2ab54f609e304376753e1679 (diff) |
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").
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@150028 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | include/clang/AST/ASTContext.h | 5 | ||||
-rw-r--r-- | include/clang/AST/Type.h | 56 | ||||
-rw-r--r-- | include/clang/Basic/DiagnosticSemaKinds.td | 2 | ||||
-rw-r--r-- | lib/AST/ASTContext.cpp | 48 | ||||
-rw-r--r-- | lib/AST/ItaniumMangle.cpp | 4 | ||||
-rw-r--r-- | lib/AST/Type.cpp | 41 | ||||
-rw-r--r-- | lib/AST/TypePrinter.cpp | 2 | ||||
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 4 | ||||
-rw-r--r-- | lib/Sema/SemaOverload.cpp | 2 | ||||
-rw-r--r-- | lib/Sema/SemaType.cpp | 6 |
10 files changed, 109 insertions, 61 deletions
diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index c0d191e565..3236977030 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -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()) diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h index 641f732c59..ef4dbdd241 100644 --- a/include/clang/AST/Type.h +++ b/include/clang/AST/Type.h @@ -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 { diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index e52b35e1cd..4366cd4dee 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -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< diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 069f1068da..fb7d747377 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -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); diff --git a/lib/AST/ItaniumMangle.cpp b/lib/AST/ItaniumMangle.cpp index 59192428b8..7df8f6fc6b 100644 --- a/lib/AST/ItaniumMangle.cpp +++ b/lib/AST/ItaniumMangle.cpp @@ -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)) diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index ebf5706ed0..b52e61b528 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -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); } } diff --git a/lib/AST/TypePrinter.cpp b/lib/AST/TypePrinter.cpp index 7e9e7c59b1..abe68ef07b 100644 --- a/lib/AST/TypePrinter.cpp +++ b/lib/AST/TypePrinter.cpp @@ -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) { diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index f656f90ea5..1829565238 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -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 diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index fa103819bd..b0b2a78320 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -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. diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index 29cede9130..67ee9376e8 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -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) { |