diff --git a/clang/include/clang/AST/ASTConcept.h b/clang/include/clang/AST/ASTConcept.h index c8f6330a73bb1..6ab82824458ab 100644 --- a/clang/include/clang/AST/ASTConcept.h +++ b/clang/include/clang/AST/ASTConcept.h @@ -15,7 +15,7 @@ #define LLVM_CLANG_AST_ASTCONCEPT_H #include "clang/AST/DeclarationName.h" -#include "clang/AST/NestedNameSpecifier.h" +#include "clang/AST/NestedNameSpecifierBase.h" #include "clang/AST/TemplateBase.h" #include "clang/Basic/SourceLocation.h" #include "clang/Basic/UnsignedOrNone.h" @@ -175,12 +175,7 @@ class ConceptReference { SourceLocation getLocation() const { return getConceptNameLoc(); } - SourceLocation getBeginLoc() const LLVM_READONLY { - // Note that if the qualifier is null the template KW must also be null. - if (auto QualifierLoc = getNestedNameSpecifierLoc()) - return QualifierLoc.getBeginLoc(); - return getConceptNameInfo().getBeginLoc(); - } + SourceLocation getBeginLoc() const LLVM_READONLY; SourceLocation getEndLoc() const LLVM_READONLY { return getTemplateArgsAsWritten() && diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h index 2b9cd035623cc..bb2e0c5bc630e 100644 --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -233,10 +233,11 @@ class ASTContext : public RefCountedBase { mutable llvm::ContextualFoldingSet TemplateSpecializationTypes; mutable llvm::FoldingSet ParenTypes{GeneralTypesLog2InitSize}; + mutable llvm::FoldingSet TagTypes; + mutable llvm::FoldingSet> + UnresolvedUsingTypes; mutable llvm::FoldingSet UsingTypes; - mutable llvm::FoldingSet TypedefTypes; - mutable llvm::FoldingSet ElaboratedTypes{ - GeneralTypesLog2InitSize}; + mutable llvm::FoldingSet> TypedefTypes; mutable llvm::FoldingSet DependentNameTypes; mutable llvm::ContextualFoldingSet @@ -277,11 +278,11 @@ class ASTContext : public RefCountedBase { mutable llvm::ContextualFoldingSet ArrayParameterTypes; - /// The set of nested name specifiers. + /// Internal storage for NestedNameSpecifiers. /// /// This set is managed by the NestedNameSpecifier class. - mutable llvm::FoldingSet NestedNameSpecifiers; - mutable NestedNameSpecifier *GlobalNestedNameSpecifier = nullptr; + mutable llvm::FoldingSet + NamespaceAndPrefixStorages; /// A cache mapping from RecordDecls to ASTRecordLayouts. /// @@ -1370,8 +1371,6 @@ class ASTContext : public RefCountedBase { /// Return a type with extended qualifiers. QualType getExtQualType(const Type *Base, Qualifiers Quals) const; - QualType getTypeDeclTypeSlow(const TypeDecl *Decl) const; - QualType getPipeType(QualType T, bool ReadOnly) const; public: @@ -1612,7 +1611,7 @@ class ASTContext : public RefCountedBase { /// Return the uniqued reference to the type for a member pointer to /// the specified type in the specified nested name. - QualType getMemberPointerType(QualType T, NestedNameSpecifier *Qualifier, + QualType getMemberPointerType(QualType T, NestedNameSpecifier Qualifier, const CXXRecordDecl *Cls) const; /// Return a non-unique reference to the type for a variable array of @@ -1749,34 +1748,51 @@ class ASTContext : public RefCountedBase { bool IsCanon = false) const; public: + QualType getTypeDeclType(ElaboratedTypeKeyword Keyword, + NestedNameSpecifier Qualifier, + const TypeDecl *Decl) const; + /// Return the unique reference to the type for the specified type /// declaration. - QualType getTypeDeclType(const TypeDecl *Decl, - const TypeDecl *PrevDecl = nullptr) const { - assert(Decl && "Passed null for Decl param"); - if (Decl->TypeForDecl) return QualType(Decl->TypeForDecl, 0); - - if (PrevDecl) { - assert(PrevDecl->TypeForDecl && "previous decl has no TypeForDecl"); - Decl->TypeForDecl = PrevDecl->TypeForDecl; - return QualType(PrevDecl->TypeForDecl, 0); - } + QualType getTypeDeclType(const TypeDecl *Decl) const; + QualType getTypeDeclType(const TagDecl *) const = delete; + QualType getTypeDeclType(const TypedefDecl *) const = delete; + QualType getTypeDeclType(const TypeAliasDecl *) const = delete; + QualType getTypeDeclType(const UnresolvedUsingTypenameDecl *) const = delete; - return getTypeDeclTypeSlow(Decl); - } + CanQualType getCanonicalTypeDeclType(const TypeDecl *TD) const; - QualType getUsingType(const UsingShadowDecl *Found, - QualType Underlying) const; + QualType getUsingType(ElaboratedTypeKeyword Keyword, + NestedNameSpecifier Qualifier, const UsingShadowDecl *D, + QualType UnderlyingType = QualType()) const; /// Return the unique reference to the type for the specified /// typedef-name decl. - QualType getTypedefType(const TypedefNameDecl *Decl, - QualType Underlying = QualType()) const; + /// FIXME: TypeMatchesDeclOrNone is a workaround for a serialization issue: + /// The decl underlying type might still not be available. + QualType getTypedefType( + ElaboratedTypeKeyword Keyword, NestedNameSpecifier Qualifier, + const TypedefNameDecl *Decl, QualType UnderlyingType = QualType(), + std::optional TypeMatchesDeclOrNone = std::nullopt) const; + + CanQualType getCanonicalTagType(const TagDecl *TD) const; + QualType getTagType(ElaboratedTypeKeyword Keyword, + NestedNameSpecifier Qualifier, const TagDecl *TD, + bool OwnsTag) const; - QualType getRecordType(const RecordDecl *Decl) const; +private: + UnresolvedUsingType *getUnresolvedUsingTypeInternal( + ElaboratedTypeKeyword Keyword, NestedNameSpecifier Qualifier, + const UnresolvedUsingTypenameDecl *D, void *InsertPos, + const Type *CanonicalType) const; - QualType getEnumType(const EnumDecl *Decl) const; + TagType *getTagTypeInternal(ElaboratedTypeKeyword Keyword, + NestedNameSpecifier Qualifier, const TagDecl *Tag, + bool OwnsTag, bool IsInjected, + const Type *CanonicalType, + bool WithFoldingSetNode) const; +public: /// Compute BestType and BestPromotionType for an enum based on the highest /// number of negative and positive bits of its elements. /// Returns true if enum width is too large. @@ -1825,10 +1841,11 @@ class ASTContext : public RefCountedBase { return MembersRepresentableByInt; } - QualType - getUnresolvedUsingType(const UnresolvedUsingTypenameDecl *Decl) const; - - QualType getInjectedClassNameType(CXXRecordDecl *Decl, QualType TST) const; + CanQualType + getCanonicalUnresolvedUsingType(const UnresolvedUsingTypenameDecl *D) const; + QualType getUnresolvedUsingType(ElaboratedTypeKeyword Keyword, + NestedNameSpecifier Qualifier, + const UnresolvedUsingTypenameDecl *D) const; QualType getAttributedType(attr::Kind attrKind, QualType modifiedType, QualType equivalentType, @@ -1868,18 +1885,20 @@ class ASTContext : public RefCountedBase { TemplateName T, ArrayRef CanonicalArgs) const; QualType - getTemplateSpecializationType(TemplateName T, + getTemplateSpecializationType(ElaboratedTypeKeyword Keyword, TemplateName T, ArrayRef SpecifiedArgs, ArrayRef CanonicalArgs, QualType Underlying = QualType()) const; QualType - getTemplateSpecializationType(TemplateName T, + getTemplateSpecializationType(ElaboratedTypeKeyword Keyword, TemplateName T, ArrayRef SpecifiedArgs, ArrayRef CanonicalArgs, QualType Canon = QualType()) const; TypeSourceInfo *getTemplateSpecializationTypeInfo( + ElaboratedTypeKeyword Keyword, SourceLocation ElaboratedKeywordLoc, + NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateKeywordLoc, TemplateName T, SourceLocation TLoc, const TemplateArgumentListInfo &SpecifiedArgs, ArrayRef CanonicalArgs, @@ -1890,11 +1909,8 @@ class ASTContext : public RefCountedBase { QualType getMacroQualifiedType(QualType UnderlyingTy, const IdentifierInfo *MacroII) const; - QualType getElaboratedType(ElaboratedTypeKeyword Keyword, - NestedNameSpecifier *NNS, QualType NamedType, - TagDecl *OwnedTagDecl = nullptr) const; QualType getDependentNameType(ElaboratedTypeKeyword Keyword, - NestedNameSpecifier *NNS, + NestedNameSpecifier NNS, const IdentifierInfo *Name) const; QualType getDependentTemplateSpecializationType( @@ -1980,21 +1996,17 @@ class ASTContext : public RefCountedBase { QualType getUnconstrainedType(QualType T) const; /// C++17 deduced class template specialization type. - QualType getDeducedTemplateSpecializationType(TemplateName Template, + QualType getDeducedTemplateSpecializationType(ElaboratedTypeKeyword Keyword, + TemplateName Template, QualType DeducedType, bool IsDependent) const; private: - QualType getDeducedTemplateSpecializationTypeInternal(TemplateName Template, - QualType DeducedType, - bool IsDependent, - QualType Canon) const; + QualType getDeducedTemplateSpecializationTypeInternal( + ElaboratedTypeKeyword Keyword, TemplateName Template, + QualType DeducedType, bool IsDependent, QualType Canon) const; public: - /// Return the unique reference to the type for the specified TagDecl - /// (struct/union/class/enum) decl. - QualType getTagDeclType(const TagDecl *Decl) const; - /// Return the unique type for "size_t" (C99 7.17), defined in /// . /// @@ -2068,7 +2080,9 @@ class ASTContext : public RefCountedBase { /// if it hasn't yet been built. QualType getRawCFConstantStringType() const { if (CFConstantStringTypeDecl) - return getTypedefType(CFConstantStringTypeDecl); + return getTypedefType(ElaboratedTypeKeyword::None, + /*Qualifier=*/std::nullopt, + CFConstantStringTypeDecl); return QualType(); } void setCFConstantStringType(QualType T); @@ -2165,10 +2179,11 @@ class ASTContext : public RefCountedBase { } #include "clang/Basic/BuiltinTemplates.inc" - /// Retrieve the Objective-C "instancetype" type, if already known; - /// otherwise, returns a NULL type; + /// Retrieve the Objective-C "instancetype" type. QualType getObjCInstanceType() { - return getTypeDeclType(getObjCInstanceTypeDecl()); + return getTypedefType(ElaboratedTypeKeyword::None, + /*Qualifier=*/std::nullopt, + getObjCInstanceTypeDecl()); } /// Retrieve the typedef declaration corresponding to the Objective-C @@ -2181,7 +2196,8 @@ class ASTContext : public RefCountedBase { /// Retrieve the C FILE type. QualType getFILEType() const { if (FILEDecl) - return getTypeDeclType(FILEDecl); + return getTypeDeclType(ElaboratedTypeKeyword::None, + /*Qualifier=*/std::nullopt, FILEDecl); return QualType(); } @@ -2193,7 +2209,8 @@ class ASTContext : public RefCountedBase { /// Retrieve the C jmp_buf type. QualType getjmp_bufType() const { if (jmp_bufDecl) - return getTypeDeclType(jmp_bufDecl); + return getTypeDeclType(ElaboratedTypeKeyword::None, + /*Qualifier=*/std::nullopt, jmp_bufDecl); return QualType(); } @@ -2205,7 +2222,8 @@ class ASTContext : public RefCountedBase { /// Retrieve the C sigjmp_buf type. QualType getsigjmp_bufType() const { if (sigjmp_bufDecl) - return getTypeDeclType(sigjmp_bufDecl); + return getTypeDeclType(ElaboratedTypeKeyword::None, + /*Qualifier=*/std::nullopt, sigjmp_bufDecl); return QualType(); } @@ -2217,12 +2235,13 @@ class ASTContext : public RefCountedBase { /// Retrieve the C ucontext_t type. QualType getucontext_tType() const { if (ucontext_tDecl) - return getTypeDeclType(ucontext_tDecl); + return getTypeDeclType(ElaboratedTypeKeyword::None, + /*Qualifier=*/std::nullopt, ucontext_tDecl); return QualType(); } /// The result type of logical operations, '<', '>', '!=', etc. - QualType getLogicalOperationType() const { + CanQualType getLogicalOperationType() const { return getLangOpts().CPlusPlus ? BoolTy : IntTy; } @@ -2287,7 +2306,8 @@ class ASTContext : public RefCountedBase { /// This is set up lazily, by Sema. \c id is always a (typedef for a) /// pointer type, a pointer to a struct. QualType getObjCIdType() const { - return getTypeDeclType(getObjCIdDecl()); + return getTypedefType(ElaboratedTypeKeyword::None, + /*Qualifier=*/std::nullopt, getObjCIdDecl()); } /// Retrieve the typedef corresponding to the predefined 'SEL' type @@ -2297,7 +2317,8 @@ class ASTContext : public RefCountedBase { /// Retrieve the type that corresponds to the predefined Objective-C /// 'SEL' type. QualType getObjCSelType() const { - return getTypeDeclType(getObjCSelDecl()); + return getTypedefType(ElaboratedTypeKeyword::None, + /*Qualifier=*/std::nullopt, getObjCSelDecl()); } /// Retrieve the typedef declaration corresponding to the predefined @@ -2309,7 +2330,8 @@ class ASTContext : public RefCountedBase { /// This is set up lazily, by Sema. \c Class is always a (typedef for a) /// pointer type, a pointer to a struct. QualType getObjCClassType() const { - return getTypeDeclType(getObjCClassDecl()); + return getTypedefType(ElaboratedTypeKeyword::None, + /*Qualifier=*/std::nullopt, getObjCClassDecl()); } /// Retrieve the Objective-C class declaration corresponding to @@ -2328,7 +2350,8 @@ class ASTContext : public RefCountedBase { /// type of 'BOOL' type. QualType getBOOLType() const { - return getTypeDeclType(getBOOLDecl()); + return getTypedefType(ElaboratedTypeKeyword::None, + /*Qualifier=*/std::nullopt, getBOOLDecl()); } /// Retrieve the type of the Objective-C \c Protocol class. @@ -2342,7 +2365,8 @@ class ASTContext : public RefCountedBase { /// Retrieve the type of the \c __builtin_va_list type. QualType getBuiltinVaListType() const { - return getTypeDeclType(getBuiltinVaListDecl()); + return getTypedefType(ElaboratedTypeKeyword::None, + /*Qualifier=*/std::nullopt, getBuiltinVaListDecl()); } /// Retrieve the C type declaration corresponding to the predefined @@ -2356,16 +2380,17 @@ class ASTContext : public RefCountedBase { /// Retrieve the type of the \c __builtin_ms_va_list type. QualType getBuiltinMSVaListType() const { - return getTypeDeclType(getBuiltinMSVaListDecl()); + return getTypedefType(ElaboratedTypeKeyword::None, + /*Qualifier=*/std::nullopt, getBuiltinMSVaListDecl()); } /// Retrieve the implicitly-predeclared 'struct _GUID' declaration. TagDecl *getMSGuidTagDecl() const { return MSGuidTagDecl; } /// Retrieve the implicitly-predeclared 'struct _GUID' type. - QualType getMSGuidType() const { + CanQualType getMSGuidType() const { assert(MSGuidTagDecl && "asked for GUID type but MS extensions disabled"); - return getTagDeclType(MSGuidTagDecl); + return getCanonicalTagType(MSGuidTagDecl); } /// Return whether a declaration to a builtin is allowed to be @@ -2446,7 +2471,7 @@ class ASTContext : public RefCountedBase { UnresolvedSetIterator End) const; TemplateName getAssumedTemplateName(DeclarationName Name) const; - TemplateName getQualifiedTemplateName(NestedNameSpecifier *NNS, + TemplateName getQualifiedTemplateName(NestedNameSpecifier Qualifier, bool TemplateKeyword, TemplateName Template) const; TemplateName @@ -2888,32 +2913,6 @@ class ASTContext : public RefCountedBase { /// Determine if two types are similar, ignoring only CVR qualifiers. bool hasCvrSimilarType(QualType T1, QualType T2); - /// Retrieves the "canonical" nested name specifier for a - /// given nested name specifier. - /// - /// The canonical nested name specifier is a nested name specifier - /// that uniquely identifies a type or namespace within the type - /// system. For example, given: - /// - /// \code - /// namespace N { - /// struct S { - /// template struct X { typename T* type; }; - /// }; - /// } - /// - /// template struct Y { - /// typename N::S::X::type member; - /// }; - /// \endcode - /// - /// Here, the nested-name-specifier for N::S::X:: will be - /// S::X, since 'S' and 'X' are uniquely defined - /// by declarations in the type system and the canonical type for - /// the template type parameter 'T' is template-param-0-0. - NestedNameSpecifier * - getCanonicalNestedNameSpecifier(NestedNameSpecifier *NNS) const; - /// Retrieves the default calling convention for the current target. CallingConv getDefaultCallingConvention(bool IsVariadic, bool IsCXXMethod, @@ -3123,7 +3122,7 @@ class ASTContext : public RefCountedBase { mergeExceptionSpecs(FunctionProtoType::ExceptionSpecInfo ESI1, FunctionProtoType::ExceptionSpecInfo ESI2, SmallVectorImpl &ExceptionTypeStorage, - bool AcceptDependent); + bool AcceptDependent) const; // For two "same" types, return a type which has // the common sugar between them. If Unqualified is true, @@ -3131,7 +3130,7 @@ class ASTContext : public RefCountedBase { // The result will drop the qualifiers which do not occur // in both types. QualType getCommonSugaredType(QualType X, QualType Y, - bool Unqualified = false); + bool Unqualified = false) const; private: // Helper for integer ordering @@ -3149,23 +3148,11 @@ class ASTContext : public RefCountedBase { bool propertyTypesAreCompatible(QualType, QualType); bool typesAreBlockPointerCompatible(QualType, QualType); - bool isObjCIdType(QualType T) const { - if (const auto *ET = dyn_cast(T)) - T = ET->getNamedType(); - return T == getObjCIdType(); - } + bool isObjCIdType(QualType T) const { return T == getObjCIdType(); } - bool isObjCClassType(QualType T) const { - if (const auto *ET = dyn_cast(T)) - T = ET->getNamedType(); - return T == getObjCClassType(); - } + bool isObjCClassType(QualType T) const { return T == getObjCClassType(); } - bool isObjCSelType(QualType T) const { - if (const auto *ET = dyn_cast(T)) - T = ET->getNamedType(); - return T == getObjCSelType(); - } + bool isObjCSelType(QualType T) const { return T == getObjCSelType(); } bool ObjCQualifiedIdTypesAreCompatible(const ObjCObjectPointerType *LHS, const ObjCObjectPointerType *RHS, diff --git a/clang/include/clang/AST/ASTImporter.h b/clang/include/clang/AST/ASTImporter.h index c40b92666a2ff..4a0ca45b785a9 100644 --- a/clang/include/clang/AST/ASTImporter.h +++ b/clang/include/clang/AST/ASTImporter.h @@ -404,7 +404,7 @@ class TypeSourceInfo; /// /// \returns The equivalent nested-name-specifier in the "to" /// context, or the import error. - llvm::Expected Import(NestedNameSpecifier *FromNNS); + llvm::Expected Import(NestedNameSpecifier FromNNS); /// Import the given nested-name-specifier-loc from the "from" /// context into the "to" context. diff --git a/clang/include/clang/AST/ASTNodeTraverser.h b/clang/include/clang/AST/ASTNodeTraverser.h index 8ebabb2bde10d..d9dc8290b0e49 100644 --- a/clang/include/clang/AST/ASTNodeTraverser.h +++ b/clang/include/clang/AST/ASTNodeTraverser.h @@ -394,12 +394,14 @@ class ASTNodeTraverser } void VisitMemberPointerType(const MemberPointerType *T) { // FIXME: Provide a NestedNameSpecifier visitor. - NestedNameSpecifier *Qualifier = T->getQualifier(); - if (NestedNameSpecifier::SpecifierKind K = Qualifier->getKind(); - K == NestedNameSpecifier::TypeSpec) - Visit(Qualifier->getAsType()); + NestedNameSpecifier Qualifier = T->getQualifier(); + if (NestedNameSpecifier::Kind K = Qualifier.getKind(); + K == NestedNameSpecifier::Kind::Type) + Visit(Qualifier.getAsType()); if (T->isSugared()) - Visit(T->getMostRecentCXXRecordDecl()->getTypeForDecl()); + Visit(cast(T->getCanonicalTypeUnqualified()) + ->getQualifier() + .getAsType()); Visit(T->getPointeeType()); } void VisitArrayType(const ArrayType *T) { Visit(T->getElementType()); } @@ -510,7 +512,7 @@ class ASTNodeTraverser } void VisitMemberPointerTypeLoc(MemberPointerTypeLoc TL) { // FIXME: Provide NestedNamespecifierLoc visitor. - Visit(TL.getQualifierLoc().getTypeLoc()); + Visit(TL.getQualifierLoc().castAsTypeLoc()); } void VisitVariableArrayTypeLoc(VariableArrayTypeLoc TL) { Visit(TL.getSizeExpr()); @@ -772,17 +774,16 @@ class ASTNodeTraverser } void VisitUsingShadowDecl(const UsingShadowDecl *D) { - if (auto *TD = dyn_cast(D->getUnderlyingDecl())) - Visit(TD->getTypeForDecl()); + Visit(D->getTargetDecl()); } void VisitFriendDecl(const FriendDecl *D) { if (D->getFriendType()) { // Traverse any CXXRecordDecl owned by this type, since // it will not be in the parent context: - if (auto *ET = D->getFriendType()->getType()->getAs()) - if (auto *TD = ET->getOwnedTagDecl()) - Visit(TD); + if (auto *TT = D->getFriendType()->getType()->getAs()) + if (TT->isTagOwned()) + Visit(TT->getOriginalDecl()); } else { Visit(D->getFriendDecl()); } diff --git a/clang/include/clang/AST/ASTTypeTraits.h b/clang/include/clang/AST/ASTTypeTraits.h index 3988a15971db5..6f40705fb7436 100644 --- a/clang/include/clang/AST/ASTTypeTraits.h +++ b/clang/include/clang/AST/ASTTypeTraits.h @@ -307,7 +307,7 @@ class DynTypedNode { /// For nodes which represent textual entities in the source code, /// return their SourceRange. For all other nodes, return SourceRange(). - SourceRange getSourceRange() const; + SourceRange getSourceRange(bool IncludeQualifier = false) const; /// @{ /// Imposes an order on \c DynTypedNode. @@ -336,9 +336,9 @@ class DynTypedNode { NodeKind)) { auto NNSLA = getUnchecked(); auto NNSLB = Other.getUnchecked(); - return std::make_pair(NNSLA.getNestedNameSpecifier(), + return std::make_pair(NNSLA.getNestedNameSpecifier().getAsVoidPointer(), NNSLA.getOpaqueData()) < - std::make_pair(NNSLB.getNestedNameSpecifier(), + std::make_pair(NNSLB.getNestedNameSpecifier().getAsVoidPointer(), NNSLB.getOpaqueData()); } @@ -393,8 +393,9 @@ class DynTypedNode { if (ASTNodeKind::getFromNodeKind().isSame( Val.NodeKind)) { auto NNSL = Val.getUnchecked(); - return llvm::hash_combine(NNSL.getNestedNameSpecifier(), - NNSL.getOpaqueData()); + return llvm::hash_combine( + NNSL.getNestedNameSpecifier().getAsVoidPointer(), + NNSL.getOpaqueData()); } assert(Val.getMemoizationData()); @@ -539,8 +540,8 @@ struct DynTypedNode::BaseConverter< : public DynCastPtrConverter {}; template <> -struct DynTypedNode::BaseConverter< - NestedNameSpecifier, void> : public PtrConverter {}; +struct DynTypedNode::BaseConverter + : public ValueConverter {}; template <> struct DynTypedNode::BaseConverter< diff --git a/clang/include/clang/AST/AbstractBasicReader.h b/clang/include/clang/AST/AbstractBasicReader.h index 514f4cef3a694..f01232d044e18 100644 --- a/clang/include/clang/AST/AbstractBasicReader.h +++ b/clang/include/clang/AST/AbstractBasicReader.h @@ -197,7 +197,7 @@ class DataStreamBasicReader : public BasicReaderBase { unsigned int_ = asImpl().readUInt32(); Decl *decl = asImpl().template readDeclAs(); if (auto *recordDecl = dyn_cast(decl)) - elemTy = getASTContext().getRecordType(recordDecl); + elemTy = getASTContext().getCanonicalTagType(recordDecl); else elemTy = cast(decl)->getType(); path.push_back( @@ -252,44 +252,34 @@ class DataStreamBasicReader : public BasicReaderBase { return EffectConditionExpr{asImpl().readExprRef()}; } - NestedNameSpecifier *readNestedNameSpecifier() { + NestedNameSpecifier readNestedNameSpecifier() { auto &ctx = getASTContext(); // We build this up iteratively. - NestedNameSpecifier *cur = nullptr; + NestedNameSpecifier cur = std::nullopt; uint32_t depth = asImpl().readUInt32(); for (uint32_t i = 0; i != depth; ++i) { auto kind = asImpl().readNestedNameSpecifierKind(); switch (kind) { - case NestedNameSpecifier::Identifier: - cur = NestedNameSpecifier::Create(ctx, cur, - asImpl().readIdentifier()); + case NestedNameSpecifier::Kind::Namespace: + cur = + NestedNameSpecifier(ctx, asImpl().readNamespaceBaseDeclRef(), cur); continue; - - case NestedNameSpecifier::Namespace: - cur = NestedNameSpecifier::Create(ctx, cur, - asImpl().readNamespaceDeclRef()); - continue; - - case NestedNameSpecifier::NamespaceAlias: - cur = NestedNameSpecifier::Create(ctx, cur, - asImpl().readNamespaceAliasDeclRef()); + case NestedNameSpecifier::Kind::Type: + assert(!cur); + cur = NestedNameSpecifier(asImpl().readQualType().getTypePtr()); continue; - - case NestedNameSpecifier::TypeSpec: - cur = NestedNameSpecifier::Create(ctx, cur, - asImpl().readQualType().getTypePtr()); + case NestedNameSpecifier::Kind::Global: + assert(!cur); + cur = NestedNameSpecifier::getGlobal(); continue; - - case NestedNameSpecifier::Global: - cur = NestedNameSpecifier::GlobalSpecifier(ctx); - continue; - - case NestedNameSpecifier::Super: - cur = NestedNameSpecifier::SuperSpecifier(ctx, - asImpl().readCXXRecordDeclRef()); + case NestedNameSpecifier::Kind::Super: + assert(!cur); + cur = NestedNameSpecifier(asImpl().readCXXRecordDeclRef()); continue; + case NestedNameSpecifier::Kind::Null: + llvm_unreachable("unexpected null nested name specifier"); } llvm_unreachable("bad nested name specifier kind"); } diff --git a/clang/include/clang/AST/AbstractBasicWriter.h b/clang/include/clang/AST/AbstractBasicWriter.h index fedde8a2e46c5..214964188e962 100644 --- a/clang/include/clang/AST/AbstractBasicWriter.h +++ b/clang/include/clang/AST/AbstractBasicWriter.h @@ -181,7 +181,7 @@ class DataStreamBasicWriter : public BasicWriterBase { const Decl *baseOrMember = elem.getAsBaseOrMember().getPointer(); if (const auto *recordDecl = dyn_cast(baseOrMember)) { asImpl().writeDeclRef(recordDecl); - elemTy = ctx.getRecordType(recordDecl); + elemTy = ctx.getCanonicalTagType(recordDecl); } else { const auto *valueDecl = cast(baseOrMember); asImpl().writeDeclRef(valueDecl); @@ -229,46 +229,44 @@ class DataStreamBasicWriter : public BasicWriterBase { asImpl().writeExprRef(CE.getCondition()); } - void writeNestedNameSpecifier(NestedNameSpecifier *NNS) { + void writeNestedNameSpecifier(NestedNameSpecifier NNS) { // Nested name specifiers usually aren't too long. I think that 8 would // typically accommodate the vast majority. - SmallVector nestedNames; + SmallVector nestedNames; // Push each of the NNS's onto a stack for serialization in reverse order. while (NNS) { nestedNames.push_back(NNS); - NNS = NNS->getPrefix(); + NNS = NNS.getKind() == NestedNameSpecifier::Kind::Namespace + ? NNS.getAsNamespaceAndPrefix().Prefix + : std::nullopt; } asImpl().writeUInt32(nestedNames.size()); while (!nestedNames.empty()) { NNS = nestedNames.pop_back_val(); - NestedNameSpecifier::SpecifierKind kind = NNS->getKind(); + NestedNameSpecifier::Kind kind = NNS.getKind(); asImpl().writeNestedNameSpecifierKind(kind); switch (kind) { - case NestedNameSpecifier::Identifier: - asImpl().writeIdentifier(NNS->getAsIdentifier()); + case NestedNameSpecifier::Kind::Namespace: + asImpl().writeNamespaceBaseDeclRef( + NNS.getAsNamespaceAndPrefix().Namespace); continue; - case NestedNameSpecifier::Namespace: - asImpl().writeNamespaceDeclRef(NNS->getAsNamespace()); + case NestedNameSpecifier::Kind::Type: + asImpl().writeQualType(QualType(NNS.getAsType(), 0)); continue; - case NestedNameSpecifier::NamespaceAlias: - asImpl().writeNamespaceAliasDeclRef(NNS->getAsNamespaceAlias()); - continue; - - case NestedNameSpecifier::TypeSpec: - asImpl().writeQualType(QualType(NNS->getAsType(), 0)); - continue; - - case NestedNameSpecifier::Global: + case NestedNameSpecifier::Kind::Global: // Don't need to write an associated value. continue; - case NestedNameSpecifier::Super: - asImpl().writeDeclRef(NNS->getAsRecordDecl()); + case NestedNameSpecifier::Kind::Super: + asImpl().writeDeclRef(NNS.getAsSuper()); continue; + + case NestedNameSpecifier::Kind::Null: + llvm_unreachable("unexpected null nested name specifier"); } llvm_unreachable("bad nested name specifier kind"); } diff --git a/clang/include/clang/AST/CanonicalType.h b/clang/include/clang/AST/CanonicalType.h index 35db68971e029..b5a4e94e1330a 100644 --- a/clang/include/clang/AST/CanonicalType.h +++ b/clang/include/clang/AST/CanonicalType.h @@ -453,7 +453,7 @@ template<> struct CanProxyAdaptor : public CanProxyBase { LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getPointeeType) - LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(NestedNameSpecifier *, getQualifier) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(NestedNameSpecifier, getQualifier) LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(const CXXRecordDecl *, getMostRecentCXXRecordDecl) }; @@ -551,21 +551,18 @@ struct CanProxyAdaptor template<> struct CanProxyAdaptor : public CanProxyBase { - LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(TagDecl *, getDecl) - LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isBeingDefined) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(TagDecl *, getOriginalDecl) }; template<> struct CanProxyAdaptor : public CanProxyBase { - LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(RecordDecl *, getDecl) - LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isBeingDefined) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(RecordDecl *, getOriginalDecl) LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, hasConstFields) }; template<> struct CanProxyAdaptor : public CanProxyBase { - LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(EnumDecl *, getDecl) - LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isBeingDefined) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(EnumDecl *, getOriginalDecl) }; template<> diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h index f70a039bf3517..80d20a23b3753 100644 --- a/clang/include/clang/AST/Decl.h +++ b/clang/include/clang/AST/Decl.h @@ -20,7 +20,7 @@ #include "clang/AST/DeclBase.h" #include "clang/AST/DeclarationName.h" #include "clang/AST/ExternalASTSource.h" -#include "clang/AST/NestedNameSpecifier.h" +#include "clang/AST/NestedNameSpecifierBase.h" #include "clang/AST/Redeclarable.h" #include "clang/AST/Type.h" #include "clang/Basic/AddressSpaces.h" @@ -565,8 +565,25 @@ class LabelDecl : public NamedDecl { static bool classofKind(Kind K) { return K == Label; } }; +/// Represents C++ namespaces and their aliases. +class NamespaceBaseDecl : public NamedDecl { +protected: + using NamedDecl::NamedDecl; + +public: + NamespaceDecl *getNamespace(); + const NamespaceDecl *getNamespace() const { + return const_cast(this)->getNamespace(); + } + + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { + return K >= firstNamespaceBase && K <= lastNamespaceBase; + } +}; + /// Represent a C++ namespace. -class NamespaceDecl : public NamedDecl, +class NamespaceDecl : public NamespaceBaseDecl, public DeclContext, public Redeclarable { /// The starting location of the source range, pointing @@ -813,9 +830,9 @@ class DeclaratorDecl : public ValueDecl { /// Retrieve the nested-name-specifier that qualifies the name of this /// declaration, if it was present in the source. - NestedNameSpecifier *getQualifier() const { + NestedNameSpecifier getQualifier() const { return hasExtInfo() ? getExtInfo()->QualifierLoc.getNestedNameSpecifier() - : nullptr; + : std::nullopt; } /// Retrieve the nested-name-specifier (with source-location @@ -3485,8 +3502,14 @@ class TypeDecl : public NamedDecl { // check out ASTContext::getTypeDeclType or one of // ASTContext::getTypedefType, ASTContext::getRecordType, etc. if you // already know the specific kind of node this is. - const Type *getTypeForDecl() const { return TypeForDecl; } - void setTypeForDecl(const Type *TD) { TypeForDecl = TD; } + const Type *getTypeForDecl() const { + assert(!isa(this)); + return TypeForDecl; + } + void setTypeForDecl(const Type *TD) { + assert(!isa(this)); + TypeForDecl = TD; + } SourceLocation getBeginLoc() const LLVM_READONLY { return LocStart; } void setLocStart(SourceLocation L) { LocStart = L; } @@ -3592,6 +3615,9 @@ class TypedefNameDecl : public TypeDecl, public Redeclarable { return isTransparentTagSlow(); } + const Type *getTypeForDecl() const = delete; + void setTypeForDecl(const Type *TD) = delete; + // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classofKind(Kind K) { @@ -3711,14 +3737,6 @@ class TagDecl : public TypeDecl, /// True if this decl is currently being defined. void setBeingDefined(bool V = true) { TagDeclBits.IsBeingDefined = V; } - /// Indicates whether it is possible for declarations of this kind - /// to have an out-of-date definition. - /// - /// This option is only enabled when modules are enabled. - void setMayHaveOutOfDateDef(bool V = true) { - TagDeclBits.MayHaveOutOfDateDef = V; - } - public: friend class ASTDeclReader; friend class ASTDeclWriter; @@ -3799,12 +3817,6 @@ class TagDecl : public TypeDecl, TagDeclBits.IsFreeStanding = isFreeStanding; } - /// Indicates whether it is possible for declarations of this kind - /// to have an out-of-date definition. - /// - /// This option is only enabled when modules are enabled. - bool mayHaveOutOfDateDef() const { return TagDeclBits.MayHaveOutOfDateDef; } - /// Whether this declaration declares a type that is /// dependent, i.e., a type that somehow depends on template /// parameters. @@ -3845,6 +3857,19 @@ class TagDecl : public TypeDecl, /// the struct/union/class/enum. TagDecl *getDefinition() const; + TagDecl *getDefinitionOrSelf() const { + if (TagDecl *Def = getDefinition()) + return Def; + return const_cast(this); + } + + /// Determines whether this entity is in the process of being defined. + bool isEntityBeingDefined() const { + if (const TagDecl *Def = getDefinition()) + return Def->isBeingDefined(); + return false; + } + StringRef getKindName() const { return TypeWithKeyword::getTagTypeKindName(getTagKind()); } @@ -3891,9 +3916,9 @@ class TagDecl : public TypeDecl, /// Retrieve the nested-name-specifier that qualifies the name of this /// declaration, if it was present in the source. - NestedNameSpecifier *getQualifier() const { + NestedNameSpecifier getQualifier() const { return hasExtInfo() ? getExtInfo()->QualifierLoc.getNestedNameSpecifier() - : nullptr; + : std::nullopt; } /// Retrieve the nested-name-specifier (with source-location @@ -3915,6 +3940,9 @@ class TagDecl : public TypeDecl, return getExtInfo()->TemplParamLists[i]; } + const Type *getTypeForDecl() const = delete; + void setTypeForDecl(const Type *TD) = delete; + using TypeDecl::printName; void printName(raw_ostream &OS, const PrintingPolicy &Policy) const override; @@ -4044,6 +4072,10 @@ class EnumDecl : public TagDecl { return cast_or_null(TagDecl::getDefinition()); } + EnumDecl *getDefinitionOrSelf() const { + return cast_or_null(TagDecl::getDefinitionOrSelf()); + } + static EnumDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, IdentifierInfo *Id, EnumDecl *PrevDecl, @@ -4402,21 +4434,6 @@ class RecordDecl : public TagDecl { void reorderDecls(const SmallVectorImpl &Decls); - /// Determines whether this declaration represents the - /// injected class name. - /// - /// The injected class name in C++ is the name of the class that - /// appears inside the class itself. For example: - /// - /// \code - /// struct C { - /// // C is implicitly declared here as a synonym for the class name. - /// }; - /// - /// C::C c; // same as "C c;" - /// \endcode - bool isInjectedClassName() const; - /// Determine whether this record is a class describing a lambda /// function object. bool isLambda() const; @@ -4441,6 +4458,10 @@ class RecordDecl : public TagDecl { return cast_or_null(TagDecl::getDefinition()); } + RecordDecl *getDefinitionOrSelf() const { + return cast_or_null(TagDecl::getDefinitionOrSelf()); + } + /// Returns whether this record is a union, or contains (at any nesting level) /// a union member. This is used by CMSE to warn about possible information /// leaks. @@ -5271,6 +5292,8 @@ void Redeclarable::setPreviousDecl(decl_type *PrevDecl) { /// We use this function to break a cycle between the inline definitions in /// Type.h and Decl.h. inline bool IsEnumDeclComplete(EnumDecl *ED) { + if (const auto *Def = ED->getDefinition()) + return Def->isComplete(); return ED->isComplete(); } diff --git a/clang/include/clang/AST/DeclBase.h b/clang/include/clang/AST/DeclBase.h index dd67ebc9873ff..5ac664202db6d 100644 --- a/clang/include/clang/AST/DeclBase.h +++ b/clang/include/clang/AST/DeclBase.h @@ -410,9 +410,6 @@ class alignas(8) Decl { virtual ~Decl(); - /// Update a potentially out-of-date declaration. - void updateOutOfDate(IdentifierInfo &II) const; - Linkage getCachedLinkage() const { return static_cast(CacheValidAndLinkage); } @@ -1564,13 +1561,6 @@ class DeclContext { LLVM_PREFERRED_TYPE(bool) uint64_t IsFreeStanding : 1; - /// Indicates whether it is possible for declarations of this kind - /// to have an out-of-date definition. - /// - /// This option is only enabled when modules are enabled. - LLVM_PREFERRED_TYPE(bool) - uint64_t MayHaveOutOfDateDef : 1; - /// Has the full definition of this type been required by a use somewhere in /// the TU. LLVM_PREFERRED_TYPE(bool) diff --git a/clang/include/clang/AST/DeclCXX.h b/clang/include/clang/AST/DeclCXX.h index 05cddd024d7cf..1d2ef0f4f2319 100644 --- a/clang/include/clang/AST/DeclCXX.h +++ b/clang/include/clang/AST/DeclCXX.h @@ -545,21 +545,6 @@ class CXXRecordDecl : public RecordDecl { return const_cast(this)->getMostRecentDecl(); } - CXXRecordDecl *getMostRecentNonInjectedDecl() { - CXXRecordDecl *Recent = - static_cast(this)->getMostRecentDecl(); - while (Recent->isInjectedClassName()) { - // FIXME: Does injected class name need to be in the redeclarations chain? - assert(Recent->getPreviousDecl()); - Recent = Recent->getPreviousDecl(); - } - return Recent; - } - - const CXXRecordDecl *getMostRecentNonInjectedDecl() const { - return const_cast(this)->getMostRecentNonInjectedDecl(); - } - CXXRecordDecl *getDefinition() const { // We only need an update if we don't already know which // declaration is the definition. @@ -567,13 +552,18 @@ class CXXRecordDecl : public RecordDecl { return DD ? DD->Definition : nullptr; } + CXXRecordDecl *getDefinitionOrSelf() const { + if (auto *Def = getDefinition()) + return Def; + return const_cast(this); + } + bool hasDefinition() const { return DefinitionData || dataPtr(); } static CXXRecordDecl *Create(const ASTContext &C, TagKind TK, DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, IdentifierInfo *Id, - CXXRecordDecl *PrevDecl = nullptr, - bool DelayTypeCreation = false); + CXXRecordDecl *PrevDecl = nullptr); static CXXRecordDecl *CreateLambda(const ASTContext &C, DeclContext *DC, TypeSourceInfo *Info, SourceLocation Loc, unsigned DependencyKind, bool IsGeneric, @@ -1889,6 +1879,35 @@ class CXXRecordDecl : public RecordDecl { DL.IsGenericLambda = IsGeneric; } + /// Determines whether this declaration represents the + /// injected class name. + /// + /// The injected class name in C++ is the name of the class that + /// appears inside the class itself. For example: + /// + /// \code + /// struct C { + /// // C is implicitly declared here as a synonym for the class name. + /// }; + /// + /// C::C c; // same as "C c;" + /// \endcode + bool isInjectedClassName() const; + + /// Determines whether this declaration has is canonically of an injected + /// class type. These are non-instantiated class template patterns, which can + /// be used from within the class template itself. For example: + /// + /// \code + /// template struct C { + /// C *t; // Here `C *` is a pointer to an injected class type. + /// }; + /// \endcode + bool hasInjectedClassType() const; + + CanQualType + getCanonicalTemplateSpecializationType(const ASTContext &Ctx) const; + // Determine whether this type is an Interface Like type for // __interface inheritance purposes. bool isInterfaceLike() const; @@ -3117,7 +3136,7 @@ class UsingDirectiveDecl : public NamedDecl { /// Retrieve the nested-name-specifier that qualifies the /// name of the namespace. - NestedNameSpecifier *getQualifier() const { + NestedNameSpecifier getQualifier() const { return QualifierLoc.getNestedNameSpecifier(); } @@ -3172,7 +3191,7 @@ class UsingDirectiveDecl : public NamedDecl { /// \code /// namespace Foo = Bar; /// \endcode -class NamespaceAliasDecl : public NamedDecl, +class NamespaceAliasDecl : public NamespaceBaseDecl, public Redeclarable { friend class ASTDeclReader; @@ -3189,14 +3208,14 @@ class NamespaceAliasDecl : public NamedDecl, /// The Decl that this alias points to, either a NamespaceDecl or /// a NamespaceAliasDecl. - NamedDecl *Namespace; + NamespaceBaseDecl *Namespace; NamespaceAliasDecl(ASTContext &C, DeclContext *DC, SourceLocation NamespaceLoc, SourceLocation AliasLoc, IdentifierInfo *Alias, NestedNameSpecifierLoc QualifierLoc, - SourceLocation IdentLoc, NamedDecl *Namespace) - : NamedDecl(NamespaceAlias, DC, AliasLoc, Alias), redeclarable_base(C), - NamespaceLoc(NamespaceLoc), IdentLoc(IdentLoc), + SourceLocation IdentLoc, NamespaceBaseDecl *Namespace) + : NamespaceBaseDecl(NamespaceAlias, DC, AliasLoc, Alias), + redeclarable_base(C), NamespaceLoc(NamespaceLoc), IdentLoc(IdentLoc), QualifierLoc(QualifierLoc), Namespace(Namespace) {} void anchor() override; @@ -3208,13 +3227,11 @@ class NamespaceAliasDecl : public NamedDecl, NamespaceAliasDecl *getMostRecentDeclImpl() override; public: - static NamespaceAliasDecl *Create(ASTContext &C, DeclContext *DC, - SourceLocation NamespaceLoc, - SourceLocation AliasLoc, - IdentifierInfo *Alias, - NestedNameSpecifierLoc QualifierLoc, - SourceLocation IdentLoc, - NamedDecl *Namespace); + static NamespaceAliasDecl * + Create(ASTContext &C, DeclContext *DC, SourceLocation NamespaceLoc, + SourceLocation AliasLoc, IdentifierInfo *Alias, + NestedNameSpecifierLoc QualifierLoc, SourceLocation IdentLoc, + NamespaceBaseDecl *Namespace); static NamespaceAliasDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID); @@ -3240,7 +3257,7 @@ class NamespaceAliasDecl : public NamedDecl, /// Retrieve the nested-name-specifier that qualifies the /// name of the namespace. - NestedNameSpecifier *getQualifier() const { + NestedNameSpecifier getQualifier() const { return QualifierLoc.getNestedNameSpecifier(); } @@ -3268,7 +3285,7 @@ class NamespaceAliasDecl : public NamedDecl, /// Retrieve the namespace that this alias refers to, which /// may either be a NamespaceDecl or a NamespaceAliasDecl. - NamedDecl *getAliasedNamespace() const { return Namespace; } + NamespaceBaseDecl *getAliasedNamespace() const { return Namespace; } SourceRange getSourceRange() const override LLVM_READONLY { return SourceRange(NamespaceLoc, IdentLoc); @@ -3602,7 +3619,7 @@ class UsingDecl : public BaseUsingDecl, public Mergeable { NestedNameSpecifierLoc getQualifierLoc() const { return QualifierLoc; } /// Retrieve the nested-name-specifier that qualifies the name. - NestedNameSpecifier *getQualifier() const { + NestedNameSpecifier getQualifier() const { return QualifierLoc.getNestedNameSpecifier(); } @@ -3792,13 +3809,11 @@ class UsingEnumDecl : public BaseUsingDecl, public Mergeable { /// The source location of the 'enum' keyword. SourceLocation getEnumLoc() const { return EnumLocation; } void setEnumLoc(SourceLocation L) { EnumLocation = L; } - NestedNameSpecifier *getQualifier() const { + NestedNameSpecifier getQualifier() const { return getQualifierLoc().getNestedNameSpecifier(); } NestedNameSpecifierLoc getQualifierLoc() const { - if (auto ETL = EnumType->getTypeLoc().getAs()) - return ETL.getQualifierLoc(); - return NestedNameSpecifierLoc(); + return getEnumTypeLoc().getPrefix(); } // Returns the "qualifier::Name" part as a TypeLoc. TypeLoc getEnumTypeLoc() const { @@ -3958,7 +3973,7 @@ class UnresolvedUsingValueDecl : public ValueDecl, NestedNameSpecifierLoc getQualifierLoc() const { return QualifierLoc; } /// Retrieve the nested-name-specifier that qualifies the name. - NestedNameSpecifier *getQualifier() const { + NestedNameSpecifier getQualifier() const { return QualifierLoc.getNestedNameSpecifier(); } @@ -4048,7 +4063,7 @@ class UnresolvedUsingTypenameDecl NestedNameSpecifierLoc getQualifierLoc() const { return QualifierLoc; } /// Retrieve the nested-name-specifier that qualifies the name. - NestedNameSpecifier *getQualifier() const { + NestedNameSpecifier getQualifier() const { return QualifierLoc.getNestedNameSpecifier(); } diff --git a/clang/include/clang/AST/DeclObjC.h b/clang/include/clang/AST/DeclObjC.h index 9014d76f8433b..2541edba83855 100644 --- a/clang/include/clang/AST/DeclObjC.h +++ b/clang/include/clang/AST/DeclObjC.h @@ -643,6 +643,9 @@ class ObjCTypeParamDecl : public TypedefNameDecl { /// from the explicitly-specified bound. SourceLocation getColonLoc() const { return ColonLoc; } + using TypeDecl::getTypeForDecl; + using TypeDecl::setTypeForDecl; + // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classofKind(Kind K) { return K == ObjCTypeParam; } diff --git a/clang/include/clang/AST/DeclTemplate.h b/clang/include/clang/AST/DeclTemplate.h index 1ff6cc6fcb7d1..e657463a24c36 100644 --- a/clang/include/clang/AST/DeclTemplate.h +++ b/clang/include/clang/AST/DeclTemplate.h @@ -1880,14 +1880,14 @@ class ClassTemplateSpecializationDecl : public CXXRecordDecl, void getNameForDiagnostic(raw_ostream &OS, const PrintingPolicy &Policy, bool Qualified) const override; - // FIXME: This is broken. CXXRecordDecl::getMostRecentDecl() returns a - // different "most recent" declaration from this function for the same - // declaration, because we don't override getMostRecentDeclImpl(). But - // it's not clear that we should override that, because the most recent - // declaration as a CXXRecordDecl sometimes is the injected-class-name. ClassTemplateSpecializationDecl *getMostRecentDecl() { return cast( - getMostRecentNonInjectedDecl()); + CXXRecordDecl::getMostRecentDecl()); + } + + ClassTemplateSpecializationDecl *getDefinitionOrSelf() const { + return cast( + CXXRecordDecl::getDefinitionOrSelf()); } /// Retrieve the template that this specialization specializes. @@ -2105,10 +2105,13 @@ class ClassTemplatePartialSpecializationDecl llvm::PointerIntPair InstantiatedFromMember; + mutable CanQualType CanonInjectedTST; + ClassTemplatePartialSpecializationDecl( ASTContext &Context, TagKind TK, DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, TemplateParameterList *Params, ClassTemplateDecl *SpecializedTemplate, ArrayRef Args, + CanQualType CanonInjectedTST, ClassTemplatePartialSpecializationDecl *PrevDecl); ClassTemplatePartialSpecializationDecl(ASTContext &C) @@ -2125,7 +2128,7 @@ class ClassTemplatePartialSpecializationDecl Create(ASTContext &Context, TagKind TK, DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, TemplateParameterList *Params, ClassTemplateDecl *SpecializedTemplate, - ArrayRef Args, QualType CanonInjectedType, + ArrayRef Args, CanQualType CanonInjectedTST, ClassTemplatePartialSpecializationDecl *PrevDecl); static ClassTemplatePartialSpecializationDecl * @@ -2142,12 +2145,6 @@ class ClassTemplatePartialSpecializationDecl return TemplateParams; } - /// Get the template argument list of the template parameter list. - ArrayRef - getInjectedTemplateArgs(const ASTContext &Context) const { - return getTemplateParameters()->getInjectedTemplateArgs(Context); - } - /// \brief All associated constraints of this partial specialization, /// including the requires clause and any constraints derived from /// constrained-parameters. @@ -2229,14 +2226,10 @@ class ClassTemplatePartialSpecializationDecl return First->InstantiatedFromMember.setInt(true); } - /// Retrieves the injected specialization type for this partial - /// specialization. This is not the same as the type-decl-type for - /// this partial specialization, which is an InjectedClassNameType. - QualType getInjectedSpecializationType() const { - assert(getTypeForDecl() && "partial specialization has no type set!"); - return cast(getTypeForDecl()) - ->getInjectedSpecializationType(); - } + /// Retrieves the canonical injected specialization type for this partial + /// specialization. + CanQualType + getCanonicalInjectedSpecializationType(const ASTContext &Ctx) const; SourceRange getSourceRange() const override LLVM_READONLY; @@ -2271,8 +2264,8 @@ class ClassTemplateDecl : public RedeclarableTemplateDecl { llvm::FoldingSetVector PartialSpecializations; - /// The injected-class-name type for this class template. - QualType InjectedClassNameType; + /// The Injected Template Specialization Type for this declaration. + CanQualType CanonInjectedTST; Common() = default; }; @@ -2409,7 +2402,7 @@ class ClassTemplateDecl : public RedeclarableTemplateDecl { findPartialSpecInstantiatedFromMember( ClassTemplatePartialSpecializationDecl *D); - /// Retrieve the template specialization type of the + /// Retrieve the canonical template specialization type of the /// injected-class-name for this class template. /// /// The injected-class-name for a class template \c X is \c @@ -2423,7 +2416,8 @@ class ClassTemplateDecl : public RedeclarableTemplateDecl { /// typedef array this_type; // "array" is equivalent to "array" /// }; /// \endcode - QualType getInjectedClassNameSpecialization(); + CanQualType + getCanonicalInjectedSpecializationType(const ASTContext &Ctx) const; using spec_iterator = SpecIterator; using spec_range = llvm::iterator_range; diff --git a/clang/include/clang/AST/DependenceFlags.h b/clang/include/clang/AST/DependenceFlags.h index bdcaabc143cc4..c4395259f0758 100644 --- a/clang/include/clang/AST/DependenceFlags.h +++ b/clang/include/clang/AST/DependenceFlags.h @@ -293,7 +293,7 @@ inline TypeDependence toSemanticDependence(TypeDependence D) { } inline NestedNameSpecifierDependence -toNestedNameSpecifierDependendence(TypeDependence D) { +toNestedNameSpecifierDependence(TypeDependence D) { return Dependence(D).nestedNameSpecifier(); } diff --git a/clang/include/clang/AST/DynamicRecursiveASTVisitor.h b/clang/include/clang/AST/DynamicRecursiveASTVisitor.h index 703cca22777ad..7b5bdca318348 100644 --- a/clang/include/clang/AST/DynamicRecursiveASTVisitor.h +++ b/clang/include/clang/AST/DynamicRecursiveASTVisitor.h @@ -134,8 +134,7 @@ template class DynamicRecursiveASTVisitorBase { /// Recursively visit a C++ nested-name-specifier. /// /// \returns false if the visitation was terminated early, true otherwise. - virtual bool - TraverseNestedNameSpecifier(MaybeConst *NNS); + virtual bool TraverseNestedNameSpecifier(NestedNameSpecifier NNS); /// Recursively visit a C++ nested-name-specifier with location /// information. @@ -181,14 +180,14 @@ template class DynamicRecursiveASTVisitorBase { /// /// \returns false if the visitation was terminated early, true /// otherwise (including when the argument is a Null type). - virtual bool TraverseType(QualType T); + virtual bool TraverseType(QualType T, bool TraverseQualifier = true); /// Recursively visit a type with location, by dispatching to /// Traverse*TypeLoc() based on the argument type's getTypeClass() property. /// /// \returns false if the visitation was terminated early, true /// otherwise (including when the argument is a Null type location). - virtual bool TraverseTypeLoc(TypeLoc TL); + virtual bool TraverseTypeLoc(TypeLoc TL, bool TraverseQualifier = true); /// Recursively visit an Objective-C protocol reference with location /// information. @@ -273,7 +272,8 @@ template class DynamicRecursiveASTVisitorBase { #define ABSTRACT_TYPE(CLASS, BASE) #define TYPE(CLASS, BASE) \ bool WalkUpFrom##CLASS##Type(MaybeConst *T); \ - virtual bool Traverse##CLASS##Type(MaybeConst *T); + virtual bool Traverse##CLASS##Type(MaybeConst *T, \ + bool TraverseQualifier = true); #include "clang/AST/TypeNodes.inc" #define TYPE(CLASS, BASE) \ @@ -283,7 +283,8 @@ template class DynamicRecursiveASTVisitorBase { // TypeLocs. #define ABSTRACT_TYPELOC(CLASS, BASE) #define TYPELOC(CLASS, BASE) \ - virtual bool Traverse##CLASS##TypeLoc(CLASS##TypeLoc TL); + virtual bool Traverse##CLASS##TypeLoc(CLASS##TypeLoc TL, \ + bool TraverseQualifier); #include "clang/AST/TypeLocNodes.def" #define TYPELOC(CLASS, BASE) \ diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h index 523c0326d47ef..d973e2cb822bd 100644 --- a/clang/include/clang/AST/Expr.h +++ b/clang/include/clang/AST/Expr.h @@ -1366,7 +1366,7 @@ class DeclRefExpr final /// If the name was qualified, retrieves the nested-name-specifier /// that precedes the name. Otherwise, returns NULL. - NestedNameSpecifier *getQualifier() const { + NestedNameSpecifier getQualifier() const { return getQualifierLoc().getNestedNameSpecifier(); } @@ -3393,7 +3393,7 @@ class MemberExpr final /// If the member name was qualified, retrieves the /// nested-name-specifier that precedes the member name. Otherwise, returns /// NULL. - NestedNameSpecifier *getQualifier() const { + NestedNameSpecifier getQualifier() const { return getQualifierLoc().getNestedNameSpecifier(); } diff --git a/clang/include/clang/AST/ExprCXX.h b/clang/include/clang/AST/ExprCXX.h index a22c32241ac61..f8fa782f3fb68 100644 --- a/clang/include/clang/AST/ExprCXX.h +++ b/clang/include/clang/AST/ExprCXX.h @@ -2780,7 +2780,7 @@ class CXXPseudoDestructorExpr : public Expr { /// If the member name was qualified, retrieves the /// nested-name-specifier that precedes the member name. Otherwise, returns /// null. - NestedNameSpecifier *getQualifier() const { + NestedNameSpecifier getQualifier() const { return QualifierLoc.getNestedNameSpecifier(); } @@ -3221,7 +3221,7 @@ class OverloadExpr : public Expr { SourceLocation getNameLoc() const { return NameInfo.getLoc(); } /// Fetches the nested-name qualifier, if one was given. - NestedNameSpecifier *getQualifier() const { + NestedNameSpecifier getQualifier() const { return QualifierLoc.getNestedNameSpecifier(); } @@ -3497,7 +3497,7 @@ class DependentScopeDeclRefExpr final /// Retrieve the nested-name-specifier that qualifies this /// declaration. - NestedNameSpecifier *getQualifier() const { + NestedNameSpecifier getQualifier() const { return QualifierLoc.getNestedNameSpecifier(); } @@ -3912,7 +3912,7 @@ class CXXDependentScopeMemberExpr final } /// Retrieve the nested-name-specifier that qualifies the member name. - NestedNameSpecifier *getQualifier() const { + NestedNameSpecifier getQualifier() const { return QualifierLoc.getNestedNameSpecifier(); } diff --git a/clang/include/clang/AST/JSONNodeDumper.h b/clang/include/clang/AST/JSONNodeDumper.h index 570662b58ccf0..8640780206dba 100644 --- a/clang/include/clang/AST/JSONNodeDumper.h +++ b/clang/include/clang/AST/JSONNodeDumper.h @@ -240,7 +240,6 @@ class JSONNodeDumper void VisitInjectedClassNameType(const InjectedClassNameType *ICNT); void VisitObjCInterfaceType(const ObjCInterfaceType *OIT); void VisitPackExpansionType(const PackExpansionType *PET); - void VisitElaboratedType(const ElaboratedType *ET); void VisitMacroQualifiedType(const MacroQualifiedType *MQT); void VisitMemberPointerType(const MemberPointerType *MPT); diff --git a/clang/include/clang/AST/NestedNameSpecifier.h b/clang/include/clang/AST/NestedNameSpecifier.h index 952c79753d10a..547a45407382c 100644 --- a/clang/include/clang/AST/NestedNameSpecifier.h +++ b/clang/include/clang/AST/NestedNameSpecifier.h @@ -6,534 +6,266 @@ // //===----------------------------------------------------------------------===// // -// This file defines the NestedNameSpecifier class, which represents -// a C++ nested-name-specifier. +// This file completes the definition of the NestedNameSpecifier class. // //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_AST_NESTEDNAMESPECIFIER_H #define LLVM_CLANG_AST_NESTEDNAMESPECIFIER_H -#include "clang/AST/DependenceFlags.h" -#include "clang/Basic/Diagnostic.h" -#include "clang/Basic/SourceLocation.h" +#include "clang/AST/Decl.h" +#include "clang/AST/NestedNameSpecifierBase.h" +#include "clang/AST/Type.h" +#include "clang/AST/TypeLoc.h" #include "llvm/ADT/DenseMapInfo.h" -#include "llvm/ADT/FoldingSet.h" -#include "llvm/ADT/PointerIntPair.h" -#include "llvm/Support/Compiler.h" -#include -#include -#include namespace clang { -class ASTContext; -class CXXRecordDecl; -class IdentifierInfo; -class LangOptions; -class NamespaceAliasDecl; -class NamespaceDecl; -struct PrintingPolicy; -class Type; -class TypeLoc; - -/// Represents a C++ nested name specifier, such as -/// "\::std::vector::". -/// -/// C++ nested name specifiers are the prefixes to qualified -/// names. For example, "foo::" in "foo::x" is a nested name -/// specifier. Nested name specifiers are made up of a sequence of -/// specifiers, each of which can be a namespace, type, identifier -/// (for dependent names), decltype specifier, or the global specifier ('::'). -/// The last two specifiers can only appear at the start of a -/// nested-namespace-specifier. -class NestedNameSpecifier : public llvm::FoldingSetNode { - /// Enumeration describing - enum StoredSpecifierKind { - StoredIdentifier = 0, - StoredDecl = 1, - StoredTypeSpec = 2 - }; - - /// The nested name specifier that precedes this nested name - /// specifier. - /// - /// The pointer is the nested-name-specifier that precedes this - /// one. The integer stores one of the first four values of type - /// SpecifierKind. - llvm::PointerIntPair Prefix; - - /// The last component in the nested name specifier, which - /// can be an identifier, a declaration, or a type. - /// - /// When the pointer is NULL, this specifier represents the global - /// specifier '::'. Otherwise, the pointer is one of - /// IdentifierInfo*, Namespace*, or Type*, depending on the kind of - /// specifier as encoded within the prefix. - void* Specifier = nullptr; - -public: - /// The kind of specifier that completes this nested name - /// specifier. - enum SpecifierKind { - /// An identifier, stored as an IdentifierInfo*. - Identifier, - - /// A namespace, stored as a NamespaceDecl*. - Namespace, - - /// A namespace alias, stored as a NamespaceAliasDecl*. - NamespaceAlias, - - /// A type, stored as a Type*. - TypeSpec, - - /// The global specifier '::'. There is no stored value. - Global, - - /// Microsoft's '__super' specifier, stored as a CXXRecordDecl* of - /// the class it appeared in. - Super - }; - -private: - /// Builds the global specifier. - NestedNameSpecifier() : Prefix(nullptr, StoredIdentifier) {} - - /// Copy constructor used internally to clone nested name - /// specifiers. - NestedNameSpecifier(const NestedNameSpecifier &Other) = default; - - /// Either find or insert the given nested name specifier - /// mockup in the given context. - static NestedNameSpecifier *FindOrInsert(const ASTContext &Context, - const NestedNameSpecifier &Mockup); - -public: - NestedNameSpecifier &operator=(const NestedNameSpecifier &) = delete; - - /// Builds a specifier combining a prefix and an identifier. - /// - /// The prefix must be dependent, since nested name specifiers - /// referencing an identifier are only permitted when the identifier - /// cannot be resolved. - static NestedNameSpecifier *Create(const ASTContext &Context, - NestedNameSpecifier *Prefix, - const IdentifierInfo *II); - - /// Builds a nested name specifier that names a namespace. - static NestedNameSpecifier *Create(const ASTContext &Context, - NestedNameSpecifier *Prefix, - const NamespaceDecl *NS); - - /// Builds a nested name specifier that names a namespace alias. - static NestedNameSpecifier *Create(const ASTContext &Context, - NestedNameSpecifier *Prefix, - const NamespaceAliasDecl *Alias); - - /// Builds a nested name specifier that names a type. - static NestedNameSpecifier * - Create(const ASTContext &Context, NestedNameSpecifier *Prefix, const Type *T); - - /// Builds a specifier that consists of just an identifier. - /// - /// The nested-name-specifier is assumed to be dependent, but has no - /// prefix because the prefix is implied by something outside of the - /// nested name specifier, e.g., in "x->Base::f", the "x" has a dependent - /// type. - static NestedNameSpecifier *Create(const ASTContext &Context, - const IdentifierInfo *II); - - /// Returns the nested name specifier representing the global - /// scope. - static NestedNameSpecifier *GlobalSpecifier(const ASTContext &Context); - - /// Returns the nested name specifier representing the __super scope - /// for the given CXXRecordDecl. - static NestedNameSpecifier *SuperSpecifier(const ASTContext &Context, - CXXRecordDecl *RD); - - /// Return the prefix of this nested name specifier. - /// - /// The prefix contains all of the parts of the nested name - /// specifier that precede this current specifier. For example, for a - /// nested name specifier that represents "foo::bar::", the current - /// specifier will contain "bar::" and the prefix will contain - /// "foo::". - NestedNameSpecifier *getPrefix() const { return Prefix.getPointer(); } - - /// Determine what kind of nested name specifier is stored. - SpecifierKind getKind() const; - - /// Retrieve the identifier stored in this nested name - /// specifier. - IdentifierInfo *getAsIdentifier() const { - if (Prefix.getInt() == StoredIdentifier) - return (IdentifierInfo *)Specifier; - - return nullptr; +auto NestedNameSpecifier::getKind() const -> Kind { + if (!isStoredKind()) { + switch (getFlagKind()) { + case FlagKind::Null: + return Kind::Null; + case FlagKind::Global: + return Kind::Global; + case FlagKind::Invalid: + llvm_unreachable("use of invalid NestedNameSpecifier"); + } + llvm_unreachable("unhandled FlagKind"); } + switch (auto [K, Ptr] = getStored(); K) { + case StoredKind::Type: + return Kind::Type; + case StoredKind::NamespaceWithGlobal: + case StoredKind::NamespaceWithNamespace: + return Kind::Namespace; + case StoredKind::NamespaceOrSuper: + switch (static_cast(Ptr)->getKind()) { + case Decl::Namespace: + case Decl::NamespaceAlias: + return Kind::Namespace; + case Decl::CXXRecord: + case Decl::ClassTemplateSpecialization: + case Decl::ClassTemplatePartialSpecialization: + return Kind::Super; + default: + llvm_unreachable("unexpected decl kind"); + } + } + llvm_unreachable("unknown StoredKind"); +} - /// Retrieve the namespace stored in this nested name - /// specifier. - NamespaceDecl *getAsNamespace() const; +NestedNameSpecifier::NestedNameSpecifier(const Type *T) + : NestedNameSpecifier({StoredKind::Type, T}) { + assert(getKind() == Kind::Type); +} - /// Retrieve the namespace alias stored in this nested name - /// specifier. - NamespaceAliasDecl *getAsNamespaceAlias() const; +auto NestedNameSpecifier::MakeNamespacePtrKind( + const ASTContext &Ctx, const NamespaceBaseDecl *Namespace, + NestedNameSpecifier Prefix) -> PtrKind { + switch (Prefix.getKind()) { + case Kind::Null: + return {StoredKind::NamespaceOrSuper, Namespace}; + case Kind::Global: + return {StoredKind::NamespaceWithGlobal, Namespace}; + case Kind::Namespace: + return {StoredKind::NamespaceWithNamespace, + MakeNamespaceAndPrefixStorage(Ctx, Namespace, Prefix)}; + case Kind::Super: + case Kind::Type: + llvm_unreachable("invalid prefix for namespace"); + } + llvm_unreachable("unhandled kind"); +} - /// Retrieve the record declaration stored in this nested name - /// specifier. - CXXRecordDecl *getAsRecordDecl() const; +/// Builds a nested name specifier that names a namespace. +NestedNameSpecifier::NestedNameSpecifier(const ASTContext &Ctx, + const NamespaceBaseDecl *Namespace, + NestedNameSpecifier Prefix) + : NestedNameSpecifier(MakeNamespacePtrKind(Ctx, Namespace, Prefix)) { + assert(getKind() == Kind::Namespace); +} - /// Retrieve the type stored in this nested name specifier. - const Type *getAsType() const { - if (Prefix.getInt() == StoredTypeSpec) - return (const Type *)Specifier; +/// Builds a nested name specifier that names a class through microsoft's +/// __super specifier. +NestedNameSpecifier::NestedNameSpecifier(CXXRecordDecl *RD) + : NestedNameSpecifier({StoredKind::NamespaceOrSuper, RD}) { + assert(getKind() == Kind::Super); +} +CXXRecordDecl *NestedNameSpecifier::getAsRecordDecl() const { + switch (getKind()) { + case Kind::Super: + return getAsSuper(); + case Kind::Type: + return getAsType()->getAsCXXRecordDecl(); + case Kind::Global: + case Kind::Namespace: + case Kind::Null: return nullptr; } + llvm_unreachable("Invalid NNS Kind!"); +} - /// Fully translate this nested name specifier to a type. - /// Unlike getAsType, this will convert this entire nested - /// name specifier chain into its equivalent type. - const Type *translateToType(const ASTContext &Context) const; - - NestedNameSpecifierDependence getDependence() const; - - /// Whether this nested name specifier refers to a dependent - /// type or not. - bool isDependent() const; - - /// Whether this nested name specifier involves a template - /// parameter. - bool isInstantiationDependent() const; +NestedNameSpecifier NestedNameSpecifier::getCanonical() const { + switch (getKind()) { + case NestedNameSpecifier::Kind::Null: + case NestedNameSpecifier::Kind::Global: + case NestedNameSpecifier::Kind::Super: + // These are canonical and unique. + return *this; + case NestedNameSpecifier::Kind::Namespace: { + // A namespace is canonical; build a nested-name-specifier with + // this namespace and no prefix. + const NamespaceBaseDecl *ND = getAsNamespaceAndPrefix().Namespace; + return NestedNameSpecifier( + {StoredKind::NamespaceOrSuper, ND->getNamespace()->getCanonicalDecl()}); + } + case NestedNameSpecifier::Kind::Type: + return NestedNameSpecifier( + getAsType()->getCanonicalTypeInternal().getTypePtr()); + } + llvm_unreachable("unhandled kind"); +} - /// Whether this nested-name-specifier contains an unexpanded - /// parameter pack (for C++11 variadic templates). - bool containsUnexpandedParameterPack() const; +bool NestedNameSpecifier::isCanonical() const { + return *this == getCanonical(); +} - /// Whether this nested name specifier contains an error. - bool containsErrors() const; +TypeLoc NestedNameSpecifierLoc::castAsTypeLoc() const { + return TypeLoc(Qualifier.getAsType(), LoadPointer(/*Offset=*/0)); +} - /// Print this nested name specifier to the given output stream. If - /// `ResolveTemplateArguments` is true, we'll print actual types, e.g. - /// `ns::SomeTemplate` instead of - /// `ns::SomeTemplate`. - void print(raw_ostream &OS, const PrintingPolicy &Policy, - bool ResolveTemplateArguments = false, - bool PrintFinalScopeResOp = true) const; +TypeLoc NestedNameSpecifierLoc::getAsTypeLoc() const { + if (Qualifier.getKind() != NestedNameSpecifier::Kind::Type) + return TypeLoc(); + return castAsTypeLoc(); +} - void Profile(llvm::FoldingSetNodeID &ID) const { - ID.AddPointer(Prefix.getOpaqueValue()); - ID.AddPointer(Specifier); +unsigned +NestedNameSpecifierLoc::getLocalDataLength(NestedNameSpecifier Qualifier) { + // Location of the trailing '::'. + unsigned Length = sizeof(SourceLocation::UIntTy); + + switch (Qualifier.getKind()) { + case NestedNameSpecifier::Kind::Global: + // Nothing more to add. + break; + + case NestedNameSpecifier::Kind::Namespace: + case NestedNameSpecifier::Kind::Super: + // The location of the identifier or namespace name. + Length += sizeof(SourceLocation::UIntTy); + break; + + case NestedNameSpecifier::Kind::Type: + // The "void*" that points at the TypeLoc data. + // Note: the 'template' keyword is part of the TypeLoc. + Length += sizeof(void *); + break; + + case NestedNameSpecifier::Kind::Null: + llvm_unreachable("Expected a non-NULL qualifier"); } - /// Dump the nested name specifier to standard output to aid - /// in debugging. - void dump(const LangOptions &LO) const; - void dump() const; - void dump(llvm::raw_ostream &OS) const; - void dump(llvm::raw_ostream &OS, const LangOptions &LO) const; -}; + return Length; +} -/// A C++ nested-name-specifier augmented with source location -/// information. -class NestedNameSpecifierLoc { - NestedNameSpecifier *Qualifier = nullptr; - void *Data = nullptr; - - /// Determines the data length for the last component in the - /// given nested-name-specifier. - static unsigned getLocalDataLength(NestedNameSpecifier *Qualifier); - - /// Determines the data length for the entire - /// nested-name-specifier. - static unsigned getDataLength(NestedNameSpecifier *Qualifier); - -public: - /// Construct an empty nested-name-specifier. - NestedNameSpecifierLoc() = default; - - /// Construct a nested-name-specifier with source location information - /// from - NestedNameSpecifierLoc(NestedNameSpecifier *Qualifier, void *Data) - : Qualifier(Qualifier), Data(Data) {} - - /// Evaluates true when this nested-name-specifier location is - /// non-empty. - explicit operator bool() const { return Qualifier; } - - /// Evaluates true when this nested-name-specifier location is - /// non-empty. - bool hasQualifier() const { return Qualifier; } - - /// Retrieve the nested-name-specifier to which this instance - /// refers. - NestedNameSpecifier *getNestedNameSpecifier() const { - return Qualifier; - } +NamespaceAndPrefixLoc NestedNameSpecifierLoc::castAsNamespaceAndPrefix() const { + auto [Namespace, Prefix] = Qualifier.getAsNamespaceAndPrefix(); + return {Namespace, NestedNameSpecifierLoc(Prefix, Data)}; +} - /// Retrieve the opaque pointer that refers to source-location data. - void *getOpaqueData() const { return Data; } - - /// Retrieve the source range covering the entirety of this - /// nested-name-specifier. - /// - /// For example, if this instance refers to a nested-name-specifier - /// \c \::std::vector::, the returned source range would cover - /// from the initial '::' to the last '::'. - SourceRange getSourceRange() const LLVM_READONLY { - return SourceRange(getBeginLoc(), getEndLoc()); - } +NamespaceAndPrefixLoc NestedNameSpecifierLoc::getAsNamespaceAndPrefix() const { + if (Qualifier.getKind() != NestedNameSpecifier::Kind::Namespace) + return {}; + return castAsNamespaceAndPrefix(); +} - /// Retrieve the source range covering just the last part of - /// this nested-name-specifier, not including the prefix. - /// - /// For example, if this instance refers to a nested-name-specifier - /// \c \::std::vector::, the returned source range would cover - /// from "vector" to the last '::'. - SourceRange getLocalSourceRange() const; - - /// Retrieve the location of the beginning of this - /// nested-name-specifier. - SourceLocation getBeginLoc() const { - if (!Qualifier) - return SourceLocation(); - - NestedNameSpecifierLoc First = *this; - while (NestedNameSpecifierLoc Prefix = First.getPrefix()) - First = Prefix; - return First.getLocalSourceRange().getBegin(); +unsigned NestedNameSpecifierLoc::getDataLength(NestedNameSpecifier Qualifier) { + unsigned Length = 0; + for (; Qualifier; Qualifier = Qualifier.getAsNamespaceAndPrefix().Prefix) { + Length += getLocalDataLength(Qualifier); + if (Qualifier.getKind() != NestedNameSpecifier::Kind::Namespace) + break; } + return Length; +} - /// Retrieve the location of the end of this - /// nested-name-specifier. - SourceLocation getEndLoc() const { return getLocalSourceRange().getEnd(); } +unsigned NestedNameSpecifierLoc::getDataLength() const { + return getDataLength(Qualifier); +} - /// Retrieve the location of the beginning of this - /// component of the nested-name-specifier. - SourceLocation getLocalBeginLoc() const { - return getLocalSourceRange().getBegin(); +SourceRange NestedNameSpecifierLoc::getLocalSourceRange() const { + switch (auto Kind = Qualifier.getKind()) { + case NestedNameSpecifier::Kind::Null: + return SourceRange(); + case NestedNameSpecifier::Kind::Global: + return LoadSourceLocation(/*Offset=*/0); + case NestedNameSpecifier::Kind::Namespace: + case NestedNameSpecifier::Kind::Super: { + unsigned Offset = + Kind == NestedNameSpecifier::Kind::Namespace + ? getDataLength(Qualifier.getAsNamespaceAndPrefix().Prefix) + : 0; + return SourceRange( + LoadSourceLocation(Offset), + LoadSourceLocation(Offset + sizeof(SourceLocation::UIntTy))); } - - /// Retrieve the location of the end of this component of the - /// nested-name-specifier. - SourceLocation getLocalEndLoc() const { - return getLocalSourceRange().getEnd(); + case NestedNameSpecifier::Kind::Type: { + // The "void*" that points at the TypeLoc data. + // Note: the 'template' keyword is part of the TypeLoc. + void *TypeData = LoadPointer(/*Offset=*/0); + TypeLoc TL(Qualifier.getAsType(), TypeData); + return SourceRange(TL.getBeginLoc(), LoadSourceLocation(sizeof(void *))); } - - /// Return the prefix of this nested-name-specifier. - /// - /// For example, if this instance refers to a nested-name-specifier - /// \c \::std::vector::, the prefix is \c \::std::. Note that the - /// returned prefix may be empty, if this is the first component of - /// the nested-name-specifier. - NestedNameSpecifierLoc getPrefix() const { - if (!Qualifier) - return *this; - - return NestedNameSpecifierLoc(Qualifier->getPrefix(), Data); } - /// For a nested-name-specifier that refers to a type, - /// retrieve the type with source-location information. - TypeLoc getTypeLoc() const; + llvm_unreachable("Invalid NNS Kind!"); +} - /// Determines the data length for the entire - /// nested-name-specifier. - unsigned getDataLength() const { return getDataLength(Qualifier); } +SourceRange NestedNameSpecifierLoc::getSourceRange() const { + return SourceRange(getBeginLoc(), getEndLoc()); +} - friend bool operator==(NestedNameSpecifierLoc X, - NestedNameSpecifierLoc Y) { - return X.Qualifier == Y.Qualifier && X.Data == Y.Data; - } +SourceLocation NestedNameSpecifierLoc::getEndLoc() const { + return getLocalSourceRange().getEnd(); +} - friend bool operator!=(NestedNameSpecifierLoc X, - NestedNameSpecifierLoc Y) { - return !(X == Y); - } -}; +/// Retrieve the location of the beginning of this +/// component of the nested-name-specifier. +SourceLocation NestedNameSpecifierLoc::getLocalBeginLoc() const { + return getLocalSourceRange().getBegin(); +} -/// Class that aids in the construction of nested-name-specifiers along -/// with source-location information for all of the components of the +/// Retrieve the location of the end of this component of the /// nested-name-specifier. -class NestedNameSpecifierLocBuilder { - /// The current representation of the nested-name-specifier we're - /// building. - NestedNameSpecifier *Representation = nullptr; - - /// Buffer used to store source-location information for the - /// nested-name-specifier. - /// - /// Note that we explicitly manage the buffer (rather than using a - /// SmallVector) because \c Declarator expects it to be possible to memcpy() - /// a \c CXXScopeSpec, and CXXScopeSpec uses a NestedNameSpecifierLocBuilder. - char *Buffer = nullptr; - - /// The size of the buffer used to store source-location information - /// for the nested-name-specifier. - unsigned BufferSize = 0; - - /// The capacity of the buffer used to store source-location - /// information for the nested-name-specifier. - unsigned BufferCapacity = 0; - -public: - NestedNameSpecifierLocBuilder() = default; - NestedNameSpecifierLocBuilder(const NestedNameSpecifierLocBuilder &Other); - - NestedNameSpecifierLocBuilder & - operator=(const NestedNameSpecifierLocBuilder &Other); - - ~NestedNameSpecifierLocBuilder() { - if (BufferCapacity) - free(Buffer); - } +SourceLocation NestedNameSpecifierLoc::getLocalEndLoc() const { + return getLocalSourceRange().getEnd(); +} - /// Retrieve the representation of the nested-name-specifier. - NestedNameSpecifier *getRepresentation() const { return Representation; } - - /// Extend the current nested-name-specifier by another - /// nested-name-specifier component of the form 'type::'. - /// - /// \param Context The AST context in which this nested-name-specifier - /// resides. - /// - /// \param TL The TypeLoc that describes the type preceding the '::'. - /// - /// \param ColonColonLoc The location of the trailing '::'. - void Extend(ASTContext &Context, TypeLoc TL, SourceLocation ColonColonLoc); - - /// Extend the current nested-name-specifier by another - /// nested-name-specifier component of the form 'identifier::'. - /// - /// \param Context The AST context in which this nested-name-specifier - /// resides. - /// - /// \param Identifier The identifier. - /// - /// \param IdentifierLoc The location of the identifier. - /// - /// \param ColonColonLoc The location of the trailing '::'. - void Extend(ASTContext &Context, IdentifierInfo *Identifier, - SourceLocation IdentifierLoc, SourceLocation ColonColonLoc); - - /// Extend the current nested-name-specifier by another - /// nested-name-specifier component of the form 'namespace::'. - /// - /// \param Context The AST context in which this nested-name-specifier - /// resides. - /// - /// \param Namespace The namespace. - /// - /// \param NamespaceLoc The location of the namespace name. - /// - /// \param ColonColonLoc The location of the trailing '::'. - void Extend(ASTContext &Context, NamespaceDecl *Namespace, - SourceLocation NamespaceLoc, SourceLocation ColonColonLoc); - - /// Extend the current nested-name-specifier by another - /// nested-name-specifier component of the form 'namespace-alias::'. - /// - /// \param Context The AST context in which this nested-name-specifier - /// resides. - /// - /// \param Alias The namespace alias. - /// - /// \param AliasLoc The location of the namespace alias - /// name. - /// - /// \param ColonColonLoc The location of the trailing '::'. - void Extend(ASTContext &Context, NamespaceAliasDecl *Alias, - SourceLocation AliasLoc, SourceLocation ColonColonLoc); - - /// Turn this (empty) nested-name-specifier into the global - /// nested-name-specifier '::'. - void MakeGlobal(ASTContext &Context, SourceLocation ColonColonLoc); - - /// Turns this (empty) nested-name-specifier into '__super' - /// nested-name-specifier. - /// - /// \param Context The AST context in which this nested-name-specifier - /// resides. - /// - /// \param RD The declaration of the class in which nested-name-specifier - /// appeared. - /// - /// \param SuperLoc The location of the '__super' keyword. - /// name. - /// - /// \param ColonColonLoc The location of the trailing '::'. - void MakeSuper(ASTContext &Context, CXXRecordDecl *RD, - SourceLocation SuperLoc, SourceLocation ColonColonLoc); - - /// Make a new nested-name-specifier from incomplete source-location - /// information. - /// - /// This routine should be used very, very rarely, in cases where we - /// need to synthesize a nested-name-specifier. Most code should instead use - /// \c Adopt() with a proper \c NestedNameSpecifierLoc. - void MakeTrivial(ASTContext &Context, NestedNameSpecifier *Qualifier, - SourceRange R); - - /// Adopt an existing nested-name-specifier (with source-range - /// information). - void Adopt(NestedNameSpecifierLoc Other); - - /// Retrieve the source range covered by this nested-name-specifier. - SourceRange getSourceRange() const LLVM_READONLY { - return NestedNameSpecifierLoc(Representation, Buffer).getSourceRange(); - } +SourceRange NestedNameSpecifierLocBuilder::getSourceRange() const { + return NestedNameSpecifierLoc(Representation, Buffer).getSourceRange(); +} - /// Retrieve a nested-name-specifier with location information, - /// copied into the given AST context. - /// - /// \param Context The context into which this nested-name-specifier will be - /// copied. - NestedNameSpecifierLoc getWithLocInContext(ASTContext &Context) const; - - /// Retrieve a nested-name-specifier with location - /// information based on the information in this builder. - /// - /// This loc will contain references to the builder's internal data and may - /// be invalidated by any change to the builder. - NestedNameSpecifierLoc getTemporary() const { - return NestedNameSpecifierLoc(Representation, Buffer); - } +} // namespace clang + +namespace llvm { + +template <> struct DenseMapInfo { + static clang::NestedNameSpecifier getEmptyKey() { return std::nullopt; } - /// Clear out this builder, and prepare it to build another - /// nested-name-specifier with source-location information. - void Clear() { - Representation = nullptr; - BufferSize = 0; + static clang::NestedNameSpecifier getTombstoneKey() { + return clang::NestedNameSpecifier::getInvalid(); } - /// Retrieve the underlying buffer. - /// - /// \returns A pair containing a pointer to the buffer of source-location - /// data and the size of the source-location data that resides in that - /// buffer. - std::pair getBuffer() const { - return std::make_pair(Buffer, BufferSize); + static unsigned getHashValue(const clang::NestedNameSpecifier &V) { + return hash_combine(V.getAsVoidPointer()); } }; -/// Insertion operator for diagnostics. This allows sending -/// NestedNameSpecifiers into a diagnostic with <<. -inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB, - NestedNameSpecifier *NNS) { - DB.AddTaggedVal(reinterpret_cast(NNS), - DiagnosticsEngine::ak_nestednamespec); - return DB; -} - -} // namespace clang - -namespace llvm { - template <> struct DenseMapInfo { - using FirstInfo = DenseMapInfo; + using FirstInfo = DenseMapInfo; using SecondInfo = DenseMapInfo; static clang::NestedNameSpecifierLoc getEmptyKey() { @@ -559,4 +291,4 @@ template <> struct DenseMapInfo { }; } // namespace llvm -#endif // LLVM_CLANG_AST_NESTEDNAMESPECIFIER_H +#endif // LLVM_CLANG_AST_NESTEDNAMESPECIFIERBASE_H diff --git a/clang/include/clang/AST/NestedNameSpecifierBase.h b/clang/include/clang/AST/NestedNameSpecifierBase.h new file mode 100644 index 0000000000000..b7ce157051faf --- /dev/null +++ b/clang/include/clang/AST/NestedNameSpecifierBase.h @@ -0,0 +1,585 @@ +//===- NestedNameSpecifier.h - C++ nested name specifiers -------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines the NestedNameSpecifier class, which represents +// a C++ nested-name-specifier. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_NESTEDNAMESPECIFIERBASE_H +#define LLVM_CLANG_AST_NESTEDNAMESPECIFIERBASE_H + +#include "clang/AST/DependenceFlags.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/SourceLocation.h" +#include "llvm/ADT/FoldingSet.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/PointerLikeTypeTraits.h" +#include +#include +#include + +namespace clang { + +class ASTContext; +class CXXRecordDecl; +class NamedDecl; +class IdentifierInfo; +class LangOptions; +class NamespaceBaseDecl; +struct PrintingPolicy; +class Type; +class TypeLoc; + +struct NamespaceAndPrefix; +struct alignas(16) NamespaceAndPrefixStorage; + +/// Represents a C++ nested name specifier, such as +/// "\::std::vector::". +/// +/// C++ nested name specifiers are the prefixes to qualified +/// names. For example, "foo::" in "foo::x" is a nested name +/// specifier. Nested name specifiers are made up of a sequence of +/// specifiers, each of which can be a namespace, type, decltype specifier, or +/// the global specifier ('::'). The last two specifiers can only appear at the +/// start of a nested-namespace-specifier. +class NestedNameSpecifier { + enum class FlagKind { Null, Global, Invalid }; + enum class StoredKind { + Type, + NamespaceOrSuper, + NamespaceWithGlobal, + NamespaceWithNamespace + }; + static constexpr uintptr_t FlagBits = 2, FlagMask = (1u << FlagBits) - 1u, + FlagOffset = 1, PtrOffset = FlagBits + FlagOffset, + PtrMask = (1u << PtrOffset) - 1u; + + uintptr_t StoredOrFlag; + + explicit NestedNameSpecifier(uintptr_t StoredOrFlag) + : StoredOrFlag(StoredOrFlag) {} + struct PtrKind { + StoredKind SK; + const void *Ptr; + }; + explicit NestedNameSpecifier(PtrKind PK) + : StoredOrFlag(uintptr_t(PK.Ptr) | (uintptr_t(PK.SK) << FlagOffset)) { + assert(PK.Ptr != nullptr); + assert((uintptr_t(PK.Ptr) & ((1u << PtrOffset) - 1u)) == 0); + assert((uintptr_t(PK.Ptr) >> PtrOffset) != 0); + } + + explicit constexpr NestedNameSpecifier(FlagKind K) + : StoredOrFlag(uintptr_t(K) << FlagOffset) {} + + bool isStoredKind() const { return (StoredOrFlag >> PtrOffset) != 0; } + + std::pair getStored() const { + assert(isStoredKind()); + return {StoredKind(StoredOrFlag >> FlagOffset & FlagMask), + reinterpret_cast(StoredOrFlag & ~PtrMask)}; + } + + FlagKind getFlagKind() const { + assert(!isStoredKind()); + return FlagKind(StoredOrFlag >> FlagOffset); + } + + static const NamespaceAndPrefixStorage * + MakeNamespaceAndPrefixStorage(const ASTContext &Ctx, + const NamespaceBaseDecl *Namespace, + NestedNameSpecifier Prefix); + static inline PtrKind MakeNamespacePtrKind(const ASTContext &Ctx, + const NamespaceBaseDecl *Namespace, + NestedNameSpecifier Prefix); + +public: + static constexpr NestedNameSpecifier getInvalid() { + return NestedNameSpecifier(FlagKind::Invalid); + } + + static constexpr NestedNameSpecifier getGlobal() { + return NestedNameSpecifier(FlagKind::Global); + } + + NestedNameSpecifier() : NestedNameSpecifier(FlagKind::Invalid) {} + + /// The kind of specifier that completes this nested name + /// specifier. + enum class Kind { + /// Empty. + Null, + + /// The global specifier '::'. There is no stored value. + Global, + + /// A type, stored as a Type*. + Type, + + /// A namespace-like entity, stored as a NamespaceBaseDecl*. + Namespace, + + /// Microsoft's '__super' specifier, stored as a CXXRecordDecl* of + /// the class it appeared in. + Super, + }; + + inline Kind getKind() const; + + NestedNameSpecifier(std::nullopt_t) : StoredOrFlag(0) {} + + explicit inline NestedNameSpecifier(const Type *T); + + /// Builds a nested name specifier that names a namespace. + inline NestedNameSpecifier(const ASTContext &Ctx, + const NamespaceBaseDecl *Namespace, + NestedNameSpecifier Prefix); + + /// Builds a nested name specifier that names a class through microsoft's + /// __super specifier. + explicit inline NestedNameSpecifier(CXXRecordDecl *RD); + + explicit operator bool() const { return StoredOrFlag != 0; } + + void *getAsVoidPointer() const { + return reinterpret_cast(StoredOrFlag); + } + static NestedNameSpecifier getFromVoidPointer(const void *Ptr) { + return NestedNameSpecifier(reinterpret_cast(Ptr)); + } + + const Type *getAsType() const { + auto [Kind, Ptr] = getStored(); + assert(Kind == StoredKind::Type); + assert(Ptr != nullptr); + return static_cast(Ptr); + } + + inline NamespaceAndPrefix getAsNamespaceAndPrefix() const; + + CXXRecordDecl *getAsSuper() const { + auto [Kind, Ptr] = getStored(); + assert(Kind == StoredKind::NamespaceOrSuper); + assert(Ptr != nullptr); + return static_cast(const_cast(Ptr)); + } + + /// Retrieve the record declaration stored in this nested name + /// specifier, or null. + inline CXXRecordDecl *getAsRecordDecl() const; + + friend bool operator==(NestedNameSpecifier LHS, NestedNameSpecifier RHS) { + return LHS.StoredOrFlag == RHS.StoredOrFlag; + } + friend bool operator!=(NestedNameSpecifier LHS, NestedNameSpecifier RHS) { + return LHS.StoredOrFlag != RHS.StoredOrFlag; + } + + /// Retrieves the "canonical" nested name specifier for a + /// given nested name specifier. + /// + /// The canonical nested name specifier is a nested name specifier + /// that uniquely identifies a type or namespace within the type + /// system. For example, given: + /// + /// \code + /// namespace N { + /// struct S { + /// template struct X { typename T* type; }; + /// }; + /// } + /// + /// template struct Y { + /// typename N::S::X::type member; + /// }; + /// \endcode + /// + /// Here, the nested-name-specifier for N::S::X:: will be + /// S::X, since 'S' and 'X' are uniquely defined + /// by declarations in the type system and the canonical type for + /// the template type parameter 'T' is template-param-0-0. + inline NestedNameSpecifier getCanonical() const; + + /// Whether this nested name specifier is canonical. + inline bool isCanonical() const; + + /// Whether this nested name specifier starts with a '::'. + bool isFullyQualified() const; + + NestedNameSpecifierDependence getDependence() const; + + /// Whether this nested name specifier refers to a dependent + /// type or not. + bool isDependent() const { + return getDependence() & NestedNameSpecifierDependence::Dependent; + } + + /// Whether this nested name specifier involves a template + /// parameter. + bool isInstantiationDependent() const { + return getDependence() & NestedNameSpecifierDependence::Instantiation; + } + + /// Whether this nested-name-specifier contains an unexpanded + /// parameter pack (for C++11 variadic templates). + bool containsUnexpandedParameterPack() const { + return getDependence() & NestedNameSpecifierDependence::UnexpandedPack; + } + + /// Whether this nested name specifier contains an error. + bool containsErrors() const { + return getDependence() & NestedNameSpecifierDependence::Error; + } + + /// Print this nested name specifier to the given output stream. If + /// `ResolveTemplateArguments` is true, we'll print actual types, e.g. + /// `ns::SomeTemplate` instead of + /// `ns::SomeTemplate`. + void print(raw_ostream &OS, const PrintingPolicy &Policy, + bool ResolveTemplateArguments = false, + bool PrintFinalScopeResOp = true) const; + + void Profile(llvm::FoldingSetNodeID &ID) const { + ID.AddInteger(StoredOrFlag); + } + + /// Dump the nested name specifier to aid in debugging. + void dump(llvm::raw_ostream *OS = nullptr, + const LangOptions *LO = nullptr) const; + void dump(const LangOptions &LO) const; + void dump(llvm::raw_ostream &OS) const; + void dump(llvm::raw_ostream &OS, const LangOptions &LO) const; + + static constexpr auto NumLowBitsAvailable = FlagOffset; +}; + +struct NamespaceAndPrefix { + const NamespaceBaseDecl *Namespace; + NestedNameSpecifier Prefix; +}; + +struct alignas(16) NamespaceAndPrefixStorage : NamespaceAndPrefix, + llvm::FoldingSetNode { + NamespaceAndPrefixStorage(const NamespaceBaseDecl *Namespace, + NestedNameSpecifier Prefix) + : NamespaceAndPrefix{Namespace, Prefix} {} + void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, Namespace, Prefix); } + static void Profile(llvm::FoldingSetNodeID &ID, + const NamespaceBaseDecl *Namespace, + NestedNameSpecifier Prefix) { + ID.AddPointer(Namespace); + Prefix.Profile(ID); + } +}; + +NamespaceAndPrefix NestedNameSpecifier::getAsNamespaceAndPrefix() const { + auto [Kind, Ptr] = getStored(); + switch (Kind) { + case StoredKind::NamespaceOrSuper: + case StoredKind::NamespaceWithGlobal: + return {static_cast(Ptr), + Kind == StoredKind::NamespaceWithGlobal + ? NestedNameSpecifier::getGlobal() + : std::nullopt}; + case StoredKind::NamespaceWithNamespace: + return *static_cast(Ptr); + case StoredKind::Type:; + } + llvm_unreachable("unexpected stored kind"); +} + +struct NamespaceAndPrefixLoc; + +/// A C++ nested-name-specifier augmented with source location +/// information. +class NestedNameSpecifierLoc { + NestedNameSpecifier Qualifier = std::nullopt; + void *Data = nullptr; + + /// Load a (possibly unaligned) source location from a given address + /// and offset. + SourceLocation LoadSourceLocation(unsigned Offset) const { + SourceLocation::UIntTy Raw; + memcpy(&Raw, static_cast(Data) + Offset, sizeof(Raw)); + return SourceLocation::getFromRawEncoding(Raw); + } + + /// Load a (possibly unaligned) pointer from a given address and + /// offset. + void *LoadPointer(unsigned Offset) const { + void *Result; + memcpy(&Result, static_cast(Data) + Offset, sizeof(void *)); + return Result; + } + + /// Determines the data length for the last component in the + /// given nested-name-specifier. + static inline unsigned getLocalDataLength(NestedNameSpecifier Qualifier); + + /// Determines the data length for the entire + /// nested-name-specifier. + static inline unsigned getDataLength(NestedNameSpecifier Qualifier); + +public: + /// Construct an empty nested-name-specifier. + NestedNameSpecifierLoc() = default; + + /// Construct a nested-name-specifier with source location information + /// from + NestedNameSpecifierLoc(NestedNameSpecifier Qualifier, void *Data) + : Qualifier(Qualifier), Data(Data) {} + + /// Evaluates true when this nested-name-specifier location is + /// non-empty. + explicit operator bool() const { return bool(Qualifier); } + + /// Evaluates true when this nested-name-specifier location is + /// non-empty. + bool hasQualifier() const { return bool(Qualifier); } + + /// Retrieve the nested-name-specifier to which this instance + /// refers. + NestedNameSpecifier getNestedNameSpecifier() const { return Qualifier; } + + /// Retrieve the opaque pointer that refers to source-location data. + void *getOpaqueData() const { return Data; } + + /// Retrieve the source range covering the entirety of this + /// nested-name-specifier. + /// + /// For example, if this instance refers to a nested-name-specifier + /// \c \::std::vector::, the returned source range would cover + /// from the initial '::' to the last '::'. + inline SourceRange getSourceRange() const LLVM_READONLY; + + /// Retrieve the source range covering just the last part of + /// this nested-name-specifier, not including the prefix. + /// + /// For example, if this instance refers to a nested-name-specifier + /// \c \::std::vector::, the returned source range would cover + /// from "vector" to the last '::'. + inline SourceRange getLocalSourceRange() const; + + /// Retrieve the location of the beginning of this + /// nested-name-specifier. + SourceLocation getBeginLoc() const; + + /// Retrieve the location of the end of this + /// nested-name-specifier. + inline SourceLocation getEndLoc() const; + + /// Retrieve the location of the beginning of this + /// component of the nested-name-specifier. + inline SourceLocation getLocalBeginLoc() const; + + /// Retrieve the location of the end of this component of the + /// nested-name-specifier. + inline SourceLocation getLocalEndLoc() const; + + /// For a nested-name-specifier that refers to a namespace, + /// retrieve the namespace and its prefix. + /// + /// For example, if this instance refers to a nested-name-specifier + /// \c \::std::chrono::, the prefix is \c \::std::. Note that the + /// returned prefix may be empty, if this is the first component of + /// the nested-name-specifier. + inline NamespaceAndPrefixLoc castAsNamespaceAndPrefix() const; + inline NamespaceAndPrefixLoc getAsNamespaceAndPrefix() const; + + /// For a nested-name-specifier that refers to a type, + /// retrieve the type with source-location information. + inline TypeLoc castAsTypeLoc() const; + inline TypeLoc getAsTypeLoc() const; + + /// Determines the data length for the entire + /// nested-name-specifier. + inline unsigned getDataLength() const; + + friend bool operator==(NestedNameSpecifierLoc X, NestedNameSpecifierLoc Y) { + return X.Qualifier == Y.Qualifier && X.Data == Y.Data; + } + + friend bool operator!=(NestedNameSpecifierLoc X, NestedNameSpecifierLoc Y) { + return !(X == Y); + } +}; + +struct NamespaceAndPrefixLoc { + const NamespaceBaseDecl *Namespace = nullptr; + NestedNameSpecifierLoc Prefix; + + explicit operator bool() const { return Namespace != nullptr; } +}; + +/// Class that aids in the construction of nested-name-specifiers along +/// with source-location information for all of the components of the +/// nested-name-specifier. +class NestedNameSpecifierLocBuilder { + /// The current representation of the nested-name-specifier we're + /// building. + NestedNameSpecifier Representation = std::nullopt; + + /// Buffer used to store source-location information for the + /// nested-name-specifier. + /// + /// Note that we explicitly manage the buffer (rather than using a + /// SmallVector) because \c Declarator expects it to be possible to memcpy() + /// a \c CXXScopeSpec, and CXXScopeSpec uses a NestedNameSpecifierLocBuilder. + char *Buffer = nullptr; + + /// The size of the buffer used to store source-location information + /// for the nested-name-specifier. + unsigned BufferSize = 0; + + /// The capacity of the buffer used to store source-location + /// information for the nested-name-specifier. + unsigned BufferCapacity = 0; + + void PushTrivial(ASTContext &Context, NestedNameSpecifier Qualifier, + SourceRange R); + +public: + NestedNameSpecifierLocBuilder() = default; + NestedNameSpecifierLocBuilder(const NestedNameSpecifierLocBuilder &Other); + + NestedNameSpecifierLocBuilder & + operator=(const NestedNameSpecifierLocBuilder &Other); + + ~NestedNameSpecifierLocBuilder() { + if (BufferCapacity) + free(Buffer); + } + + /// Retrieve the representation of the nested-name-specifier. + NestedNameSpecifier getRepresentation() const { return Representation; } + + /// Make a nested-name-specifier of the form 'type::'. + /// + /// \param Context The AST context in which this nested-name-specifier + /// resides. + /// + /// \param TL The TypeLoc that describes the type preceding the '::'. + /// + /// \param ColonColonLoc The location of the trailing '::'. + void Make(ASTContext &Context, TypeLoc TL, SourceLocation ColonColonLoc); + + /// Extend the current nested-name-specifier by another + /// nested-name-specifier component of the form 'namespace::'. + /// + /// \param Context The AST context in which this nested-name-specifier + /// resides. + /// + /// \param Namespace The namespace. + /// + /// \param NamespaceLoc The location of the namespace name. + /// + /// \param ColonColonLoc The location of the trailing '::'. + void Extend(ASTContext &Context, const NamespaceBaseDecl *Namespace, + SourceLocation NamespaceLoc, SourceLocation ColonColonLoc); + + /// Turn this (empty) nested-name-specifier into the global + /// nested-name-specifier '::'. + void MakeGlobal(ASTContext &Context, SourceLocation ColonColonLoc); + + /// Turns this (empty) nested-name-specifier into '__super' + /// nested-name-specifier. + /// + /// \param Context The AST context in which this nested-name-specifier + /// resides. + /// + /// \param RD The declaration of the class in which nested-name-specifier + /// appeared. + /// + /// \param SuperLoc The location of the '__super' keyword. + /// name. + /// + /// \param ColonColonLoc The location of the trailing '::'. + void MakeSuper(ASTContext &Context, CXXRecordDecl *RD, + SourceLocation SuperLoc, SourceLocation ColonColonLoc); + + /// Make a new nested-name-specifier from incomplete source-location + /// information. + /// + /// This routine should be used very, very rarely, in cases where we + /// need to synthesize a nested-name-specifier. Most code should instead use + /// \c Adopt() with a proper \c NestedNameSpecifierLoc. + void MakeTrivial(ASTContext &Context, NestedNameSpecifier Qualifier, + SourceRange R) { + Representation = Qualifier; + BufferSize = 0; + PushTrivial(Context, Qualifier, R); + } + + /// Adopt an existing nested-name-specifier (with source-range + /// information). + void Adopt(NestedNameSpecifierLoc Other); + + /// Retrieve the source range covered by this nested-name-specifier. + inline SourceRange getSourceRange() const LLVM_READONLY; + + /// Retrieve a nested-name-specifier with location information, + /// copied into the given AST context. + /// + /// \param Context The context into which this nested-name-specifier will be + /// copied. + NestedNameSpecifierLoc getWithLocInContext(ASTContext &Context) const; + + /// Retrieve a nested-name-specifier with location + /// information based on the information in this builder. + /// + /// This loc will contain references to the builder's internal data and may + /// be invalidated by any change to the builder. + NestedNameSpecifierLoc getTemporary() const { + return NestedNameSpecifierLoc(Representation, Buffer); + } + + /// Clear out this builder, and prepare it to build another + /// nested-name-specifier with source-location information. + void Clear() { + Representation = std::nullopt; + BufferSize = 0; + } + + /// Retrieve the underlying buffer. + /// + /// \returns A pair containing a pointer to the buffer of source-location + /// data and the size of the source-location data that resides in that + /// buffer. + std::pair getBuffer() const { + return std::make_pair(Buffer, BufferSize); + } +}; + +/// Insertion operator for diagnostics. This allows sending +/// NestedNameSpecifiers into a diagnostic with <<. +inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB, + NestedNameSpecifier NNS) { + DB.AddTaggedVal(reinterpret_cast(NNS.getAsVoidPointer()), + DiagnosticsEngine::ak_nestednamespec); + return DB; +} + +} // namespace clang + +namespace llvm { + +template <> struct PointerLikeTypeTraits { + static void *getAsVoidPointer(clang::NestedNameSpecifier P) { + return P.getAsVoidPointer(); + } + static clang::NestedNameSpecifier getFromVoidPointer(const void *P) { + return clang::NestedNameSpecifier::getFromVoidPointer(P); + } + static constexpr int NumLowBitsAvailable = + clang::NestedNameSpecifier::NumLowBitsAvailable; +}; + +} // namespace llvm + +#endif // LLVM_CLANG_AST_NESTEDNAMESPECIFIERBASE_H \ No newline at end of file diff --git a/clang/include/clang/AST/ODRHash.h b/clang/include/clang/AST/ODRHash.h index 11f917a1a4634..ae3fab697786a 100644 --- a/clang/include/clang/AST/ODRHash.h +++ b/clang/include/clang/AST/ODRHash.h @@ -93,7 +93,7 @@ class ODRHash { void AddQualType(QualType T); void AddStmt(const Stmt *S); void AddIdentifierInfo(const IdentifierInfo *II); - void AddNestedNameSpecifier(const NestedNameSpecifier *NNS); + void AddNestedNameSpecifier(NestedNameSpecifier NNS); void AddDependentTemplateName(const DependentTemplateStorage &Name); void AddTemplateName(TemplateName Name); void AddDeclarationNameInfo(DeclarationNameInfo NameInfo, diff --git a/clang/include/clang/AST/PrettyPrinter.h b/clang/include/clang/AST/PrettyPrinter.h index 875769cd02bc0..fd995a653d167 100644 --- a/clang/include/clang/AST/PrettyPrinter.h +++ b/clang/include/clang/AST/PrettyPrinter.h @@ -63,9 +63,9 @@ struct PrintingPolicy { SuppressTagKeyword(LO.CPlusPlus), IncludeTagDefinition(false), SuppressScope(false), SuppressUnwrittenScope(false), SuppressInlineNamespace(SuppressInlineNamespaceMode::Redundant), - SuppressElaboration(false), SuppressInitializers(false), - ConstantArraySizeAsWritten(false), AnonymousTagLocations(true), - SuppressStrongLifetime(false), SuppressLifetimeQualifiers(false), + SuppressInitializers(false), ConstantArraySizeAsWritten(false), + AnonymousTagLocations(true), SuppressStrongLifetime(false), + SuppressLifetimeQualifiers(false), SuppressTemplateArgsInCXXConstructors(false), SuppressDefaultTemplateArgs(true), Bool(LO.Bool), Nullptr(LO.CPlusPlus11 || LO.C23), NullptrTypeInNamespace(LO.CPlusPlus), @@ -150,11 +150,6 @@ struct PrintingPolicy { LLVM_PREFERRED_TYPE(SuppressInlineNamespaceMode) unsigned SuppressInlineNamespace : 2; - /// Ignore qualifiers and tag keywords as specified by elaborated type sugar, - /// instead letting the underlying type print as normal. - LLVM_PREFERRED_TYPE(bool) - unsigned SuppressElaboration : 1; - /// Suppress printing of variable initializers. /// /// This flag is used when printing the loop variable in a for-range diff --git a/clang/include/clang/AST/PropertiesBase.td b/clang/include/clang/AST/PropertiesBase.td index 1215056ffde1b..5b10127526e4e 100644 --- a/clang/include/clang/AST/PropertiesBase.td +++ b/clang/include/clang/AST/PropertiesBase.td @@ -91,6 +91,7 @@ def DeclRef : RefPropertyType<"Decl"> { let ConstWhenWriting = 1; } SubclassPropertyType<"FunctionDecl", DeclRef>; def NamedDeclRef : SubclassPropertyType<"NamedDecl", DeclRef>; + def NamespaceBaseDeclRef : SubclassPropertyType<"NamespaceBaseDecl", DeclRef>; def NamespaceDeclRef : SubclassPropertyType<"NamespaceDecl", DeclRef>; def NamespaceAliasDeclRef : @@ -126,9 +127,8 @@ def LValuePathSerializationHelper : PropertyType<"APValue::LValuePathSerializationHelper"> { let BufferElementTypes = [ LValuePathEntry ]; } -def NestedNameSpecifier : PropertyType<"NestedNameSpecifier *">; -def NestedNameSpecifierKind : - EnumPropertyType<"NestedNameSpecifier::SpecifierKind">; +def NestedNameSpecifier : PropertyType<"NestedNameSpecifier">; +def NestedNameSpecifierKind : EnumPropertyType<"NestedNameSpecifier::Kind">; def OverloadedOperatorKind : EnumPropertyType; def Qualifiers : PropertyType; def QualType : DefaultValuePropertyType; diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h index 5cb2f57edffe4..65e015ac88ef7 100644 --- a/clang/include/clang/AST/RecursiveASTVisitor.h +++ b/clang/include/clang/AST/RecursiveASTVisitor.h @@ -216,14 +216,14 @@ template class RecursiveASTVisitor { /// /// \returns false if the visitation was terminated early, true /// otherwise (including when the argument is a Null type). - bool TraverseType(QualType T); + bool TraverseType(QualType T, bool TraverseQualifier = true); /// Recursively visit a type with location, by dispatching to /// Traverse*TypeLoc() based on the argument type's getTypeClass() property. /// /// \returns false if the visitation was terminated early, true /// otherwise (including when the argument is a Null type location). - bool TraverseTypeLoc(TypeLoc TL); + bool TraverseTypeLoc(TypeLoc TL, bool TraverseQualifier = true); /// Recursively visit an attribute, by dispatching to /// Traverse*Attr() based on the argument's dynamic type. @@ -242,7 +242,7 @@ template class RecursiveASTVisitor { /// Recursively visit a C++ nested-name-specifier. /// /// \returns false if the visitation was terminated early, true otherwise. - bool TraverseNestedNameSpecifier(NestedNameSpecifier *NNS); + bool TraverseNestedNameSpecifier(NestedNameSpecifier NNS); /// Recursively visit a C++ nested-name-specifier with location /// information. @@ -389,7 +389,8 @@ template class RecursiveASTVisitor { // Declare Traverse*() for all concrete Type classes. #define ABSTRACT_TYPE(CLASS, BASE) -#define TYPE(CLASS, BASE) bool Traverse##CLASS##Type(CLASS##Type *T); +#define TYPE(CLASS, BASE) \ + bool Traverse##CLASS##Type(CLASS##Type *T, bool TraverseQualifier); #include "clang/AST/TypeNodes.inc" // The above header #undefs ABSTRACT_TYPE and TYPE upon exit. @@ -410,7 +411,8 @@ template class RecursiveASTVisitor { // Declare Traverse*() for all concrete TypeLoc classes. #define ABSTRACT_TYPELOC(CLASS, BASE) -#define TYPELOC(CLASS, BASE) bool Traverse##CLASS##TypeLoc(CLASS##TypeLoc TL); +#define TYPELOC(CLASS, BASE) \ + bool Traverse##CLASS##TypeLoc(CLASS##TypeLoc TL, bool TraverseQualifier); #include "clang/AST/TypeLocNodes.def" // The above header #undefs ABSTRACT_TYPELOC and TYPELOC upon exit. @@ -499,6 +501,8 @@ template class RecursiveASTVisitor { bool TraverseOMPExecutableDirective(OMPExecutableDirective *S); bool TraverseOMPLoopDirective(OMPLoopDirective *S); bool TraverseOMPClause(OMPClause *C); + bool TraverseTagType(TagType *T, bool TraverseQualifier); + bool TraverseTagTypeLoc(TagTypeLoc TL, bool TraverseQualifier); #define GEN_CLANG_CLAUSE_CLASS #define CLAUSE_CLASS(Enum, Str, Class) bool Visit##Class(Class *C); #include "llvm/Frontend/OpenMP/OMP.inc" @@ -698,7 +702,8 @@ RecursiveASTVisitor::TraverseStmt(Stmt *S, DataRecursionQueue *Queue) { } template -bool RecursiveASTVisitor::TraverseType(QualType T) { +bool RecursiveASTVisitor::TraverseType(QualType T, + bool TraverseQualifier) { if (T.isNull()) return true; @@ -707,7 +712,8 @@ bool RecursiveASTVisitor::TraverseType(QualType T) { #define TYPE(CLASS, BASE) \ case Type::CLASS: \ return getDerived().Traverse##CLASS##Type( \ - static_cast(const_cast(T.getTypePtr()))); + static_cast(const_cast(T.getTypePtr())), \ + TraverseQualifier); #include "clang/AST/TypeNodes.inc" } @@ -715,7 +721,8 @@ bool RecursiveASTVisitor::TraverseType(QualType T) { } template -bool RecursiveASTVisitor::TraverseTypeLoc(TypeLoc TL) { +bool RecursiveASTVisitor::TraverseTypeLoc(TypeLoc TL, + bool TraverseQualifier) { if (TL.isNull()) return true; @@ -723,7 +730,8 @@ bool RecursiveASTVisitor::TraverseTypeLoc(TypeLoc TL) { #define ABSTRACT_TYPELOC(CLASS, BASE) #define TYPELOC(CLASS, BASE) \ case TypeLoc::CLASS: \ - return getDerived().Traverse##CLASS##TypeLoc(TL.castAs()); + return getDerived().Traverse##CLASS##TypeLoc(TL.castAs(), \ + TraverseQualifier); #include "clang/AST/TypeLocNodes.def" } @@ -779,48 +787,43 @@ bool RecursiveASTVisitor::TraverseDecl(Decl *D) { template bool RecursiveASTVisitor::TraverseNestedNameSpecifier( - NestedNameSpecifier *NNS) { - if (!NNS) + NestedNameSpecifier NNS) { + switch (NNS.getKind()) { + case NestedNameSpecifier::Kind::Null: + case NestedNameSpecifier::Kind::Global: + case NestedNameSpecifier::Kind::Super: return true; - - if (NNS->getPrefix()) - TRY_TO(TraverseNestedNameSpecifier(NNS->getPrefix())); - - switch (NNS->getKind()) { - case NestedNameSpecifier::Identifier: - case NestedNameSpecifier::Namespace: - case NestedNameSpecifier::NamespaceAlias: - case NestedNameSpecifier::Global: - case NestedNameSpecifier::Super: + case NestedNameSpecifier::Kind::Namespace: + TRY_TO(TraverseNestedNameSpecifier(NNS.getAsNamespaceAndPrefix().Prefix)); + return true; + case NestedNameSpecifier::Kind::Type: { + auto *T = const_cast(NNS.getAsType()); + TRY_TO(TraverseNestedNameSpecifier(T->getPrefix())); + TRY_TO(TraverseType(QualType(T, 0), /*TraverseQualifier=*/false)); return true; - - case NestedNameSpecifier::TypeSpec: - TRY_TO(TraverseType(QualType(NNS->getAsType(), 0))); } - - return true; + } + llvm_unreachable("unhandled kind"); } template bool RecursiveASTVisitor::TraverseNestedNameSpecifierLoc( NestedNameSpecifierLoc NNS) { - if (!NNS) + switch (NNS.getNestedNameSpecifier().getKind()) { + case NestedNameSpecifier::Kind::Null: + case NestedNameSpecifier::Kind::Global: + case NestedNameSpecifier::Kind::Super: return true; - - if (NestedNameSpecifierLoc Prefix = NNS.getPrefix()) - TRY_TO(TraverseNestedNameSpecifierLoc(Prefix)); - - switch (NNS.getNestedNameSpecifier()->getKind()) { - case NestedNameSpecifier::Identifier: - case NestedNameSpecifier::Namespace: - case NestedNameSpecifier::NamespaceAlias: - case NestedNameSpecifier::Global: - case NestedNameSpecifier::Super: + case NestedNameSpecifier::Kind::Namespace: + TRY_TO( + TraverseNestedNameSpecifierLoc(NNS.castAsNamespaceAndPrefix().Prefix)); return true; - - case NestedNameSpecifier::TypeSpec: - TRY_TO(TraverseTypeLoc(NNS.getTypeLoc())); - break; + case NestedNameSpecifier::Kind::Type: { + TypeLoc TL = NNS.castAsTypeLoc(); + TRY_TO(TraverseNestedNameSpecifierLoc(TL.getPrefix())); + TRY_TO(TraverseTypeLoc(TL, /*TraverseQualifier=*/false)); + return true; + } } return true; @@ -977,10 +980,13 @@ RecursiveASTVisitor::TraverseLambdaCapture(LambdaExpr *LE, // This macro makes available a variable T, the passed-in type. #define DEF_TRAVERSE_TYPE(TYPE, CODE) \ template \ - bool RecursiveASTVisitor::Traverse##TYPE(TYPE *T) { \ + bool RecursiveASTVisitor::Traverse##TYPE(TYPE *T, \ + bool TraverseQualifier) { \ if (!getDerived().shouldTraversePostOrder()) \ TRY_TO(WalkUpFrom##TYPE(T)); \ - { CODE; } \ + { \ + CODE; \ + } \ if (getDerived().shouldTraversePostOrder()) \ TRY_TO(WalkUpFrom##TYPE(T)); \ return true; \ @@ -1002,10 +1008,11 @@ DEF_TRAVERSE_TYPE(RValueReferenceType, { TRY_TO(TraverseType(T->getPointeeType())); }) DEF_TRAVERSE_TYPE(MemberPointerType, { - TRY_TO(TraverseNestedNameSpecifier(T->getQualifier())); - if (T->isSugared()) - TRY_TO(TraverseType( - QualType(T->getMostRecentCXXRecordDecl()->getTypeForDecl(), 0))); + NestedNameSpecifier Qualifier = + T->isSugared() ? cast(T->getCanonicalTypeUnqualified()) + ->getQualifier() + : T->getQualifier(); + TRY_TO(TraverseNestedNameSpecifier(Qualifier)); TRY_TO(TraverseType(T->getPointeeType())); }) @@ -1089,9 +1096,18 @@ DEF_TRAVERSE_TYPE(FunctionProtoType, { TRY_TO(TraverseStmt(NE)); }) -DEF_TRAVERSE_TYPE(UsingType, {}) -DEF_TRAVERSE_TYPE(UnresolvedUsingType, {}) -DEF_TRAVERSE_TYPE(TypedefType, {}) +DEF_TRAVERSE_TYPE(UsingType, { + if (TraverseQualifier) + TRY_TO(TraverseNestedNameSpecifier(T->getQualifier())); +}) +DEF_TRAVERSE_TYPE(UnresolvedUsingType, { + if (TraverseQualifier) + TRY_TO(TraverseNestedNameSpecifier(T->getQualifier())); +}) +DEF_TRAVERSE_TYPE(TypedefType, { + if (TraverseQualifier) + TRY_TO(TraverseNestedNameSpecifier(T->getQualifier())); +}) DEF_TRAVERSE_TYPE(TypeOfExprType, { TRY_TO(TraverseStmt(T->getUnderlyingExpr())); }) @@ -1117,13 +1133,7 @@ DEF_TRAVERSE_TYPE(AutoType, { TRY_TO(TraverseTemplateArguments(T->getTypeConstraintArguments())); } }) -DEF_TRAVERSE_TYPE(DeducedTemplateSpecializationType, { - TRY_TO(TraverseTemplateName(T->getTemplateName())); - TRY_TO(TraverseType(T->getDeducedType())); -}) -DEF_TRAVERSE_TYPE(RecordType, {}) -DEF_TRAVERSE_TYPE(EnumType, {}) DEF_TRAVERSE_TYPE(TemplateTypeParmType, {}) DEF_TRAVERSE_TYPE(SubstTemplateTypeParmType, { TRY_TO(TraverseType(T->getReplacementType())); @@ -1132,13 +1142,6 @@ DEF_TRAVERSE_TYPE(SubstTemplateTypeParmPackType, { TRY_TO(TraverseTemplateArgument(T->getArgumentPack())); }) -DEF_TRAVERSE_TYPE(TemplateSpecializationType, { - TRY_TO(TraverseTemplateName(T->getTemplateName())); - TRY_TO(TraverseTemplateArguments(T->template_arguments())); -}) - -DEF_TRAVERSE_TYPE(InjectedClassNameType, {}) - DEF_TRAVERSE_TYPE(AttributedType, { TRY_TO(TraverseType(T->getModifiedType())); }) @@ -1167,22 +1170,54 @@ DEF_TRAVERSE_TYPE(ParenType, { TRY_TO(TraverseType(T->getInnerType())); }) DEF_TRAVERSE_TYPE(MacroQualifiedType, { TRY_TO(TraverseType(T->getUnderlyingType())); }) -DEF_TRAVERSE_TYPE(ElaboratedType, { - if (T->getQualifier()) { +template +bool RecursiveASTVisitor::TraverseTagType(TagType *T, + bool TraverseQualifier) { + if (TraverseQualifier) TRY_TO(TraverseNestedNameSpecifier(T->getQualifier())); - } - TRY_TO(TraverseType(T->getNamedType())); -}) + return true; +} + +DEF_TRAVERSE_TYPE(EnumType, { TRY_TO(TraverseTagType(T, TraverseQualifier)); }) +DEF_TRAVERSE_TYPE(RecordType, + { TRY_TO(TraverseTagType(T, TraverseQualifier)); }) +DEF_TRAVERSE_TYPE(InjectedClassNameType, + { TRY_TO(TraverseTagType(T, TraverseQualifier)); }) -DEF_TRAVERSE_TYPE(DependentNameType, - { TRY_TO(TraverseNestedNameSpecifier(T->getQualifier())); }) +DEF_TRAVERSE_TYPE(DependentNameType, { + if (TraverseQualifier) + TRY_TO(TraverseNestedNameSpecifier(T->getQualifier())); +}) DEF_TRAVERSE_TYPE(DependentTemplateSpecializationType, { const DependentTemplateStorage &S = T->getDependentTemplateName(); - TRY_TO(TraverseNestedNameSpecifier(S.getQualifier())); + if (TraverseQualifier) + TRY_TO(TraverseNestedNameSpecifier(S.getQualifier())); TRY_TO(TraverseTemplateArguments(T->template_arguments())); }) +DEF_TRAVERSE_TYPE(TemplateSpecializationType, { + if (TraverseQualifier) { + TRY_TO(TraverseTemplateName(T->getTemplateName())); + } else { + // FIXME: Try to preserve the rest of the template name. + TRY_TO(TraverseTemplateName(TemplateName( + T->getTemplateName().getAsTemplateDecl(/*IgnoreDeduced=*/true)))); + } + TRY_TO(TraverseTemplateArguments(T->template_arguments())); +}) + +DEF_TRAVERSE_TYPE(DeducedTemplateSpecializationType, { + if (TraverseQualifier) { + TRY_TO(TraverseTemplateName(T->getTemplateName())); + } else { + // FIXME: Try to preserve the rest of the template name. + TRY_TO(TraverseTemplateName(TemplateName( + T->getTemplateName().getAsTemplateDecl(/*IgnoreDeduced=*/true)))); + } + TRY_TO(TraverseType(T->getDeducedType())); +}) + DEF_TRAVERSE_TYPE(PackExpansionType, { TRY_TO(TraverseType(T->getPattern())); }) DEF_TRAVERSE_TYPE(ObjCTypeParamType, {}) @@ -1221,13 +1256,16 @@ DEF_TRAVERSE_TYPE(DependentBitIntType, // continue to work. #define DEF_TRAVERSE_TYPELOC(TYPE, CODE) \ template \ - bool RecursiveASTVisitor::Traverse##TYPE##Loc(TYPE##Loc TL) { \ + bool RecursiveASTVisitor::Traverse##TYPE##Loc( \ + TYPE##Loc TL, bool TraverseQualifier) { \ if (!getDerived().shouldTraversePostOrder()) { \ TRY_TO(WalkUpFrom##TYPE##Loc(TL)); \ if (getDerived().shouldWalkTypesOfTypeLocs()) \ TRY_TO(WalkUpFrom##TYPE(const_cast(TL.getTypePtr()))); \ } \ - { CODE; } \ + { \ + CODE; \ + } \ if (getDerived().shouldTraversePostOrder()) { \ TRY_TO(WalkUpFrom##TYPE##Loc(TL)); \ if (getDerived().shouldWalkTypesOfTypeLocs()) \ @@ -1237,8 +1275,10 @@ DEF_TRAVERSE_TYPE(DependentBitIntType, } template -bool -RecursiveASTVisitor::TraverseQualifiedTypeLoc(QualifiedTypeLoc TL) { +bool RecursiveASTVisitor::TraverseQualifiedTypeLoc( + QualifiedTypeLoc TL, bool TraverseQualifier) { + assert(TraverseQualifier && + "Qualifiers should never occur within NestedNameSpecifiers"); // Move this over to the 'main' typeloc tree. Note that this is a // move -- we pretend that we were really looking at the unqualified // typeloc all along -- rather than a recursion, so we don't follow @@ -1391,9 +1431,21 @@ DEF_TRAVERSE_TYPELOC(FunctionProtoType, { TRY_TO(TraverseStmt(NE)); }) -DEF_TRAVERSE_TYPELOC(UsingType, {}) -DEF_TRAVERSE_TYPELOC(UnresolvedUsingType, {}) -DEF_TRAVERSE_TYPELOC(TypedefType, {}) +DEF_TRAVERSE_TYPELOC(UsingType, { + if (NestedNameSpecifierLoc QualifierLoc = TL.getQualifierLoc(); + TraverseQualifier && QualifierLoc) + TRY_TO(TraverseNestedNameSpecifierLoc(QualifierLoc)); +}) +DEF_TRAVERSE_TYPELOC(UnresolvedUsingType, { + if (NestedNameSpecifierLoc QualifierLoc = TL.getQualifierLoc(); + TraverseQualifier && QualifierLoc) + TRY_TO(TraverseNestedNameSpecifierLoc(QualifierLoc)); +}) +DEF_TRAVERSE_TYPELOC(TypedefType, { + if (NestedNameSpecifierLoc QualifierLoc = TL.getQualifierLoc(); + TraverseQualifier && QualifierLoc) + TRY_TO(TraverseNestedNameSpecifierLoc(QualifierLoc)); +}) DEF_TRAVERSE_TYPELOC(TypeOfExprType, { TRY_TO(TraverseStmt(TL.getUnderlyingExpr())); }) @@ -1423,13 +1475,6 @@ DEF_TRAVERSE_TYPELOC(AutoType, { } }) -DEF_TRAVERSE_TYPELOC(DeducedTemplateSpecializationType, { - TRY_TO(TraverseTemplateName(TL.getTypePtr()->getTemplateName())); - TRY_TO(TraverseType(TL.getTypePtr()->getDeducedType())); -}) - -DEF_TRAVERSE_TYPELOC(RecordType, {}) -DEF_TRAVERSE_TYPELOC(EnumType, {}) DEF_TRAVERSE_TYPELOC(TemplateTypeParmType, {}) DEF_TRAVERSE_TYPELOC(SubstTemplateTypeParmType, { TRY_TO(TraverseType(TL.getTypePtr()->getReplacementType())); @@ -1438,16 +1483,6 @@ DEF_TRAVERSE_TYPELOC(SubstTemplateTypeParmPackType, { TRY_TO(TraverseTemplateArgument(TL.getTypePtr()->getArgumentPack())); }) -// FIXME: use the loc for the template name? -DEF_TRAVERSE_TYPELOC(TemplateSpecializationType, { - TRY_TO(TraverseTemplateName(TL.getTypePtr()->getTemplateName())); - for (unsigned I = 0, E = TL.getNumArgs(); I != E; ++I) { - TRY_TO(TraverseTemplateArgumentLoc(TL.getArgLoc(I))); - } -}) - -DEF_TRAVERSE_TYPELOC(InjectedClassNameType, {}) - DEF_TRAVERSE_TYPELOC(ParenType, { TRY_TO(TraverseTypeLoc(TL.getInnerLoc())); }) DEF_TRAVERSE_TYPELOC(MacroQualifiedType, @@ -1468,27 +1503,63 @@ DEF_TRAVERSE_TYPELOC(HLSLAttributedResourceType, DEF_TRAVERSE_TYPELOC(HLSLInlineSpirvType, { TRY_TO(TraverseType(TL.getType())); }) -DEF_TRAVERSE_TYPELOC(ElaboratedType, { - if (TL.getQualifierLoc()) { - TRY_TO(TraverseNestedNameSpecifierLoc(TL.getQualifierLoc())); - } - TRY_TO(TraverseTypeLoc(TL.getNamedTypeLoc())); -}) +template +bool RecursiveASTVisitor::TraverseTagTypeLoc(TagTypeLoc TL, + bool TraverseQualifier) { + if (NestedNameSpecifierLoc QualifierLoc = TL.getQualifierLoc(); + TraverseQualifier && QualifierLoc) + TRY_TO(TraverseNestedNameSpecifierLoc(QualifierLoc)); + return true; +} + +DEF_TRAVERSE_TYPELOC(EnumType, + { TRY_TO(TraverseTagTypeLoc(TL, TraverseQualifier)); }) +DEF_TRAVERSE_TYPELOC(RecordType, + { TRY_TO(TraverseTagTypeLoc(TL, TraverseQualifier)); }) +DEF_TRAVERSE_TYPELOC(InjectedClassNameType, + { TRY_TO(TraverseTagTypeLoc(TL, TraverseQualifier)); }) DEF_TRAVERSE_TYPELOC(DependentNameType, { - TRY_TO(TraverseNestedNameSpecifierLoc(TL.getQualifierLoc())); + if (TraverseQualifier) + TRY_TO(TraverseNestedNameSpecifierLoc(TL.getQualifierLoc())); }) DEF_TRAVERSE_TYPELOC(DependentTemplateSpecializationType, { - if (TL.getQualifierLoc()) { + if (TraverseQualifier) TRY_TO(TraverseNestedNameSpecifierLoc(TL.getQualifierLoc())); + + for (unsigned I = 0, E = TL.getNumArgs(); I != E; ++I) { + TRY_TO(TraverseTemplateArgumentLoc(TL.getArgLoc(I))); } +}) + +DEF_TRAVERSE_TYPELOC(TemplateSpecializationType, { + if (TraverseQualifier) + TRY_TO(TraverseNestedNameSpecifierLoc(TL.getQualifierLoc())); + + // FIXME: Try to preserve the rest of the template name. + TRY_TO(TraverseTemplateName( + TemplateName(TL.getTypePtr()->getTemplateName().getAsTemplateDecl( + /*IgnoreDeduced=*/true)))); for (unsigned I = 0, E = TL.getNumArgs(); I != E; ++I) { TRY_TO(TraverseTemplateArgumentLoc(TL.getArgLoc(I))); } }) +DEF_TRAVERSE_TYPELOC(DeducedTemplateSpecializationType, { + if (TraverseQualifier) + TRY_TO(TraverseNestedNameSpecifierLoc(TL.getQualifierLoc())); + + const auto *T = TL.getTypePtr(); + // FIXME: Try to preserve the rest of the template name. + TRY_TO( + TraverseTemplateName(TemplateName(T->getTemplateName().getAsTemplateDecl( + /*IgnoreDeduced=*/true)))); + + TRY_TO(TraverseType(T->getDeducedType())); +}) + DEF_TRAVERSE_TYPELOC(PackExpansionType, { TRY_TO(TraverseTypeLoc(TL.getPatternLoc())); }) @@ -1629,8 +1700,9 @@ DEF_TRAVERSE_DECL(FriendDecl, { TRY_TO(TraverseTypeLoc(D->getFriendType()->getTypeLoc())); // Traverse any CXXRecordDecl owned by this type, since // it will not be in the parent context: - if (auto *ET = D->getFriendType()->getType()->getAs()) - TRY_TO(TraverseDecl(ET->getOwnedTagDecl())); + if (auto *TT = D->getFriendType()->getType()->getAs(); + TT && TT->isTagOwned()) + TRY_TO(TraverseDecl(TT->getOriginalDecl())); } else { TRY_TO(TraverseDecl(D->getFriendDecl())); } diff --git a/clang/include/clang/AST/TemplateBase.h b/clang/include/clang/AST/TemplateBase.h index b67036cae4261..ac0c0cc7e0286 100644 --- a/clang/include/clang/AST/TemplateBase.h +++ b/clang/include/clang/AST/TemplateBase.h @@ -15,7 +15,7 @@ #define LLVM_CLANG_AST_TEMPLATEBASE_H #include "clang/AST/DependenceFlags.h" -#include "clang/AST/NestedNameSpecifier.h" +#include "clang/AST/NestedNameSpecifierBase.h" #include "clang/AST/TemplateName.h" #include "clang/AST/Type.h" #include "clang/Basic/LLVM.h" @@ -476,31 +476,25 @@ class TemplateArgument { /// Location information for a TemplateArgument. struct TemplateArgumentLocInfo { -private: struct TemplateTemplateArgLocInfo { - // FIXME: We'd like to just use the qualifier in the TemplateName, - // but template arguments get canonicalized too quickly. - NestedNameSpecifier *Qualifier; void *QualifierLocData; + SourceLocation TemplateKwLoc; SourceLocation TemplateNameLoc; SourceLocation EllipsisLoc; }; - llvm::PointerUnion - Pointer; - TemplateTemplateArgLocInfo *getTemplate() const { return cast(Pointer); } -public: TemplateArgumentLocInfo() {} TemplateArgumentLocInfo(TypeSourceInfo *Declarator) { Pointer = Declarator; } TemplateArgumentLocInfo(Expr *E) { Pointer = E; } // Ctx is used for allocation -- this case is unusually large and also rare, // so we store the payload out-of-line. - TemplateArgumentLocInfo(ASTContext &Ctx, NestedNameSpecifierLoc QualifierLoc, + TemplateArgumentLocInfo(ASTContext &Ctx, SourceLocation TemplateKwLoc, + NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateNameLoc, SourceLocation EllipsisLoc); @@ -510,10 +504,8 @@ struct TemplateArgumentLocInfo { Expr *getAsExpr() const { return cast(Pointer); } - NestedNameSpecifierLoc getTemplateQualifierLoc() const { - const auto *Template = getTemplate(); - return NestedNameSpecifierLoc(Template->Qualifier, - Template->QualifierLocData); + SourceLocation getTemplateKwLoc() const { + return getTemplate()->TemplateKwLoc; } SourceLocation getTemplateNameLoc() const { @@ -523,6 +515,10 @@ struct TemplateArgumentLocInfo { SourceLocation getTemplateEllipsisLoc() const { return getTemplate()->EllipsisLoc; } + +private: + llvm::PointerUnion + Pointer; }; /// Location wrapper for a TemplateArgument. TemplateArgument is to @@ -556,14 +552,10 @@ class TemplateArgumentLoc { } TemplateArgumentLoc(ASTContext &Ctx, const TemplateArgument &Argument, + SourceLocation TemplateKWLoc, NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateNameLoc, - SourceLocation EllipsisLoc = SourceLocation()) - : Argument(Argument), - LocInfo(Ctx, QualifierLoc, TemplateNameLoc, EllipsisLoc) { - assert(Argument.getKind() == TemplateArgument::Template || - Argument.getKind() == TemplateArgument::TemplateExpansion); - } + SourceLocation EllipsisLoc = SourceLocation()); /// - Fetches the primary location of the argument. SourceLocation getLocation() const { @@ -612,13 +604,15 @@ class TemplateArgumentLoc { return LocInfo.getAsExpr(); } - NestedNameSpecifierLoc getTemplateQualifierLoc() const { + SourceLocation getTemplateKWLoc() const { if (Argument.getKind() != TemplateArgument::Template && Argument.getKind() != TemplateArgument::TemplateExpansion) - return NestedNameSpecifierLoc(); - return LocInfo.getTemplateQualifierLoc(); + return SourceLocation(); + return LocInfo.getTemplateKwLoc(); } + NestedNameSpecifierLoc getTemplateQualifierLoc() const; + SourceLocation getTemplateNameLoc() const { if (Argument.getKind() != TemplateArgument::Template && Argument.getKind() != TemplateArgument::TemplateExpansion) diff --git a/clang/include/clang/AST/TemplateName.h b/clang/include/clang/AST/TemplateName.h index 63949f898f6a2..37ea401a0045a 100644 --- a/clang/include/clang/AST/TemplateName.h +++ b/clang/include/clang/AST/TemplateName.h @@ -14,7 +14,7 @@ #define LLVM_CLANG_AST_TEMPLATENAME_H #include "clang/AST/DependenceFlags.h" -#include "clang/AST/NestedNameSpecifier.h" +#include "clang/AST/NestedNameSpecifierBase.h" #include "clang/Basic/LLVM.h" #include "clang/Basic/OperatorKinds.h" #include "clang/Basic/UnsignedOrNone.h" @@ -335,10 +335,18 @@ class TemplateName { /// structure, if any. QualifiedTemplateName *getAsQualifiedTemplateName() const; + /// Retrieve the underlying qualified template name, + /// looking through underlying nodes. + QualifiedTemplateName *getAsAdjustedQualifiedTemplateName() const; + /// Retrieve the underlying dependent template name /// structure, if any. DependentTemplateName *getAsDependentTemplateName() const; + // Retrieve the qualifier stored in either a underlying DependentTemplateName + // or QualifiedTemplateName. + NestedNameSpecifier getQualifier() const; + /// Retrieve the using shadow declaration through which the underlying /// template declaration is introduced, if any. UsingShadowDecl *getAsUsingShadowDecl() const; @@ -503,7 +511,7 @@ class QualifiedTemplateName : public llvm::FoldingSetNode { /// "template" keyword is always redundant in this case (otherwise, /// the template name would be a dependent name and we would express /// this name with DependentTemplateName). - llvm::PointerIntPair Qualifier; + llvm::PointerIntPair Qualifier; /// The underlying template name, it is either /// 1) a Template -- a template declaration that this qualified name refers @@ -512,7 +520,7 @@ class QualifiedTemplateName : public llvm::FoldingSetNode { /// using-shadow declaration. TemplateName UnderlyingTemplate; - QualifiedTemplateName(NestedNameSpecifier *NNS, bool TemplateKeyword, + QualifiedTemplateName(NestedNameSpecifier NNS, bool TemplateKeyword, TemplateName Template) : Qualifier(NNS, TemplateKeyword ? 1 : 0), UnderlyingTemplate(Template) { assert(UnderlyingTemplate.getKind() == TemplateName::Template || @@ -521,7 +529,7 @@ class QualifiedTemplateName : public llvm::FoldingSetNode { public: /// Return the nested name specifier that qualifies this name. - NestedNameSpecifier *getQualifier() const { return Qualifier.getPointer(); } + NestedNameSpecifier getQualifier() const { return Qualifier.getPointer(); } /// Whether the template name was prefixed by the "template" /// keyword. @@ -534,9 +542,9 @@ class QualifiedTemplateName : public llvm::FoldingSetNode { Profile(ID, getQualifier(), hasTemplateKeyword(), UnderlyingTemplate); } - static void Profile(llvm::FoldingSetNodeID &ID, NestedNameSpecifier *NNS, + static void Profile(llvm::FoldingSetNodeID &ID, NestedNameSpecifier NNS, bool TemplateKeyword, TemplateName TN) { - ID.AddPointer(NNS); + NNS.Profile(ID); ID.AddBoolean(TemplateKeyword); ID.AddPointer(TN.getAsVoidPointer()); } @@ -585,18 +593,18 @@ class DependentTemplateStorage { /// /// The bit stored in this qualifier describes whether the \c Name field /// was preceeded by a template keyword. - llvm::PointerIntPair Qualifier; + llvm::PointerIntPair Qualifier; /// The dependent template name. IdentifierOrOverloadedOperator Name; public: - DependentTemplateStorage(NestedNameSpecifier *Qualifier, + DependentTemplateStorage(NestedNameSpecifier Qualifier, IdentifierOrOverloadedOperator Name, bool HasTemplateKeyword); /// Return the nested name specifier that qualifies this name. - NestedNameSpecifier *getQualifier() const { return Qualifier.getPointer(); } + NestedNameSpecifier getQualifier() const { return Qualifier.getPointer(); } IdentifierOrOverloadedOperator getName() const { return Name; } @@ -609,10 +617,10 @@ class DependentTemplateStorage { Profile(ID, getQualifier(), getName(), hasTemplateKeyword()); } - static void Profile(llvm::FoldingSetNodeID &ID, NestedNameSpecifier *NNS, + static void Profile(llvm::FoldingSetNodeID &ID, NestedNameSpecifier NNS, IdentifierOrOverloadedOperator Name, bool HasTemplateKeyword) { - ID.AddPointer(NNS); + NNS.Profile(ID); ID.AddBoolean(HasTemplateKeyword); Name.Profile(ID); } diff --git a/clang/include/clang/AST/TextNodeDumper.h b/clang/include/clang/AST/TextNodeDumper.h index 1917a8ac29f05..6d2795111685a 100644 --- a/clang/include/clang/AST/TextNodeDumper.h +++ b/clang/include/clang/AST/TextNodeDumper.h @@ -211,7 +211,7 @@ class TextNodeDumper void dumpAccessSpecifier(AccessSpecifier AS); void dumpCleanupObject(const ExprWithCleanups::CleanupObject &C); void dumpTemplateSpecializationKind(TemplateSpecializationKind TSK); - void dumpNestedNameSpecifier(const NestedNameSpecifier *NNS); + void dumpNestedNameSpecifier(NestedNameSpecifier NNS); void dumpConceptReference(const ConceptReference *R); void dumpTemplateArgument(const TemplateArgument &TA); void dumpBareTemplateName(TemplateName TN); diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h index 21b97102db95a..db0b159d6b0cd 100644 --- a/clang/include/clang/AST/Type.h +++ b/clang/include/clang/AST/Type.h @@ -18,7 +18,7 @@ #define LLVM_CLANG_AST_TYPE_H #include "clang/AST/DependenceFlags.h" -#include "clang/AST/NestedNameSpecifier.h" +#include "clang/AST/NestedNameSpecifierBase.h" #include "clang/AST/TemplateName.h" #include "clang/Basic/AddressSpaces.h" #include "clang/Basic/AttrKinds.h" @@ -133,6 +133,7 @@ struct PrintingPolicy; class RecordDecl; class Stmt; class TagDecl; +class ClassTemplateDecl; class TemplateArgument; class TemplateArgumentListInfo; class TemplateArgumentLoc; @@ -2044,8 +2045,8 @@ class alignas(TypeAlignment) Type : public ExtQualsTypeCommonBase { unsigned InnerRef : 1; }; - class TypeWithKeywordBitfields { - friend class TypeWithKeyword; + class KeywordWrapperBitfields { + template friend class KeywordWrapper; LLVM_PREFERRED_TYPE(TypeBitfields) unsigned : NumTypeBits; @@ -2057,15 +2058,23 @@ class alignas(TypeAlignment) Type : public ExtQualsTypeCommonBase { enum { NumTypeWithKeywordBits = NumTypeBits + 8 }; - class ElaboratedTypeBitfields { - friend class ElaboratedType; + class TagTypeBitfields { + friend class TagType; - LLVM_PREFERRED_TYPE(TypeWithKeywordBitfields) + LLVM_PREFERRED_TYPE(KeywordWrapperBitfields) unsigned : NumTypeWithKeywordBits; - /// Whether the ElaboratedType has a trailing OwnedTagDecl. + /// Whether the TagType has a trailing Qualifier. LLVM_PREFERRED_TYPE(bool) - unsigned HasOwnedTagDecl : 1; + unsigned HasQualifier : 1; + + /// Whether the TagType owns the Tag. + LLVM_PREFERRED_TYPE(bool) + unsigned OwnsTag : 1; + + /// Whether the TagType was created from an injected name. + LLVM_PREFERRED_TYPE(bool) + unsigned IsInjected : 1; }; class VectorTypeBitfields { @@ -2124,22 +2133,37 @@ class alignas(TypeAlignment) Type : public ExtQualsTypeCommonBase { unsigned Kind : 1; }; + class UnresolvedUsingBitfields { + friend class UnresolvedUsingType; + + LLVM_PREFERRED_TYPE(KeywordWrapperBitfields) + unsigned : NumTypeWithKeywordBits; + + /// True if there is a non-null qualifier. + LLVM_PREFERRED_TYPE(bool) + unsigned hasQualifier : 1; + }; + class UsingBitfields { friend class UsingType; - LLVM_PREFERRED_TYPE(TypeBitfields) - unsigned : NumTypeBits; + LLVM_PREFERRED_TYPE(KeywordWrapperBitfields) + unsigned : NumTypeWithKeywordBits; - /// True if the underlying type is different from the declared one. + /// True if there is a non-null qualifier. LLVM_PREFERRED_TYPE(bool) - unsigned hasTypeDifferentFromDecl : 1; + unsigned hasQualifier : 1; }; class TypedefBitfields { friend class TypedefType; - LLVM_PREFERRED_TYPE(TypeBitfields) - unsigned : NumTypeBits; + LLVM_PREFERRED_TYPE(KeywordWrapperBitfields) + unsigned : NumTypeWithKeywordBits; + + /// True if there is a non-null qualifier. + LLVM_PREFERRED_TYPE(bool) + unsigned hasQualifier : 1; /// True if the underlying type is different from the declared one. LLVM_PREFERRED_TYPE(bool) @@ -2205,8 +2229,8 @@ class alignas(TypeAlignment) Type : public ExtQualsTypeCommonBase { class TemplateSpecializationTypeBitfields { friend class TemplateSpecializationType; - LLVM_PREFERRED_TYPE(TypeBitfields) - unsigned : NumTypeBits; + LLVM_PREFERRED_TYPE(KeywordWrapperBitfields) + unsigned : NumTypeWithKeywordBits; /// Whether this template specialization type is a substituted type alias. LLVM_PREFERRED_TYPE(bool) @@ -2225,7 +2249,7 @@ class alignas(TypeAlignment) Type : public ExtQualsTypeCommonBase { class DependentTemplateSpecializationTypeBitfields { friend class DependentTemplateSpecializationType; - LLVM_PREFERRED_TYPE(TypeWithKeywordBitfields) + LLVM_PREFERRED_TYPE(KeywordWrapperBitfields) unsigned : NumTypeWithKeywordBits; /// The number of template arguments named in this class template @@ -2281,13 +2305,14 @@ class alignas(TypeAlignment) Type : public ExtQualsTypeCommonBase { AutoTypeBitfields AutoTypeBits; TypeOfBitfields TypeOfBits; TypedefBitfields TypedefBits; + UnresolvedUsingBitfields UnresolvedUsingBits; UsingBitfields UsingBits; BuiltinTypeBitfields BuiltinTypeBits; FunctionTypeBitfields FunctionTypeBits; ObjCObjectTypeBitfields ObjCObjectTypeBits; ReferenceTypeBitfields ReferenceTypeBits; - TypeWithKeywordBitfields TypeWithKeywordBits; - ElaboratedTypeBitfields ElaboratedTypeBits; + KeywordWrapperBitfields KeywordWrapperBits; + TagTypeBitfields TagTypeBits; VectorTypeBitfields VectorTypeBits; TemplateTypeParmTypeBitfields TemplateTypeParmTypeBits; SubstTemplateTypeParmTypeBitfields SubstTemplateTypeParmTypeBits; @@ -2906,6 +2931,11 @@ class alignas(TypeAlignment) Type : public ExtQualsTypeCommonBase { /// qualifiers from the outermost type. const ArrayType *castAsArrayTypeUnsafe() const; + /// If this type represents a qualified-id, this returns its nested name + /// specifier. For example, for the qualified-id "foo::bar::baz", this returns + /// "foo::bar". Returns null if this type represents an unqualified-id. + NestedNameSpecifier getPrefix() const; + /// Determine whether this type had the specified attribute applied to it /// (looking through top-level type sugar). bool hasAttr(attr::Kind AK) const; @@ -3583,12 +3613,12 @@ class MemberPointerType : public Type, public llvm::FoldingSetNode { /// The class of which the pointee is a member. Must ultimately be a /// CXXRecordType, but could be a typedef or a template parameter too. - NestedNameSpecifier *Qualifier; + NestedNameSpecifier Qualifier; - MemberPointerType(QualType Pointee, NestedNameSpecifier *Qualifier, + MemberPointerType(QualType Pointee, NestedNameSpecifier Qualifier, QualType CanonicalPtr) : Type(MemberPointer, CanonicalPtr, - (toTypeDependence(Qualifier->getDependence()) & + (toTypeDependence(Qualifier.getDependence()) & ~TypeDependence::VariablyModified) | Pointee->getDependence()), PointeeType(Pointee), Qualifier(Qualifier) {} @@ -3608,7 +3638,7 @@ class MemberPointerType : public Type, public llvm::FoldingSetNode { return !PointeeType->isFunctionProtoType(); } - NestedNameSpecifier *getQualifier() const { return Qualifier; } + NestedNameSpecifier getQualifier() const { return Qualifier; } /// Note: this can trigger extra deserialization when external AST sources are /// used. Prefer `getCXXRecordDecl()` unless you really need the most recent /// decl. @@ -3627,7 +3657,7 @@ class MemberPointerType : public Type, public llvm::FoldingSetNode { } static void Profile(llvm::FoldingSetNodeID &ID, QualType Pointee, - const NestedNameSpecifier *Qualifier, + const NestedNameSpecifier Qualifier, const CXXRecordDecl *Cls); static bool classof(const Type *T) { @@ -5742,84 +5772,254 @@ class FunctionProtoType final bool Canonical); }; +/// The elaboration keyword that precedes a qualified type name or +/// introduces an elaborated-type-specifier. +enum class ElaboratedTypeKeyword { + /// The "struct" keyword introduces the elaborated-type-specifier. + Struct, + + /// The "__interface" keyword introduces the elaborated-type-specifier. + Interface, + + /// The "union" keyword introduces the elaborated-type-specifier. + Union, + + /// The "class" keyword introduces the elaborated-type-specifier. + Class, + + /// The "enum" keyword introduces the elaborated-type-specifier. + Enum, + + /// The "typename" keyword precedes the qualified type name, e.g., + /// \c typename T::type. + Typename, + + /// No keyword precedes the qualified type name. + None +}; + +/// The kind of a tag type. +enum class TagTypeKind { + /// The "struct" keyword. + Struct, + + /// The "__interface" keyword. + Interface, + + /// The "union" keyword. + Union, + + /// The "class" keyword. + Class, + + /// The "enum" keyword. + Enum +}; + +/// Provides a few static helpers for converting and printing +/// elaborated type keyword and tag type kind enumerations. +struct KeywordHelpers { + /// Converts a type specifier (DeclSpec::TST) into an elaborated type keyword. + static ElaboratedTypeKeyword getKeywordForTypeSpec(unsigned TypeSpec); + + /// Converts a type specifier (DeclSpec::TST) into a tag type kind. + /// It is an error to provide a type specifier which *isn't* a tag kind here. + static TagTypeKind getTagTypeKindForTypeSpec(unsigned TypeSpec); + + /// Converts a TagTypeKind into an elaborated type keyword. + static ElaboratedTypeKeyword getKeywordForTagTypeKind(TagTypeKind Tag); + + /// Converts an elaborated type keyword into a TagTypeKind. + /// It is an error to provide an elaborated type keyword + /// which *isn't* a tag kind here. + static TagTypeKind getTagTypeKindForKeyword(ElaboratedTypeKeyword Keyword); + + static bool KeywordIsTagTypeKind(ElaboratedTypeKeyword Keyword); + + static StringRef getKeywordName(ElaboratedTypeKeyword Keyword); + + static StringRef getTagTypeKindName(TagTypeKind Kind) { + return getKeywordName(getKeywordForTagTypeKind(Kind)); + } +}; + +template class KeywordWrapper : public T, public KeywordHelpers { +protected: + template + KeywordWrapper(ElaboratedTypeKeyword Keyword, As &&...as) + : T(std::forward(as)...) { + this->KeywordWrapperBits.Keyword = llvm::to_underlying(Keyword); + } + +public: + ElaboratedTypeKeyword getKeyword() const { + return static_cast(this->KeywordWrapperBits.Keyword); + } + + class CannotCastToThisType {}; + static CannotCastToThisType classof(const T *); +}; + +/// A helper class for Type nodes having an ElaboratedTypeKeyword. +/// The keyword in stored in the free bits of the base class. +class TypeWithKeyword : public KeywordWrapper { +protected: + TypeWithKeyword(ElaboratedTypeKeyword Keyword, TypeClass tc, + QualType Canonical, TypeDependence Dependence) + : KeywordWrapper(Keyword, tc, Canonical, Dependence) {} +}; + +template struct FoldingSetPlaceholder : llvm::FoldingSetNode { + void Profile(llvm::FoldingSetNodeID &ID) { getType()->Profile(ID); } + + inline const T *getType() const { + constexpr unsigned long Offset = + llvm::alignTo(sizeof(T), alignof(FoldingSetPlaceholder)); + const auto *Addr = reinterpret_cast( + reinterpret_cast(this) - Offset); + assert(llvm::isAddrAligned(llvm::Align(alignof(T)), Addr)); + return Addr; + } +}; + /// Represents the dependent type named by a dependently-scoped /// typename using declaration, e.g. /// using typename Base::foo; /// /// Template instantiation turns these into the underlying type. -class UnresolvedUsingType : public Type { +class UnresolvedUsingType final + : public TypeWithKeyword, + private llvm::TrailingObjects, + NestedNameSpecifier> { friend class ASTContext; // ASTContext creates these. + friend TrailingObjects; UnresolvedUsingTypenameDecl *Decl; - UnresolvedUsingType(const UnresolvedUsingTypenameDecl *D) - : Type(UnresolvedUsing, QualType(), - TypeDependence::DependentInstantiation), - Decl(const_cast(D)) {} + unsigned numTrailingObjects( + OverloadToken>) const { + assert(UnresolvedUsingBits.hasQualifier || + getKeyword() != ElaboratedTypeKeyword::None); + return 1; + } + + FoldingSetPlaceholder *getFoldingSetPlaceholder() { + assert(numTrailingObjects( + OverloadToken>{}) == + 1); + return getTrailingObjects>(); + } + + UnresolvedUsingType(ElaboratedTypeKeyword Keyword, + NestedNameSpecifier Qualifier, + const UnresolvedUsingTypenameDecl *D, + const Type *CanonicalType); public: + NestedNameSpecifier getQualifier() const { + return UnresolvedUsingBits.hasQualifier + ? *getTrailingObjects() + : std::nullopt; + } + UnresolvedUsingTypenameDecl *getDecl() const { return Decl; } bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } - static bool classof(const Type *T) { - return T->getTypeClass() == UnresolvedUsing; + static void Profile(llvm::FoldingSetNodeID &ID, ElaboratedTypeKeyword Keyword, + NestedNameSpecifier Qualifier, + const UnresolvedUsingTypenameDecl *D) { + static_assert(llvm::to_underlying(ElaboratedTypeKeyword::None) <= 7); + ID.AddInteger(uintptr_t(D) | llvm::to_underlying(Keyword)); + if (Qualifier) + Qualifier.Profile(ID); } - void Profile(llvm::FoldingSetNodeID &ID) { - return Profile(ID, Decl); + void Profile(llvm::FoldingSetNodeID &ID) const { + Profile(ID, getKeyword(), getQualifier(), getDecl()); } - static void Profile(llvm::FoldingSetNodeID &ID, - UnresolvedUsingTypenameDecl *D) { - ID.AddPointer(D); + static bool classof(const Type *T) { + return T->getTypeClass() == UnresolvedUsing; } }; -class UsingType final : public Type, +class UsingType final : public TypeWithKeyword, public llvm::FoldingSetNode, - private llvm::TrailingObjects { - UsingShadowDecl *Found; + llvm::TrailingObjects { + UsingShadowDecl *D; + QualType UnderlyingType; + friend class ASTContext; // ASTContext creates these. friend TrailingObjects; - UsingType(const UsingShadowDecl *Found, QualType Underlying, QualType Canon); + UsingType(ElaboratedTypeKeyword Keyword, NestedNameSpecifier Qualifier, + const UsingShadowDecl *D, QualType UnderlyingType); public: - UsingShadowDecl *getFoundDecl() const { return Found; } - QualType getUnderlyingType() const; - - bool isSugared() const { return true; } + NestedNameSpecifier getQualifier() const { + return UsingBits.hasQualifier ? *getTrailingObjects() : std::nullopt; + } - // This always has the 'same' type as declared, but not necessarily identical. - QualType desugar() const { return getUnderlyingType(); } + UsingShadowDecl *getDecl() const { return D; } - // Internal helper, for debugging purposes. - bool typeMatchesDecl() const { return !UsingBits.hasTypeDifferentFromDecl; } + QualType desugar() const { return UnderlyingType; } + bool isSugared() const { return true; } - void Profile(llvm::FoldingSetNodeID &ID) { - Profile(ID, Found, getUnderlyingType()); + static void Profile(llvm::FoldingSetNodeID &ID, ElaboratedTypeKeyword Keyword, + NestedNameSpecifier Qualifier, const UsingShadowDecl *D, + QualType UnderlyingType) { + static_assert(llvm::to_underlying(ElaboratedTypeKeyword::None) <= 7); + ID.AddInteger(uintptr_t(D) | llvm::to_underlying(Keyword)); + UnderlyingType.Profile(ID); + if (Qualifier) + Qualifier.Profile(ID); } - static void Profile(llvm::FoldingSetNodeID &ID, const UsingShadowDecl *Found, - QualType Underlying) { - ID.AddPointer(Found); - Underlying.Profile(ID); + + void Profile(llvm::FoldingSetNodeID &ID) const { + Profile(ID, getKeyword(), getQualifier(), D, desugar()); } static bool classof(const Type *T) { return T->getTypeClass() == Using; } }; -class TypedefType final : public Type, - public llvm::FoldingSetNode, - private llvm::TrailingObjects { +class TypedefType final + : public TypeWithKeyword, + private llvm::TrailingObjects, + NestedNameSpecifier, QualType> { TypedefNameDecl *Decl; friend class ASTContext; // ASTContext creates these. friend TrailingObjects; - TypedefType(TypeClass tc, const TypedefNameDecl *D, QualType UnderlyingType, - bool HasTypeDifferentFromDecl); + unsigned + numTrailingObjects(OverloadToken>) const { + assert(TypedefBits.hasQualifier || TypedefBits.hasTypeDifferentFromDecl || + getKeyword() != ElaboratedTypeKeyword::None); + return 1; + } + + unsigned numTrailingObjects(OverloadToken) const { + return TypedefBits.hasQualifier; + } + + TypedefType(TypeClass TC, ElaboratedTypeKeyword Keyword, + NestedNameSpecifier Qualifier, const TypedefNameDecl *D, + QualType UnderlyingType, bool HasTypeDifferentFromDecl); + + FoldingSetPlaceholder *getFoldingSetPlaceholder() { + assert(numTrailingObjects( + OverloadToken>{}) == 1); + return getTrailingObjects>(); + } public: + NestedNameSpecifier getQualifier() const { + return TypedefBits.hasQualifier ? *getTrailingObjects() + : std::nullopt; + } + TypedefNameDecl *getDecl() const { return Decl; } bool isSugared() const { return true; } @@ -5830,16 +6030,25 @@ class TypedefType final : public Type, // Internal helper, for debugging purposes. bool typeMatchesDecl() const { return !TypedefBits.hasTypeDifferentFromDecl; } - void Profile(llvm::FoldingSetNodeID &ID) { - Profile(ID, Decl, typeMatchesDecl() ? QualType() : desugar()); - } - static void Profile(llvm::FoldingSetNodeID &ID, const TypedefNameDecl *Decl, - QualType Underlying) { - ID.AddPointer(Decl); + static void Profile(llvm::FoldingSetNodeID &ID, ElaboratedTypeKeyword Keyword, + NestedNameSpecifier Qualifier, + const TypedefNameDecl *Decl, QualType Underlying) { + + ID.AddInteger(uintptr_t(Decl) | (Keyword != ElaboratedTypeKeyword::None) | + (!Qualifier << 1)); + if (Keyword != ElaboratedTypeKeyword::None) + ID.AddInteger(llvm::to_underlying(Keyword)); + if (Qualifier) + Qualifier.Profile(ID); if (!Underlying.isNull()) Underlying.Profile(ID); } + void Profile(llvm::FoldingSetNodeID &ID) const { + Profile(ID, getKeyword(), getQualifier(), getDecl(), + typeMatchesDecl() ? QualType() : desugar()); + } + static bool classof(const Type *T) { return T->getTypeClass() == Typedef; } }; @@ -6106,71 +6315,148 @@ class UnaryTransformType : public Type, public llvm::FoldingSetNode { } }; -class TagType : public Type { - friend class ASTReader; - template friend class serialization::AbstractTypeReader; +class TagType : public TypeWithKeyword { + friend class ASTContext; // ASTContext creates these. /// Stores the TagDecl associated with this type. The decl may point to any /// TagDecl that declares the entity. TagDecl *decl; + void *getTrailingPointer() const; + NestedNameSpecifier &getTrailingQualifier() const; + protected: - TagType(TypeClass TC, const TagDecl *D, QualType can); + TagType(TypeClass TC, ElaboratedTypeKeyword Keyword, + NestedNameSpecifier Qualifier, const TagDecl *TD, bool OwnsTag, + bool IsInjected, const Type *CanonicalType); public: - TagDecl *getDecl() const; + TagDecl *getOriginalDecl() const { return decl; } + + NestedNameSpecifier getQualifier() const; + + /// Does the TagType own this declaration of the Tag? + bool isTagOwned() const { return TagTypeBits.OwnsTag; } - /// Determines whether this type is in the process of being defined. - bool isBeingDefined() const; + bool isInjected() const { return TagTypeBits.IsInjected; } + + ClassTemplateDecl *getTemplateDecl() const; + TemplateName getTemplateName(const ASTContext &Ctx) const; + ArrayRef getTemplateArgs(const ASTContext &Ctx) const; + + bool isSugared() const { return false; } + QualType desugar() const { return getCanonicalTypeInternal(); } static bool classof(const Type *T) { - return T->getTypeClass() == Enum || T->getTypeClass() == Record; + return T->getTypeClass() == Enum || T->getTypeClass() == Record || + T->getTypeClass() == InjectedClassName; + } +}; + +struct TagTypeFoldingSetPlaceholder : public llvm::FoldingSetNode { + static constexpr size_t getOffset() { + return alignof(TagType) - + (sizeof(TagTypeFoldingSetPlaceholder) % alignof(TagType)); + } + + static void Profile(llvm::FoldingSetNodeID &ID, ElaboratedTypeKeyword Keyword, + NestedNameSpecifier Qualifier, const TagDecl *Tag, + bool OwnsTag, bool IsInjected) { + ID.AddInteger(uintptr_t(Tag) | OwnsTag | (IsInjected << 1) | + ((Keyword != ElaboratedTypeKeyword::None) << 2)); + if (Keyword != ElaboratedTypeKeyword::None) + ID.AddInteger(llvm::to_underlying(Keyword)); + if (Qualifier) + Qualifier.Profile(ID); + } + + void Profile(llvm::FoldingSetNodeID &ID) const { + const TagType *T = getTagType(); + Profile(ID, T->getKeyword(), T->getQualifier(), T->getOriginalDecl(), + T->isTagOwned(), T->isInjected()); + } + + TagType *getTagType() { + return reinterpret_cast(reinterpret_cast(this + 1) + + getOffset()); + } + const TagType *getTagType() const { + return const_cast(this)->getTagType(); + } + static TagTypeFoldingSetPlaceholder *fromTagType(TagType *T) { + return reinterpret_cast( + reinterpret_cast(T) - getOffset()) - + 1; } }; /// A helper class that allows the use of isa/cast/dyncast /// to detect TagType objects of structs/unions/classes. -class RecordType : public TagType { -protected: - friend class ASTContext; // ASTContext creates these. - - explicit RecordType(const RecordDecl *D) - : TagType(Record, reinterpret_cast(D), QualType()) {} - explicit RecordType(TypeClass TC, RecordDecl *D) - : TagType(TC, reinterpret_cast(D), QualType()) {} +class RecordType final : public TagType { + using TagType::TagType; public: - RecordDecl *getDecl() const { - return reinterpret_cast(TagType::getDecl()); + RecordDecl *getOriginalDecl() const { + return reinterpret_cast(TagType::getOriginalDecl()); } /// Recursively check all fields in the record for const-ness. If any field /// is declared const, return true. Otherwise, return false. bool hasConstFields() const; - bool isSugared() const { return false; } - QualType desugar() const { return QualType(this, 0); } - static bool classof(const Type *T) { return T->getTypeClass() == Record; } }; /// A helper class that allows the use of isa/cast/dyncast /// to detect TagType objects of enums. -class EnumType : public TagType { +class EnumType final : public TagType { + using TagType::TagType; + +public: + EnumDecl *getOriginalDecl() const { + return reinterpret_cast(TagType::getOriginalDecl()); + } + + static bool classof(const Type *T) { return T->getTypeClass() == Enum; } +}; + +/// The injected class name of a C++ class template or class +/// template partial specialization. Used to record that a type was +/// spelled with a bare identifier rather than as a template-id; the +/// equivalent for non-templated classes is just RecordType. +/// +/// Injected class name types are always dependent. Template +/// instantiation turns these into RecordTypes. +/// +/// Injected class name types are always canonical. This works +/// because it is impossible to compare an injected class name type +/// with the corresponding non-injected template type, for the same +/// reason that it is impossible to directly compare template +/// parameters from different dependent contexts: injected class name +/// types can only occur within the scope of a particular templated +/// declaration, and within that scope every template specialization +/// will canonicalize to the injected class name (when appropriate +/// according to the rules of the language). +class InjectedClassNameType final : public TagType { friend class ASTContext; // ASTContext creates these. - explicit EnumType(const EnumDecl *D) - : TagType(Enum, reinterpret_cast(D), QualType()) {} + InjectedClassNameType(ElaboratedTypeKeyword Keyword, + NestedNameSpecifier Qualifier, const TagDecl *TD, + bool IsInjected, CanQualType CanonicalInjectedTST, + const Type *CanonicalType); + + QualType CanonicalInjectedTST; public: - EnumDecl *getDecl() const { - return reinterpret_cast(TagType::getDecl()); - } + CanQualType getCanonicalInjectedTST() const; - bool isSugared() const { return false; } - QualType desugar() const { return QualType(this, 0); } + CXXRecordDecl *getOriginalDecl() const { + return reinterpret_cast(TagType::getOriginalDecl()); + } - static bool classof(const Type *T) { return T->getTypeClass() == Enum; } + static bool classof(const Type *T) { + return T->getTypeClass() == InjectedClassName; + } }; /// An attributed type is a type to which a type attribute has been applied. @@ -6781,34 +7067,38 @@ class AutoType : public DeducedType { }; /// Represents a C++17 deduced template specialization type. -class DeducedTemplateSpecializationType : public DeducedType, +class DeducedTemplateSpecializationType : public KeywordWrapper, public llvm::FoldingSetNode { friend class ASTContext; // ASTContext creates these /// The name of the template whose arguments will be deduced. TemplateName Template; - DeducedTemplateSpecializationType(TemplateName Template, + DeducedTemplateSpecializationType(ElaboratedTypeKeyword Keyword, + TemplateName Template, QualType DeducedAsType, bool IsDeducedAsDependent, QualType Canon) - : DeducedType(DeducedTemplateSpecialization, DeducedAsType, - toTypeDependence(Template.getDependence()) | - (IsDeducedAsDependent - ? TypeDependence::DependentInstantiation - : TypeDependence::None), - Canon), + : KeywordWrapper(Keyword, DeducedTemplateSpecialization, DeducedAsType, + toTypeDependence(Template.getDependence()) | + (IsDeducedAsDependent + ? TypeDependence::DependentInstantiation + : TypeDependence::None), + Canon), Template(Template) {} public: /// Retrieve the name of the template that we are deducing. - TemplateName getTemplateName() const { return Template;} + TemplateName getTemplateName() const { return Template; } void Profile(llvm::FoldingSetNodeID &ID) const { - Profile(ID, getTemplateName(), getDeducedType(), isDependentType()); + Profile(ID, getKeyword(), getTemplateName(), getDeducedType(), + isDependentType()); } - static void Profile(llvm::FoldingSetNodeID &ID, TemplateName Template, - QualType Deduced, bool IsDependent) { + static void Profile(llvm::FoldingSetNodeID &ID, ElaboratedTypeKeyword Keyword, + TemplateName Template, QualType Deduced, + bool IsDependent) { + ID.AddInteger(llvm::to_underlying(Keyword)); Template.Profile(ID); Deduced.Profile(ID); ID.AddBoolean(IsDependent || Template.isDependent()); @@ -6839,7 +7129,8 @@ class DeducedTemplateSpecializationType : public DeducedType, /// TemplateArguments, followed by a QualType representing the /// non-canonical aliased type when the template is a type alias /// template. -class TemplateSpecializationType : public Type, public llvm::FoldingSetNode { +class TemplateSpecializationType : public TypeWithKeyword, + public llvm::FoldingSetNode { friend class ASTContext; // ASTContext creates these /// The name of the template being specialized. This is @@ -6851,8 +7142,8 @@ class TemplateSpecializationType : public Type, public llvm::FoldingSetNode { /// replacement must, recursively, be one of these). TemplateName Template; - TemplateSpecializationType(TemplateName T, bool IsAlias, - ArrayRef Args, + TemplateSpecializationType(ElaboratedTypeKeyword Keyword, TemplateName T, + bool IsAlias, ArrayRef Args, QualType Underlying); public: @@ -6953,241 +7244,6 @@ bool isSubstitutedDefaultArgument(ASTContext &Ctx, TemplateArgument Arg, ArrayRef Args, unsigned Depth); -/// The injected class name of a C++ class template or class -/// template partial specialization. Used to record that a type was -/// spelled with a bare identifier rather than as a template-id; the -/// equivalent for non-templated classes is just RecordType. -/// -/// Injected class name types are always dependent. Template -/// instantiation turns these into RecordTypes. -/// -/// Injected class name types are always canonical. This works -/// because it is impossible to compare an injected class name type -/// with the corresponding non-injected template type, for the same -/// reason that it is impossible to directly compare template -/// parameters from different dependent contexts: injected class name -/// types can only occur within the scope of a particular templated -/// declaration, and within that scope every template specialization -/// will canonicalize to the injected class name (when appropriate -/// according to the rules of the language). -class InjectedClassNameType : public Type { - friend class ASTContext; // ASTContext creates these. - friend class ASTNodeImporter; - friend class ASTReader; // FIXME: ASTContext::getInjectedClassNameType is not - // currently suitable for AST reading, too much - // interdependencies. - template friend class serialization::AbstractTypeReader; - - CXXRecordDecl *Decl; - - /// The template specialization which this type represents. - /// For example, in - /// template class A { ... }; - /// this is A, whereas in - /// template class A > { ... }; - /// this is A >. - /// - /// It is always unqualified, always a template specialization type, - /// and always dependent. - QualType InjectedType; - - InjectedClassNameType(CXXRecordDecl *D, QualType TST) - : Type(InjectedClassName, QualType(), - TypeDependence::DependentInstantiation), - Decl(D), InjectedType(TST) { - assert(isa(TST)); - assert(!TST.hasQualifiers()); - assert(TST->isDependentType()); - } - -public: - QualType getInjectedSpecializationType() const { return InjectedType; } - - const TemplateSpecializationType *getInjectedTST() const { - return cast(InjectedType.getTypePtr()); - } - - TemplateName getTemplateName() const { - return getInjectedTST()->getTemplateName(); - } - - CXXRecordDecl *getDecl() const; - - bool isSugared() const { return false; } - QualType desugar() const { return QualType(this, 0); } - - static bool classof(const Type *T) { - return T->getTypeClass() == InjectedClassName; - } -}; - -/// The elaboration keyword that precedes a qualified type name or -/// introduces an elaborated-type-specifier. -enum class ElaboratedTypeKeyword { - /// The "struct" keyword introduces the elaborated-type-specifier. - Struct, - - /// The "__interface" keyword introduces the elaborated-type-specifier. - Interface, - - /// The "union" keyword introduces the elaborated-type-specifier. - Union, - - /// The "class" keyword introduces the elaborated-type-specifier. - Class, - - /// The "enum" keyword introduces the elaborated-type-specifier. - Enum, - - /// The "typename" keyword precedes the qualified type name, e.g., - /// \c typename T::type. - Typename, - - /// No keyword precedes the qualified type name. - None -}; - -/// The kind of a tag type. -enum class TagTypeKind { - /// The "struct" keyword. - Struct, - - /// The "__interface" keyword. - Interface, - - /// The "union" keyword. - Union, - - /// The "class" keyword. - Class, - - /// The "enum" keyword. - Enum -}; - -/// A helper class for Type nodes having an ElaboratedTypeKeyword. -/// The keyword in stored in the free bits of the base class. -/// Also provides a few static helpers for converting and printing -/// elaborated type keyword and tag type kind enumerations. -class TypeWithKeyword : public Type { -protected: - TypeWithKeyword(ElaboratedTypeKeyword Keyword, TypeClass tc, - QualType Canonical, TypeDependence Dependence) - : Type(tc, Canonical, Dependence) { - TypeWithKeywordBits.Keyword = llvm::to_underlying(Keyword); - } - -public: - ElaboratedTypeKeyword getKeyword() const { - return static_cast(TypeWithKeywordBits.Keyword); - } - - /// Converts a type specifier (DeclSpec::TST) into an elaborated type keyword. - static ElaboratedTypeKeyword getKeywordForTypeSpec(unsigned TypeSpec); - - /// Converts a type specifier (DeclSpec::TST) into a tag type kind. - /// It is an error to provide a type specifier which *isn't* a tag kind here. - static TagTypeKind getTagTypeKindForTypeSpec(unsigned TypeSpec); - - /// Converts a TagTypeKind into an elaborated type keyword. - static ElaboratedTypeKeyword getKeywordForTagTypeKind(TagTypeKind Tag); - - /// Converts an elaborated type keyword into a TagTypeKind. - /// It is an error to provide an elaborated type keyword - /// which *isn't* a tag kind here. - static TagTypeKind getTagTypeKindForKeyword(ElaboratedTypeKeyword Keyword); - - static bool KeywordIsTagTypeKind(ElaboratedTypeKeyword Keyword); - - static StringRef getKeywordName(ElaboratedTypeKeyword Keyword); - - static StringRef getTagTypeKindName(TagTypeKind Kind) { - return getKeywordName(getKeywordForTagTypeKind(Kind)); - } - - class CannotCastToThisType {}; - static CannotCastToThisType classof(const Type *); -}; - -/// Represents a type that was referred to using an elaborated type -/// keyword, e.g., struct S, or via a qualified name, e.g., N::M::type, -/// or both. -/// -/// This type is used to keep track of a type name as written in the -/// source code, including tag keywords and any nested-name-specifiers. -/// The type itself is always "sugar", used to express what was written -/// in the source code but containing no additional semantic information. -class ElaboratedType final - : public TypeWithKeyword, - public llvm::FoldingSetNode, - private llvm::TrailingObjects { - friend class ASTContext; // ASTContext creates these - friend TrailingObjects; - - /// The nested name specifier containing the qualifier. - NestedNameSpecifier *NNS; - - /// The type that this qualified name refers to. - QualType NamedType; - - /// The (re)declaration of this tag type owned by this occurrence is stored - /// as a trailing object if there is one. Use getOwnedTagDecl to obtain - /// it, or obtain a null pointer if there is none. - - ElaboratedType(ElaboratedTypeKeyword Keyword, NestedNameSpecifier *NNS, - QualType NamedType, QualType CanonType, TagDecl *OwnedTagDecl) - : TypeWithKeyword(Keyword, Elaborated, CanonType, - // Any semantic dependence on the qualifier will have - // been incorporated into NamedType. We still need to - // track syntactic (instantiation / error / pack) - // dependence on the qualifier. - NamedType->getDependence() | - (NNS ? toSyntacticDependence( - toTypeDependence(NNS->getDependence())) - : TypeDependence::None)), - NNS(NNS), NamedType(NamedType) { - ElaboratedTypeBits.HasOwnedTagDecl = false; - if (OwnedTagDecl) { - ElaboratedTypeBits.HasOwnedTagDecl = true; - *getTrailingObjects() = OwnedTagDecl; - } - } - -public: - /// Retrieve the qualification on this type. - NestedNameSpecifier *getQualifier() const { return NNS; } - - /// Retrieve the type named by the qualified-id. - QualType getNamedType() const { return NamedType; } - - /// Remove a single level of sugar. - QualType desugar() const { return getNamedType(); } - - /// Returns whether this type directly provides sugar. - bool isSugared() const { return true; } - - /// Return the (re)declaration of this type owned by this occurrence of this - /// type, or nullptr if there is none. - TagDecl *getOwnedTagDecl() const { - return ElaboratedTypeBits.HasOwnedTagDecl ? *getTrailingObjects() : nullptr; - } - - void Profile(llvm::FoldingSetNodeID &ID) { - Profile(ID, getKeyword(), NNS, NamedType, getOwnedTagDecl()); - } - - static void Profile(llvm::FoldingSetNodeID &ID, ElaboratedTypeKeyword Keyword, - NestedNameSpecifier *NNS, QualType NamedType, - TagDecl *OwnedTagDecl) { - ID.AddInteger(llvm::to_underlying(Keyword)); - ID.AddPointer(NNS); - NamedType.Profile(ID); - ID.AddPointer(OwnedTagDecl); - } - - static bool classof(const Type *T) { return T->getTypeClass() == Elaborated; } -}; - /// Represents a qualified type name for which the type name is /// dependent. /// @@ -7204,24 +7260,24 @@ class DependentNameType : public TypeWithKeyword, public llvm::FoldingSetNode { friend class ASTContext; // ASTContext creates these /// The nested name specifier containing the qualifier. - NestedNameSpecifier *NNS; + NestedNameSpecifier NNS; /// The type that this typename specifier refers to. const IdentifierInfo *Name; - DependentNameType(ElaboratedTypeKeyword Keyword, NestedNameSpecifier *NNS, + DependentNameType(ElaboratedTypeKeyword Keyword, NestedNameSpecifier NNS, const IdentifierInfo *Name, QualType CanonType) : TypeWithKeyword(Keyword, DependentName, CanonType, TypeDependence::DependentInstantiation | - toTypeDependence(NNS->getDependence())), + (NNS ? toTypeDependence(NNS.getDependence()) + : TypeDependence::Dependent)), NNS(NNS), Name(Name) { - assert(NNS); assert(Name); } public: /// Retrieve the qualification on this type. - NestedNameSpecifier *getQualifier() const { return NNS; } + NestedNameSpecifier getQualifier() const { return NNS; } /// Retrieve the identifier that terminates this type name. /// For example, "type" in "typename T::type". @@ -7237,9 +7293,9 @@ class DependentNameType : public TypeWithKeyword, public llvm::FoldingSetNode { } static void Profile(llvm::FoldingSetNodeID &ID, ElaboratedTypeKeyword Keyword, - NestedNameSpecifier *NNS, const IdentifierInfo *Name) { + NestedNameSpecifier NNS, const IdentifierInfo *Name) { ID.AddInteger(llvm::to_underlying(Keyword)); - ID.AddPointer(NNS); + NNS.Profile(ID); ID.AddPointer(Name); } @@ -8760,8 +8816,8 @@ inline bool Type::isIntegerType() const { if (const EnumType *ET = dyn_cast(CanonicalType)) { // Incomplete enum types are not treated as integer types. // FIXME: In C++, enum types are never integer types. - return IsEnumDeclComplete(ET->getDecl()) && - !IsEnumDeclScoped(ET->getDecl()); + return IsEnumDeclComplete(ET->getOriginalDecl()) && + !IsEnumDeclScoped(ET->getOriginalDecl()); } return isBitIntType(); } @@ -8819,7 +8875,7 @@ inline bool Type::isScalarType() const { if (const EnumType *ET = dyn_cast(CanonicalType)) // Enums are scalar types, but only if they are defined. Incomplete enums // are not treated as scalar types. - return IsEnumDeclComplete(ET->getDecl()); + return IsEnumDeclComplete(ET->getOriginalDecl()); return isa(CanonicalType) || isa(CanonicalType) || isa(CanonicalType) || @@ -8835,7 +8891,7 @@ inline bool Type::isIntegralOrEnumerationType() const { // Check for a complete enum type; incomplete enum types are not properly an // enumeration type in the sense required here. if (const auto *ET = dyn_cast(CanonicalType)) - return IsEnumDeclComplete(ET->getDecl()); + return IsEnumDeclComplete(ET->getOriginalDecl()); return isBitIntType(); } @@ -8971,8 +9027,6 @@ template const T *Type::getAsAdjusted() const { Ty = A->getWrappedType().getTypePtr(); else if (const auto *A = dyn_cast(Ty)) Ty = A->getWrappedType().getTypePtr(); - else if (const auto *E = dyn_cast(Ty)) - Ty = E->desugar().getTypePtr(); else if (const auto *P = dyn_cast(Ty)) Ty = P->desugar().getTypePtr(); else if (const auto *A = dyn_cast(Ty)) diff --git a/clang/include/clang/AST/TypeLoc.h b/clang/include/clang/AST/TypeLoc.h index cf06e27758996..478a7670f7abd 100644 --- a/clang/include/clang/AST/TypeLoc.h +++ b/clang/include/clang/AST/TypeLoc.h @@ -16,7 +16,7 @@ #include "clang/AST/ASTConcept.h" #include "clang/AST/DeclarationName.h" -#include "clang/AST/NestedNameSpecifier.h" +#include "clang/AST/NestedNameSpecifierBase.h" #include "clang/AST/TemplateBase.h" #include "clang/AST/Type.h" #include "clang/Basic/LLVM.h" @@ -193,6 +193,21 @@ class TypeLoc { /// Get the SourceLocation of the template keyword (if any). SourceLocation getTemplateKeywordLoc() const; + /// If this type represents a qualified-id, this returns it's nested name + /// specifier. For example, for the qualified-id "foo::bar::baz", this returns + /// "foo::bar". Returns null if this type represents an unqualified-id. + NestedNameSpecifierLoc getPrefix() const; + + /// This returns the position of the type after any elaboration, such as the + /// 'struct' keyword, and name qualifiers. This will the 'template' keyword if + /// present, or the name location otherwise. + SourceLocation getNonPrefixBeginLoc() const; + + /// This returns the position of the type after any elaboration, such as the + /// 'struct' keyword. This may be the position of the name qualifiers, + /// 'template' keyword, or the name location otherwise. + SourceLocation getNonElaboratedBeginLoc() const; + /// Initializes this to state that every location in this /// type is the given location. /// @@ -679,62 +694,164 @@ class BuiltinTypeLoc : public ConcreteTypeLoc { -public: - QualType getUnderlyingType() const { - return getTypePtr()->getUnderlyingType(); +struct ElaboratedNameLocInfo { + SourceLocation NameLoc; + SourceLocation ElaboratedKeywordLoc; + + ElaboratedNameLocInfo() = default; + ElaboratedNameLocInfo(SourceLocation ElaboratedKeywordLoc, + NestedNameSpecifierLoc QualifierLoc, + SourceLocation NameLoc) + : NameLoc(NameLoc), ElaboratedKeywordLoc(ElaboratedKeywordLoc), + QualifierData(QualifierLoc.getOpaqueData()) {} + ElaboratedNameLocInfo(ASTContext &Context, ElaboratedTypeKeyword Keyword, + NestedNameSpecifier Qualifier, SourceLocation Loc) + : NameLoc(Loc), + ElaboratedKeywordLoc( + Keyword != ElaboratedTypeKeyword::None ? Loc : SourceLocation()), + QualifierData(getTrivialQualifierData(Context, Qualifier, Loc)) {} + + NestedNameSpecifierLoc getQualifierLoc(NestedNameSpecifier Qualifier) const { + assert(!Qualifier == !QualifierData); + return NestedNameSpecifierLoc(Qualifier, QualifierData); + } + + SourceRange getLocalSourceRange(NestedNameSpecifier Qualifier) const { + SourceLocation BeginLoc = ElaboratedKeywordLoc; + if (NestedNameSpecifierLoc QualifierLoc = getQualifierLoc(Qualifier); + BeginLoc.isInvalid() && Qualifier) + BeginLoc = QualifierLoc.getBeginLoc(); + if (BeginLoc.isInvalid()) + BeginLoc = NameLoc; + return SourceRange(BeginLoc, NameLoc); } - UsingShadowDecl *getFoundDecl() const { return getTypePtr()->getFoundDecl(); } -}; -/// Wrapper for source info for typedefs. -class TypedefTypeLoc : public InheritingConcreteTypeLoc { -public: - TypedefNameDecl *getTypedefNameDecl() const { - return getTypePtr()->getDecl(); +private: + void *QualifierData; + + static void *getTrivialQualifierData(ASTContext &Context, + NestedNameSpecifier Qualifier, + SourceLocation Loc) { + if (!Qualifier) + return nullptr; + NestedNameSpecifierLocBuilder Builder; + Builder.MakeTrivial(Context, Qualifier, Loc); + return Builder.getWithLocInContext(Context).getOpaqueData(); } }; -/// Wrapper for source info for injected class names of class -/// templates. -class InjectedClassNameTypeLoc : - public InheritingConcreteTypeLoc { +template +class ElaboratedNameTypeLoc + : public ConcreteTypeLoc { public: - CXXRecordDecl *getDecl() const { - return getTypePtr()->getDecl(); + auto *getDecl() const { return this->getTypePtr()->getDecl(); } + + void set(SourceLocation ElaboratedKeywordLoc, + NestedNameSpecifierLoc QualifierLoc, SourceLocation NameLoc) { + assert(QualifierLoc.getNestedNameSpecifier() == + this->getTypePtr()->getQualifier()); + *this->getLocalData() = + ElaboratedNameLocInfo(ElaboratedKeywordLoc, QualifierLoc, NameLoc); + } + + SourceLocation getElaboratedKeywordLoc() const { + return this->getLocalData()->ElaboratedKeywordLoc; + } + + NestedNameSpecifierLoc getQualifierLoc() const { + return this->getLocalData()->getQualifierLoc( + this->getTypePtr()->getQualifier()); + } + + SourceLocation getNameLoc() const { return this->getLocalData()->NameLoc; } + + SourceRange getLocalSourceRange() const { + return this->getLocalData()->getLocalSourceRange( + this->getTypePtr()->getQualifier()); + } + + void initializeLocal(ASTContext &Context, SourceLocation Loc) { + const auto *Ptr = this->getTypePtr(); + *this->getLocalData() = ElaboratedNameLocInfo(Context, Ptr->getKeyword(), + Ptr->getQualifier(), Loc); } }; +/// Wrapper for source info for typedefs. +class TypedefTypeLoc + : public ElaboratedNameTypeLoc {}; + /// Wrapper for source info for unresolved typename using decls. -class UnresolvedUsingTypeLoc : - public InheritingConcreteTypeLoc { -public: - UnresolvedUsingTypenameDecl *getDecl() const { - return getTypePtr()->getDecl(); - } +class UnresolvedUsingTypeLoc + : public ElaboratedNameTypeLoc {}; + +/// Wrapper for source info for types used via transparent aliases. +class UsingTypeLoc : public ElaboratedNameTypeLoc {}; + +struct TagTypeLocInfo { + SourceLocation NameLoc; + SourceLocation ElaboratedKWLoc; + void *QualifierData; }; -/// Wrapper for source info for tag types. Note that this only -/// records source info for the name itself; a type written 'struct foo' -/// should be represented as an ElaboratedTypeLoc. We currently -/// only do that when C++ is enabled because of the expense of -/// creating an ElaboratedType node for so many type references in C. -class TagTypeLoc : public InheritingConcreteTypeLoc { +class TagTypeLoc : public ConcreteTypeLoc { public: - TagDecl *getDecl() const { return getTypePtr()->getDecl(); } + TagDecl *getOriginalDecl() const { return getTypePtr()->getOriginalDecl(); } /// True if the tag was defined in this type specifier. bool isDefinition() const; + + SourceLocation getElaboratedKeywordLoc() const { + return getLocalData()->ElaboratedKWLoc; + } + + void setElaboratedKeywordLoc(SourceLocation Loc) { + getLocalData()->ElaboratedKWLoc = Loc; + } + + NestedNameSpecifierLoc getQualifierLoc() const { + NestedNameSpecifier Qualifier = getTypePtr()->getQualifier(); + void *QualifierData = getLocalData()->QualifierData; + assert(!Qualifier == !QualifierData); + return NestedNameSpecifierLoc(Qualifier, QualifierData); + } + + void setQualifierLoc(NestedNameSpecifierLoc QualifierLoc) { + assert(QualifierLoc.getNestedNameSpecifier() == + getTypePtr()->getQualifier()); + getLocalData()->QualifierData = QualifierLoc.getOpaqueData(); + } + + SourceLocation getNameLoc() const { return getLocalData()->NameLoc; } + + void setNameLoc(SourceLocation Loc) { getLocalData()->NameLoc = Loc; } + + SourceRange getLocalSourceRange() const { + SourceLocation BeginLoc = getElaboratedKeywordLoc(); + if (NestedNameSpecifierLoc Qualifier = getQualifierLoc(); + BeginLoc.isInvalid() && Qualifier) + BeginLoc = Qualifier.getBeginLoc(); + if (BeginLoc.isInvalid()) + BeginLoc = getNameLoc(); + return SourceRange(BeginLoc, getNameLoc()); + } + + void initializeLocal(ASTContext &Context, SourceLocation Loc) { + setElaboratedKeywordLoc(getTypePtr()->getKeyword() != + ElaboratedTypeKeyword::None + ? Loc + : SourceLocation()); + if (NestedNameSpecifier Qualifier = getTypePtr()->getQualifier()) { + NestedNameSpecifierLocBuilder Builder; + Builder.MakeTrivial(Context, Qualifier, Loc); + setQualifierLoc(Builder.getWithLocInContext(Context)); + } else { + getLocalData()->QualifierData = nullptr; + } + setNameLoc(Loc); + } }; /// Wrapper for source info for record types. @@ -742,7 +859,9 @@ class RecordTypeLoc : public InheritingConcreteTypeLoc { public: - RecordDecl *getDecl() const { return getTypePtr()->getDecl(); } + RecordDecl *getOriginalDecl() const { + return getTypePtr()->getOriginalDecl(); + } }; /// Wrapper for source info for enum types. @@ -750,7 +869,18 @@ class EnumTypeLoc : public InheritingConcreteTypeLoc { public: - EnumDecl *getDecl() const { return getTypePtr()->getDecl(); } + EnumDecl *getOriginalDecl() const { return getTypePtr()->getOriginalDecl(); } +}; + +/// Wrapper for source info for injected class names of class +/// templates. +class InjectedClassNameTypeLoc + : public InheritingConcreteTypeLoc { +public: + CXXRecordDecl *getOriginalDecl() const { + return getTypePtr()->getOriginalDecl(); + } }; /// Wrapper for template type parameters. @@ -1405,7 +1535,7 @@ class MemberPointerTypeLoc : public PointerLikeTypeLocgetQualifier()) { + if (NestedNameSpecifier Qualifier = getTypePtr()->getQualifier()) { NestedNameSpecifierLocBuilder Builder; Builder.MakeTrivial(Context, Qualifier, Loc); setQualifierLoc(Builder.getWithLocInContext(Context)); @@ -1701,9 +1831,11 @@ struct TemplateNameLocInfo { }; struct TemplateSpecializationLocInfo : TemplateNameLocInfo { + SourceRange SR; + SourceLocation ElaboratedKWLoc; SourceLocation TemplateKWLoc; SourceLocation LAngleLoc; - SourceLocation RAngleLoc; + void *QualifierData; }; class TemplateSpecializationTypeLoc : @@ -1712,54 +1844,53 @@ class TemplateSpecializationTypeLoc : TemplateSpecializationType, TemplateSpecializationLocInfo> { public: - SourceLocation getTemplateKeywordLoc() const { - return getLocalData()->TemplateKWLoc; - } + void set(SourceLocation ElaboratedKeywordLoc, + NestedNameSpecifierLoc QualifierLoc, + SourceLocation TemplateKeywordLoc, SourceLocation NameLoc, + SourceLocation LAngleLoc, SourceLocation RAngleLoc); - void setTemplateKeywordLoc(SourceLocation Loc) { - getLocalData()->TemplateKWLoc = Loc; - } + void set(SourceLocation ElaboratedKeywordLoc, + NestedNameSpecifierLoc QualifierLoc, + SourceLocation TemplateKeywordLoc, SourceLocation NameLoc, + const TemplateArgumentListInfo &TAL); - SourceLocation getLAngleLoc() const { - return getLocalData()->LAngleLoc; + SourceLocation getElaboratedKeywordLoc() const { + return getLocalData()->ElaboratedKWLoc; } - void setLAngleLoc(SourceLocation Loc) { - getLocalData()->LAngleLoc = Loc; - } + NestedNameSpecifierLoc getQualifierLoc() const { + if (!getLocalData()->QualifierData) + return NestedNameSpecifierLoc(); - SourceLocation getRAngleLoc() const { - return getLocalData()->RAngleLoc; + auto *QTN = + getTypePtr()->getTemplateName().getAsAdjustedQualifiedTemplateName(); + assert(QTN && "missing qualification"); + return NestedNameSpecifierLoc(QTN->getQualifier(), + getLocalData()->QualifierData); } - void setRAngleLoc(SourceLocation Loc) { - getLocalData()->RAngleLoc = Loc; + SourceLocation getTemplateKeywordLoc() const { + return getLocalData()->TemplateKWLoc; } + SourceLocation getTemplateNameLoc() const { return getLocalData()->NameLoc; } + + SourceLocation getLAngleLoc() const { return getLocalData()->LAngleLoc; } + unsigned getNumArgs() const { return getTypePtr()->template_arguments().size(); } - void setArgLocInfo(unsigned i, TemplateArgumentLocInfo AI) { - getArgInfos()[i] = AI; - } - - TemplateArgumentLocInfo getArgLocInfo(unsigned i) const { - return getArgInfos()[i]; + MutableArrayRef getArgLocInfos() { + return {getArgInfos(), getNumArgs()}; } TemplateArgumentLoc getArgLoc(unsigned i) const { return TemplateArgumentLoc(getTypePtr()->template_arguments()[i], - getArgLocInfo(i)); - } - - SourceLocation getTemplateNameLoc() const { - return getLocalData()->NameLoc; + getArgInfos()[i]); } - void setTemplateNameLoc(SourceLocation Loc) { - getLocalData()->NameLoc = Loc; - } + SourceLocation getRAngleLoc() const { return getLocalData()->SR.getEnd(); } /// - Copy the location information from the given info. void copy(TemplateSpecializationTypeLoc Loc) { @@ -1773,21 +1904,9 @@ class TemplateSpecializationTypeLoc : memcpy(Data, Loc.Data, size); } - SourceRange getLocalSourceRange() const { - if (getTemplateKeywordLoc().isValid()) - return SourceRange(getTemplateKeywordLoc(), getRAngleLoc()); - else - return SourceRange(getTemplateNameLoc(), getRAngleLoc()); - } + SourceRange getLocalSourceRange() const { return getLocalData()->SR; } - void initializeLocal(ASTContext &Context, SourceLocation Loc) { - setTemplateKeywordLoc(SourceLocation()); - setTemplateNameLoc(Loc); - setLAngleLoc(Loc); - setRAngleLoc(Loc); - initializeArgLocs(Context, getTypePtr()->template_arguments(), - getArgInfos(), Loc); - } + void initializeLocal(ASTContext &Context, SourceLocation Loc); static void initializeArgLocs(ASTContext &Context, ArrayRef Args, @@ -2346,99 +2465,66 @@ class AutoTypeLoc void initializeLocal(ASTContext &Context, SourceLocation Loc); }; -class DeducedTemplateSpecializationTypeLoc - : public InheritingConcreteTypeLoc { -public: - SourceLocation getTemplateNameLoc() const { - return getNameLoc(); - } - - void setTemplateNameLoc(SourceLocation Loc) { - setNameLoc(Loc); - } -}; - -struct ElaboratedLocInfo { +struct DeducedTemplateSpecializationLocInfo : TypeSpecLocInfo { SourceLocation ElaboratedKWLoc; - /// Data associated with the nested-name-specifier location. void *QualifierData; }; -class ElaboratedTypeLoc : public ConcreteTypeLoc { +class DeducedTemplateSpecializationTypeLoc + : public ConcreteTypeLoc { public: - SourceLocation getElaboratedKeywordLoc() const { - return !isEmpty() ? getLocalData()->ElaboratedKWLoc : SourceLocation(); + SourceLocation getElaboratedKWLoc() const { + return getLocalData()->ElaboratedKWLoc; } - void setElaboratedKeywordLoc(SourceLocation Loc) { - if (isEmpty()) { - assert(Loc.isInvalid()); - return; - } + void setElaboratedKWLoc(SourceLocation Loc) { getLocalData()->ElaboratedKWLoc = Loc; } + SourceLocation getTemplateNameLoc() const { return getNameLoc(); } + + void setTemplateNameLoc(SourceLocation Loc) { setNameLoc(Loc); } + NestedNameSpecifierLoc getQualifierLoc() const { - return !isEmpty() ? NestedNameSpecifierLoc(getTypePtr()->getQualifier(), - getLocalData()->QualifierData) - : NestedNameSpecifierLoc(); + void *Data = getLocalData()->QualifierData; + if (!Data) + return NestedNameSpecifierLoc(); + NestedNameSpecifier Qualifier = getTypePtr() + ->getTemplateName() + .getAsAdjustedQualifiedTemplateName() + ->getQualifier(); + return NestedNameSpecifierLoc(Qualifier, Data); } void setQualifierLoc(NestedNameSpecifierLoc QualifierLoc) { - assert(QualifierLoc.getNestedNameSpecifier() == - getTypePtr()->getQualifier() && - "Inconsistent nested-name-specifier pointer"); - if (isEmpty()) { - assert(!QualifierLoc.hasQualifier()); + if (!QualifierLoc) { + // Even if we have a nested-name-specifier in the dependent + // template specialization type, we won't record the nested-name-specifier + // location information when this type-source location information is + // part of a nested-name-specifier. + getLocalData()->QualifierData = nullptr; return; } - getLocalData()->QualifierData = QualifierLoc.getOpaqueData(); - } - - SourceRange getLocalSourceRange() const { - if (getElaboratedKeywordLoc().isValid()) - if (getQualifierLoc()) - return SourceRange(getElaboratedKeywordLoc(), - getQualifierLoc().getEndLoc()); - else - return SourceRange(getElaboratedKeywordLoc()); - else - return getQualifierLoc().getSourceRange(); - } - - void initializeLocal(ASTContext &Context, SourceLocation Loc); - - TypeLoc getNamedTypeLoc() const { return getInnerTypeLoc(); } - - QualType getInnerType() const { return getTypePtr()->getNamedType(); } - bool isEmpty() const { - return getTypePtr()->getKeyword() == ElaboratedTypeKeyword::None && - !getTypePtr()->getQualifier(); - } - - unsigned getLocalDataAlignment() const { - // FIXME: We want to return 1 here in the empty case, but - // there are bugs in how alignment is handled in TypeLocs - // that prevent this from working. - return ConcreteTypeLoc::getLocalDataAlignment(); + assert(QualifierLoc.getNestedNameSpecifier() == + getTypePtr() + ->getTemplateName() + .getAsAdjustedQualifiedTemplateName() + ->getQualifier() && + "Inconsistent nested-name-specifier pointer"); + getLocalData()->QualifierData = QualifierLoc.getOpaqueData(); } +}; - unsigned getLocalDataSize() const { - return !isEmpty() ? ConcreteTypeLoc::getLocalDataSize() : 0; - } +struct ElaboratedLocInfo { + SourceLocation ElaboratedKWLoc; - void copy(ElaboratedTypeLoc Loc) { - unsigned size = getFullDataSize(); - assert(size == Loc.getFullDataSize()); - memcpy(Data, Loc.Data, size); - } + /// Data associated with the nested-name-specifier location. + void *QualifierData; }; // This is exactly the structure of an ElaboratedTypeLoc whose inner @@ -2749,8 +2835,6 @@ inline T TypeLoc::getAsAdjusted() const { Cur = ATL.getWrappedLoc(); else if (auto ATL = Cur.getAs()) Cur = ATL.getWrappedLoc(); - else if (auto ETL = Cur.getAs()) - Cur = ETL.getNamedTypeLoc(); else if (auto ATL = Cur.getAs()) Cur = ATL.getOriginalLoc(); else if (auto MQL = Cur.getAs()) diff --git a/clang/include/clang/AST/TypeProperties.td b/clang/include/clang/AST/TypeProperties.td index a6157649060b1..8fbeeb38c51c9 100644 --- a/clang/include/clang/AST/TypeProperties.td +++ b/clang/include/clang/AST/TypeProperties.td @@ -379,38 +379,59 @@ let Class = AtomicType in { } let Class = UnresolvedUsingType in { - def : Property<"declaration", DeclRef> { - let Read = [{ node->getDecl() }]; + def : Property<"IsCanonical", Bool> { + let Read = [{ node->isCanonicalUnqualified() }]; } - + def : Property<"Keyword", ElaboratedTypeKeyword> { + let Conditional = [{ !IsCanonical }]; + let Read = [{ node->getKeyword() }]; + } + def : Property<"Qualifier", NestedNameSpecifier> { + let Conditional = [{ !IsCanonical }]; + let Read = [{ node->getQualifier() }]; + } + def : Property<"D", DeclRef> { let Read = [{ node->getDecl() }]; } def : Creator<[{ - return ctx.getUnresolvedUsingType(cast(declaration)); + auto *UD = cast(D); + return IsCanonical ? ctx.getCanonicalUnresolvedUsingType(UD) : ctx.getUnresolvedUsingType(*Keyword, *Qualifier, UD); }]>; } let Class = UsingType in { - def : Property<"foundDeclaration", UsingShadowDeclRef> { - let Read = [{ node->getFoundDecl() }]; + def : Property<"Keyword", ElaboratedTypeKeyword> { + let Read = [{ node->getKeyword() }]; } - def : Property<"underlyingType", QualType> { - let Read = [{ node->getUnderlyingType() }]; + def : Property<"Qualifier", NestedNameSpecifier> { + let Read = [{ node->getQualifier() }]; + } + def : Property<"D", UsingShadowDeclRef> { let Read = [{ node->getDecl() }]; } + def : Property<"UnderlyingType", QualType> { + let Read = [{ node->desugar() }]; } - def : Creator<[{ - return ctx.getUsingType(foundDeclaration, underlyingType); + return ctx.getUsingType(Keyword, Qualifier, D, UnderlyingType); }]>; } let Class = TypedefType in { + def : Property<"Keyword", ElaboratedTypeKeyword> { + let Read = [{ node->getKeyword() }]; + } + def : Property<"Qualifier", NestedNameSpecifier> { + let Read = [{ node->getQualifier() }]; + } def : Property<"declaration", DeclRef> { let Read = [{ node->getDecl() }]; } - def : Property<"underlyingType", QualType> { + def : Property<"UnderlyingType", QualType> { let Read = [{ node->desugar() }]; } + def : Property<"TypeMatchesDecl", Bool> { + let Read = [{ node->typeMatchesDecl() }]; + } def : Creator<[{ - return ctx.getTypedefType(cast(declaration), underlyingType); + return ctx.getTypedefType(Keyword, Qualifier, cast(declaration), UnderlyingType, TypeMatchesDecl); }]>; } @@ -520,6 +541,9 @@ let Class = AutoType in { } let Class = DeducedTemplateSpecializationType in { + def : Property<"keyword", ElaboratedTypeKeyword> { + let Read = [{ node->getKeyword() }]; + } def : Property<"templateName", Optional> { let Read = [{ makeOptionalFromNullable(node->getTemplateName()) }]; } @@ -533,97 +557,42 @@ let Class = DeducedTemplateSpecializationType in { } def : Creator<[{ - return ctx.getDeducedTemplateSpecializationType( + return ctx.getDeducedTemplateSpecializationType(keyword, makeNullableFromOptional(templateName), deducedType, dependent); }]>; } let Class = TagType in { - def : Property<"dependent", Bool> { - let Read = [{ node->isDependentType() }]; + def : Property<"IsCanonical", Bool> { + let Read = [{ node->isCanonicalUnqualified() }]; } - def : Property<"declaration", DeclRef> { - // We don't know which declaration was originally referenced here, and we - // cannot reference a declaration that follows the use (because that can - // introduce deserialization cycles), so conservatively generate a - // reference to the first declaration. - // FIXME: If this is a reference to a class template specialization, that - // can still introduce a deserialization cycle. - let Read = [{ node->getDecl()->getCanonicalDecl() }]; + def : Property<"Keyword", ElaboratedTypeKeyword> { + let Conditional = [{ !IsCanonical }]; + let Read = [{ node->getKeyword() }]; + } + def : Property<"Qualifier", NestedNameSpecifier> { + let Conditional = [{ !IsCanonical }]; + let Read = [{ node->getQualifier() }]; } + def : Property<"TD", TagDeclRef> { let Read = [{ node->getOriginalDecl() }]; } } let Class = EnumType in { + def : Property<"OwnsTag", Bool> { let Read = [{ node->isTagOwned() }]; } def : Creator<[{ - QualType result = ctx.getEnumType(cast(declaration)); - if (dependent) - const_cast(result.getTypePtr()) - ->addDependence(TypeDependence::DependentInstantiation); - return result; + return IsCanonical ? ctx.getCanonicalTagType(TD) : ctx.getTagType(*Keyword, *Qualifier, TD, OwnsTag); }]>; } - let Class = RecordType in { + def : Property<"OwnsTag", Bool> { let Read = [{ node->isTagOwned() }]; } def : Creator<[{ - auto record = cast(declaration); - QualType result = ctx.getRecordType(record); - if (dependent) - const_cast(result.getTypePtr()) - ->addDependence(TypeDependence::DependentInstantiation); - return result; + return IsCanonical ? ctx.getCanonicalTagType(TD) : ctx.getTagType(*Keyword, *Qualifier, TD, OwnsTag); }]>; } - -let Class = ElaboratedType in { - def : Property<"keyword", ElaboratedTypeKeyword> { - let Read = [{ node->getKeyword() }]; - } - def : Property<"qualifier", NestedNameSpecifier> { - let Read = [{ node->getQualifier() }]; - } - def : Property<"namedType", QualType> { - let Read = [{ node->getNamedType() }]; - } - def : Property<"ownedTag", Optional> { - let Read = [{ makeOptionalFromPointer( - const_cast(node->getOwnedTagDecl())) }]; - } - - def : Creator<[{ - return ctx.getElaboratedType(keyword, qualifier, namedType, - makePointerFromOptional(ownedTag)); - }]>; -} - let Class = InjectedClassNameType in { - def : Property<"declaration", DeclRef> { - // FIXME: drilling down to the canonical declaration is what the - // existing serialization code was doing, but it's not clear why. - let Read = [{ node->getDecl()->getCanonicalDecl() }]; - } - def : Property<"injectedSpecializationType", QualType> { - let Read = [{ node->getInjectedSpecializationType() }]; - } - def : Creator<[{ - // FIXME: ASTContext::getInjectedClassNameType is not currently suitable - // for AST reading, too much interdependencies. - const Type *T = nullptr; - auto typeDecl = cast(declaration); - for (auto *DI = typeDecl; DI; DI = DI->getPreviousDecl()) { - if (const Type *existing = DI->getTypeForDecl()) { - T = existing; - break; - } - } - if (!T) { - T = new (ctx, TypeAlignment) - InjectedClassNameType(typeDecl, injectedSpecializationType); - for (auto *DI = typeDecl; DI; DI = DI->getPreviousDecl()) - DI->setTypeForDecl(T); - } - return QualType(T, 0); + return IsCanonical ? ctx.getCanonicalTagType(TD) : ctx.getTagType(*Keyword, *Qualifier, TD, /*OwnsTag=*/false); }]>; } @@ -741,6 +710,9 @@ let Class = DependentAddressSpaceType in { } let Class = TemplateSpecializationType in { + def : Property<"keyword", ElaboratedTypeKeyword> { + let Read = [{ node->getKeyword() }]; + } def : Property<"templateName", TemplateName> { let Read = [{ node->getTemplateName() }]; } @@ -753,7 +725,7 @@ let Class = TemplateSpecializationType in { } def : Creator<[{ - return ctx.getTemplateSpecializationType(templateName, args, {}, UnderlyingType); + return ctx.getTemplateSpecializationType(keyword, templateName, args, {}, UnderlyingType); }]>; } diff --git a/clang/lib/AST/APValue.cpp b/clang/lib/AST/APValue.cpp index ee3dc84479fd9..2d62209bbc28c 100644 --- a/clang/lib/AST/APValue.cpp +++ b/clang/lib/AST/APValue.cpp @@ -902,8 +902,9 @@ void APValue::printPretty(raw_ostream &Out, const PrintingPolicy &Policy, } case APValue::Struct: { Out << '{'; - const RecordDecl *RD = Ty->castAs()->getDecl(); bool First = true; + const RecordDecl *RD = + Ty->castAs()->getOriginalDecl()->getDefinitionOrSelf(); if (unsigned N = getStructNumBases()) { const CXXRecordDecl *CD = cast(RD); CXXRecordDecl::base_class_const_iterator BI = CD->bases_begin(); diff --git a/clang/lib/AST/ASTConcept.cpp b/clang/lib/AST/ASTConcept.cpp index c9cfec6bd64b5..bdf0d9d8bdde1 100644 --- a/clang/lib/AST/ASTConcept.cpp +++ b/clang/lib/AST/ASTConcept.cpp @@ -14,6 +14,7 @@ #include "clang/AST/ASTConcept.h" #include "clang/AST/ASTContext.h" #include "clang/AST/ExprConcepts.h" +#include "clang/AST/NestedNameSpecifier.h" #include "clang/AST/PrettyPrinter.h" #include "llvm/ADT/StringExtras.h" @@ -92,10 +93,16 @@ ConceptReference::Create(const ASTContext &C, NestedNameSpecifierLoc NNS, FoundDecl, NamedConcept, ArgsAsWritten); } +SourceLocation ConceptReference::getBeginLoc() const { + // Note that if the qualifier is null the template KW must also be null. + if (auto QualifierLoc = getNestedNameSpecifierLoc()) + return QualifierLoc.getBeginLoc(); + return getConceptNameInfo().getBeginLoc(); +} + void ConceptReference::print(llvm::raw_ostream &OS, const PrintingPolicy &Policy) const { - if (NestedNameSpec) - NestedNameSpec.getNestedNameSpecifier()->print(OS, Policy); + NestedNameSpec.getNestedNameSpecifier().print(OS, Policy); ConceptName.printName(OS, Policy); if (hasExplicitTemplateArgs()) { OS << "<"; diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 679812adcdf12..96e097858a49b 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -653,7 +653,7 @@ comments::FullComment *ASTContext::getCommentForDecl( // does not have one of its own. QualType QT = TD->getUnderlyingType(); if (const auto *TT = QT->getAs()) - if (const Decl *TD = TT->getDecl()) + if (const Decl *TD = TT->getOriginalDecl()) if (comments::FullComment *FC = getCommentForDecl(TD, PP)) return cloneFullComment(FC, D); } @@ -1931,10 +1931,12 @@ TypeInfoChars ASTContext::getTypeInfoDataSizeInChars(QualType T) const { // of a base-class subobject. We decide whether that's possible // during class layout, so here we can just trust the layout results. if (getLangOpts().CPlusPlus) { - if (const auto *RT = T->getAs(); - RT && !RT->getDecl()->isInvalidDecl()) { - const ASTRecordLayout &layout = getASTRecordLayout(RT->getDecl()); - Info.Width = layout.getDataSize(); + if (const auto *RT = T->getAs()) { + const auto *RD = RT->getOriginalDecl()->getDefinitionOrSelf(); + if (!RD->isInvalidDecl()) { + const ASTRecordLayout &layout = getASTRecordLayout(RD); + Info.Width = layout.getDataSize(); + } } } @@ -2001,8 +2003,9 @@ bool ASTContext::isPromotableIntegerType(QualType T) const { // Enumerated types are promotable to their compatible integer types // (C99 6.3.1.1) a.k.a. its underlying type (C++ [conv.prom]p2). if (const auto *ET = T->getAs()) { - if (T->isDependentType() || ET->getDecl()->getPromotionType().isNull() || - ET->getDecl()->isScoped()) + const EnumDecl *ED = ET->getOriginalDecl()->getDefinitionOrSelf(); + if (T->isDependentType() || ED->getPromotionType().isNull() || + ED->isScoped()) return false; return true; @@ -2038,8 +2041,8 @@ unsigned ASTContext::getTypeAlignIfKnown(QualType T, return Align; // Otherwise, see if the declaration of the type had an attribute. - if (const auto *TT = T->getAs()) - return TT->getDecl()->getMaxAlignment(); + if (const auto *TD = T->getAsTagDecl()) + return TD->getMaxAlignment(); return 0; } @@ -2470,15 +2473,16 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const { case Type::Record: case Type::Enum: { const auto *TT = cast(T); + const TagDecl *TD = TT->getOriginalDecl()->getDefinitionOrSelf(); - if (TT->getDecl()->isInvalidDecl()) { + if (TD->isInvalidDecl()) { Width = 8; Align = 8; break; } - if (const auto *ET = dyn_cast(TT)) { - const EnumDecl *ED = ET->getDecl(); + if (isa(TT)) { + const EnumDecl *ED = cast(TD); TypeInfo Info = getTypeInfo(ED->getIntegerType()->getUnqualifiedDesugaredType()); if (unsigned AttrAlign = ED->getMaxAlignment()) { @@ -2488,8 +2492,7 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const { return Info; } - const auto *RT = cast(TT); - const RecordDecl *RD = RT->getDecl(); + const auto *RD = cast(TD); const ASTRecordLayout &Layout = getASTRecordLayout(RD); Width = toBits(Layout.getSize()); Align = toBits(Layout.getAlignment()); @@ -2541,9 +2544,6 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const { break; } - case Type::Elaborated: - return getTypeInfo(cast(T)->getNamedType().getTypePtr()); - case Type::Attributed: return getTypeInfo( cast(T)->getEquivalentType().getTypePtr()); @@ -2614,8 +2614,7 @@ unsigned ASTContext::getTypeUnadjustedAlign(const Type *T) const { unsigned UnadjustedAlign; if (const auto *RT = T->getAs()) { - const RecordDecl *RD = RT->getDecl(); - const ASTRecordLayout &Layout = getASTRecordLayout(RD); + const ASTRecordLayout &Layout = getASTRecordLayout(RT->getOriginalDecl()); UnadjustedAlign = toBits(Layout.getUnadjustedAlignment()); } else if (const auto *ObjCI = T->getAs()) { const ASTRecordLayout &Layout = getASTObjCInterfaceLayout(ObjCI->getDecl()); @@ -2691,7 +2690,7 @@ unsigned ASTContext::getPreferredTypeAlign(const Type *T) const { return ABIAlign; if (const auto *RT = T->getAs()) { - const RecordDecl *RD = RT->getDecl(); + const RecordDecl *RD = RT->getOriginalDecl()->getDefinitionOrSelf(); // When used as part of a typedef, or together with a 'packed' attribute, // the 'aligned' attribute can be used to decrease alignment. Note that the @@ -2714,7 +2713,10 @@ unsigned ASTContext::getPreferredTypeAlign(const Type *T) const { if (const auto *CT = T->getAs()) T = CT->getElementType().getTypePtr(); if (const auto *ET = T->getAs()) - T = ET->getDecl()->getIntegerType().getTypePtr(); + T = ET->getOriginalDecl() + ->getDefinitionOrSelf() + ->getIntegerType() + .getTypePtr(); if (T->isSpecificBuiltinType(BuiltinType::Double) || T->isSpecificBuiltinType(BuiltinType::LongLong) || T->isSpecificBuiltinType(BuiltinType::ULongLong) || @@ -2846,7 +2848,8 @@ static bool unionHasUniqueObjectRepresentations(const ASTContext &Context, const RecordDecl *RD, bool CheckIfTriviallyCopyable) { assert(RD->isUnion() && "Must be union type"); - CharUnits UnionSize = Context.getTypeSizeInChars(RD->getTypeForDecl()); + CharUnits UnionSize = + Context.getTypeSizeInChars(Context.getCanonicalTagType(RD)); for (const auto *Field : RD->fields()) { if (!Context.hasUniqueObjectRepresentations(Field->getType(), @@ -3040,7 +3043,8 @@ bool ASTContext::hasUniqueObjectRepresentations( return !ABI->getMemberPointerInfo(MPT).HasPadding; if (Ty->isRecordType()) { - const RecordDecl *Record = Ty->castAs()->getDecl(); + const RecordDecl *Record = + Ty->castAs()->getOriginalDecl()->getDefinitionOrSelf(); if (Record->isInvalidDecl()) return false; @@ -3413,7 +3417,10 @@ static void encodeTypeForFunctionPointerAuth(const ASTContext &Ctx, // type, or an unsigned integer type. // // So we have to treat enum types as integers. - QualType UnderlyingType = cast(T)->getDecl()->getIntegerType(); + QualType UnderlyingType = cast(T) + ->getOriginalDecl() + ->getDefinitionOrSelf() + ->getIntegerType(); return encodeTypeForFunctionPointerAuth( Ctx, OS, UnderlyingType.isNull() ? Ctx.IntTy : UnderlyingType); } @@ -3451,7 +3458,7 @@ static void encodeTypeForFunctionPointerAuth(const ASTContext &Ctx, OS << "M"; const auto *MPT = T->castAs(); encodeTypeForFunctionPointerAuth( - Ctx, OS, QualType(MPT->getQualifier()->getAsType(), 0)); + Ctx, OS, QualType(MPT->getQualifier().getAsType(), 0)); encodeTypeForFunctionPointerAuth(Ctx, OS, MPT->getPointeeType()); return; } @@ -3557,7 +3564,8 @@ static void encodeTypeForFunctionPointerAuth(const ASTContext &Ctx, llvm_unreachable("should never get here"); } case Type::Record: { - const RecordDecl *RD = T->castAs()->getDecl(); + const RecordDecl *RD = + T->castAs()->getOriginalDecl()->getDefinitionOrSelf(); const IdentifierInfo *II = RD->getIdentifier(); // In C++, an immediate typedef of an anonymous struct or union @@ -3735,12 +3743,6 @@ ASTContext::adjustType(QualType Orig, adjustType(BTFT->getWrappedType(), Adjust)); } - case Type::Elaborated: { - const auto *ET = cast(Orig); - return getElaboratedType(ET->getKeyword(), ET->getQualifier(), - adjustType(ET->getNamedType(), Adjust)); - } - case Type::Paren: return getParenType( adjustType(cast(Orig)->getInnerType(), Adjust)); @@ -4158,14 +4160,13 @@ QualType ASTContext::getRValueReferenceType(QualType T) const { } QualType ASTContext::getMemberPointerType(QualType T, - NestedNameSpecifier *Qualifier, + NestedNameSpecifier Qualifier, const CXXRecordDecl *Cls) const { if (!Qualifier) { assert(Cls && "At least one of Qualifier or Cls must be provided"); - Qualifier = NestedNameSpecifier::Create(*this, /*Prefix=*/nullptr, - getTypeDeclType(Cls).getTypePtr()); + Qualifier = NestedNameSpecifier(getCanonicalTagType(Cls).getTypePtr()); } else if (!Cls) { - Cls = Qualifier->getAsRecordDecl(); + Cls = Qualifier.getAsRecordDecl(); } // Unique pointers, to guarantee there is only one pointer of a particular // structure. @@ -4177,12 +4178,11 @@ QualType ASTContext::getMemberPointerType(QualType T, MemberPointerTypes.FindNodeOrInsertPos(ID, InsertPos)) return QualType(PT, 0); - NestedNameSpecifier *CanonicalQualifier = [&] { + NestedNameSpecifier CanonicalQualifier = [&] { if (!Cls) - return getCanonicalNestedNameSpecifier(Qualifier); - NestedNameSpecifier *R = NestedNameSpecifier::Create( - *this, /*Prefix=*/nullptr, Cls->getCanonicalDecl()->getTypeForDecl()); - assert(R == getCanonicalNestedNameSpecifier(R)); + return Qualifier.getCanonical(); + NestedNameSpecifier R(getCanonicalTagType(Cls).getTypePtr()); + assert(R.isCanonical()); return R; }(); // If the pointee or class type isn't canonical, this won't be a canonical @@ -5216,153 +5216,301 @@ QualType ASTContext::getDependentBitIntType(bool IsUnsigned, return QualType(New, 0); } -#ifndef NDEBUG -static bool NeedsInjectedClassNameType(const RecordDecl *D) { - if (!isa(D)) return false; - const auto *RD = cast(D); - if (isa(RD)) - return true; - if (RD->getDescribedClassTemplate() && - !isa(RD)) - return true; - return false; -} -#endif +QualType ASTContext::getTypeDeclType(ElaboratedTypeKeyword Keyword, + NestedNameSpecifier Qualifier, + const TypeDecl *Decl) const { + if (auto *Tag = dyn_cast(Decl)) + return getTagType(Keyword, Qualifier, Tag, + /*OwnsTag=*/false); + if (auto *Typedef = dyn_cast(Decl)) + return getTypedefType(Keyword, Qualifier, Typedef); + if (auto *UD = dyn_cast(Decl)) + return getUnresolvedUsingType(Keyword, Qualifier, UD); -/// getInjectedClassNameType - Return the unique reference to the -/// injected class name type for the specified templated declaration. -QualType ASTContext::getInjectedClassNameType(CXXRecordDecl *Decl, - QualType TST) const { - assert(NeedsInjectedClassNameType(Decl)); - if (Decl->TypeForDecl) { - assert(isa(Decl->TypeForDecl)); - } else if (CXXRecordDecl *PrevDecl = Decl->getPreviousDecl()) { - assert(PrevDecl->TypeForDecl && "previous declaration has no type"); - Decl->TypeForDecl = PrevDecl->TypeForDecl; - assert(isa(Decl->TypeForDecl)); - } else { - Type *newType = new (*this, alignof(InjectedClassNameType)) - InjectedClassNameType(Decl, TST); - Decl->TypeForDecl = newType; - Types.push_back(newType); - } + assert(Keyword == ElaboratedTypeKeyword::None); + assert(!Qualifier); return QualType(Decl->TypeForDecl, 0); } -/// getTypeDeclType - Return the unique reference to the type for the -/// specified type declaration. -QualType ASTContext::getTypeDeclTypeSlow(const TypeDecl *Decl) const { - assert(Decl && "Passed null for Decl param"); - assert(!Decl->TypeForDecl && "TypeForDecl present in slow case"); - - if (const auto *Typedef = dyn_cast(Decl)) - return getTypedefType(Typedef); - - assert(!isa(Decl) && - "Template type parameter types are always available."); - - if (const auto *Record = dyn_cast(Decl)) { - assert(Record->isFirstDecl() && "struct/union has previous declaration"); - assert(!NeedsInjectedClassNameType(Record)); - return getRecordType(Record); - } else if (const auto *Enum = dyn_cast(Decl)) { - assert(Enum->isFirstDecl() && "enum has previous declaration"); - return getEnumType(Enum); - } else if (const auto *Using = dyn_cast(Decl)) { - return getUnresolvedUsingType(Using); - } else - llvm_unreachable("TypeDecl without a type?"); - +CanQualType ASTContext::getCanonicalTypeDeclType(const TypeDecl *TD) const { + if (auto *Tag = dyn_cast(TD)) + return getCanonicalTagType(Tag); + if (auto *TN = dyn_cast(TD)) + return getCanonicalType(TN->getUnderlyingType()); + if (const auto *UD = dyn_cast(TD)) + return getCanonicalUnresolvedUsingType(UD); + assert(TD->TypeForDecl); + return TD->TypeForDecl->getCanonicalTypeUnqualified(); +} + +QualType ASTContext::getTypeDeclType(const TypeDecl *Decl) const { + if (const auto *TD = dyn_cast(Decl)) + return getCanonicalTagType(TD); + if (const auto *TD = dyn_cast(Decl); + isa_and_nonnull(TD)) + return getTypedefType(ElaboratedTypeKeyword::None, + /*Qualifier=*/std::nullopt, TD); + if (const auto *Using = dyn_cast(Decl)) + return getCanonicalUnresolvedUsingType(Using); + + assert(Decl->TypeForDecl); return QualType(Decl->TypeForDecl, 0); } /// getTypedefType - Return the unique reference to the type for the /// specified typedef name decl. -QualType ASTContext::getTypedefType(const TypedefNameDecl *Decl, - QualType Underlying) const { - if (!Decl->TypeForDecl) { - if (Underlying.isNull()) - Underlying = Decl->getUnderlyingType(); - auto *NewType = new (*this, alignof(TypedefType)) TypedefType( - Type::Typedef, Decl, Underlying, /*HasTypeDifferentFromDecl=*/false); - Decl->TypeForDecl = NewType; +QualType +ASTContext::getTypedefType(ElaboratedTypeKeyword Keyword, + NestedNameSpecifier Qualifier, + const TypedefNameDecl *Decl, QualType UnderlyingType, + std::optional TypeMatchesDeclOrNone) const { + if (!TypeMatchesDeclOrNone) { + QualType DeclUnderlyingType = Decl->getUnderlyingType(); + assert(!DeclUnderlyingType.isNull()); + if (UnderlyingType.isNull()) + UnderlyingType = DeclUnderlyingType; + else + assert(hasSameType(UnderlyingType, DeclUnderlyingType)); + TypeMatchesDeclOrNone = UnderlyingType == DeclUnderlyingType; + } else { + // FIXME: This is a workaround for a serialization cycle: assume the decl + // underlying type is not available; don't touch it. + assert(!UnderlyingType.isNull()); + } + + if (Keyword == ElaboratedTypeKeyword::None && !Qualifier && + *TypeMatchesDeclOrNone) { + if (Decl->TypeForDecl) + return QualType(Decl->TypeForDecl, 0); + + auto *NewType = new (*this, alignof(TypedefType)) + TypedefType(Type::Typedef, Keyword, Qualifier, Decl, UnderlyingType, + !*TypeMatchesDeclOrNone); + Types.push_back(NewType); + Decl->TypeForDecl = NewType; return QualType(NewType, 0); } - if (Underlying.isNull() || Decl->getUnderlyingType() == Underlying) - return QualType(Decl->TypeForDecl, 0); - assert(hasSameType(Decl->getUnderlyingType(), Underlying)); llvm::FoldingSetNodeID ID; - TypedefType::Profile(ID, Decl, Underlying); + TypedefType::Profile(ID, Keyword, Qualifier, Decl, UnderlyingType); void *InsertPos = nullptr; - if (TypedefType *T = TypedefTypes.FindNodeOrInsertPos(ID, InsertPos)) { - assert(!T->typeMatchesDecl() && - "non-divergent case should be handled with TypeDecl"); - return QualType(T, 0); - } + if (FoldingSetPlaceholder *Placeholder = + TypedefTypes.FindNodeOrInsertPos(ID, InsertPos)) + return QualType(Placeholder->getType(), 0); - void *Mem = Allocate(TypedefType::totalSizeToAlloc(true), - alignof(TypedefType)); - auto *NewType = new (Mem) TypedefType(Type::Typedef, Decl, Underlying, - /*HasTypeDifferentFromDecl=*/true); - TypedefTypes.InsertNode(NewType, InsertPos); + void *Mem = + Allocate(TypedefType::totalSizeToAlloc, + NestedNameSpecifier, QualType>( + 1, !!Qualifier, !*TypeMatchesDeclOrNone), + alignof(TypedefType)); + auto *NewType = + new (Mem) TypedefType(Type::Typedef, Keyword, Qualifier, Decl, + UnderlyingType, !*TypeMatchesDeclOrNone); + auto *Placeholder = new (NewType->getFoldingSetPlaceholder()) + FoldingSetPlaceholder(); + TypedefTypes.InsertNode(Placeholder, InsertPos); Types.push_back(NewType); return QualType(NewType, 0); } -QualType ASTContext::getUsingType(const UsingShadowDecl *Found, - QualType Underlying) const { +QualType ASTContext::getUsingType(ElaboratedTypeKeyword Keyword, + NestedNameSpecifier Qualifier, + const UsingShadowDecl *D, + QualType UnderlyingType) const { + // FIXME: This is expensive to compute every time! + if (UnderlyingType.isNull()) { + const auto *UD = cast(D->getIntroducer()); + UnderlyingType = + getTypeDeclType(UD->hasTypename() ? ElaboratedTypeKeyword::Typename + : ElaboratedTypeKeyword::None, + UD->getQualifier(), cast(D->getTargetDecl())); + } + llvm::FoldingSetNodeID ID; - UsingType::Profile(ID, Found, Underlying); + UsingType::Profile(ID, Keyword, Qualifier, D, UnderlyingType); void *InsertPos = nullptr; - if (UsingType *T = UsingTypes.FindNodeOrInsertPos(ID, InsertPos)) + if (const UsingType *T = UsingTypes.FindNodeOrInsertPos(ID, InsertPos)) return QualType(T, 0); - const Type *TypeForDecl = - cast(Found->getTargetDecl())->getTypeForDecl(); + assert(!UnderlyingType.hasLocalQualifiers()); - assert(!Underlying.hasLocalQualifiers()); - QualType Canon = Underlying->getCanonicalTypeInternal(); - assert(TypeForDecl->getCanonicalTypeInternal() == Canon); + assert( + hasSameType(getCanonicalTypeDeclType(cast(D->getTargetDecl())), + UnderlyingType)); - if (Underlying.getTypePtr() == TypeForDecl) - Underlying = QualType(); void *Mem = - Allocate(UsingType::totalSizeToAlloc(!Underlying.isNull()), + Allocate(UsingType::totalSizeToAlloc(!!Qualifier), alignof(UsingType)); - UsingType *NewType = new (Mem) UsingType(Found, Underlying, Canon); - Types.push_back(NewType); - UsingTypes.InsertNode(NewType, InsertPos); - return QualType(NewType, 0); + UsingType *T = new (Mem) UsingType(Keyword, Qualifier, D, UnderlyingType); + Types.push_back(T); + UsingTypes.InsertNode(T, InsertPos); + return QualType(T, 0); } -QualType ASTContext::getRecordType(const RecordDecl *Decl) const { - if (Decl->TypeForDecl) return QualType(Decl->TypeForDecl, 0); +TagType *ASTContext::getTagTypeInternal(ElaboratedTypeKeyword Keyword, + NestedNameSpecifier Qualifier, + const TagDecl *TD, bool OwnsTag, + bool IsInjected, + const Type *CanonicalType, + bool WithFoldingSetNode) const { + auto [TC, Size] = [&] { + switch (TD->getDeclKind()) { + case Decl::Enum: + static_assert(alignof(EnumType) == alignof(TagType)); + return std::make_tuple(Type::Enum, sizeof(EnumType)); + case Decl::ClassTemplatePartialSpecialization: + case Decl::ClassTemplateSpecialization: + case Decl::CXXRecord: + static_assert(alignof(RecordType) == alignof(TagType)); + static_assert(alignof(InjectedClassNameType) == alignof(TagType)); + if (cast(TD)->hasInjectedClassType()) + return std::make_tuple(Type::InjectedClassName, + sizeof(InjectedClassNameType)); + [[fallthrough]]; + case Decl::Record: + return std::make_tuple(Type::Record, sizeof(RecordType)); + default: + llvm_unreachable("unexpected decl kind"); + } + }(); - if (const RecordDecl *PrevDecl = Decl->getPreviousDecl()) - if (PrevDecl->TypeForDecl) - return QualType(Decl->TypeForDecl = PrevDecl->TypeForDecl, 0); + if (Qualifier) { + static_assert(alignof(NestedNameSpecifier) <= alignof(TagType)); + Size = llvm::alignTo(Size, alignof(NestedNameSpecifier)) + + sizeof(NestedNameSpecifier); + } + void *Mem; + if (WithFoldingSetNode) { + // FIXME: It would be more profitable to tail allocate the folding set node + // from the type, instead of the other way around, due to the greater + // alignment requirements of the type. But this makes it harder to deal with + // the different type node sizes. This would require either uniquing from + // different folding set nodes, or having the folding set node accept a + // contextual parameter which is not fixed at construction. + Mem = Allocate( + sizeof(TagTypeFoldingSetPlaceholder) + + TagTypeFoldingSetPlaceholder::getOffset() + Size, + std::max(alignof(TagTypeFoldingSetPlaceholder), alignof(TagType))); + auto *T = new (Mem) TagTypeFoldingSetPlaceholder(); + Mem = T->getTagType(); + } else { + Mem = Allocate(Size, alignof(TagType)); + } + + auto *T = [&, TC = TC]() -> TagType * { + switch (TC) { + case Type::Enum: { + assert(isa(TD)); + auto *T = new (Mem) EnumType(TC, Keyword, Qualifier, TD, OwnsTag, + IsInjected, CanonicalType); + assert(reinterpret_cast(T) == + reinterpret_cast(static_cast(T)) && + "TagType must be the first base of EnumType"); + return T; + } + case Type::Record: { + assert(isa(TD)); + auto *T = new (Mem) RecordType(TC, Keyword, Qualifier, TD, OwnsTag, + IsInjected, CanonicalType); + assert(reinterpret_cast(T) == + reinterpret_cast(static_cast(T)) && + "TagType must be the first base of RecordType"); + return T; + } + case Type::InjectedClassName: { + CanQualType CanonicalInjectedTST = + cast(TD)->getCanonicalTemplateSpecializationType( + *this); + auto *T = + new (Mem) InjectedClassNameType(Keyword, Qualifier, TD, IsInjected, + CanonicalInjectedTST, CanonicalType); + assert(reinterpret_cast(T) == + reinterpret_cast(static_cast(T)) && + "TagType must be the first base of InjectedClassNameType"); + return T; + } + default: + llvm_unreachable("unexpected type class"); + } + }(); + assert(T->getKeyword() == Keyword); + assert(T->getQualifier() == Qualifier); + assert(T->getOriginalDecl() == TD); + assert(T->isInjected() == IsInjected); + assert(T->isTagOwned() == OwnsTag); + assert((T->isCanonicalUnqualified() + ? QualType() + : T->getCanonicalTypeInternal()) == QualType(CanonicalType, 0)); + Types.push_back(T); + return T; +} - auto *newType = new (*this, alignof(RecordType)) RecordType(Decl); - Decl->TypeForDecl = newType; - Types.push_back(newType); - return QualType(newType, 0); +static bool getNonInjectedClassName(const TagDecl *&TD) { + if (const auto *RD = dyn_cast(TD); + RD && RD->isInjectedClassName()) { + TD = cast(RD->getDeclContext()); + return true; + } + return false; } -QualType ASTContext::getEnumType(const EnumDecl *Decl) const { - if (Decl->TypeForDecl) return QualType(Decl->TypeForDecl, 0); +CanQualType ASTContext::getCanonicalTagType(const TagDecl *TD) const { + ::getNonInjectedClassName(TD); + TD = TD->getCanonicalDecl(); + if (TD->TypeForDecl) + return TD->TypeForDecl->getCanonicalTypeUnqualified(); + + const Type *CanonicalType = getTagTypeInternal( + ElaboratedTypeKeyword::None, + /*Qualifier=*/std::nullopt, TD, + /*OwnsTag=*/false, /*IsInjected=*/false, /*CanonicalType=*/nullptr, + /*WithFoldingSetNode=*/false); + TD->TypeForDecl = CanonicalType; + return CanQualType::CreateUnsafe(QualType(CanonicalType, 0)); +} + +QualType ASTContext::getTagType(ElaboratedTypeKeyword Keyword, + NestedNameSpecifier Qualifier, + const TagDecl *TD, bool OwnsTag) const { + ElaboratedTypeKeyword PreferredKeyword = + getLangOpts().CPlusPlus + ? ElaboratedTypeKeyword::None + : KeywordHelpers::getKeywordForTagTypeKind(TD->getTagKind()); + + if (Keyword == PreferredKeyword && !Qualifier && !OwnsTag) { + if (const Type *T = TD->TypeForDecl; T && !T->isCanonicalUnqualified()) + return QualType(T, 0); + + bool IsInjected = ::getNonInjectedClassName(TD); + const Type *CanonicalType = getCanonicalTagType(TD).getTypePtr(); + const Type *T = + getTagTypeInternal(Keyword, + /*Qualifier=*/std::nullopt, TD, + /*OwnsTag=*/false, IsInjected, CanonicalType, + /*WithFoldingSetNode=*/false); + TD->TypeForDecl = T; + return QualType(T, 0); + } - if (const EnumDecl *PrevDecl = Decl->getPreviousDecl()) - if (PrevDecl->TypeForDecl) - return QualType(Decl->TypeForDecl = PrevDecl->TypeForDecl, 0); + bool IsInjected = ::getNonInjectedClassName(TD); - auto *newType = new (*this, alignof(EnumType)) EnumType(Decl); - Decl->TypeForDecl = newType; - Types.push_back(newType); - return QualType(newType, 0); + llvm::FoldingSetNodeID ID; + TagTypeFoldingSetPlaceholder::Profile(ID, Keyword, Qualifier, TD, OwnsTag, + IsInjected); + + void *InsertPos = nullptr; + if (TagTypeFoldingSetPlaceholder *T = + TagTypes.FindNodeOrInsertPos(ID, InsertPos)) + return QualType(T->getTagType(), 0); + + const Type *CanonicalType = getCanonicalTagType(TD).getTypePtr(); + TagType *T = getTagTypeInternal(Keyword, Qualifier, TD, OwnsTag, IsInjected, + CanonicalType, /*WithFoldingSetNode=*/true); + TagTypes.InsertNode(TagTypeFoldingSetPlaceholder::fromTagType(T), InsertPos); + return QualType(T, 0); } bool ASTContext::computeBestEnumTypes(bool IsPacked, unsigned NumNegativeBits, @@ -5457,21 +5605,69 @@ bool ASTContext::isRepresentableIntegerValue(llvm::APSInt &Value, QualType T) { return Value.getSignificantBits() <= BitWidth; } -QualType ASTContext::getUnresolvedUsingType( - const UnresolvedUsingTypenameDecl *Decl) const { - if (Decl->TypeForDecl) - return QualType(Decl->TypeForDecl, 0); +UnresolvedUsingType *ASTContext::getUnresolvedUsingTypeInternal( + ElaboratedTypeKeyword Keyword, NestedNameSpecifier Qualifier, + const UnresolvedUsingTypenameDecl *D, void *InsertPos, + const Type *CanonicalType) const { + void *Mem = Allocate( + UnresolvedUsingType::totalSizeToAlloc< + FoldingSetPlaceholder, NestedNameSpecifier>( + !!InsertPos, !!Qualifier), + alignof(UnresolvedUsingType)); + auto *T = new (Mem) UnresolvedUsingType(Keyword, Qualifier, D, CanonicalType); + if (InsertPos) { + auto *Placeholder = new (T->getFoldingSetPlaceholder()) + FoldingSetPlaceholder(); + TypedefTypes.InsertNode(Placeholder, InsertPos); + } + Types.push_back(T); + return T; +} - if (const UnresolvedUsingTypenameDecl *CanonicalDecl = - Decl->getCanonicalDecl()) - if (CanonicalDecl->TypeForDecl) - return QualType(Decl->TypeForDecl = CanonicalDecl->TypeForDecl, 0); +CanQualType ASTContext::getCanonicalUnresolvedUsingType( + const UnresolvedUsingTypenameDecl *D) const { + D = D->getCanonicalDecl(); + if (D->TypeForDecl) + return D->TypeForDecl->getCanonicalTypeUnqualified(); - Type *newType = - new (*this, alignof(UnresolvedUsingType)) UnresolvedUsingType(Decl); - Decl->TypeForDecl = newType; - Types.push_back(newType); - return QualType(newType, 0); + const Type *CanonicalType = getUnresolvedUsingTypeInternal( + ElaboratedTypeKeyword::None, + /*Qualifier=*/std::nullopt, D, + /*InsertPos=*/nullptr, /*CanonicalType=*/nullptr); + D->TypeForDecl = CanonicalType; + return CanQualType::CreateUnsafe(QualType(CanonicalType, 0)); +} + +QualType +ASTContext::getUnresolvedUsingType(ElaboratedTypeKeyword Keyword, + NestedNameSpecifier Qualifier, + const UnresolvedUsingTypenameDecl *D) const { + if (Keyword == ElaboratedTypeKeyword::None && !Qualifier) { + if (const Type *T = D->TypeForDecl; T && !T->isCanonicalUnqualified()) + return QualType(T, 0); + + const Type *CanonicalType = getCanonicalUnresolvedUsingType(D).getTypePtr(); + const Type *T = + getUnresolvedUsingTypeInternal(ElaboratedTypeKeyword::None, + /*Qualifier=*/std::nullopt, D, + /*InsertPos=*/nullptr, CanonicalType); + D->TypeForDecl = T; + return QualType(T, 0); + } + + llvm::FoldingSetNodeID ID; + UnresolvedUsingType::Profile(ID, Keyword, Qualifier, D); + + void *InsertPos = nullptr; + if (FoldingSetPlaceholder *Placeholder = + UnresolvedUsingTypes.FindNodeOrInsertPos(ID, InsertPos)) + return QualType(Placeholder->getType(), 0); + assert(InsertPos); + + const Type *CanonicalType = getCanonicalUnresolvedUsingType(D).getTypePtr(); + const Type *T = getUnresolvedUsingTypeInternal(Keyword, Qualifier, D, + InsertPos, CanonicalType); + return QualType(T, 0); } QualType ASTContext::getAttributedType(attr::Kind attrKind, @@ -5691,34 +5887,32 @@ QualType ASTContext::getTemplateTypeParmType(unsigned Depth, unsigned Index, } TypeSourceInfo *ASTContext::getTemplateSpecializationTypeInfo( + ElaboratedTypeKeyword Keyword, SourceLocation ElaboratedKeywordLoc, + NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateKeywordLoc, TemplateName Name, SourceLocation NameLoc, const TemplateArgumentListInfo &SpecifiedArgs, ArrayRef CanonicalArgs, QualType Underlying) const { - QualType TST = getTemplateSpecializationType(Name, SpecifiedArgs.arguments(), - CanonicalArgs, Underlying); + QualType TST = getTemplateSpecializationType( + Keyword, Name, SpecifiedArgs.arguments(), CanonicalArgs, Underlying); TypeSourceInfo *DI = CreateTypeSourceInfo(TST); - TemplateSpecializationTypeLoc TL = - DI->getTypeLoc().castAs(); - TL.setTemplateKeywordLoc(SourceLocation()); - TL.setTemplateNameLoc(NameLoc); - TL.setLAngleLoc(SpecifiedArgs.getLAngleLoc()); - TL.setRAngleLoc(SpecifiedArgs.getRAngleLoc()); - for (unsigned i = 0, e = TL.getNumArgs(); i != e; ++i) - TL.setArgLocInfo(i, SpecifiedArgs[i].getLocInfo()); + DI->getTypeLoc().castAs().set( + ElaboratedKeywordLoc, QualifierLoc, TemplateKeywordLoc, NameLoc, + SpecifiedArgs); return DI; } QualType ASTContext::getTemplateSpecializationType( - TemplateName Template, ArrayRef SpecifiedArgs, + ElaboratedTypeKeyword Keyword, TemplateName Template, + ArrayRef SpecifiedArgs, ArrayRef CanonicalArgs, QualType Underlying) const { SmallVector SpecifiedArgVec; SpecifiedArgVec.reserve(SpecifiedArgs.size()); for (const TemplateArgumentLoc &Arg : SpecifiedArgs) SpecifiedArgVec.push_back(Arg.getArgument()); - return getTemplateSpecializationType(Template, SpecifiedArgVec, CanonicalArgs, - Underlying); + return getTemplateSpecializationType(Keyword, Template, SpecifiedArgVec, + CanonicalArgs, Underlying); } [[maybe_unused]] static bool @@ -5749,7 +5943,8 @@ QualType ASTContext::getCanonicalTemplateSpecializationType( sizeof(TemplateArgument) * Args.size(), alignof(TemplateSpecializationType)); auto *Spec = new (Mem) - TemplateSpecializationType(Template, /*IsAlias=*/false, Args, QualType()); + TemplateSpecializationType(ElaboratedTypeKeyword::None, Template, + /*IsAlias=*/false, Args, QualType()); assert(Spec->isDependentType() && "canonical template specialization must be dependent"); Types.push_back(Spec); @@ -5758,7 +5953,8 @@ QualType ASTContext::getCanonicalTemplateSpecializationType( } QualType ASTContext::getTemplateSpecializationType( - TemplateName Template, ArrayRef SpecifiedArgs, + ElaboratedTypeKeyword Keyword, TemplateName Template, + ArrayRef SpecifiedArgs, ArrayRef CanonicalArgs, QualType Underlying) const { assert(!Template.getUnderlying().getAsDependentTemplateName() && "No dependent template names here!"); @@ -5768,7 +5964,8 @@ QualType ASTContext::getTemplateSpecializationType( if (Underlying.isNull()) { TemplateName CanonTemplate = getCanonicalTemplateName(Template, /*IgnoreDeduced=*/true); - bool NonCanonical = Template != CanonTemplate; + bool NonCanonical = + Template != CanonTemplate || Keyword != ElaboratedTypeKeyword::None; SmallVector CanonArgsVec; if (CanonicalArgs.empty()) { CanonArgsVec = SmallVector(SpecifiedArgs); @@ -5799,42 +5996,12 @@ QualType ASTContext::getTemplateSpecializationType( sizeof(TemplateArgument) * SpecifiedArgs.size() + (IsTypeAlias ? sizeof(QualType) : 0), alignof(TemplateSpecializationType)); - auto *Spec = new (Mem) TemplateSpecializationType(Template, IsTypeAlias, - SpecifiedArgs, Underlying); + auto *Spec = new (Mem) TemplateSpecializationType( + Keyword, Template, IsTypeAlias, SpecifiedArgs, Underlying); Types.push_back(Spec); return QualType(Spec, 0); } -QualType ASTContext::getElaboratedType(ElaboratedTypeKeyword Keyword, - NestedNameSpecifier *NNS, - QualType NamedType, - TagDecl *OwnedTagDecl) const { - llvm::FoldingSetNodeID ID; - ElaboratedType::Profile(ID, Keyword, NNS, NamedType, OwnedTagDecl); - - void *InsertPos = nullptr; - ElaboratedType *T = ElaboratedTypes.FindNodeOrInsertPos(ID, InsertPos); - if (T) - return QualType(T, 0); - - QualType Canon = NamedType; - if (!Canon.isCanonical()) { - Canon = getCanonicalType(NamedType); - ElaboratedType *CheckT = ElaboratedTypes.FindNodeOrInsertPos(ID, InsertPos); - assert(!CheckT && "Elaborated canonical type broken"); - (void)CheckT; - } - - void *Mem = - Allocate(ElaboratedType::totalSizeToAlloc(!!OwnedTagDecl), - alignof(ElaboratedType)); - T = new (Mem) ElaboratedType(Keyword, NNS, NamedType, Canon, OwnedTagDecl); - - Types.push_back(T); - ElaboratedTypes.InsertNode(T, InsertPos); - return QualType(T, 0); -} - QualType ASTContext::getParenType(QualType InnerType) const { llvm::FoldingSetNodeID ID; @@ -5897,7 +6064,7 @@ getCanonicalElaboratedTypeKeyword(ElaboratedTypeKeyword Keyword) { } QualType ASTContext::getDependentNameType(ElaboratedTypeKeyword Keyword, - NestedNameSpecifier *NNS, + NestedNameSpecifier NNS, const IdentifierInfo *Name) const { llvm::FoldingSetNodeID ID; DependentNameType::Profile(ID, Keyword, NNS, Name); @@ -5909,7 +6076,7 @@ QualType ASTContext::getDependentNameType(ElaboratedTypeKeyword Keyword, ElaboratedTypeKeyword CanonKeyword = getCanonicalElaboratedTypeKeyword(Keyword); - NestedNameSpecifier *CanonNNS = getCanonicalNestedNameSpecifier(NNS); + NestedNameSpecifier CanonNNS = NNS.getCanonical(); QualType Canon; if (CanonKeyword != Keyword || CanonNNS != NNS) { @@ -5948,13 +6115,13 @@ QualType ASTContext::getDependentTemplateSpecializationType( ID, InsertPos)) return QualType(T, 0); - NestedNameSpecifier *NNS = Name.getQualifier(); + NestedNameSpecifier NNS = Name.getQualifier(); QualType Canon; if (!IsCanonical) { ElaboratedTypeKeyword CanonKeyword = getCanonicalElaboratedTypeKeyword(Keyword); - NestedNameSpecifier *CanonNNS = getCanonicalNestedNameSpecifier(NNS); + NestedNameSpecifier CanonNNS = NNS.getCanonical(); bool AnyNonCanonArgs = false; auto CanonArgs = ::getCanonicalTemplateArguments(*this, Args, AnyNonCanonArgs); @@ -5974,7 +6141,7 @@ QualType ASTContext::getDependentTemplateSpecializationType( } else { assert(Keyword == getCanonicalElaboratedTypeKeyword(Keyword)); assert(Name.hasTemplateKeyword()); - assert(NNS == getCanonicalNestedNameSpecifier(NNS)); + assert(NNS.isCanonical()); #ifndef NDEBUG for (const auto &Arg : Args) assert(Arg.structurallyEquals(getCanonicalTemplateArgument(Arg))); @@ -6025,7 +6192,8 @@ TemplateArgument ASTContext::getInjectedTemplateArg(NamedDecl *Param) const { } else { auto *TTP = cast(Param); TemplateName Name = getQualifiedTemplateName( - nullptr, /*TemplateKeyword=*/false, TemplateName(TTP)); + /*Qualifier=*/std::nullopt, /*TemplateKeyword=*/false, + TemplateName(TTP)); if (TTP->isParameterPack()) Arg = TemplateArgument(Name, /*NumExpansions=*/std::nullopt); else @@ -6297,11 +6465,11 @@ void ASTContext::adjustObjCTypeParamBoundType(const ObjCTypeParamDecl *Orig, ObjCTypeParamDecl *New) const { New->setTypeSourceInfo(getTrivialTypeSourceInfo(Orig->getUnderlyingType())); // Update TypeForDecl after updating TypeSourceInfo. - auto NewTypeParamTy = cast(New->getTypeForDecl()); + auto *NewTypeParamTy = cast(New->TypeForDecl); SmallVector protocols; protocols.append(NewTypeParamTy->qual_begin(), NewTypeParamTy->qual_end()); QualType UpdatedTy = getObjCTypeParamType(New, protocols); - New->setTypeForDecl(UpdatedTy.getTypePtr()); + New->TypeForDecl = UpdatedTy.getTypePtr(); } /// ObjCObjectAdoptsQTypeProtocols - Checks that protocols in IC's @@ -6698,20 +6866,20 @@ QualType ASTContext::getUnconstrainedType(QualType T) const { } QualType ASTContext::getDeducedTemplateSpecializationTypeInternal( - TemplateName Template, QualType DeducedType, bool IsDependent, - QualType Canon) const { + ElaboratedTypeKeyword Keyword, TemplateName Template, QualType DeducedType, + bool IsDependent, QualType Canon) const { // Look in the folding set for an existing type. void *InsertPos = nullptr; llvm::FoldingSetNodeID ID; - DeducedTemplateSpecializationType::Profile(ID, Template, DeducedType, + DeducedTemplateSpecializationType::Profile(ID, Keyword, Template, DeducedType, IsDependent); if (DeducedTemplateSpecializationType *DTST = DeducedTemplateSpecializationTypes.FindNodeOrInsertPos(ID, InsertPos)) return QualType(DTST, 0); auto *DTST = new (*this, alignof(DeducedTemplateSpecializationType)) - DeducedTemplateSpecializationType(Template, DeducedType, IsDependent, - Canon); + DeducedTemplateSpecializationType(Keyword, Template, DeducedType, + IsDependent, Canon); #ifndef NDEBUG llvm::FoldingSetNodeID TempID; @@ -6727,14 +6895,20 @@ QualType ASTContext::getDeducedTemplateSpecializationTypeInternal( /// which has been deduced to the given type, or to the canonical undeduced /// such type, or the canonical deduced-but-dependent such type. QualType ASTContext::getDeducedTemplateSpecializationType( - TemplateName Template, QualType DeducedType, bool IsDependent) const { - QualType Canon = DeducedType.isNull() - ? getDeducedTemplateSpecializationTypeInternal( - getCanonicalTemplateName(Template), QualType(), - IsDependent, QualType()) - : DeducedType.getCanonicalType(); - return getDeducedTemplateSpecializationTypeInternal(Template, DeducedType, - IsDependent, Canon); + ElaboratedTypeKeyword Keyword, TemplateName Template, QualType DeducedType, + bool IsDependent) const { + // FIXME: This could save an extra hash table lookup if it handled all the + // parameters already being canonical. + // FIXME: Can this be formed from a DependentTemplateName, such that the + // keyword should be part of the canonical type? + QualType Canon = + DeducedType.isNull() + ? getDeducedTemplateSpecializationTypeInternal( + ElaboratedTypeKeyword::None, getCanonicalTemplateName(Template), + QualType(), IsDependent, QualType()) + : DeducedType.getCanonicalType(); + return getDeducedTemplateSpecializationTypeInternal( + Keyword, Template, DeducedType, IsDependent, Canon); } /// getAtomicType - Return the uniqued reference to the atomic type for @@ -6784,15 +6958,6 @@ QualType ASTContext::getAutoRRefDeductType() const { return AutoRRefDeductTy; } -/// getTagDeclType - Return the unique reference to the type for the -/// specified TagDecl (struct/union/class/enum) decl. -QualType ASTContext::getTagDeclType(const TagDecl *Decl) const { - assert(Decl); - // FIXME: What is the design on getTagDeclType when it requires casting - // away const? mutable? - return getTypeDeclType(const_cast(Decl)); -} - /// getSizeType - Return the unique type for "size_t" (C99 7.17), the result /// of the sizeof operator (C99 6.5.3.4p4). The value is target dependent and /// needs to agree with the definition in . @@ -7010,8 +7175,8 @@ bool ASTContext::UnwrapSimilarTypes(QualType &T1, QualType &T2, *RD2 = T2MPType->getMostRecentCXXRecordDecl(); RD1 != RD2 && RD1->getCanonicalDecl() != RD2->getCanonicalDecl()) return false; - if (getCanonicalNestedNameSpecifier(T1MPType->getQualifier()) != - getCanonicalNestedNameSpecifier(T2MPType->getQualifier())) + if (T1MPType->getQualifier().getCanonical() != + T2MPType->getQualifier().getCanonical()) return false; T1 = T1MPType->getPointeeType(); T2 = T2MPType->getPointeeType(); @@ -7168,9 +7333,8 @@ TemplateName ASTContext::getCanonicalTemplateName(TemplateName Name, case TemplateName::DependentTemplate: { DependentTemplateName *DTN = Name.getAsDependentTemplateName(); assert(DTN && "Non-dependent template names must refer to template decls."); - NestedNameSpecifier *Qualifier = DTN->getQualifier(); - NestedNameSpecifier *CanonQualifier = - getCanonicalNestedNameSpecifier(Qualifier); + NestedNameSpecifier Qualifier = DTN->getQualifier(); + NestedNameSpecifier CanonQualifier = Qualifier.getCanonical(); if (Qualifier != CanonQualifier || !DTN->hasTemplateKeyword()) return getDependentTemplateName({CanonQualifier, DTN->getName(), /*HasTemplateKeyword=*/true}); @@ -7387,50 +7551,40 @@ bool ASTContext::isSameDefaultTemplateArgument(const NamedDecl *X, return hasSameTemplateName(TAX.getAsTemplate(), TAY.getAsTemplate()); } -static NamespaceDecl *getNamespace(const NestedNameSpecifier *X) { - if (auto *NS = X->getAsNamespace()) - return NS; - if (auto *NAS = X->getAsNamespaceAlias()) - return NAS->getNamespace(); - return nullptr; -} +static bool isSameQualifier(const NestedNameSpecifier X, + const NestedNameSpecifier Y) { + if (X == Y) + return true; + if (!X || !Y) + return false; -static bool isSameQualifier(const NestedNameSpecifier *X, - const NestedNameSpecifier *Y) { - if (auto *NSX = getNamespace(X)) { - auto *NSY = getNamespace(Y); - if (!NSY || NSX->getCanonicalDecl() != NSY->getCanonicalDecl()) - return false; - } else if (X->getKind() != Y->getKind()) + auto Kind = X.getKind(); + if (Kind != Y.getKind()) return false; // FIXME: For namespaces and types, we're permitted to check that the entity // is named via the same tokens. We should probably do so. - switch (X->getKind()) { - case NestedNameSpecifier::Identifier: - if (X->getAsIdentifier() != Y->getAsIdentifier()) + switch (Kind) { + case NestedNameSpecifier::Kind::Namespace: { + auto [NamespaceX, PrefixX] = X.getAsNamespaceAndPrefix(); + auto [NamespaceY, PrefixY] = Y.getAsNamespaceAndPrefix(); + if (!declaresSameEntity(NamespaceX->getNamespace(), + NamespaceY->getNamespace())) return false; - break; - case NestedNameSpecifier::Namespace: - case NestedNameSpecifier::NamespaceAlias: - // We've already checked that we named the same namespace. - break; - case NestedNameSpecifier::TypeSpec: - if (X->getAsType()->getCanonicalTypeInternal() != - Y->getAsType()->getCanonicalTypeInternal()) + return isSameQualifier(PrefixX, PrefixY); + } + case NestedNameSpecifier::Kind::Type: { + const auto *TX = X.getAsType(), *TY = Y.getAsType(); + if (TX->getCanonicalTypeInternal() != TY->getCanonicalTypeInternal()) return false; - break; - case NestedNameSpecifier::Global: - case NestedNameSpecifier::Super: + return isSameQualifier(TX->getPrefix(), TY->getPrefix()); + } + case NestedNameSpecifier::Kind::Null: + case NestedNameSpecifier::Kind::Global: + case NestedNameSpecifier::Kind::Super: return true; } - - // Recurse into earlier portion of NNS, if any. - auto *PX = X->getPrefix(); - auto *PY = Y->getPrefix(); - if (PX && PY) - return isSameQualifier(PX, PY); - return !PX && !PY; + llvm_unreachable("unhandled qualifier kind"); } static bool hasSameCudaAttrs(const FunctionDecl *A, const FunctionDecl *B) { @@ -7823,70 +7977,6 @@ bool ASTContext::isSameTemplateArgument(const TemplateArgument &Arg1, llvm_unreachable("Unhandled template argument kind"); } -NestedNameSpecifier * -ASTContext::getCanonicalNestedNameSpecifier(NestedNameSpecifier *NNS) const { - if (!NNS) - return nullptr; - - switch (NNS->getKind()) { - case NestedNameSpecifier::Identifier: - // Canonicalize the prefix but keep the identifier the same. - return NestedNameSpecifier::Create(*this, - getCanonicalNestedNameSpecifier(NNS->getPrefix()), - NNS->getAsIdentifier()); - - case NestedNameSpecifier::Namespace: - // A namespace is canonical; build a nested-name-specifier with - // this namespace and no prefix. - return NestedNameSpecifier::Create(*this, nullptr, - NNS->getAsNamespace()->getFirstDecl()); - - case NestedNameSpecifier::NamespaceAlias: - // A namespace is canonical; build a nested-name-specifier with - // this namespace and no prefix. - return NestedNameSpecifier::Create( - *this, nullptr, - NNS->getAsNamespaceAlias()->getNamespace()->getFirstDecl()); - - // The difference between TypeSpec and TypeSpecWithTemplate is that the - // latter will have the 'template' keyword when printed. - case NestedNameSpecifier::TypeSpec: { - const Type *T = getCanonicalType(NNS->getAsType()); - - // If we have some kind of dependent-named type (e.g., "typename T::type"), - // break it apart into its prefix and identifier, then reconsititute those - // as the canonical nested-name-specifier. This is required to canonicalize - // a dependent nested-name-specifier involving typedefs of dependent-name - // types, e.g., - // typedef typename T::type T1; - // typedef typename T1::type T2; - if (const auto *DNT = T->getAs()) - return NestedNameSpecifier::Create(*this, DNT->getQualifier(), - DNT->getIdentifier()); - if (const auto *DTST = T->getAs()) { - const DependentTemplateStorage &DTN = DTST->getDependentTemplateName(); - QualType NewT = getDependentTemplateSpecializationType( - ElaboratedTypeKeyword::None, - {/*NNS=*/nullptr, DTN.getName(), /*HasTemplateKeyword=*/true}, - DTST->template_arguments(), /*IsCanonical=*/true); - assert(NewT.isCanonical()); - NestedNameSpecifier *Prefix = DTN.getQualifier(); - if (!Prefix) - Prefix = getCanonicalNestedNameSpecifier(NNS->getPrefix()); - return NestedNameSpecifier::Create(*this, Prefix, NewT.getTypePtr()); - } - return NestedNameSpecifier::Create(*this, nullptr, T); - } - - case NestedNameSpecifier::Global: - case NestedNameSpecifier::Super: - // The global specifier and __super specifer are canonical and unique. - return NNS; - } - - llvm_unreachable("Invalid NestedNameSpecifier::Kind!"); -} - const ArrayType *ASTContext::getAsArrayType(QualType T) const { // Handle the non-qualified case efficiently. if (!T.hasLocalQualifiers()) { @@ -8205,7 +8295,7 @@ QualType ASTContext::getPromotedIntegerType(QualType Promotable) const { assert(!Promotable.isNull()); assert(isPromotableIntegerType(Promotable)); if (const auto *ET = Promotable->getAs()) - return ET->getDecl()->getPromotionType(); + return ET->getOriginalDecl()->getDefinitionOrSelf()->getPromotionType(); if (const auto *BT = Promotable->getAs()) { // C++ [conv.prom]: A prvalue of type char16_t, char32_t, or wchar_t @@ -8264,8 +8354,9 @@ Qualifiers::ObjCLifetime ASTContext::getInnerObjCOwnership(QualType T) const { static const Type *getIntegerTypeForEnum(const EnumType *ET) { // Incomplete enum types are not treated as integer types. // FIXME: In C++, enum types are never integer types. - if (ET->getDecl()->isComplete() && !ET->getDecl()->isScoped()) - return ET->getDecl()->getIntegerType().getTypePtr(); + const EnumDecl *ED = ET->getOriginalDecl()->getDefinitionOrSelf(); + if (ED->isComplete() && !ED->isScoped()) + return ED->getIntegerType().getTypePtr(); return nullptr; } @@ -8394,7 +8485,7 @@ TypedefDecl *ASTContext::getCFConstantStringDecl() const { CFConstantStringTagDecl->completeDefinition(); // This type is designed to be compatible with NSConstantString, but cannot // use the same name, since NSConstantString is an interface. - auto tagType = getTagDeclType(CFConstantStringTagDecl); + CanQualType tagType = getCanonicalTagType(CFConstantStringTagDecl); CFConstantStringTypeDecl = buildImplicitTypedef(tagType, "__NSConstantString"); @@ -8409,14 +8500,15 @@ RecordDecl *ASTContext::getCFConstantStringTagDecl() const { // getCFConstantStringType - Return the type used for constant CFStrings. QualType ASTContext::getCFConstantStringType() const { - return getTypedefType(getCFConstantStringDecl()); + return getTypedefType(ElaboratedTypeKeyword::None, /*Qualifier=*/std::nullopt, + getCFConstantStringDecl()); } QualType ASTContext::getObjCSuperType() const { if (ObjCSuperType.isNull()) { RecordDecl *ObjCSuperTypeDecl = buildImplicitRecord("objc_super"); getTranslationUnitDecl()->addDecl(ObjCSuperTypeDecl); - ObjCSuperType = getTagDeclType(ObjCSuperTypeDecl); + ObjCSuperType = getCanonicalTagType(ObjCSuperTypeDecl); } return ObjCSuperType; } @@ -8425,12 +8517,12 @@ void ASTContext::setCFConstantStringType(QualType T) { const auto *TD = T->castAs(); CFConstantStringTypeDecl = cast(TD->getDecl()); const auto *TagType = TD->castAs(); - CFConstantStringTagDecl = TagType->getDecl(); + CFConstantStringTagDecl = TagType->getOriginalDecl()->getDefinitionOrSelf(); } QualType ASTContext::getBlockDescriptorType() const { if (BlockDescriptorType) - return getTagDeclType(BlockDescriptorType); + return getCanonicalTagType(BlockDescriptorType); RecordDecl *RD; // FIXME: Needs the FlagAppleBlock bit. @@ -8460,12 +8552,12 @@ QualType ASTContext::getBlockDescriptorType() const { BlockDescriptorType = RD; - return getTagDeclType(BlockDescriptorType); + return getCanonicalTagType(BlockDescriptorType); } QualType ASTContext::getBlockDescriptorExtendedType() const { if (BlockDescriptorExtendedType) - return getTagDeclType(BlockDescriptorExtendedType); + return getCanonicalTagType(BlockDescriptorExtendedType); RecordDecl *RD; // FIXME: Needs the FlagAppleBlock bit. @@ -8499,7 +8591,7 @@ QualType ASTContext::getBlockDescriptorExtendedType() const { RD->completeDefinition(); BlockDescriptorExtendedType = RD; - return getTagDeclType(BlockDescriptorExtendedType); + return getCanonicalTagType(BlockDescriptorExtendedType); } OpenCLTypeKind ASTContext::getOpenCLTypeKind(const Type *T) const { @@ -9137,7 +9229,7 @@ static char getObjCEncodingForPrimitiveType(const ASTContext *C, } static char ObjCEncodingForEnumType(const ASTContext *C, const EnumType *ET) { - EnumDecl *Enum = ET->getDecl(); + EnumDecl *Enum = ET->getOriginalDecl()->getDefinitionOrSelf(); // The encoding of an non-fixed enum type is always 'i', regardless of size. if (!Enum->isFixed()) @@ -9306,13 +9398,14 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string &S, return; } } else if (const auto *RTy = PointeeTy->getAs()) { + const IdentifierInfo *II = RTy->getOriginalDecl()->getIdentifier(); // GCC binary compat: Need to convert "struct objc_class *" to "#". - if (RTy->getDecl()->getIdentifier() == &Idents.get("objc_class")) { + if (II == &Idents.get("objc_class")) { S += '#'; return; } // GCC binary compat: Need to convert "struct objc_object *" to "@". - if (RTy->getDecl()->getIdentifier() == &Idents.get("objc_object")) { + if (II == &Idents.get("objc_object")) { S += '@'; return; } @@ -9377,7 +9470,7 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string &S, return; case Type::Record: { - RecordDecl *RDecl = cast(CT)->getDecl(); + RecordDecl *RDecl = cast(CT)->getOriginalDecl(); S += RDecl->isUnion() ? '(' : '{'; // Anonymous structures print as '?' if (const IdentifierInfo *II = RDecl->getIdentifier()) { @@ -9865,7 +9958,7 @@ CreateAArch64ABIBuiltinVaListDecl(const ASTContext *Context) { } VaListTagDecl->completeDefinition(); Context->VaListTagDecl = VaListTagDecl; - QualType VaListTagType = Context->getRecordType(VaListTagDecl); + CanQualType VaListTagType = Context->getCanonicalTagType(VaListTagDecl); // } __builtin_va_list; return Context->buildImplicitTypedef(VaListTagType, "__builtin_va_list"); @@ -9917,14 +10010,15 @@ static TypedefDecl *CreatePowerABIBuiltinVaListDecl(const ASTContext *Context) { } VaListTagDecl->completeDefinition(); Context->VaListTagDecl = VaListTagDecl; - QualType VaListTagType = Context->getRecordType(VaListTagDecl); + CanQualType VaListTagType = Context->getCanonicalTagType(VaListTagDecl); // } __va_list_tag; TypedefDecl *VaListTagTypedefDecl = Context->buildImplicitTypedef(VaListTagType, "__va_list_tag"); QualType VaListTagTypedefType = - Context->getTypedefType(VaListTagTypedefDecl); + Context->getTypedefType(ElaboratedTypeKeyword::None, + /*Qualifier=*/std::nullopt, VaListTagTypedefDecl); // typedef __va_list_tag __builtin_va_list[1]; llvm::APInt Size(Context->getTypeSize(Context->getSizeType()), 1); @@ -9976,7 +10070,7 @@ CreateX86_64ABIBuiltinVaListDecl(const ASTContext *Context) { } VaListTagDecl->completeDefinition(); Context->VaListTagDecl = VaListTagDecl; - QualType VaListTagType = Context->getRecordType(VaListTagDecl); + CanQualType VaListTagType = Context->getCanonicalTagType(VaListTagDecl); // }; @@ -10032,7 +10126,7 @@ CreateAAPCSABIBuiltinVaListDecl(const ASTContext *Context) { Context->VaListTagDecl = VaListDecl; // typedef struct __va_list __builtin_va_list; - QualType T = Context->getRecordType(VaListDecl); + CanQualType T = Context->getCanonicalTagType(VaListDecl); return Context->buildImplicitTypedef(T, "__builtin_va_list"); } @@ -10079,7 +10173,7 @@ CreateSystemZBuiltinVaListDecl(const ASTContext *Context) { } VaListTagDecl->completeDefinition(); Context->VaListTagDecl = VaListTagDecl; - QualType VaListTagType = Context->getRecordType(VaListTagDecl); + CanQualType VaListTagType = Context->getCanonicalTagType(VaListTagDecl); // }; @@ -10126,13 +10220,15 @@ static TypedefDecl *CreateHexagonBuiltinVaListDecl(const ASTContext *Context) { } VaListTagDecl->completeDefinition(); Context->VaListTagDecl = VaListTagDecl; - QualType VaListTagType = Context->getRecordType(VaListTagDecl); + CanQualType VaListTagType = Context->getCanonicalTagType(VaListTagDecl); // } __va_list_tag; TypedefDecl *VaListTagTypedefDecl = Context->buildImplicitTypedef(VaListTagType, "__va_list_tag"); - QualType VaListTagTypedefType = Context->getTypedefType(VaListTagTypedefDecl); + QualType VaListTagTypedefType = + Context->getTypedefType(ElaboratedTypeKeyword::None, + /*Qualifier=*/std::nullopt, VaListTagTypedefDecl); // typedef __va_list_tag __builtin_va_list[1]; llvm::APInt Size(Context->getTypeSize(Context->getSizeType()), 1); @@ -10170,7 +10266,7 @@ CreateXtensaABIBuiltinVaListDecl(const ASTContext *Context) { } VaListTagDecl->completeDefinition(); Context->VaListTagDecl = VaListTagDecl; - QualType VaListTagType = Context->getRecordType(VaListTagDecl); + CanQualType VaListTagType = Context->getCanonicalTagType(VaListTagDecl); // } __va_list_tag; TypedefDecl *VaListTagTypedefDecl = @@ -10286,7 +10382,7 @@ TemplateName ASTContext::getAssumedTemplateName(DeclarationName Name) const { /// Retrieve the template name that represents a qualified /// template name such as \c std::vector. -TemplateName ASTContext::getQualifiedTemplateName(NestedNameSpecifier *NNS, +TemplateName ASTContext::getQualifiedTemplateName(NestedNameSpecifier Qualifier, bool TemplateKeyword, TemplateName Template) const { assert(Template.getKind() == TemplateName::Template || @@ -10294,14 +10390,14 @@ TemplateName ASTContext::getQualifiedTemplateName(NestedNameSpecifier *NNS, // FIXME: Canonicalization? llvm::FoldingSetNodeID ID; - QualifiedTemplateName::Profile(ID, NNS, TemplateKeyword, Template); + QualifiedTemplateName::Profile(ID, Qualifier, TemplateKeyword, Template); void *InsertPos = nullptr; QualifiedTemplateName *QTN = - QualifiedTemplateNames.FindNodeOrInsertPos(ID, InsertPos); + QualifiedTemplateNames.FindNodeOrInsertPos(ID, InsertPos); if (!QTN) { QTN = new (*this, alignof(QualifiedTemplateName)) - QualifiedTemplateName(NNS, TemplateKeyword, Template); + QualifiedTemplateName(Qualifier, TemplateKeyword, Template); QualifiedTemplateNames.InsertNode(QTN, InsertPos); } @@ -11271,7 +11367,7 @@ QualType ASTContext::mergeTransparentUnionType(QualType T, QualType SubType, bool OfBlockPointer, bool Unqualified) { if (const RecordType *UT = T->getAsUnionType()) { - RecordDecl *UD = UT->getDecl(); + RecordDecl *UD = UT->getOriginalDecl()->getMostRecentDecl(); if (UD->hasAttr()) { for (const auto *I : UD->fields()) { QualType ET = I->getType().getUnqualifiedType(); @@ -11503,7 +11599,8 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs, // Look at the converted type of enum types, since that is the type used // to pass enum values. if (const auto *Enum = paramTy->getAs()) { - paramTy = Enum->getDecl()->getIntegerType(); + paramTy = + Enum->getOriginalDecl()->getDefinitionOrSelf()->getIntegerType(); if (paramTy.isNull()) return {}; } @@ -11535,7 +11632,8 @@ static QualType mergeEnumWithInteger(ASTContext &Context, const EnumType *ET, // a signed integer type, or an unsigned integer type. // Compatibility is based on the underlying type, not the promotion // type. - QualType underlyingType = ET->getDecl()->getIntegerType(); + QualType underlyingType = + ET->getOriginalDecl()->getDefinitionOrSelf()->getIntegerType(); if (underlyingType.isNull()) return {}; if (Context.hasSameType(underlyingType, other)) @@ -12094,7 +12192,7 @@ QualType ASTContext::mergeObjCGCQualifiers(QualType LHS, QualType RHS) { unsigned ASTContext::getIntWidth(QualType T) const { if (const auto *ET = T->getAs()) - T = ET->getDecl()->getIntegerType(); + T = ET->getOriginalDecl()->getDefinitionOrSelf()->getIntegerType(); if (T->isBooleanType()) return 1; if (const auto *EIT = T->getAs()) @@ -12120,7 +12218,7 @@ QualType ASTContext::getCorrespondingUnsignedType(QualType T) const { // For enums, get the underlying integer type of the enum, and let the general // integer type signchanging code handle it. if (const auto *ETy = T->getAs()) - T = ETy->getDecl()->getIntegerType(); + T = ETy->getOriginalDecl()->getDefinitionOrSelf()->getIntegerType(); switch (T->castAs()->getKind()) { case BuiltinType::Char_U: @@ -12194,7 +12292,7 @@ QualType ASTContext::getCorrespondingSignedType(QualType T) const { // For enums, get the underlying integer type of the enum, and let the general // integer type signchanging code handle it. if (const auto *ETy = T->getAs()) - T = ETy->getDecl()->getIntegerType(); + T = ETy->getOriginalDecl()->getDefinitionOrSelf()->getIntegerType(); switch (T->castAs()->getKind()) { case BuiltinType::Char_S: @@ -13554,7 +13652,7 @@ static T *getCommonDeclChecked(T *X, T *Y) { const_cast(cast(Y)))); } -static TemplateName getCommonTemplateName(ASTContext &Ctx, TemplateName X, +static TemplateName getCommonTemplateName(const ASTContext &Ctx, TemplateName X, TemplateName Y, bool IgnoreDeduced = false) { if (X.getAsVoidPointer() == Y.getAsVoidPointer()) @@ -13569,7 +13667,7 @@ static TemplateName getCommonTemplateName(ASTContext &Ctx, TemplateName X, return CX; } -static TemplateName getCommonTemplateNameChecked(ASTContext &Ctx, +static TemplateName getCommonTemplateNameChecked(const ASTContext &Ctx, TemplateName X, TemplateName Y, bool IgnoreDeduced) { TemplateName R = getCommonTemplateName(Ctx, X, Y, IgnoreDeduced); @@ -13577,7 +13675,7 @@ static TemplateName getCommonTemplateNameChecked(ASTContext &Ctx, return R; } -static auto getCommonTypes(ASTContext &Ctx, ArrayRef Xs, +static auto getCommonTypes(const ASTContext &Ctx, ArrayRef Xs, ArrayRef Ys, bool Unqualified = false) { assert(Xs.size() == Ys.size()); SmallVector Rs(Xs.size()); @@ -13592,7 +13690,7 @@ static SourceLocation getCommonAttrLoc(const T *X, const T *Y) { : SourceLocation(); } -static TemplateArgument getCommonTemplateArgument(ASTContext &Ctx, +static TemplateArgument getCommonTemplateArgument(const ASTContext &Ctx, const TemplateArgument &X, const TemplateArgument &Y) { if (X.getKind() != Y.getKind()) @@ -13638,7 +13736,7 @@ static TemplateArgument getCommonTemplateArgument(ASTContext &Ctx, } } -static bool getCommonTemplateArguments(ASTContext &Ctx, +static bool getCommonTemplateArguments(const ASTContext &Ctx, SmallVectorImpl &R, ArrayRef Xs, ArrayRef Ys) { @@ -13653,7 +13751,7 @@ static bool getCommonTemplateArguments(ASTContext &Ctx, return false; } -static auto getCommonTemplateArguments(ASTContext &Ctx, +static auto getCommonTemplateArguments(const ASTContext &Ctx, ArrayRef Xs, ArrayRef Ys) { SmallVector R; @@ -13664,162 +13762,101 @@ static auto getCommonTemplateArguments(ASTContext &Ctx, } template -static ElaboratedTypeKeyword getCommonTypeKeyword(const T *X, const T *Y) { - return X->getKeyword() == Y->getKeyword() ? X->getKeyword() - : ElaboratedTypeKeyword::None; +static ElaboratedTypeKeyword getCommonTypeKeyword(const T *X, const T *Y, + bool IsSame) { + ElaboratedTypeKeyword KX = X->getKeyword(), KY = Y->getKeyword(); + if (KX == KY) + return KX; + KX = getCanonicalElaboratedTypeKeyword(KX); + assert(!IsSame || KX == getCanonicalElaboratedTypeKeyword(KY)); + return KX; } /// Returns a NestedNameSpecifier which has only the common sugar /// present in both NNS1 and NNS2. -static NestedNameSpecifier *getCommonNNS(ASTContext &Ctx, - NestedNameSpecifier *NNS1, - NestedNameSpecifier *NNS2, - bool IsSame) { +static NestedNameSpecifier getCommonNNS(const ASTContext &Ctx, + NestedNameSpecifier NNS1, + NestedNameSpecifier NNS2, bool IsSame) { // If they are identical, all sugar is common. if (NNS1 == NNS2) return NNS1; - // IsSame implies both NNSes are equivalent. - NestedNameSpecifier *Canon = Ctx.getCanonicalNestedNameSpecifier(NNS1); - if (Canon != Ctx.getCanonicalNestedNameSpecifier(NNS2)) { + // IsSame implies both Qualifiers are equivalent. + NestedNameSpecifier Canon = NNS1.getCanonical(); + if (Canon != NNS2.getCanonical()) { assert(!IsSame && "Should be the same NestedNameSpecifier"); // If they are not the same, there is nothing to unify. - // FIXME: It would be useful here if we could represent a canonically - // empty NNS, which is not identical to an empty-as-written NNS. - return nullptr; + return std::nullopt; } - NestedNameSpecifier *R = nullptr; - NestedNameSpecifier::SpecifierKind K1 = NNS1->getKind(), K2 = NNS2->getKind(); - switch (K1) { - case NestedNameSpecifier::SpecifierKind::Identifier: { - assert(K2 == NestedNameSpecifier::SpecifierKind::Identifier); - IdentifierInfo *II = NNS1->getAsIdentifier(); - assert(II == NNS2->getAsIdentifier()); - // For an identifier, the prefixes are significant, so they must be the - // same. - NestedNameSpecifier *P = ::getCommonNNS(Ctx, NNS1->getPrefix(), - NNS2->getPrefix(), /*IsSame=*/true); - R = NestedNameSpecifier::Create(Ctx, P, II); - break; - } - case NestedNameSpecifier::SpecifierKind::Namespace: - case NestedNameSpecifier::SpecifierKind::NamespaceAlias: { - assert(K2 == NestedNameSpecifier::SpecifierKind::Namespace || - K2 == NestedNameSpecifier::SpecifierKind::NamespaceAlias); - // The prefixes for namespaces are not significant, its declaration - // identifies it uniquely. - NestedNameSpecifier *P = - ::getCommonNNS(Ctx, NNS1->getPrefix(), NNS2->getPrefix(), - /*IsSame=*/false); - NamespaceAliasDecl *A1 = NNS1->getAsNamespaceAlias(), - *A2 = NNS2->getAsNamespaceAlias(); - // Are they the same namespace alias? - if (declaresSameEntity(A1, A2)) { - R = NestedNameSpecifier::Create(Ctx, P, ::getCommonDeclChecked(A1, A2)); + NestedNameSpecifier R = std::nullopt; + NestedNameSpecifier::Kind Kind = NNS1.getKind(); + assert(Kind == NNS2.getKind()); + switch (Kind) { + case NestedNameSpecifier::Kind::Namespace: { + auto [Namespace1, Prefix1] = NNS1.getAsNamespaceAndPrefix(); + auto [Namespace2, Prefix2] = NNS2.getAsNamespaceAndPrefix(); + auto Kind = Namespace1->getKind(); + if (Kind != Namespace2->getKind() || + (Kind == Decl::NamespaceAlias && + !declaresSameEntity(Namespace1, Namespace2))) { + R = NestedNameSpecifier( + Ctx, + ::getCommonDeclChecked(Namespace1->getNamespace(), + Namespace2->getNamespace()), + /*Prefix=*/std::nullopt); break; } - // Otherwise, look at the namespaces only. - NamespaceDecl *N1 = A1 ? A1->getNamespace() : NNS1->getAsNamespace(), - *N2 = A2 ? A2->getNamespace() : NNS2->getAsNamespace(); - R = NestedNameSpecifier::Create(Ctx, P, ::getCommonDeclChecked(N1, N2)); + // The prefixes for namespaces are not significant, its declaration + // identifies it uniquely. + NestedNameSpecifier Prefix = ::getCommonNNS(Ctx, Prefix1, Prefix2, + /*IsSame=*/false); + R = NestedNameSpecifier(Ctx, ::getCommonDeclChecked(Namespace1, Namespace2), + Prefix); break; } - case NestedNameSpecifier::SpecifierKind::TypeSpec: { - // FIXME: See comment below, on Super case. - if (K2 == NestedNameSpecifier::SpecifierKind::Super) - return Ctx.getCanonicalNestedNameSpecifier(NNS1); - - assert(K2 == NestedNameSpecifier::SpecifierKind::TypeSpec); - - const Type *T1 = NNS1->getAsType(), *T2 = NNS2->getAsType(); - if (T1 == T2) { - // If the types are indentical, then only the prefixes differ. - // A well-formed NNS never has these types, as they have - // special normalized forms. - assert((!isa(T1))); - // Only for a DependentTemplateSpecializationType the prefix - // is actually significant. A DependentName, which would be another - // plausible case, cannot occur here, as explained above. - bool IsSame = isa(T1); - NestedNameSpecifier *P = - ::getCommonNNS(Ctx, NNS1->getPrefix(), NNS2->getPrefix(), IsSame); - R = NestedNameSpecifier::Create(Ctx, P, T1); - break; - } - // TODO: Try to salvage the original prefix. - // If getCommonSugaredType removed any top level sugar, the original prefix - // is not applicable anymore. + case NestedNameSpecifier::Kind::Type: { + const Type *T1 = NNS1.getAsType(), *T2 = NNS2.getAsType(); const Type *T = Ctx.getCommonSugaredType(QualType(T1, 0), QualType(T2, 0), /*Unqualified=*/true) .getTypePtr(); - - // A NestedNameSpecifier has special normalization rules for certain types. - switch (T->getTypeClass()) { - case Type::Elaborated: { - // An ElaboratedType is stripped off, it's Qualifier becomes the prefix. - auto *ET = cast(T); - R = NestedNameSpecifier::Create(Ctx, ET->getQualifier(), - ET->getNamedType().getTypePtr()); - break; - } - case Type::DependentName: { - // A DependentName is turned into an Identifier NNS. - auto *DN = cast(T); - R = NestedNameSpecifier::Create(Ctx, DN->getQualifier(), - DN->getIdentifier()); - break; - } - case Type::DependentTemplateSpecialization: { - // A DependentTemplateSpecializationType loses it's Qualifier, which - // is turned into the prefix. - auto *DTST = cast(T); - const DependentTemplateStorage &DTN = DTST->getDependentTemplateName(); - DependentTemplateStorage NewDTN(/*Qualifier=*/nullptr, DTN.getName(), - DTN.hasTemplateKeyword()); - T = Ctx.getDependentTemplateSpecializationType(DTST->getKeyword(), NewDTN, - DTST->template_arguments()) - .getTypePtr(); - R = NestedNameSpecifier::Create(Ctx, DTN.getQualifier(), T); - break; - } - default: - R = NestedNameSpecifier::Create(Ctx, /*Prefix=*/nullptr, T); - break; - } + R = NestedNameSpecifier(T); break; } - case NestedNameSpecifier::SpecifierKind::Super: + case NestedNameSpecifier::Kind::Super: { // FIXME: Can __super even be used with data members? // If it's only usable in functions, we will never see it here, // unless we save the qualifiers used in function types. // In that case, it might be possible NNS2 is a type, // in which case we should degrade the result to // a CXXRecordType. - return Ctx.getCanonicalNestedNameSpecifier(NNS1); - case NestedNameSpecifier::SpecifierKind::Global: - // The global NNS is a singleton. - assert(K2 == NestedNameSpecifier::SpecifierKind::Global && - "Global NNS cannot be equivalent to any other kind"); - llvm_unreachable("Global NestedNameSpecifiers did not compare equal"); - } - assert(Ctx.getCanonicalNestedNameSpecifier(R) == Canon); + R = NestedNameSpecifier( + getCommonDeclChecked(NNS1.getAsSuper(), NNS2.getAsSuper())); + break; + } + case NestedNameSpecifier::Kind::Null: + case NestedNameSpecifier::Kind::Global: + // These are singletons. + llvm_unreachable("singletons did not compare equal"); + } + assert(R.getCanonical() == Canon); return R; } template -static NestedNameSpecifier *getCommonQualifier(ASTContext &Ctx, const T *X, - const T *Y, bool IsSame) { +static NestedNameSpecifier getCommonQualifier(const ASTContext &Ctx, const T *X, + const T *Y, bool IsSame) { return ::getCommonNNS(Ctx, X->getQualifier(), Y->getQualifier(), IsSame); } template -static QualType getCommonElementType(ASTContext &Ctx, const T *X, const T *Y) { +static QualType getCommonElementType(const ASTContext &Ctx, const T *X, + const T *Y) { return Ctx.getCommonSugaredType(X->getElementType(), Y->getElementType()); } template -static QualType getCommonArrayElementType(ASTContext &Ctx, const T *X, +static QualType getCommonArrayElementType(const ASTContext &Ctx, const T *X, Qualifiers &QX, const T *Y, Qualifiers &QY) { QualType EX = X->getElementType(), EY = Y->getElementType(); @@ -13836,11 +13873,13 @@ static QualType getCommonArrayElementType(ASTContext &Ctx, const T *X, } template -static QualType getCommonPointeeType(ASTContext &Ctx, const T *X, const T *Y) { +static QualType getCommonPointeeType(const ASTContext &Ctx, const T *X, + const T *Y) { return Ctx.getCommonSugaredType(X->getPointeeType(), Y->getPointeeType()); } -template static auto *getCommonSizeExpr(ASTContext &Ctx, T *X, T *Y) { +template +static auto *getCommonSizeExpr(const ASTContext &Ctx, T *X, T *Y) { assert(Ctx.hasSameExpr(X->getSizeExpr(), Y->getSizeExpr())); return X->getSizeExpr(); } @@ -13860,8 +13899,9 @@ static auto getCommonIndexTypeCVRQualifiers(const ArrayType *X, // each type (in a canonical sense) only once, in the order they appear // from X to Y. If they occur in both X and Y, the result will contain // the common sugared type between them. -static void mergeTypeLists(ASTContext &Ctx, SmallVectorImpl &Out, - ArrayRef X, ArrayRef Y) { +static void mergeTypeLists(const ASTContext &Ctx, + SmallVectorImpl &Out, ArrayRef X, + ArrayRef Y) { llvm::DenseMap Found; for (auto Ts : {X, Y}) { for (QualType T : Ts) { @@ -13880,7 +13920,7 @@ FunctionProtoType::ExceptionSpecInfo ASTContext::mergeExceptionSpecs(FunctionProtoType::ExceptionSpecInfo ESI1, FunctionProtoType::ExceptionSpecInfo ESI2, SmallVectorImpl &ExceptionTypeStorage, - bool AcceptDependent) { + bool AcceptDependent) const { ExceptionSpecificationType EST1 = ESI1.Type, EST2 = ESI2.Type; // If either of them can throw anything, that is the result. @@ -13944,7 +13984,7 @@ ASTContext::mergeExceptionSpecs(FunctionProtoType::ExceptionSpecInfo ESI1, llvm_unreachable("invalid ExceptionSpecificationType"); } -static QualType getCommonNonSugarTypeNode(ASTContext &Ctx, const Type *X, +static QualType getCommonNonSugarTypeNode(const ASTContext &Ctx, const Type *X, Qualifiers &QX, const Type *Y, Qualifiers &QY) { Type::TypeClass TC = X->getTypeClass(); @@ -13962,10 +14002,8 @@ static QualType getCommonNonSugarTypeNode(ASTContext &Ctx, const Type *X, SUGAR_FREE_TYPE(Builtin) SUGAR_FREE_TYPE(DeducedTemplateSpecialization) SUGAR_FREE_TYPE(DependentBitInt) - SUGAR_FREE_TYPE(Enum) SUGAR_FREE_TYPE(BitInt) SUGAR_FREE_TYPE(ObjCInterface) - SUGAR_FREE_TYPE(Record) SUGAR_FREE_TYPE(SubstTemplateTypeParmPack) SUGAR_FREE_TYPE(UnresolvedUsing) SUGAR_FREE_TYPE(HLSLAttributedResource) @@ -14183,13 +14221,15 @@ static QualType getCommonNonSugarTypeNode(ASTContext &Ctx, const Type *X, getCommonElementType(Ctx, VX, VY), getCommonSizeExpr(Ctx, VX, VY), getCommonAttrLoc(VX, VY), VX->getVectorKind()); } + case Type::Enum: + case Type::Record: case Type::InjectedClassName: { - const auto *IX = cast(X), - *IY = cast(Y); - return Ctx.getInjectedClassNameType( - getCommonDeclChecked(IX->getDecl(), IY->getDecl()), - Ctx.getCommonSugaredType(IX->getInjectedSpecializationType(), - IY->getInjectedSpecializationType())); + const auto *TX = cast(X), *TY = cast(Y); + return Ctx.getTagType( + ::getCommonTypeKeyword(TX, TY, /*IsSame=*/false), + ::getCommonQualifier(Ctx, TX, TY, /*IsSame=*/false), + ::getCommonDeclChecked(TX->getOriginalDecl(), TY->getOriginalDecl()), + /*OwnedTag=*/false); } case Type::TemplateSpecialization: { const auto *TX = cast(X), @@ -14197,6 +14237,7 @@ static QualType getCommonNonSugarTypeNode(ASTContext &Ctx, const Type *X, auto As = getCommonTemplateArguments(Ctx, TX->template_arguments(), TY->template_arguments()); return Ctx.getTemplateSpecializationType( + getCommonTypeKeyword(TX, TY, /*IsSame=*/false), ::getCommonTemplateNameChecked(Ctx, TX->getTemplateName(), TY->getTemplateName(), /*IgnoreDeduced=*/true), @@ -14224,7 +14265,7 @@ static QualType getCommonNonSugarTypeNode(ASTContext &Ctx, const Type *X, *NY = cast(Y); assert(NX->getIdentifier() == NY->getIdentifier()); return Ctx.getDependentNameType( - getCommonTypeKeyword(NX, NY), + getCommonTypeKeyword(NX, NY, /*IsSame=*/true), getCommonQualifier(Ctx, NX, NY, /*IsSame=*/true), NX->getIdentifier()); } case Type::DependentTemplateSpecialization: { @@ -14240,7 +14281,7 @@ static QualType getCommonNonSugarTypeNode(ASTContext &Ctx, const Type *X, /*IsSame=*/true), SX.getName(), SX.hasTemplateKeyword() || SY.hasTemplateKeyword()); return Ctx.getDependentTemplateSpecializationType( - getCommonTypeKeyword(TX, TY), Name, As); + getCommonTypeKeyword(TX, TY, /*IsSame=*/true), Name, As); } case Type::UnaryTransform: { const auto *TX = cast(X), @@ -14281,7 +14322,7 @@ static QualType getCommonNonSugarTypeNode(ASTContext &Ctx, const Type *X, llvm_unreachable("Unknown Type Class"); } -static QualType getCommonSugarTypeNode(ASTContext &Ctx, const Type *X, +static QualType getCommonSugarTypeNode(const ASTContext &Ctx, const Type *X, const Type *Y, SplitQualType Underlying) { Type::TypeClass TC = X->getTypeClass(); @@ -14296,6 +14337,8 @@ static QualType getCommonSugarTypeNode(ASTContext &Ctx, const Type *X, #include "clang/AST/TypeNodes.inc" #define CANONICAL_TYPE(Class) UNEXPECTED_TYPE(Class, "canonical") + CANONICAL_TYPE(Record) + CANONICAL_TYPE(Enum) CANONICAL_TYPE(Atomic) CANONICAL_TYPE(BitInt) CANONICAL_TYPE(BlockPointer) @@ -14304,7 +14347,6 @@ static QualType getCommonSugarTypeNode(ASTContext &Ctx, const Type *X, CANONICAL_TYPE(ConstantArray) CANONICAL_TYPE(ArrayParameter) CANONICAL_TYPE(ConstantMatrix) - CANONICAL_TYPE(Enum) CANONICAL_TYPE(ExtVector) CANONICAL_TYPE(FunctionNoProto) CANONICAL_TYPE(FunctionProto) @@ -14317,7 +14359,6 @@ static QualType getCommonSugarTypeNode(ASTContext &Ctx, const Type *X, CANONICAL_TYPE(ObjCObjectPointer) CANONICAL_TYPE(Pipe) CANONICAL_TYPE(Pointer) - CANONICAL_TYPE(Record) CANONICAL_TYPE(RValueReference) CANONICAL_TYPE(VariableArray) CANONICAL_TYPE(Vector) @@ -14393,15 +14434,6 @@ static QualType getCommonSugarTypeNode(ASTContext &Ctx, const Type *X, case Type::DeducedTemplateSpecialization: // FIXME: Try to merge these. return QualType(); - - case Type::Elaborated: { - const auto *EX = cast(X), *EY = cast(Y); - return Ctx.getElaboratedType( - ::getCommonTypeKeyword(EX, EY), - ::getCommonQualifier(Ctx, EX, EY, /*IsSame=*/false), - Ctx.getQualifiedType(Underlying), - ::getCommonDecl(EX->getOwnedTagDecl(), EY->getOwnedTagDecl())); - } case Type::MacroQualified: { const auto *MX = cast(X), *MY = cast(Y); @@ -14445,16 +14477,19 @@ static QualType getCommonSugarTypeNode(ASTContext &Ctx, const Type *X, if (getCommonTemplateArguments(Ctx, As, TX->template_arguments(), TY->template_arguments())) return QualType(); - return Ctx.getTemplateSpecializationType(CTN, As, - /*CanonicalArgs=*/{}, - Ctx.getQualifiedType(Underlying)); + return Ctx.getTemplateSpecializationType( + getCommonTypeKeyword(TX, TY, /*IsSame=*/false), CTN, As, + /*CanonicalArgs=*/{}, Ctx.getQualifiedType(Underlying)); } case Type::Typedef: { const auto *TX = cast(X), *TY = cast(Y); const TypedefNameDecl *CD = ::getCommonDecl(TX->getDecl(), TY->getDecl()); if (!CD) return QualType(); - return Ctx.getTypedefType(CD, Ctx.getQualifiedType(Underlying)); + return Ctx.getTypedefType( + ::getCommonTypeKeyword(TX, TY, /*IsSame=*/false), + ::getCommonQualifier(Ctx, TX, TY, /*IsSame=*/false), CD, + Ctx.getQualifiedType(Underlying)); } case Type::TypeOf: { // The common sugar between two typeof expressions, where one is @@ -14485,11 +14520,12 @@ static QualType getCommonSugarTypeNode(ASTContext &Ctx, const Type *X, } case Type::Using: { const auto *UX = cast(X), *UY = cast(Y); - const UsingShadowDecl *CD = - ::getCommonDecl(UX->getFoundDecl(), UY->getFoundDecl()); + const UsingShadowDecl *CD = ::getCommonDecl(UX->getDecl(), UY->getDecl()); if (!CD) return QualType(); - return Ctx.getUsingType(CD, Ctx.getQualifiedType(Underlying)); + return Ctx.getUsingType(::getCommonTypeKeyword(UX, UY, /*IsSame=*/false), + ::getCommonQualifier(Ctx, UX, UY, /*IsSame=*/false), + CD, Ctx.getQualifiedType(Underlying)); } case Type::MemberPointer: { const auto *PX = cast(X), @@ -14544,7 +14580,7 @@ static auto unwrapSugar(SplitQualType &T, Qualifiers &QTotal) { } QualType ASTContext::getCommonSugaredType(QualType X, QualType Y, - bool Unqualified) { + bool Unqualified) const { assert(Unqualified ? hasSameUnqualifiedType(X, Y) : hasSameType(X, Y)); if (X == Y) return X; diff --git a/clang/lib/AST/ASTDiagnostic.cpp b/clang/lib/AST/ASTDiagnostic.cpp index 0fa9234159f22..830e34b00d88e 100644 --- a/clang/lib/AST/ASTDiagnostic.cpp +++ b/clang/lib/AST/ASTDiagnostic.cpp @@ -36,11 +36,6 @@ QualType clang::desugarForDiagnostic(ASTContext &Context, QualType QT, while (true) { const Type *Ty = QC.strip(QT); - // Don't aka just because we saw an elaborated type... - if (const ElaboratedType *ET = dyn_cast(Ty)) { - QT = ET->desugar(); - continue; - } // ... or a using type ... if (const UsingType *UT = dyn_cast(Ty)) { QT = UT->desugar(); @@ -130,7 +125,8 @@ QualType clang::desugarForDiagnostic(ASTContext &Context, QualType QT, if (DesugarArgument) { ShouldAKA = true; QT = Context.getTemplateSpecializationType( - TST->getTemplateName(), Args, /*CanonicalArgs=*/{}, QT); + TST->getKeyword(), TST->getTemplateName(), Args, + /*CanonicalArgs=*/{}, QT); } break; } @@ -200,7 +196,8 @@ break; \ // Don't desugar through the primary typedef of an anonymous type. if (const TagType *UTT = Underlying->getAs()) if (const TypedefType *QTT = dyn_cast(QT)) - if (UTT->getDecl()->getTypedefNameForAnonDecl() == QTT->getDecl()) + if (UTT->getOriginalDecl()->getTypedefNameForAnonDecl() == + QTT->getDecl()) break; // Record that we actually looked through an opaque type here. @@ -461,13 +458,12 @@ void clang::FormatASTNodeDiagnosticArgument( ND->getNameForDiagnostic(OS, Context.getPrintingPolicy(), Qualified); break; } - case DiagnosticsEngine::ak_nestednamespec: { - NestedNameSpecifier *NNS = reinterpret_cast(Val); - NNS->print(OS, Context.getPrintingPolicy(), + case DiagnosticsEngine::ak_nestednamespec: + NestedNameSpecifier::getFromVoidPointer(reinterpret_cast(Val)) + .print(OS, Context.getPrintingPolicy(), /*ResolveTemplateArguments=*/false, /*PrintFinalScopeResOp=*/false); break; - } case DiagnosticsEngine::ak_declcontext: { DeclContext *DC = reinterpret_cast (Val); assert(DC && "Should never have a null declaration context"); @@ -484,9 +480,8 @@ void clang::FormatASTNodeDiagnosticArgument( } else if (isLambdaCallOperator(DC)) { OS << "lambda expression"; } else if (TypeDecl *Type = dyn_cast(DC)) { - OS << ConvertTypeToDiagnosticString(Context, - Context.getTypeDeclType(Type), - PrevArgs, QualTypeVals); + OS << ConvertTypeToDiagnosticString( + Context, Context.getTypeDeclType(Type), PrevArgs, QualTypeVals); } else { assert(isa(DC) && "Expected a NamedDecl"); NamedDecl *ND = cast(DC); @@ -1158,12 +1153,13 @@ class TemplateDiff { return nullptr; const ClassTemplateSpecializationDecl *CTSD = - dyn_cast(RT->getDecl()); + dyn_cast(RT->getOriginalDecl()); if (!CTSD) return nullptr; Ty = Context.getTemplateSpecializationType( + ElaboratedTypeKeyword::None, TemplateName(CTSD->getSpecializedTemplate()), CTSD->getTemplateArgs().asArray(), /*CanonicalArgs=*/{}, Ty.getLocalUnqualifiedType().getCanonicalType()); @@ -1743,25 +1739,10 @@ class TemplateDiff { std::string FromTypeStr = FromType.isNull() ? "(no argument)" : FromType.getAsString(Policy); - std::string ToTypeStr = ToType.isNull() ? "(no argument)" - : ToType.getAsString(Policy); - // Print without ElaboratedType sugar if it is better. + std::string ToTypeStr = + ToType.isNull() ? "(no argument)" : ToType.getAsString(Policy); // TODO: merge this with other aka printing above. if (FromTypeStr == ToTypeStr) { - const auto *FromElTy = dyn_cast(FromType), - *ToElTy = dyn_cast(ToType); - if (FromElTy || ToElTy) { - std::string FromNamedTypeStr = - FromElTy ? FromElTy->getNamedType().getAsString(Policy) - : FromTypeStr; - std::string ToNamedTypeStr = - ToElTy ? ToElTy->getNamedType().getAsString(Policy) : ToTypeStr; - if (FromNamedTypeStr != ToNamedTypeStr) { - FromTypeStr = FromNamedTypeStr; - ToTypeStr = ToNamedTypeStr; - goto PrintTypes; - } - } // Switch to canonical typename if it is better. std::string FromCanTypeStr = FromType.getCanonicalType().getAsString(Policy); @@ -1772,8 +1753,8 @@ class TemplateDiff { } } - PrintTypes: - if (PrintTree) OS << '['; + if (PrintTree) + OS << '['; OS << (FromDefault ? "(default) " : ""); Bold(); OS << FromTypeStr; diff --git a/clang/lib/AST/ASTDumper.cpp b/clang/lib/AST/ASTDumper.cpp index 5e4487e0687d3..8e651a0a68629 100644 --- a/clang/lib/AST/ASTDumper.cpp +++ b/clang/lib/AST/ASTDumper.cpp @@ -117,7 +117,9 @@ void ASTDumper::dumpTemplateDeclSpecialization(const SpecializationDecl *D, // FIXME: The redecls() range sometimes has elements of a less-specific // type. (In particular, ClassTemplateSpecializationDecl::redecls() gives // us TagDecls, and should give CXXRecordDecls). - auto *Redecl = cast(RedeclWithBadType); + auto *Redecl = dyn_cast(RedeclWithBadType); + if (!Redecl) + continue; switch (Redecl->getTemplateSpecializationKind()) { case TSK_ExplicitInstantiationDeclaration: case TSK_ExplicitInstantiationDefinition: diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index 90d309e49b264..cd9af82358960 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -933,8 +933,10 @@ ASTNodeImporter::import(const TemplateArgumentLoc &TALoc) { else return TSIOrErr.takeError(); } else { - auto ToTemplateQualifierLocOrErr = - import(FromInfo.getTemplateQualifierLoc()); + auto ToTemplateKWLocOrErr = import(FromInfo.getTemplateKwLoc()); + if (!ToTemplateKWLocOrErr) + return ToTemplateKWLocOrErr.takeError(); + auto ToTemplateQualifierLocOrErr = import(TALoc.getTemplateQualifierLoc()); if (!ToTemplateQualifierLocOrErr) return ToTemplateQualifierLocOrErr.takeError(); auto ToTemplateNameLocOrErr = import(FromInfo.getTemplateNameLoc()); @@ -945,8 +947,9 @@ ASTNodeImporter::import(const TemplateArgumentLoc &TALoc) { if (!ToTemplateEllipsisLocOrErr) return ToTemplateEllipsisLocOrErr.takeError(); ToInfo = TemplateArgumentLocInfo( - Importer.getToContext(), *ToTemplateQualifierLocOrErr, - *ToTemplateNameLocOrErr, *ToTemplateEllipsisLocOrErr); + Importer.getToContext(), *ToTemplateKWLocOrErr, + *ToTemplateQualifierLocOrErr, *ToTemplateNameLocOrErr, + *ToTemplateEllipsisLocOrErr); } return TemplateArgumentLoc(Arg, ToInfo); @@ -1410,13 +1413,15 @@ ASTNodeImporter::VisitFunctionProtoType(const FunctionProtoType *T) { ExpectedType ASTNodeImporter::VisitUnresolvedUsingType( const UnresolvedUsingType *T) { Error Err = Error::success(); - auto ToD = importChecked(Err, T->getDecl()); - auto ToPrevD = importChecked(Err, T->getDecl()->getPreviousDecl()); + auto ToQualifier = importChecked(Err, T->getQualifier()); + auto *ToD = importChecked(Err, T->getDecl()); if (Err) return std::move(Err); - return Importer.getToContext().getTypeDeclType( - ToD, cast_or_null(ToPrevD)); + if (T->isCanonicalUnqualified()) + return Importer.getToContext().getCanonicalUnresolvedUsingType(ToD); + return Importer.getToContext().getUnresolvedUsingType(T->getKeyword(), + ToQualifier, ToD); } ExpectedType ASTNodeImporter::VisitParenType(const ParenType *T) { @@ -1444,15 +1449,17 @@ ExpectedType ASTNodeImporter::VisitTypedefType(const TypedefType *T) { if (!ToDeclOrErr) return ToDeclOrErr.takeError(); - TypedefNameDecl *ToDecl = *ToDeclOrErr; - if (ToDecl->getTypeForDecl()) - return QualType(ToDecl->getTypeForDecl(), 0); + auto ToQualifierOrErr = import(T->getQualifier()); + if (!ToQualifierOrErr) + return ToQualifierOrErr.takeError(); - ExpectedType ToUnderlyingTypeOrErr = import(T->desugar()); + ExpectedType ToUnderlyingTypeOrErr = + T->typeMatchesDecl() ? QualType() : import(T->desugar()); if (!ToUnderlyingTypeOrErr) return ToUnderlyingTypeOrErr.takeError(); - return Importer.getToContext().getTypedefType(ToDecl, *ToUnderlyingTypeOrErr); + return Importer.getToContext().getTypedefType( + T->getKeyword(), *ToQualifierOrErr, *ToDeclOrErr, *ToUnderlyingTypeOrErr); } ExpectedType ASTNodeImporter::VisitTypeOfExprType(const TypeOfExprType *T) { @@ -1471,14 +1478,14 @@ ExpectedType ASTNodeImporter::VisitTypeOfType(const TypeOfType *T) { } ExpectedType ASTNodeImporter::VisitUsingType(const UsingType *T) { - Expected FoundOrErr = import(T->getFoundDecl()); - if (!FoundOrErr) - return FoundOrErr.takeError(); - Expected UnderlyingOrErr = import(T->getUnderlyingType()); - if (!UnderlyingOrErr) - return UnderlyingOrErr.takeError(); - - return Importer.getToContext().getUsingType(*FoundOrErr, *UnderlyingOrErr); + Error Err = Error::success(); + auto ToQualifier = importChecked(Err, T->getQualifier()); + auto *ToD = importChecked(Err, T->getDecl()); + QualType ToT = importChecked(Err, T->desugar()); + if (Err) + return std::move(Err); + return Importer.getToContext().getUsingType(T->getKeyword(), ToQualifier, ToD, + ToT); } ExpectedType ASTNodeImporter::VisitDecltypeType(const DecltypeType *T) { @@ -1541,36 +1548,37 @@ ExpectedType ASTNodeImporter::VisitDeducedTemplateSpecializationType( return ToDeducedTypeOrErr.takeError(); return Importer.getToContext().getDeducedTemplateSpecializationType( - *ToTemplateNameOrErr, *ToDeducedTypeOrErr, T->isDependentType()); + T->getKeyword(), *ToTemplateNameOrErr, *ToDeducedTypeOrErr, + T->isDependentType()); } -ExpectedType ASTNodeImporter::VisitInjectedClassNameType( - const InjectedClassNameType *T) { - Expected ToDeclOrErr = import(T->getDecl()); +ExpectedType ASTNodeImporter::VisitTagType(const TagType *T) { + Expected ToDeclOrErr = import(T->getOriginalDecl()); if (!ToDeclOrErr) return ToDeclOrErr.takeError(); - // The InjectedClassNameType is created in VisitRecordDecl when the - // T->getDecl() is imported. Here we can return the existing type. - const Type *Ty = (*ToDeclOrErr)->getTypeForDecl(); - assert(isa_and_nonnull(Ty)); - return QualType(Ty, 0); -} + if (T->isCanonicalUnqualified()) + return Importer.getToContext().getCanonicalTagType(*ToDeclOrErr); -ExpectedType ASTNodeImporter::VisitRecordType(const RecordType *T) { - Expected ToDeclOrErr = import(T->getDecl()); - if (!ToDeclOrErr) - return ToDeclOrErr.takeError(); + auto ToQualifierOrErr = import(T->getQualifier()); + if (!ToQualifierOrErr) + return ToQualifierOrErr.takeError(); - return Importer.getToContext().getTagDeclType(*ToDeclOrErr); + return Importer.getToContext().getTagType(T->getKeyword(), *ToQualifierOrErr, + *ToDeclOrErr, T->isTagOwned()); } ExpectedType ASTNodeImporter::VisitEnumType(const EnumType *T) { - Expected ToDeclOrErr = import(T->getDecl()); - if (!ToDeclOrErr) - return ToDeclOrErr.takeError(); + return VisitTagType(T); +} - return Importer.getToContext().getTagDeclType(*ToDeclOrErr); +ExpectedType ASTNodeImporter::VisitRecordType(const RecordType *T) { + return VisitTagType(T); +} + +ExpectedType +ASTNodeImporter::VisitInjectedClassNameType(const InjectedClassNameType *T) { + return VisitTagType(T); } ExpectedType ASTNodeImporter::VisitAttributedType(const AttributedType *T) { @@ -1663,27 +1671,8 @@ ExpectedType ASTNodeImporter::VisitTemplateSpecializationType( if (!ToUnderlyingOrErr) return ToUnderlyingOrErr.takeError(); return Importer.getToContext().getTemplateSpecializationType( - *ToTemplateOrErr, ToTemplateArgs, {}, *ToUnderlyingOrErr); -} - -ExpectedType ASTNodeImporter::VisitElaboratedType(const ElaboratedType *T) { - // Note: the qualifier in an ElaboratedType is optional. - auto ToQualifierOrErr = import(T->getQualifier()); - if (!ToQualifierOrErr) - return ToQualifierOrErr.takeError(); - - ExpectedType ToNamedTypeOrErr = import(T->getNamedType()); - if (!ToNamedTypeOrErr) - return ToNamedTypeOrErr.takeError(); - - Expected ToOwnedTagDeclOrErr = import(T->getOwnedTagDecl()); - if (!ToOwnedTagDeclOrErr) - return ToOwnedTagDeclOrErr.takeError(); - - return Importer.getToContext().getElaboratedType(T->getKeyword(), - *ToQualifierOrErr, - *ToNamedTypeOrErr, - *ToOwnedTagDeclOrErr); + T->getKeyword(), *ToTemplateOrErr, ToTemplateArgs, {}, + *ToUnderlyingOrErr); } ExpectedType @@ -1976,7 +1965,7 @@ Error ASTNodeImporter::ImportDeclParts( const Type *LeafT = getLeafPointeeType(P->getType().getCanonicalType().getTypePtr()); auto *RT = dyn_cast(LeafT); - if (RT && RT->getDecl() == D) { + if (RT && RT->getOriginalDecl() == D) { Importer.FromDiag(D->getLocation(), diag::err_unsupported_ast_node) << D->getDeclKindName(); return make_error(ASTImportError::UnsupportedConstruct); @@ -2229,8 +2218,8 @@ Error ASTNodeImporter::ImportFieldDeclDefinition(const FieldDecl *From, const RecordType *RecordTo = ToType->getAs(); if (RecordFrom && RecordTo) { - FromRecordDecl = RecordFrom->getDecl(); - ToRecordDecl = RecordTo->getDecl(); + FromRecordDecl = RecordFrom->getOriginalDecl(); + ToRecordDecl = RecordTo->getOriginalDecl(); } } @@ -2451,7 +2440,7 @@ Error ASTNodeImporter::ImportDefinition( return Err; ExpectedType ToTypeOrErr = - import(Importer.getFromContext().getTypeDeclType(From)); + import(QualType(Importer.getFromContext().getCanonicalTagType(From))); if (!ToTypeOrErr) return ToTypeOrErr.takeError(); @@ -3026,7 +3015,7 @@ ExpectedDecl ASTNodeImporter::VisitEnumDecl(EnumDecl *D) { if (auto *Typedef = dyn_cast(FoundDecl)) { if (const auto *Tag = Typedef->getUnderlyingType()->getAs()) - FoundDecl = Tag->getDecl(); + FoundDecl = Tag->getOriginalDecl(); } if (auto *FoundEnum = dyn_cast(FoundDecl)) { @@ -3157,7 +3146,7 @@ ExpectedDecl ASTNodeImporter::VisitRecordDecl(RecordDecl *D) { Decl *Found = FoundDecl; if (auto *Typedef = dyn_cast(Found)) { if (const auto *Tag = Typedef->getUnderlyingType()->getAs()) - Found = Tag->getDecl(); + Found = Tag->getOriginalDecl(); } if (auto *FoundRecord = dyn_cast(Found)) { @@ -3236,17 +3225,6 @@ ExpectedDecl ASTNodeImporter::VisitRecordDecl(RecordDecl *D) { return CDeclOrErr.takeError(); Numbering.ContextDecl = *CDeclOrErr; D2CXX->setLambdaNumbering(Numbering); - } else if (DCXX->isInjectedClassName()) { - // We have to be careful to do a similar dance to the one in - // Sema::ActOnStartCXXMemberDeclarations - const bool DelayTypeCreation = true; - if (GetImportedOrCreateDecl( - D2CXX, D, Importer.getToContext(), D->getTagKind(), DC, - *BeginLocOrErr, Loc, Name.getAsIdentifierInfo(), - cast_or_null(PrevDecl), DelayTypeCreation)) - return D2CXX; - Importer.getToContext().getTypeDeclType( - D2CXX, dyn_cast(DC)); } else { if (GetImportedOrCreateDecl(D2CXX, D, Importer.getToContext(), D->getTagKind(), DC, *BeginLocOrErr, Loc, @@ -3266,51 +3244,6 @@ ExpectedDecl ASTNodeImporter::VisitRecordDecl(RecordDecl *D) { if (Error Err = importInto(ToDescribed, FromDescribed)) return std::move(Err); D2CXX->setDescribedClassTemplate(ToDescribed); - if (!DCXX->isInjectedClassName() && !IsFriendTemplate) { - // In a record describing a template the type should be an - // InjectedClassNameType (see Sema::CheckClassTemplate). Update the - // previously set type to the correct value here (ToDescribed is not - // available at record create). - CXXRecordDecl *Injected = nullptr; - for (NamedDecl *Found : D2CXX->noload_lookup(Name)) { - auto *Record = dyn_cast(Found); - if (Record && Record->isInjectedClassName()) { - Injected = Record; - break; - } - } - // Create an injected type for the whole redecl chain. - // The chain may contain an already existing injected type at the start, - // if yes this should be reused. We must ensure that only one type - // object exists for the injected type (including the injected record - // declaration), ASTContext does not check it. - SmallVector Redecls = - getCanonicalForwardRedeclChain(D2CXX); - const Type *FrontTy = - cast(Redecls.front())->getTypeForDecl(); - QualType InjSpec; - if (auto *InjTy = FrontTy->getAs()) - InjSpec = InjTy->getInjectedSpecializationType(); - else - InjSpec = ToDescribed->getInjectedClassNameSpecialization(); - for (auto *R : Redecls) { - auto *RI = cast(R); - if (R != Redecls.front() || - !isa(RI->getTypeForDecl())) - RI->setTypeForDecl(nullptr); - // This function tries to get the injected type from getTypeForDecl, - // then from the previous declaration if possible. If not, it creates - // a new type. - Importer.getToContext().getInjectedClassNameType(RI, InjSpec); - } - // Set the new type for the injected decl too. - if (Injected) { - Injected->setTypeForDecl(nullptr); - // This function will copy the injected type from D2CXX into Injected. - // The injected decl does not have a previous decl to copy from. - Importer.getToContext().getTypeDeclType(Injected, D2CXX); - } - } } else if (MemberSpecializationInfo *MemberInfo = DCXX->getMemberSpecializationInfo()) { TemplateSpecializationKind SK = @@ -3634,11 +3567,12 @@ class IsTypeDeclaredInsideVisitor } std::optional VisitTagType(const TagType *T) { - if (auto *Spec = dyn_cast(T->getDecl())) + if (auto *Spec = + dyn_cast(T->getOriginalDecl())) for (const auto &Arg : Spec->getTemplateArgs().asArray()) if (checkTemplateArgument(Arg)) return true; - return isAncestorDeclContextOf(ParentDC, T->getDecl()); + return isAncestorDeclContextOf(ParentDC, T->getOriginalDecl()); } std::optional VisitPointerType(const PointerType *T) { @@ -3650,17 +3584,11 @@ class IsTypeDeclaredInsideVisitor } std::optional VisitTypedefType(const TypedefType *T) { - const TypedefNameDecl *TD = T->getDecl(); - assert(TD); - return isAncestorDeclContextOf(ParentDC, TD); + return isAncestorDeclContextOf(ParentDC, T->getDecl()); } std::optional VisitUsingType(const UsingType *T) { - if (T->getFoundDecl() && - isAncestorDeclContextOf(ParentDC, T->getFoundDecl())) - return true; - - return {}; + return isAncestorDeclContextOf(ParentDC, T->getDecl()); } std::optional @@ -6329,16 +6257,10 @@ ExpectedDecl ASTNodeImporter::VisitClassTemplateSpecializationDecl( // Create the specialization. ClassTemplateSpecializationDecl *D2 = nullptr; if (PartialSpec) { - QualType CanonInjType; - if (Error Err = importInto( - CanonInjType, PartialSpec->getInjectedSpecializationType())) - return std::move(Err); - CanonInjType = CanonInjType.getCanonicalType(); - if (GetImportedOrCreateDecl( D2, D, Importer.getToContext(), D->getTagKind(), DC, *BeginLocOrErr, *IdLocOrErr, ToTPList, ClassTemplate, ArrayRef(TemplateArgs), - CanonInjType, + /*CanonInjectedTST=*/CanQualType(), cast_or_null(PrevDecl))) return D2; @@ -9758,53 +9680,34 @@ Expected ASTImporter::Import(Stmt *FromS) { return ToSOrErr; } -Expected -ASTImporter::Import(NestedNameSpecifier *FromNNS) { - if (!FromNNS) - return nullptr; - - NestedNameSpecifier *Prefix = nullptr; - if (Error Err = importInto(Prefix, FromNNS->getPrefix())) - return std::move(Err); - - switch (FromNNS->getKind()) { - case NestedNameSpecifier::Identifier: - assert(FromNNS->getAsIdentifier() && "NNS should contain identifier."); - return NestedNameSpecifier::Create(ToContext, Prefix, - Import(FromNNS->getAsIdentifier())); - - case NestedNameSpecifier::Namespace: - if (ExpectedDecl NSOrErr = Import(FromNNS->getAsNamespace())) { - return NestedNameSpecifier::Create(ToContext, Prefix, - cast(*NSOrErr)); - } else +Expected ASTImporter::Import(NestedNameSpecifier FromNNS) { + switch (FromNNS.getKind()) { + case NestedNameSpecifier::Kind::Null: + case NestedNameSpecifier::Kind::Global: + return FromNNS; + case NestedNameSpecifier::Kind::Namespace: { + auto [Namespace, Prefix] = FromNNS.getAsNamespaceAndPrefix(); + auto NSOrErr = Import(Namespace); + if (!NSOrErr) return NSOrErr.takeError(); - - case NestedNameSpecifier::NamespaceAlias: - if (ExpectedDecl NSADOrErr = Import(FromNNS->getAsNamespaceAlias())) - return NestedNameSpecifier::Create(ToContext, Prefix, - cast(*NSADOrErr)); - else - return NSADOrErr.takeError(); - - case NestedNameSpecifier::Global: - return NestedNameSpecifier::GlobalSpecifier(ToContext); - - case NestedNameSpecifier::Super: - if (ExpectedDecl RDOrErr = Import(FromNNS->getAsRecordDecl())) - return NestedNameSpecifier::SuperSpecifier(ToContext, - cast(*RDOrErr)); + auto PrefixOrErr = Import(Prefix); + if (!PrefixOrErr) + return PrefixOrErr.takeError(); + return NestedNameSpecifier(ToContext, cast(*NSOrErr), + Prefix); + } + case NestedNameSpecifier::Kind::Super: + if (ExpectedDecl RDOrErr = Import(FromNNS.getAsSuper())) + return NestedNameSpecifier(cast(*RDOrErr)); else return RDOrErr.takeError(); - - case NestedNameSpecifier::TypeSpec: - if (ExpectedTypePtr TyOrErr = Import(FromNNS->getAsType())) { - return NestedNameSpecifier::Create(ToContext, Prefix, *TyOrErr); + case NestedNameSpecifier::Kind::Type: + if (ExpectedTypePtr TyOrErr = Import(FromNNS.getAsType())) { + return NestedNameSpecifier(*TyOrErr); } else { return TyOrErr.takeError(); } } - llvm_unreachable("Invalid nested name specifier kind"); } @@ -9818,69 +9721,62 @@ ASTImporter::Import(NestedNameSpecifierLoc FromNNS) { // serialization in reverse order. while (NNS) { NestedNames.push_back(NNS); - NNS = NNS.getPrefix(); + NNS = NNS.getAsNamespaceAndPrefix().Prefix; } NestedNameSpecifierLocBuilder Builder; while (!NestedNames.empty()) { NNS = NestedNames.pop_back_val(); - NestedNameSpecifier *Spec = nullptr; + NestedNameSpecifier Spec = std::nullopt; if (Error Err = importInto(Spec, NNS.getNestedNameSpecifier())) return std::move(Err); - NestedNameSpecifier::SpecifierKind Kind = Spec->getKind(); + NestedNameSpecifier::Kind Kind = Spec.getKind(); SourceLocation ToLocalBeginLoc, ToLocalEndLoc; - if (Kind != NestedNameSpecifier::Super) { + if (Kind != NestedNameSpecifier::Kind::Super) { if (Error Err = importInto(ToLocalBeginLoc, NNS.getLocalBeginLoc())) return std::move(Err); - if (Kind != NestedNameSpecifier::Global) + if (Kind != NestedNameSpecifier::Kind::Global) if (Error Err = importInto(ToLocalEndLoc, NNS.getLocalEndLoc())) return std::move(Err); } switch (Kind) { - case NestedNameSpecifier::Identifier: - Builder.Extend(getToContext(), Spec->getAsIdentifier(), ToLocalBeginLoc, - ToLocalEndLoc); - break; - - case NestedNameSpecifier::Namespace: - Builder.Extend(getToContext(), Spec->getAsNamespace(), ToLocalBeginLoc, - ToLocalEndLoc); - break; - - case NestedNameSpecifier::NamespaceAlias: - Builder.Extend(getToContext(), Spec->getAsNamespaceAlias(), + case NestedNameSpecifier::Kind::Namespace: + Builder.Extend(getToContext(), Spec.getAsNamespaceAndPrefix().Namespace, ToLocalBeginLoc, ToLocalEndLoc); break; - case NestedNameSpecifier::TypeSpec: { + case NestedNameSpecifier::Kind::Type: { SourceLocation ToTLoc; - if (Error Err = importInto(ToTLoc, NNS.getTypeLoc().getBeginLoc())) + if (Error Err = importInto(ToTLoc, NNS.castAsTypeLoc().getBeginLoc())) return std::move(Err); TypeSourceInfo *TSI = getToContext().getTrivialTypeSourceInfo( - QualType(Spec->getAsType(), 0), ToTLoc); - Builder.Extend(getToContext(), TSI->getTypeLoc(), ToLocalEndLoc); + QualType(Spec.getAsType(), 0), ToTLoc); + Builder.Make(getToContext(), TSI->getTypeLoc(), ToLocalEndLoc); break; } - case NestedNameSpecifier::Global: + case NestedNameSpecifier::Kind::Global: Builder.MakeGlobal(getToContext(), ToLocalBeginLoc); break; - case NestedNameSpecifier::Super: { + case NestedNameSpecifier::Kind::Super: { auto ToSourceRangeOrErr = Import(NNS.getSourceRange()); if (!ToSourceRangeOrErr) return ToSourceRangeOrErr.takeError(); - Builder.MakeSuper(getToContext(), Spec->getAsRecordDecl(), + Builder.MakeSuper(getToContext(), Spec.getAsSuper(), ToSourceRangeOrErr->getBegin(), ToSourceRangeOrErr->getEnd()); + break; + } + case NestedNameSpecifier::Kind::Null: + llvm_unreachable("unexpected null nested name specifier"); } - } } return Builder.getWithLocInContext(getToContext()); @@ -10460,7 +10356,7 @@ ASTNodeImporter::ImportAPValue(const APValue &FromValue) { if (Err) return std::move(Err); if (auto *RD = dyn_cast(FromDecl)) - FromElemTy = Importer.FromContext.getRecordType(RD); + FromElemTy = Importer.FromContext.getCanonicalTagType(RD); else FromElemTy = cast(FromDecl)->getType(); ToPath[LoopIdx] = APValue::LValuePathEntry(APValue::BaseOrMemberType( diff --git a/clang/lib/AST/ASTImporterLookupTable.cpp b/clang/lib/AST/ASTImporterLookupTable.cpp index 4ed3198d7ea62..29c3af1703b4f 100644 --- a/clang/lib/AST/ASTImporterLookupTable.cpp +++ b/clang/lib/AST/ASTImporterLookupTable.cpp @@ -49,8 +49,6 @@ struct Builder : RecursiveASTVisitor { bool VisitFriendDecl(FriendDecl *D) { if (D->getFriendType()) { QualType Ty = D->getFriendType()->getType(); - if (isa(Ty)) - Ty = cast(Ty)->getNamedType(); // A FriendDecl with a dependent type (e.g. ClassTemplateSpecialization) // always has that decl as child node. // However, there are non-dependent cases which does not have the @@ -64,13 +62,15 @@ struct Builder : RecursiveASTVisitor { dyn_cast(Ty)) { if (SubstTy->getAsCXXRecordDecl()) LT.add(SubstTy->getAsCXXRecordDecl()); - } else if (isa(Ty)) { - // We do not put friend typedefs to the lookup table because - // ASTImporter does not organize typedefs into redecl chains. - } else if (isa(Ty)) { - // Similar to TypedefType, not putting into lookup table. } else { - llvm_unreachable("Unhandled type of friend class"); + if (isa(Ty)) { + // We do not put friend typedefs to the lookup table because + // ASTImporter does not organize typedefs into redecl chains. + } else if (isa(Ty)) { + // Similar to TypedefType, not putting into lookup table. + } else { + llvm_unreachable("Unhandled type of friend class"); + } } } } diff --git a/clang/lib/AST/ASTStructuralEquivalence.cpp b/clang/lib/AST/ASTStructuralEquivalence.cpp index 704de8156132c..8ed7bae3dc0da 100644 --- a/clang/lib/AST/ASTStructuralEquivalence.cpp +++ b/clang/lib/AST/ASTStructuralEquivalence.cpp @@ -110,8 +110,8 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, const TemplateArgumentLoc &Arg1, const TemplateArgumentLoc &Arg2); static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, - NestedNameSpecifier *NNS1, - NestedNameSpecifier *NNS2); + NestedNameSpecifier NNS1, + NestedNameSpecifier NNS2); static bool IsStructurallyEquivalent(const IdentifierInfo *Name1, const IdentifierInfo *Name2); @@ -577,38 +577,30 @@ static bool IsStructurallyEquivalent(const IdentifierInfo *Name1, /// Determine whether two nested-name-specifiers are equivalent. static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, - NestedNameSpecifier *NNS1, - NestedNameSpecifier *NNS2) { - if (NNS1->getKind() != NNS2->getKind()) - return false; - - NestedNameSpecifier *Prefix1 = NNS1->getPrefix(), - *Prefix2 = NNS2->getPrefix(); - if ((bool)Prefix1 != (bool)Prefix2) - return false; - - if (Prefix1) - if (!IsStructurallyEquivalent(Context, Prefix1, Prefix2)) - return false; - - switch (NNS1->getKind()) { - case NestedNameSpecifier::Identifier: - return IsStructurallyEquivalent(NNS1->getAsIdentifier(), - NNS2->getAsIdentifier()); - case NestedNameSpecifier::Namespace: - return IsStructurallyEquivalent(Context, NNS1->getAsNamespace(), - NNS2->getAsNamespace()); - case NestedNameSpecifier::NamespaceAlias: - return IsStructurallyEquivalent(Context, NNS1->getAsNamespaceAlias(), - NNS2->getAsNamespaceAlias()); - case NestedNameSpecifier::TypeSpec: - return IsStructurallyEquivalent(Context, QualType(NNS1->getAsType(), 0), - QualType(NNS2->getAsType(), 0)); - case NestedNameSpecifier::Global: + NestedNameSpecifier NNS1, + NestedNameSpecifier NNS2) { + auto Kind = NNS1.getKind(); + if (Kind != NNS2.getKind()) + return false; + switch (Kind) { + case NestedNameSpecifier::Kind::Null: + case NestedNameSpecifier::Kind::Global: return true; - case NestedNameSpecifier::Super: - return IsStructurallyEquivalent(Context, NNS1->getAsRecordDecl(), - NNS2->getAsRecordDecl()); + case NestedNameSpecifier::Kind::Namespace: { + auto [Namespace1, Prefix1] = NNS1.getAsNamespaceAndPrefix(); + auto [Namespace2, Prefix2] = NNS2.getAsNamespaceAndPrefix(); + if (!IsStructurallyEquivalent(Context, + const_cast(Namespace1), + const_cast(Namespace2))) + return false; + return IsStructurallyEquivalent(Context, Prefix1, Prefix2); + } + case NestedNameSpecifier::Kind::Type: + return IsStructurallyEquivalent(Context, QualType(NNS1.getAsType(), 0), + QualType(NNS2.getAsType(), 0)); + case NestedNameSpecifier::Kind::Super: + return IsStructurallyEquivalent(Context, NNS1.getAsSuper(), + NNS2.getAsSuper()); } return false; } @@ -616,9 +608,7 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, const DependentTemplateStorage &S1, const DependentTemplateStorage &S2) { - if (NestedNameSpecifier *NNS1 = S1.getQualifier(), *NNS2 = S2.getQualifier(); - !NNS1 != !NNS2 || - (NNS1 && !IsStructurallyEquivalent(Context, NNS1, NNS2))) + if (!IsStructurallyEquivalent(Context, S1.getQualifier(), S2.getQualifier())) return false; IdentifierOrOverloadedOperator IO1 = S1.getName(), IO2 = S2.getName(); @@ -1187,23 +1177,35 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, return false; break; - case Type::Using: - if (!IsStructurallyEquivalent(Context, cast(T1)->getFoundDecl(), - cast(T2)->getFoundDecl())) + case Type::Using: { + auto *U1 = cast(T1), *U2 = cast(T2); + if (U1->getKeyword() != U2->getKeyword()) return false; - if (!IsStructurallyEquivalent(Context, - cast(T1)->getUnderlyingType(), - cast(T2)->getUnderlyingType())) + if (!IsStructurallyEquivalent(Context, U1->getQualifier(), + U2->getQualifier())) + return false; + if (!IsStructurallyEquivalent(Context, U1->getDecl(), U2->getDecl())) + return false; + if (!IsStructurallyEquivalent(Context, U1->desugar(), U2->desugar())) return false; break; - - case Type::Typedef: - if (!IsStructurallyEquivalent(Context, cast(T1)->getDecl(), - cast(T2)->getDecl()) || - !IsStructurallyEquivalent(Context, cast(T1)->desugar(), - cast(T2)->desugar())) + } + case Type::Typedef: { + auto *U1 = cast(T1), *U2 = cast(T2); + if (U1->getKeyword() != U2->getKeyword()) + return false; + if (!IsStructurallyEquivalent(Context, U1->getQualifier(), + U2->getQualifier())) + return false; + if (!IsStructurallyEquivalent(Context, U1->getDecl(), U2->getDecl())) + return false; + if (U1->typeMatchesDecl() != U2->typeMatchesDecl()) + return false; + if (!U1->typeMatchesDecl() && + !IsStructurallyEquivalent(Context, U1->desugar(), U2->desugar())) return false; break; + } case Type::TypeOfExpr: if (!IsStructurallyEquivalent( @@ -1267,10 +1269,20 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, case Type::Record: case Type::Enum: - if (!IsStructurallyEquivalent(Context, cast(T1)->getDecl(), - cast(T2)->getDecl())) + case Type::InjectedClassName: { + const auto *TT1 = cast(T1), *TT2 = cast(T2); + if (TT1->getKeyword() != TT2->getKeyword()) + return false; + if (TT1->isTagOwned() != TT2->isTagOwned()) + return false; + if (!IsStructurallyEquivalent(Context, TT1->getQualifier(), + TT2->getQualifier())) + return false; + if (!IsStructurallyEquivalent(Context, TT1->getOriginalDecl(), + TT2->getOriginalDecl())) return false; break; + } case Type::TemplateTypeParm: { const auto *Parm1 = cast(T1); @@ -1329,33 +1341,6 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, break; } - case Type::Elaborated: { - const auto *Elab1 = cast(T1); - const auto *Elab2 = cast(T2); - // CHECKME: what if a keyword is ElaboratedTypeKeyword::None or - // ElaboratedTypeKeyword::Typename - // ? - if (Elab1->getKeyword() != Elab2->getKeyword()) - return false; - if (!IsStructurallyEquivalent(Context, Elab1->getQualifier(), - Elab2->getQualifier())) - return false; - if (!IsStructurallyEquivalent(Context, Elab1->getNamedType(), - Elab2->getNamedType())) - return false; - break; - } - - case Type::InjectedClassName: { - const auto *Inj1 = cast(T1); - const auto *Inj2 = cast(T2); - if (!IsStructurallyEquivalent(Context, - Inj1->getInjectedSpecializationType(), - Inj2->getInjectedSpecializationType())) - return false; - break; - } - case Type::DependentName: { const auto *Typename1 = cast(T1); const auto *Typename2 = cast(T2); @@ -1523,8 +1508,8 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, // types if (Field1->isAnonymousStructOrUnion() && Field2->isAnonymousStructOrUnion()) { - RecordDecl *D1 = Field1->getType()->castAs()->getDecl(); - RecordDecl *D2 = Field2->getType()->castAs()->getDecl(); + RecordDecl *D1 = Field1->getType()->castAs()->getOriginalDecl(); + RecordDecl *D2 = Field2->getType()->castAs()->getOriginalDecl(); return IsStructurallyEquivalent(Context, D1, D2); } @@ -1602,7 +1587,7 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, FieldDecl *Field1, FieldDecl *Field2) { const auto *Owner2 = cast(Field2->getDeclContext()); return IsStructurallyEquivalent(Context, Field1, Field2, - Context.ToCtx.getTypeDeclType(Owner2)); + Context.ToCtx.getCanonicalTagType(Owner2)); } /// Determine structural equivalence of two methods. @@ -1770,7 +1755,7 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, if (Context.Complain) { Context.Diag2(D2->getLocation(), Context.getApplicableDiagnostic( diag::err_odr_tag_type_inconsistent)) - << Context.ToCtx.getTypeDeclType(D2) + << Context.ToCtx.getCanonicalTagType(D2) << (&Context.FromCtx != &Context.ToCtx); Context.Diag1(D1->getLocation(), diag::note_odr_tag_kind_here) << D1->getDeclName() << (unsigned)D1->getTagKind(); @@ -1872,7 +1857,7 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, Context.Diag2(D2->getLocation(), Context.getApplicableDiagnostic( diag::err_odr_tag_type_inconsistent)) - << Context.ToCtx.getTypeDeclType(D2) + << Context.ToCtx.getCanonicalTagType(D2) << (&Context.FromCtx != &Context.ToCtx); Context.Diag2(D2->getLocation(), diag::note_odr_number_of_bases) << D2CXX->getNumBases(); @@ -1893,7 +1878,7 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, Context.Diag2(D2->getLocation(), Context.getApplicableDiagnostic( diag::err_odr_tag_type_inconsistent)) - << Context.ToCtx.getTypeDeclType(D2) + << Context.ToCtx.getCanonicalTagType(D2) << (&Context.FromCtx != &Context.ToCtx); Context.Diag2(Base2->getBeginLoc(), diag::note_odr_base) << Base2->getType() << Base2->getSourceRange(); @@ -1909,7 +1894,7 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, Context.Diag2(D2->getLocation(), Context.getApplicableDiagnostic( diag::err_odr_tag_type_inconsistent)) - << Context.ToCtx.getTypeDeclType(D2) + << Context.ToCtx.getCanonicalTagType(D2) << (&Context.FromCtx != &Context.ToCtx); Context.Diag2(Base2->getBeginLoc(), diag::note_odr_virtual_base) << Base2->isVirtual() << Base2->getSourceRange(); @@ -1931,7 +1916,7 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, Context.Diag2(D2->getLocation(), Context.getApplicableDiagnostic( diag::err_odr_tag_type_inconsistent)) - << Context.ToCtx.getTypeDeclType(D2CXX) + << Context.ToCtx.getCanonicalTagType(D2CXX) << (&Context.FromCtx != &Context.ToCtx); Context.Diag1((*Friend1)->getFriendLoc(), diag::note_odr_friend); Context.Diag2(D2->getLocation(), diag::note_odr_missing_friend); @@ -1944,7 +1929,7 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, Context.Diag2(D2->getLocation(), Context.getApplicableDiagnostic( diag::err_odr_tag_type_inconsistent)) - << Context.ToCtx.getTypeDeclType(D2CXX) + << Context.ToCtx.getCanonicalTagType(D2CXX) << (&Context.FromCtx != &Context.ToCtx); Context.Diag1((*Friend1)->getFriendLoc(), diag::note_odr_friend); Context.Diag2((*Friend2)->getFriendLoc(), diag::note_odr_friend); @@ -1958,7 +1943,7 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, Context.Diag2(D2->getLocation(), Context.getApplicableDiagnostic( diag::err_odr_tag_type_inconsistent)) - << Context.ToCtx.getTypeDeclType(D2) + << Context.ToCtx.getCanonicalTagType(D2) << (&Context.FromCtx != &Context.ToCtx); Context.Diag2((*Friend2)->getFriendLoc(), diag::note_odr_friend); Context.Diag1(D1->getLocation(), diag::note_odr_missing_friend); @@ -1970,7 +1955,7 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, Context.Diag2(D2->getLocation(), Context.getApplicableDiagnostic( diag::err_odr_tag_type_inconsistent)) - << Context.ToCtx.getTypeDeclType(D2) + << Context.ToCtx.getCanonicalTagType(D2) << (&Context.FromCtx != &Context.ToCtx); const CXXBaseSpecifier *Base1 = D1CXX->bases_begin(); Context.Diag1(Base1->getBeginLoc(), diag::note_odr_base) @@ -1982,7 +1967,7 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, } // Check the fields for consistency. - QualType D2Type = Context.ToCtx.getTypeDeclType(D2); + CanQualType D2Type = Context.ToCtx.getCanonicalTagType(D2); RecordDecl::field_iterator Field2 = D2->field_begin(), Field2End = D2->field_end(); for (RecordDecl::field_iterator Field1 = D1->field_begin(), @@ -1993,7 +1978,7 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, Context.Diag2(D2->getLocation(), Context.getApplicableDiagnostic( diag::err_odr_tag_type_inconsistent)) - << Context.ToCtx.getTypeDeclType(D2) + << Context.ToCtx.getCanonicalTagType(D2) << (&Context.FromCtx != &Context.ToCtx); Context.Diag1(Field1->getLocation(), diag::note_odr_field) << Field1->getDeclName() << Field1->getType(); @@ -2010,7 +1995,7 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, if (Context.Complain) { Context.Diag2(D2->getLocation(), Context.getApplicableDiagnostic( diag::err_odr_tag_type_inconsistent)) - << Context.ToCtx.getTypeDeclType(D2) + << Context.ToCtx.getCanonicalTagType(D2) << (&Context.FromCtx != &Context.ToCtx); Context.Diag2(Field2->getLocation(), diag::note_odr_field) << Field2->getDeclName() << Field2->getType(); @@ -2089,7 +2074,7 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, Context.Diag2(D2->getLocation(), Context.getApplicableDiagnostic( diag::err_odr_tag_type_inconsistent)) - << Context.ToCtx.getTypeDeclType(D2) + << Context.ToCtx.getCanonicalTagType(D2) << (&Context.FromCtx != &Context.ToCtx); Context.Diag1((*EC1)->getLocation(), diag::note_odr_enumerator) << (*EC1)->getDeclName() << toString((*EC1)->getInitVal(), 10); @@ -2107,7 +2092,7 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, Context.Diag2(D2->getLocation(), Context.getApplicableDiagnostic( diag::err_odr_tag_type_inconsistent)) - << Context.ToCtx.getTypeDeclType(D2) + << Context.ToCtx.getCanonicalTagType(D2) << (&Context.FromCtx != &Context.ToCtx); Context.Diag2((*EC2)->getLocation(), diag::note_odr_enumerator) << (*EC2)->getDeclName() << toString((*EC2)->getInitVal(), 10); @@ -2125,7 +2110,7 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, if (Context.Complain) { Context.Diag2(D2->getLocation(), Context.getApplicableDiagnostic( diag::err_odr_tag_type_inconsistent)) - << Context.ToCtx.getTypeDeclType(D2) + << Context.ToCtx.getCanonicalTagType(D2) << (&Context.FromCtx != &Context.ToCtx); Context.Diag2((*EC2)->getLocation(), diag::note_odr_enumerator) << (*EC2)->getDeclName() << toString((*EC2)->getInitVal(), 10); @@ -2521,7 +2506,7 @@ DiagnosticBuilder StructuralEquivalenceContext::Diag2(SourceLocation Loc, UnsignedOrNone StructuralEquivalenceContext::findUntaggedStructOrUnionIndex(RecordDecl *Anon) { ASTContext &Context = Anon->getASTContext(); - QualType AnonTy = Context.getRecordType(Anon); + CanQualType AnonTy = Context.getCanonicalTagType(Anon); const auto *Owner = dyn_cast(Anon->getDeclContext()); if (!Owner) @@ -2543,12 +2528,8 @@ StructuralEquivalenceContext::findUntaggedStructOrUnionIndex(RecordDecl *Anon) { // If the field looks like this: // struct { ... } A; QualType FieldType = F->getType(); - // In case of nested structs. - while (const auto *ElabType = dyn_cast(FieldType)) - FieldType = ElabType->getNamedType(); - if (const auto *RecType = dyn_cast(FieldType)) { - const RecordDecl *RecDecl = RecType->getDecl(); + const RecordDecl *RecDecl = RecType->getOriginalDecl(); if (RecDecl->getDeclContext() == Owner && !RecDecl->getIdentifier()) { if (Context.hasSameType(FieldType, AnonTy)) break; diff --git a/clang/lib/AST/ASTTypeTraits.cpp b/clang/lib/AST/ASTTypeTraits.cpp index 99916f523aa95..d2f7fdbbad04d 100644 --- a/clang/lib/AST/ASTTypeTraits.cpp +++ b/clang/lib/AST/ASTTypeTraits.cpp @@ -194,8 +194,8 @@ void DynTypedNode::print(llvm::raw_ostream &OS, else if (const NestedNameSpecifier *NNS = get()) NNS->print(OS, PP); else if (const NestedNameSpecifierLoc *NNSL = get()) { - if (const NestedNameSpecifier *NNS = NNSL->getNestedNameSpecifier()) - NNS->print(OS, PP); + if (NestedNameSpecifier NNS = NNSL->getNestedNameSpecifier()) + NNS.print(OS, PP); else OS << "(empty NestedNameSpecifierLoc)"; } else if (const QualType *QT = get()) @@ -234,13 +234,39 @@ void DynTypedNode::dump(llvm::raw_ostream &OS, OS << "Unable to dump values of type " << NodeKind.asStringRef() << "\n"; } -SourceRange DynTypedNode::getSourceRange() const { +SourceRange DynTypedNode::getSourceRange(bool IncludeQualifier) const { if (const CXXCtorInitializer *CCI = get()) return CCI->getSourceRange(); if (const NestedNameSpecifierLoc *NNSL = get()) return NNSL->getSourceRange(); - if (const TypeLoc *TL = get()) - return TL->getSourceRange(); + if (const TypeLoc *TL = get()) { + if (IncludeQualifier) + return TL->getSourceRange(); + switch (TL->getTypeLocClass()) { + case TypeLoc::DependentName: + return TL->castAs().getNameLoc(); + case TypeLoc::TemplateSpecialization: { + auto T = TL->castAs(); + return SourceRange(T.getTemplateNameLoc(), T.getEndLoc()); + } + case TypeLoc::DependentTemplateSpecialization: { + auto T = TL->castAs(); + return SourceRange(T.getTemplateNameLoc(), T.getEndLoc()); + } + case TypeLoc::Enum: + case TypeLoc::Record: + case TypeLoc::InjectedClassName: + return TL->castAs().getNameLoc(); + case TypeLoc::Typedef: + return TL->castAs().getNameLoc(); + case TypeLoc::UnresolvedUsing: + return TL->castAs().getNameLoc(); + case TypeLoc::Using: + return TL->castAs().getNameLoc(); + default: + return TL->getSourceRange(); + } + } if (const Decl *D = get()) return D->getSourceRange(); if (const Stmt *S = get()) diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp index ee9c3890794af..10cd8a7e6c73a 100644 --- a/clang/lib/AST/ByteCode/Compiler.cpp +++ b/clang/lib/AST/ByteCode/Compiler.cpp @@ -509,9 +509,10 @@ bool Compiler::VisitCastExpr(const CastExpr *CE) { // Possibly diagnose casts to enum types if the target type does not // have a fixed size. if (Ctx.getLangOpts().CPlusPlus && CE->getType()->isEnumeralType()) { - if (const auto *ET = CE->getType().getCanonicalType()->castAs(); - !ET->getDecl()->isFixed()) { - if (!this->emitCheckEnumValue(*FromT, ET->getDecl(), CE)) + const auto *ET = CE->getType().getCanonicalType()->castAs(); + const auto *ED = ET->getOriginalDecl()->getDefinitionOrSelf(); + if (!ED->isFixed()) { + if (!this->emitCheckEnumValue(*FromT, ED, CE)) return false; } } @@ -4488,7 +4489,7 @@ const RecordType *Compiler::getRecordTy(QualType Ty) { template Record *Compiler::getRecord(QualType Ty) { if (const auto *RecordTy = getRecordTy(Ty)) - return getRecord(RecordTy->getDecl()); + return getRecord(RecordTy->getOriginalDecl()->getDefinitionOrSelf()); return nullptr; } diff --git a/clang/lib/AST/ByteCode/Context.cpp b/clang/lib/AST/ByteCode/Context.cpp index a629ff9569428..f9b2e0b400525 100644 --- a/clang/lib/AST/ByteCode/Context.cpp +++ b/clang/lib/AST/ByteCode/Context.cpp @@ -314,7 +314,7 @@ std::optional Context::classify(QualType T) const { } if (const auto *ET = T->getAs()) { - const auto *D = ET->getDecl(); + const auto *D = ET->getOriginalDecl()->getDefinitionOrSelf(); if (!D->isComplete()) return std::nullopt; return classify(D->getIntegerType()); diff --git a/clang/lib/AST/ByteCode/Descriptor.cpp b/clang/lib/AST/ByteCode/Descriptor.cpp index c89eca9bef440..1f8072fbf27f6 100644 --- a/clang/lib/AST/ByteCode/Descriptor.cpp +++ b/clang/lib/AST/ByteCode/Descriptor.cpp @@ -427,12 +427,14 @@ QualType Descriptor::getType() const { if (const auto *D = asValueDecl()) return D->getType(); if (const auto *T = dyn_cast_if_present(asDecl())) - return QualType(T->getTypeForDecl(), 0); + return T->getASTContext().getTypeDeclType(T); // The Source sometimes has a different type than the once // we really save. Try to consult the Record first. - if (isRecord()) - return QualType(ElemRecord->getDecl()->getTypeForDecl(), 0); + if (isRecord()) { + const RecordDecl *RD = ElemRecord->getDecl(); + return RD->getASTContext().getCanonicalTagType(RD); + } if (const auto *E = asExpr()) return E->getType(); llvm_unreachable("Invalid descriptor type"); diff --git a/clang/lib/AST/ByteCode/Interp.cpp b/clang/lib/AST/ByteCode/Interp.cpp index 51cf0c59f0b50..83bee1b0f778d 100644 --- a/clang/lib/AST/ByteCode/Interp.cpp +++ b/clang/lib/AST/ByteCode/Interp.cpp @@ -1985,7 +1985,7 @@ bool GetTypeidPtr(InterpState &S, CodePtr OpPC, const Type *TypeInfoType) { return false; // Pick the most-derived type. - const Type *T = P.getDeclPtr().getType().getTypePtr(); + CanQualType T = P.getDeclPtr().getType()->getCanonicalTypeUnqualified(); // ... unless we're currently constructing this object. // FIXME: We have a similar check to this in more places. if (S.Current->getFunction()) { @@ -1993,14 +1993,14 @@ bool GetTypeidPtr(InterpState &S, CodePtr OpPC, const Type *TypeInfoType) { if (const Function *Func = Frame->getFunction(); Func && (Func->isConstructor() || Func->isDestructor()) && P.block() == Frame->getThis().block()) { - T = Func->getParentDecl()->getTypeForDecl(); + T = S.getContext().getASTContext().getCanonicalTagType( + Func->getParentDecl()); break; } } } - S.Stk.push(T->getCanonicalTypeUnqualified().getTypePtr(), - TypeInfoType); + S.Stk.push(T->getTypePtr(), TypeInfoType); return true; } diff --git a/clang/lib/AST/ByteCode/Interp.h b/clang/lib/AST/ByteCode/Interp.h index 85a07abb5ed01..48a5d35bcbaea 100644 --- a/clang/lib/AST/ByteCode/Interp.h +++ b/clang/lib/AST/ByteCode/Interp.h @@ -1743,10 +1743,7 @@ inline bool GetPtrDerivedPop(InterpState &S, CodePtr OpPC, uint32_t Off, const Record *TargetRecord = Ptr.atFieldSub(Off).getRecord(); assert(TargetRecord); - if (TargetRecord->getDecl() - ->getTypeForDecl() - ->getAsCXXRecordDecl() - ->getCanonicalDecl() != + if (TargetRecord->getDecl()->getCanonicalDecl() != TargetType->getAsCXXRecordDecl()->getCanonicalDecl()) { QualType MostDerivedType = Ptr.getDeclDesc()->getType(); S.CCEDiag(S.Current->getSource(OpPC), diag::note_constexpr_invalid_downcast) diff --git a/clang/lib/AST/ByteCode/InterpBuiltin.cpp b/clang/lib/AST/ByteCode/InterpBuiltin.cpp index 1fe6d146b511d..19afbf3772ab7 100644 --- a/clang/lib/AST/ByteCode/InterpBuiltin.cpp +++ b/clang/lib/AST/ByteCode/InterpBuiltin.cpp @@ -2660,7 +2660,7 @@ bool InterpretOffsetOf(InterpState &S, CodePtr OpPC, const OffsetOfExpr *E, const RecordType *RT = CurrentType->getAs(); if (!RT) return false; - const RecordDecl *RD = RT->getDecl(); + const RecordDecl *RD = RT->getOriginalDecl()->getDefinitionOrSelf(); if (RD->isInvalidDecl()) return false; const ASTRecordLayout &RL = S.getASTContext().getASTRecordLayout(RD); @@ -2693,7 +2693,7 @@ bool InterpretOffsetOf(InterpState &S, CodePtr OpPC, const OffsetOfExpr *E, const RecordType *RT = CurrentType->getAs(); if (!RT) return false; - const RecordDecl *RD = RT->getDecl(); + const RecordDecl *RD = RT->getOriginalDecl()->getDefinitionOrSelf(); if (RD->isInvalidDecl()) return false; const ASTRecordLayout &RL = S.getASTContext().getASTRecordLayout(RD); @@ -2705,7 +2705,8 @@ bool InterpretOffsetOf(InterpState &S, CodePtr OpPC, const OffsetOfExpr *E, return false; // Add the offset to the base. - Result += RL.getBaseClassOffset(cast(BaseRT->getDecl())); + Result += RL.getBaseClassOffset(cast( + BaseRT->getOriginalDecl()->getDefinitionOrSelf())); break; } case OffsetOfNode::Identifier: diff --git a/clang/lib/AST/ByteCode/InterpFrame.cpp b/clang/lib/AST/ByteCode/InterpFrame.cpp index a5a4bd25fe712..9fde953cfab8e 100644 --- a/clang/lib/AST/ByteCode/InterpFrame.cpp +++ b/clang/lib/AST/ByteCode/InterpFrame.cpp @@ -159,7 +159,7 @@ void InterpFrame::describe(llvm::raw_ostream &OS) const { } else if (const auto *M = dyn_cast(F)) { print(OS, This, S.getASTContext(), S.getASTContext().getLValueReferenceType( - S.getASTContext().getRecordType(M->getParent()))); + S.getASTContext().getCanonicalTagType(M->getParent()))); OS << "."; } } diff --git a/clang/lib/AST/ByteCode/Pointer.cpp b/clang/lib/AST/ByteCode/Pointer.cpp index 6769e51a8ad00..fca52a2f382ea 100644 --- a/clang/lib/AST/ByteCode/Pointer.cpp +++ b/clang/lib/AST/ByteCode/Pointer.cpp @@ -666,7 +666,7 @@ std::optional Pointer::toRValue(const Context &Ctx, assert(Record && "Missing record descriptor"); bool Ok = true; - if (RT->getDecl()->isUnion()) { + if (RT->getOriginalDecl()->isUnion()) { const FieldDecl *ActiveField = nullptr; APValue Value; for (const auto &F : Record->fields()) { @@ -705,14 +705,15 @@ std::optional Pointer::toRValue(const Context &Ctx, for (unsigned I = 0; I < NB; ++I) { const Record::Base *BD = Record->getBase(I); - QualType BaseTy = Ctx.getASTContext().getRecordType(BD->Decl); + QualType BaseTy = Ctx.getASTContext().getCanonicalTagType(BD->Decl); const Pointer &BP = Ptr.atField(BD->Offset); Ok &= Composite(BaseTy, BP, R.getStructBase(I)); } for (unsigned I = 0; I < NV; ++I) { const Record::Base *VD = Record->getVirtualBase(I); - QualType VirtBaseTy = Ctx.getASTContext().getRecordType(VD->Decl); + QualType VirtBaseTy = + Ctx.getASTContext().getCanonicalTagType(VD->Decl); const Pointer &VP = Ptr.atField(VD->Offset); Ok &= Composite(VirtBaseTy, VP, R.getStructBase(NB + I)); } diff --git a/clang/lib/AST/ByteCode/Program.cpp b/clang/lib/AST/ByteCode/Program.cpp index 5ac0f59f32d4e..47dd6f082bc48 100644 --- a/clang/lib/AST/ByteCode/Program.cpp +++ b/clang/lib/AST/ByteCode/Program.cpp @@ -326,7 +326,7 @@ Record *Program::getOrCreateRecord(const RecordDecl *RD) { const auto *RT = Spec.getType()->getAs(); if (!RT) return nullptr; - const RecordDecl *BD = RT->getDecl(); + const RecordDecl *BD = RT->getOriginalDecl()->getDefinitionOrSelf(); const Record *BR = getOrCreateRecord(BD); const Descriptor *Desc = GetBaseDesc(BD, BR); @@ -343,7 +343,7 @@ Record *Program::getOrCreateRecord(const RecordDecl *RD) { if (!RT) return nullptr; - const RecordDecl *BD = RT->getDecl(); + const RecordDecl *BD = RT->getOriginalDecl()->getDefinitionOrSelf(); const Record *BR = getOrCreateRecord(BD); const Descriptor *Desc = GetBaseDesc(BD, BR); @@ -400,7 +400,8 @@ Descriptor *Program::createDescriptor(const DeclTy &D, const Type *Ty, // Classes and structures. if (const auto *RT = Ty->getAs()) { - if (const auto *Record = getOrCreateRecord(RT->getDecl())) + if (const auto *Record = + getOrCreateRecord(RT->getOriginalDecl()->getDefinitionOrSelf())) return allocateDescriptor(D, Record, MDSize, IsConst, IsTemporary, IsMutable, IsVolatile); return allocateDescriptor(D, MDSize); diff --git a/clang/lib/AST/ByteCode/Record.cpp b/clang/lib/AST/ByteCode/Record.cpp index 1d4ac7103cb76..a7934ccb4e55e 100644 --- a/clang/lib/AST/ByteCode/Record.cpp +++ b/clang/lib/AST/ByteCode/Record.cpp @@ -51,7 +51,7 @@ const Record::Base *Record::getBase(const RecordDecl *FD) const { const Record::Base *Record::getBase(QualType T) const { if (auto *RT = T->getAs()) { - const RecordDecl *RD = RT->getDecl(); + const RecordDecl *RD = RT->getOriginalDecl()->getDefinitionOrSelf(); return BaseMap.lookup(RD); } return nullptr; diff --git a/clang/lib/AST/CXXInheritance.cpp b/clang/lib/AST/CXXInheritance.cpp index f0376168e43a2..e4b77edc063dc 100644 --- a/clang/lib/AST/CXXInheritance.cpp +++ b/clang/lib/AST/CXXInheritance.cpp @@ -132,8 +132,8 @@ bool CXXRecordDecl::forallBases(ForallBasesCallback BaseMatches) const { if (!Ty) return false; - CXXRecordDecl *Base = - cast_if_present(Ty->getDecl()->getDefinition()); + CXXRecordDecl *Base = cast_if_present( + Ty->getOriginalDecl()->getDefinition()); if (!Base || (Base->isDependentContext() && !Base->isCurrentInstantiation(Record))) { @@ -256,7 +256,8 @@ bool CXXBasePaths::lookupInBases(ASTContext &Context, BaseSpec.getType()->getAs(); if (!TST) { if (auto *RT = BaseSpec.getType()->getAs()) - BaseRecord = cast(RT->getDecl()); + BaseRecord = cast(RT->getOriginalDecl()) + ->getDefinitionOrSelf(); } else { TemplateName TN = TST->getTemplateName(); if (auto *TD = @@ -336,7 +337,8 @@ bool CXXRecordDecl::lookupInBases(BaseMatchesCallback BaseMatches, CXXRecordDecl *VBase = nullptr; if (const RecordType *Record = PE.Base->getType()->getAs()) - VBase = cast(Record->getDecl()); + VBase = cast(Record->getOriginalDecl()) + ->getDefinitionOrSelf(); if (!VBase) break; @@ -348,7 +350,8 @@ bool CXXRecordDecl::lookupInBases(BaseMatchesCallback BaseMatches, CXXRecordDecl *HidingClass = nullptr; if (const RecordType *Record = HidingP.back().Base->getType()->getAs()) - HidingClass = cast(Record->getDecl()); + HidingClass = cast(Record->getOriginalDecl()) + ->getDefinitionOrSelf(); if (!HidingClass) break; @@ -468,7 +471,8 @@ void FinalOverriderCollector::Collect(const CXXRecordDecl *RD, for (const auto &Base : RD->bases()) { if (const RecordType *RT = Base.getType()->getAs()) { - const CXXRecordDecl *BaseDecl = cast(RT->getDecl()); + const CXXRecordDecl *BaseDecl = + cast(RT->getOriginalDecl())->getDefinitionOrSelf(); if (!BaseDecl->isPolymorphic()) continue; diff --git a/clang/lib/AST/Comment.cpp b/clang/lib/AST/Comment.cpp index cd73d2709dc65..37e21c340c316 100644 --- a/clang/lib/AST/Comment.cpp +++ b/clang/lib/AST/Comment.cpp @@ -147,8 +147,6 @@ static TypeLoc lookThroughTypedefOrTypeAliasLocs(TypeLoc &SrcTL) { return BlockPointerTL.getPointeeLoc().getUnqualifiedLoc(); if (MemberPointerTypeLoc MemberPointerTL = TL.getAs()) return MemberPointerTL.getPointeeLoc().getUnqualifiedLoc(); - if (ElaboratedTypeLoc ETL = TL.getAs()) - return ETL.getNamedTypeLoc(); return TL; } diff --git a/clang/lib/AST/CommentSema.cpp b/clang/lib/AST/CommentSema.cpp index 95f6bf79d118c..5a16621578a3e 100644 --- a/clang/lib/AST/CommentSema.cpp +++ b/clang/lib/AST/CommentSema.cpp @@ -902,17 +902,9 @@ bool Sema::isClassOrStructOrTagTypedefDecl() { if (isClassOrStructDeclImpl(ThisDeclInfo->CurrentDecl)) return true; - if (auto *ThisTypedefDecl = dyn_cast(ThisDeclInfo->CurrentDecl)) { - auto UnderlyingType = ThisTypedefDecl->getUnderlyingType(); - if (auto ThisElaboratedType = dyn_cast(UnderlyingType)) { - auto DesugaredType = ThisElaboratedType->desugar(); - if (auto *DesugaredTypePtr = DesugaredType.getTypePtrOrNull()) { - if (auto *ThisRecordType = dyn_cast(DesugaredTypePtr)) { - return isClassOrStructDeclImpl(ThisRecordType->getAsRecordDecl()); - } - } - } - } + if (auto *ThisTypedefDecl = dyn_cast(ThisDeclInfo->CurrentDecl)) + if (auto *D = ThisTypedefDecl->getUnderlyingType()->getAsRecordDecl()) + return isClassOrStructDeclImpl(D); return false; } diff --git a/clang/lib/AST/ComparisonCategories.cpp b/clang/lib/AST/ComparisonCategories.cpp index 28244104d6636..0c7a7f4eacbbf 100644 --- a/clang/lib/AST/ComparisonCategories.cpp +++ b/clang/lib/AST/ComparisonCategories.cpp @@ -166,7 +166,7 @@ const ComparisonCategoryInfo &ComparisonCategories::getInfoForType(QualType Ty) QualType ComparisonCategoryInfo::getType() const { assert(Record); - return QualType(Record->getTypeForDecl(), 0); + return Record->getASTContext().getCanonicalTagType(Record); } StringRef ComparisonCategories::getCategoryString(ComparisonCategoryType Kind) { diff --git a/clang/lib/AST/ComputeDependence.cpp b/clang/lib/AST/ComputeDependence.cpp index 14ec93eb1d166..e95bcd75634fa 100644 --- a/clang/lib/AST/ComputeDependence.cpp +++ b/clang/lib/AST/ComputeDependence.cpp @@ -500,9 +500,8 @@ ExprDependence clang::computeDependence(OMPIteratorExpr *E) { ExprDependence clang::computeDependence(DeclRefExpr *E, const ASTContext &Ctx) { auto Deps = ExprDependence::None; - if (auto *NNS = E->getQualifier()) - Deps |= toExprDependence(NNS->getDependence() & - ~NestedNameSpecifierDependence::Dependent); + Deps |= toExprDependence(E->getQualifier().getDependence() & + ~NestedNameSpecifierDependence::Dependent); if (auto *FirstArg = E->getTemplateArgs()) { unsigned NumArgs = E->getNumTemplateArgs(); @@ -673,9 +672,8 @@ ExprDependence clang::computeDependence(MemberExpr *E) { auto D = E->getBase()->getDependence(); D |= getDependenceInExpr(E->getMemberNameInfo()); - if (auto *NNS = E->getQualifier()) - D |= toExprDependence(NNS->getDependence() & - ~NestedNameSpecifierDependence::Dependent); + D |= toExprDependence(E->getQualifier().getDependence() & + ~NestedNameSpecifierDependence::Dependent); for (const auto &A : E->template_arguments()) D |= toExprDependence(A.getArgument().getDependence()); @@ -783,9 +781,8 @@ ExprDependence clang::computeDependence(CXXPseudoDestructorExpr *E) { if (auto *ST = E->getScopeTypeInfo()) D |= turnTypeToValueDependence( toExprDependenceAsWritten(ST->getType()->getDependence())); - if (auto *Q = E->getQualifier()) - D |= toExprDependence(Q->getDependence() & - ~NestedNameSpecifierDependence::Dependent); + D |= toExprDependence(E->getQualifier().getDependence() & + ~NestedNameSpecifierDependence::Dependent); return D; } @@ -801,9 +798,8 @@ clang::computeDependence(OverloadExpr *E, bool KnownDependent, if (KnownContainsUnexpandedParameterPack) Deps |= ExprDependence::UnexpandedPack; Deps |= getDependenceInExpr(E->getNameInfo()); - if (auto *Q = E->getQualifier()) - Deps |= toExprDependence(Q->getDependence() & - ~NestedNameSpecifierDependence::Dependent); + Deps |= toExprDependence(E->getQualifier().getDependence() & + ~NestedNameSpecifierDependence::Dependent); for (auto *D : E->decls()) { if (D->getDeclContext()->isDependentContext() || isa(D)) @@ -820,8 +816,7 @@ clang::computeDependence(OverloadExpr *E, bool KnownDependent, ExprDependence clang::computeDependence(DependentScopeDeclRefExpr *E) { auto D = ExprDependence::TypeValue; D |= getDependenceInExpr(E->getNameInfo()); - if (auto *Q = E->getQualifier()) - D |= toExprDependence(Q->getDependence()); + D |= toExprDependence(E->getQualifier().getDependence()); for (const auto &A : E->template_arguments()) D |= toExprDependence(A.getArgument().getDependence()); return D; @@ -872,8 +867,7 @@ ExprDependence clang::computeDependence(CXXDependentScopeMemberExpr *E) { auto D = ExprDependence::TypeValueInstantiation; if (!E->isImplicitAccess()) D |= E->getBase()->getDependence(); - if (auto *Q = E->getQualifier()) - D |= toExprDependence(Q->getDependence()); + D |= toExprDependence(E->getQualifier().getDependence()); D |= getDependenceInExpr(E->getMemberNameInfo()); for (const auto &A : E->template_arguments()) D |= toExprDependence(A.getArgument().getDependence()); diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp index 8855d0107daca..dc0ce6e66bac7 100644 --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -1690,9 +1690,9 @@ void NamedDecl::printQualifiedName(raw_ostream &OS, return; } printNestedNameSpecifier(OS, P); - if (getDeclName()) - OS << *this; - else { + if (getDeclName()) { + printName(OS, P); + } else { // Give the printName override a chance to pick a different name before we // fall back to "(anonymous)". SmallString<64> NameBuffer; @@ -1880,18 +1880,13 @@ bool NamedDecl::declarationReplaces(const NamedDecl *OldD, // Using declarations can be replaced if they import the same name from the // same context. - if (const auto *UD = dyn_cast(this)) { - ASTContext &Context = getASTContext(); - return Context.getCanonicalNestedNameSpecifier(UD->getQualifier()) == - Context.getCanonicalNestedNameSpecifier( - cast(OldD)->getQualifier()); - } - if (const auto *UUVD = dyn_cast(this)) { - ASTContext &Context = getASTContext(); - return Context.getCanonicalNestedNameSpecifier(UUVD->getQualifier()) == - Context.getCanonicalNestedNameSpecifier( - cast(OldD)->getQualifier()); - } + if (const auto *UD = dyn_cast(this)) + return UD->getQualifier().getCanonical() == + + cast(OldD)->getQualifier().getCanonical(); + if (const auto *UUVD = dyn_cast(this)) + return UUVD->getQualifier().getCanonical() == + cast(OldD)->getQualifier().getCanonical(); if (isRedeclarable(getKind())) { if (getCanonicalDecl() != OldD->getCanonicalDecl()) @@ -2861,7 +2856,8 @@ VarDecl::needsDestruction(const ASTContext &Ctx) const { bool VarDecl::hasFlexibleArrayInit(const ASTContext &Ctx) const { assert(hasInit() && "Expect initializer to check for flexible array init"); auto *Ty = getType()->getAs(); - if (!Ty || !Ty->getDecl()->hasFlexibleArrayMember()) + if (!Ty || + !Ty->getOriginalDecl()->getDefinitionOrSelf()->hasFlexibleArrayMember()) return false; auto *List = dyn_cast(getInit()->IgnoreParens()); if (!List) @@ -2876,7 +2872,10 @@ bool VarDecl::hasFlexibleArrayInit(const ASTContext &Ctx) const { CharUnits VarDecl::getFlexibleArrayInitChars(const ASTContext &Ctx) const { assert(hasInit() && "Expect initializer to check for flexible array init"); auto *Ty = getType()->getAs(); - if (!Ty || !Ty->getDecl()->hasFlexibleArrayMember()) + if (!Ty) + return CharUnits::Zero(); + const RecordDecl *RD = Ty->getOriginalDecl()->getDefinitionOrSelf(); + if (!Ty || !RD->hasFlexibleArrayMember()) return CharUnits::Zero(); auto *List = dyn_cast(getInit()->IgnoreParens()); if (!List || List->getNumInits() == 0) @@ -2886,7 +2885,7 @@ CharUnits VarDecl::getFlexibleArrayInitChars(const ASTContext &Ctx) const { if (!InitTy) return CharUnits::Zero(); CharUnits FlexibleArraySize = Ctx.getTypeSizeInChars(InitTy); - const ASTRecordLayout &RL = Ctx.getASTRecordLayout(Ty->getDecl()); + const ASTRecordLayout &RL = Ctx.getASTRecordLayout(RD); CharUnits FlexibleArrayOffset = Ctx.toCharUnitsFromBits(RL.getFieldOffset(RL.getFieldCount() - 1)); if (FlexibleArrayOffset + FlexibleArraySize < RL.getSize()) @@ -2988,7 +2987,10 @@ bool ParmVarDecl::isDestroyedInCallee() const { // FIXME: isParamDestroyedInCallee() should probably imply // isDestructedType() const auto *RT = getType()->getAs(); - if (RT && RT->getDecl()->isParamDestroyedInCallee() && + if (RT && + RT->getOriginalDecl() + ->getDefinitionOrSelf() + ->isParamDestroyedInCallee() && getType().isDestructedType()) return true; @@ -3499,7 +3501,7 @@ bool FunctionDecl::isUsableAsGlobalAllocationFunctionInConstantEvaluation( while (const auto *TD = T->getAs()) T = TD->getDecl()->getUnderlyingType(); const IdentifierInfo *II = - T->castAs()->getDecl()->getIdentifier(); + T->castAs()->getOriginalDecl()->getIdentifier(); if (II && II->isStr("__hot_cold_t")) Consume(); } @@ -4650,7 +4652,7 @@ bool FieldDecl::isAnonymousStructOrUnion() const { return false; if (const auto *Record = getType()->getAs()) - return Record->getDecl()->isAnonymousStructOrUnion(); + return Record->getOriginalDecl()->isAnonymousStructOrUnion(); return false; } @@ -4707,7 +4709,7 @@ bool FieldDecl::isZeroSize(const ASTContext &Ctx) const { const auto *RT = getType()->getAs(); if (!RT) return false; - const RecordDecl *RD = RT->getDecl()->getDefinition(); + const RecordDecl *RD = RT->getOriginalDecl()->getDefinition(); if (!RD) { assert(isInvalidDecl() && "valid field has incomplete type"); return false; @@ -4830,10 +4832,6 @@ TagDecl *TagDecl::getCanonicalDecl() { return getFirstDecl(); } void TagDecl::setTypedefNameForAnonDecl(TypedefNameDecl *TDD) { TypedefNameDeclOrQualifier = TDD; - if (const Type *T = getTypeForDecl()) { - (void)T; - assert(T->isLinkageValid()); - } assert(isLinkageValid()); } @@ -4861,25 +4859,16 @@ void TagDecl::completeDefinition() { } TagDecl *TagDecl::getDefinition() const { - if (isCompleteDefinition()) + if (isCompleteDefinition() || isBeingDefined()) return const_cast(this); - // If it's possible for us to have an out-of-date definition, check now. - if (mayHaveOutOfDateDef()) { - if (IdentifierInfo *II = getIdentifier()) { - if (II->isOutOfDate()) { - updateOutOfDate(*II); - } - } - } - if (const auto *CXXRD = dyn_cast(this)) return CXXRD->getDefinition(); - for (auto *R : redecls()) - if (R->isCompleteDefinition()) + for (TagDecl *R : + redecl_range(redecl_iterator(getNextRedeclaration()), redecl_iterator())) + if (R->isCompleteDefinition() || R->isBeingDefined()) return R; - return nullptr; } @@ -4913,7 +4902,7 @@ void TagDecl::printName(raw_ostream &OS, const PrintingPolicy &Policy) const { // is already printed as part of the type. PrintingPolicy Copy(Policy); Copy.SuppressScope = true; - getASTContext().getTagDeclType(this).print(OS, Copy); + QualType(getASTContext().getCanonicalTagType(this)).print(OS, Copy); return; } // Otherwise, do the normal printing. @@ -4957,19 +4946,13 @@ EnumDecl *EnumDecl::Create(ASTContext &C, DeclContext *DC, IdentifierInfo *Id, EnumDecl *PrevDecl, bool IsScoped, bool IsScopedUsingClassTag, bool IsFixed) { - auto *Enum = new (C, DC) EnumDecl(C, DC, StartLoc, IdLoc, Id, PrevDecl, - IsScoped, IsScopedUsingClassTag, IsFixed); - Enum->setMayHaveOutOfDateDef(C.getLangOpts().Modules); - C.getTypeDeclType(Enum, PrevDecl); - return Enum; + return new (C, DC) EnumDecl(C, DC, StartLoc, IdLoc, Id, PrevDecl, IsScoped, + IsScopedUsingClassTag, IsFixed); } EnumDecl *EnumDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID) { - EnumDecl *Enum = - new (C, ID) EnumDecl(C, nullptr, SourceLocation(), SourceLocation(), - nullptr, nullptr, false, false, false); - Enum->setMayHaveOutOfDateDef(C.getLangOpts().Modules); - return Enum; + return new (C, ID) EnumDecl(C, nullptr, SourceLocation(), SourceLocation(), + nullptr, nullptr, false, false, false); } SourceRange EnumDecl::getIntegerTypeRange() const { @@ -5029,7 +5012,7 @@ EnumDecl *EnumDecl::getTemplateInstantiationPattern() const { EnumDecl *ED = getInstantiatedFromMemberEnum(); while (auto *NewED = ED->getInstantiatedFromMemberEnum()) ED = NewED; - return getDefinitionOrSelf(ED); + return ::getDefinitionOrSelf(ED); } } @@ -5119,26 +5102,15 @@ RecordDecl::RecordDecl(Kind DK, TagKind TK, const ASTContext &C, RecordDecl *RecordDecl::Create(const ASTContext &C, TagKind TK, DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, IdentifierInfo *Id, RecordDecl* PrevDecl) { - RecordDecl *R = new (C, DC) RecordDecl(Record, TK, C, DC, - StartLoc, IdLoc, Id, PrevDecl); - R->setMayHaveOutOfDateDef(C.getLangOpts().Modules); - - C.getTypeDeclType(R, PrevDecl); - return R; + return new (C, DC) + RecordDecl(Record, TK, C, DC, StartLoc, IdLoc, Id, PrevDecl); } RecordDecl *RecordDecl::CreateDeserialized(const ASTContext &C, GlobalDeclID ID) { - RecordDecl *R = new (C, ID) + return new (C, ID) RecordDecl(Record, TagTypeKind::Struct, C, nullptr, SourceLocation(), SourceLocation(), nullptr, nullptr); - R->setMayHaveOutOfDateDef(C.getLangOpts().Modules); - return R; -} - -bool RecordDecl::isInjectedClassName() const { - return isImplicit() && getDeclName() && getDeclContext()->isRecord() && - cast(getDeclContext())->getDeclName() == getDeclName(); } bool RecordDecl::isLambda() const { @@ -5162,7 +5134,7 @@ bool RecordDecl::isOrContainsUnion() const { if (const RecordDecl *Def = getDefinition()) { for (const FieldDecl *FD : Def->fields()) { const RecordType *RT = FD->getType()->getAs(); - if (RT && RT->getDecl()->isOrContainsUnion()) + if (RT && RT->getOriginalDecl()->isOrContainsUnion()) return true; } } @@ -5294,8 +5266,9 @@ const FieldDecl *RecordDecl::findFirstNamedDataMember() const { return I; if (const auto *RT = I->getType()->getAs()) - if (const FieldDecl *NamedDataMember = - RT->getDecl()->findFirstNamedDataMember()) + if (const FieldDecl *NamedDataMember = RT->getOriginalDecl() + ->getDefinitionOrSelf() + ->findFirstNamedDataMember()) return NamedDataMember; } @@ -5657,14 +5630,14 @@ void TypedefNameDecl::anchor() {} TagDecl *TypedefNameDecl::getAnonDeclWithTypedefName(bool AnyRedecl) const { if (auto *TT = getTypeSourceInfo()->getType()->getAs()) { - auto *OwningTypedef = TT->getDecl()->getTypedefNameForAnonDecl(); + auto *OwningTypedef = TT->getOriginalDecl()->getTypedefNameForAnonDecl(); auto *ThisTypedef = this; if (AnyRedecl && OwningTypedef) { OwningTypedef = OwningTypedef->getCanonicalDecl(); ThisTypedef = ThisTypedef->getCanonicalDecl(); } if (OwningTypedef == ThisTypedef) - return TT->getDecl(); + return TT->getOriginalDecl()->getDefinitionOrSelf(); } return nullptr; @@ -5673,7 +5646,7 @@ TagDecl *TypedefNameDecl::getAnonDeclWithTypedefName(bool AnyRedecl) const { bool TypedefNameDecl::isTransparentTagSlow() const { auto determineIsTransparent = [&]() { if (auto *TT = getUnderlyingType()->getAs()) { - if (auto *TD = TT->getDecl()) { + if (auto *TD = TT->getOriginalDecl()) { if (TD->getName() != getName()) return false; SourceLocation TTLoc = getLocation(); diff --git a/clang/lib/AST/DeclBase.cpp b/clang/lib/AST/DeclBase.cpp index 13c46fdbff96a..680a4d74171a9 100644 --- a/clang/lib/AST/DeclBase.cpp +++ b/clang/lib/AST/DeclBase.cpp @@ -58,10 +58,6 @@ using namespace clang; #define ABSTRACT_DECL(DECL) #include "clang/AST/DeclNodes.inc" -void Decl::updateOutOfDate(IdentifierInfo &II) const { - getASTContext().getExternalSource()->updateOutOfDateIdentifier(II); -} - #define DECL(DERIVED, BASE) \ static_assert(alignof(Decl) >= alignof(DERIVED##Decl), \ "Alignment sufficient after objects prepended to " #DERIVED); @@ -489,8 +485,7 @@ bool Decl::isFlexibleArrayMemberLike( // Look through typedefs. if (TypedefTypeLoc TTL = TL.getAsAdjusted()) { - const TypedefNameDecl *TDL = TTL.getTypedefNameDecl(); - TInfo = TDL->getTypeSourceInfo(); + TInfo = TTL.getDecl()->getTypeSourceInfo(); continue; } @@ -1512,30 +1507,19 @@ DeclContext *DeclContext::getPrimaryContext() { case Decl::ObjCCategoryImpl: return this; - default: - if (getDeclKind() >= Decl::firstTag && getDeclKind() <= Decl::lastTag) { - // If this is a tag type that has a definition or is currently - // being defined, that definition is our primary context. - auto *Tag = cast(this); - - if (TagDecl *Def = Tag->getDefinition()) - return Def; - - if (const auto *TagTy = dyn_cast(Tag->getTypeForDecl())) { - // Note, TagType::getDecl returns the (partial) definition one exists. - TagDecl *PossiblePartialDef = TagTy->getDecl(); - if (PossiblePartialDef->isBeingDefined()) - return PossiblePartialDef; - } else { - assert(isa(Tag->getTypeForDecl())); - } - - return Tag; - } + // If this is a tag type that has a definition or is currently + // being defined, that definition is our primary context. + case Decl::ClassTemplatePartialSpecialization: + case Decl::ClassTemplateSpecialization: + case Decl::CXXRecord: + return cast(this)->getDefinitionOrSelf(); + case Decl::Record: + case Decl::Enum: + return cast(this)->getDefinitionOrSelf(); + default: assert(getDeclKind() >= Decl::firstFunction && - getDeclKind() <= Decl::lastFunction && - "Unknown DeclContext kind"); + getDeclKind() <= Decl::lastFunction && "Unknown DeclContext kind"); return this; } } diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp index ccb308e103253..6ab0650171301 100644 --- a/clang/lib/AST/DeclCXX.cpp +++ b/clang/lib/AST/DeclCXX.cpp @@ -132,16 +132,9 @@ CXXRecordDecl::CXXRecordDecl(Kind K, TagKind TK, const ASTContext &C, CXXRecordDecl *CXXRecordDecl::Create(const ASTContext &C, TagKind TK, DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, IdentifierInfo *Id, - CXXRecordDecl *PrevDecl, - bool DelayTypeCreation) { - auto *R = new (C, DC) CXXRecordDecl(CXXRecord, TK, C, DC, StartLoc, IdLoc, Id, - PrevDecl); - R->setMayHaveOutOfDateDef(C.getLangOpts().Modules); - - // FIXME: DelayTypeCreation seems like such a hack - if (!DelayTypeCreation) - C.getTypeDeclType(R, PrevDecl); - return R; + CXXRecordDecl *PrevDecl) { + return new (C, DC) + CXXRecordDecl(CXXRecord, TK, C, DC, StartLoc, IdLoc, Id, PrevDecl); } CXXRecordDecl * @@ -154,10 +147,7 @@ CXXRecordDecl::CreateLambda(const ASTContext &C, DeclContext *DC, R->setBeingDefined(true); R->DefinitionData = new (C) struct LambdaDefinitionData( R, Info, DependencyKind, IsGeneric, CaptureDefault); - R->setMayHaveOutOfDateDef(false); R->setImplicit(true); - - C.getTypeDeclType(R, /*PrevDecl=*/nullptr); return R; } @@ -166,7 +156,6 @@ CXXRecordDecl *CXXRecordDecl::CreateDeserialized(const ASTContext &C, auto *R = new (C, ID) CXXRecordDecl(CXXRecord, TagTypeKind::Struct, C, nullptr, SourceLocation(), SourceLocation(), nullptr, nullptr); - R->setMayHaveOutOfDateDef(false); return R; } @@ -178,7 +167,7 @@ static bool hasRepeatedBaseClass(const CXXRecordDecl *StartRD) { SmallVector WorkList = {StartRD}; while (!WorkList.empty()) { const CXXRecordDecl *RD = WorkList.pop_back_val(); - if (RD->getTypeForDecl()->isDependentType()) + if (RD->isDependentType()) continue; for (const CXXBaseSpecifier &BaseSpec : RD->bases()) { if (const CXXRecordDecl *B = BaseSpec.getType()->getAsCXXRecordDecl()) { @@ -228,7 +217,8 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases, if (BaseType->isDependentType()) continue; auto *BaseClassDecl = - cast(BaseType->castAs()->getDecl()); + cast(BaseType->castAs()->getOriginalDecl()) + ->getDefinitionOrSelf(); // C++2a [class]p7: // A standard-layout class is a class that: @@ -1218,7 +1208,7 @@ void CXXRecordDecl::addedMember(Decl *D) { bool IsZeroSize = Field->isZeroSize(Context); if (const auto *RecordTy = T->getAs()) { - auto *FieldRec = cast(RecordTy->getDecl()); + auto *FieldRec = cast(RecordTy->getOriginalDecl()); if (FieldRec->getDefinition()) { addedClassSubobject(FieldRec); @@ -1925,7 +1915,8 @@ static void CollectVisibleConversions( = CXXRecordDecl::MergeAccess(Access, I.getAccessSpecifier()); bool BaseInVirtual = InVirtual || I.isVirtual(); - auto *Base = cast(RT->getDecl()); + auto *Base = + cast(RT->getOriginalDecl())->getDefinitionOrSelf(); CollectVisibleConversions(Context, Base, BaseInVirtual, BaseAccess, *HiddenTypes, Output, VOutput, HiddenVBaseCs); } @@ -1963,9 +1954,11 @@ static void CollectVisibleConversions(ASTContext &Context, const auto *RT = I.getType()->getAs(); if (!RT) continue; - CollectVisibleConversions(Context, cast(RT->getDecl()), - I.isVirtual(), I.getAccessSpecifier(), - HiddenTypes, Output, VBaseCs, HiddenVBaseCs); + CollectVisibleConversions( + Context, + cast(RT->getOriginalDecl())->getDefinitionOrSelf(), + I.isVirtual(), I.getAccessSpecifier(), HiddenTypes, Output, VBaseCs, + HiddenVBaseCs); } // Add any unhidden conversions provided by virtual bases. @@ -2125,11 +2118,10 @@ const CXXRecordDecl *CXXRecordDecl::getTemplateInstantiationPattern() const { CXXDestructorDecl *CXXRecordDecl::getDestructor() const { ASTContext &Context = getASTContext(); - QualType ClassType = Context.getTypeDeclType(this); + CanQualType ClassType = Context.getCanonicalTagType(this); - DeclarationName Name - = Context.DeclarationNames.getCXXDestructorName( - Context.getCanonicalType(ClassType)); + DeclarationName Name = + Context.DeclarationNames.getCXXDestructorName(ClassType); DeclContext::lookup_result R = lookup(Name); @@ -2149,6 +2141,39 @@ bool CXXRecordDecl::hasDeletedDestructor() const { return false; } +bool CXXRecordDecl::isInjectedClassName() const { + if (!isImplicit() || !getDeclName()) + return false; + + if (const auto *RD = dyn_cast(getDeclContext())) + return RD->getDeclName() == getDeclName(); + + return false; +} + +bool CXXRecordDecl::hasInjectedClassType() const { + switch (getDeclKind()) { + case Decl::ClassTemplatePartialSpecialization: + return true; + case Decl::ClassTemplateSpecialization: + return false; + case Decl::CXXRecord: + return getDescribedClassTemplate() != nullptr; + default: + llvm_unreachable("unexpected decl kind"); + } +} + +CanQualType CXXRecordDecl::getCanonicalTemplateSpecializationType( + const ASTContext &Ctx) const { + if (auto *RD = dyn_cast(this)) + return RD->getCanonicalInjectedSpecializationType(Ctx); + if (const ClassTemplateDecl *TD = getDescribedClassTemplate(); + TD && !isa(this)) + return TD->getCanonicalInjectedSpecializationType(Ctx); + return CanQualType(); +} + static bool isDeclContextInNamespace(const DeclContext *DC) { while (!DC->isTranslationUnit()) { if (DC->isNamespace()) @@ -2262,7 +2287,7 @@ void CXXRecordDecl::completeDefinition(CXXFinalOverriderMap *FinalOverriders) { Context.getDiagnostics().Report( AT->getLocation(), diag::warn_cxx20_compat_requires_explicit_init_non_aggregate) - << AT << FD << Context.getRecordType(this); + << AT << FD << Context.getCanonicalTagType(this); } } @@ -2274,7 +2299,7 @@ void CXXRecordDecl::completeDefinition(CXXFinalOverriderMap *FinalOverriders) { if (const auto *AT = FD->getAttr()) Context.getDiagnostics().Report(AT->getLocation(), diag::warn_attribute_needs_aggregate) - << AT << Context.getRecordType(this); + << AT << Context.getCanonicalTagType(this); } setHasUninitializedExplicitInitFields(false); } @@ -2286,8 +2311,8 @@ bool CXXRecordDecl::mayBeAbstract() const { return false; for (const auto &B : bases()) { - const auto *BaseDecl = - cast(B.getType()->castAs()->getDecl()); + const auto *BaseDecl = cast( + B.getType()->castAs()->getOriginalDecl()); if (BaseDecl->isAbstract()) return true; } @@ -2450,7 +2475,8 @@ CXXMethodDecl::getCorrespondingMethodInClass(const CXXRecordDecl *RD, const RecordType *RT = I.getType()->getAs(); if (!RT) continue; - const auto *Base = cast(RT->getDecl()); + const auto *Base = + cast(RT->getOriginalDecl())->getDefinitionOrSelf(); if (CXXMethodDecl *D = this->getCorrespondingMethodInClass(Base)) AddFinalOverrider(D); } @@ -2702,8 +2728,7 @@ bool CXXMethodDecl::isCopyAssignmentOperator() const { ParamType = Ref->getPointeeType(); ASTContext &Context = getASTContext(); - QualType ClassType - = Context.getCanonicalType(Context.getTypeDeclType(getParent())); + CanQualType ClassType = Context.getCanonicalTagType(getParent()); return Context.hasSameUnqualifiedType(ClassType, ParamType); } @@ -2723,8 +2748,7 @@ bool CXXMethodDecl::isMoveAssignmentOperator() const { ParamType = ParamType->getPointeeType(); ASTContext &Context = getASTContext(); - QualType ClassType - = Context.getCanonicalType(Context.getTypeDeclType(getParent())); + CanQualType ClassType = Context.getCanonicalTagType(getParent()); return Context.hasSameUnqualifiedType(ClassType, ParamType); } @@ -2759,7 +2783,7 @@ CXXMethodDecl::overridden_methods() const { static QualType getThisObjectType(ASTContext &C, const FunctionProtoType *FPT, const CXXRecordDecl *Decl) { - QualType ClassTy = C.getTypeDeclType(Decl); + CanQualType ClassTy = C.getCanonicalTagType(Decl); return C.getQualifiedType(ClassTy, FPT->getMethodQuals()); } @@ -3017,11 +3041,9 @@ bool CXXConstructorDecl::isCopyOrMoveConstructor(unsigned &TypeQuals) const { // Is it a reference to our class type? ASTContext &Context = getASTContext(); - CanQualType PointeeType - = Context.getCanonicalType(ParamRefType->getPointeeType()); - CanQualType ClassTy - = Context.getCanonicalType(Context.getTagDeclType(getParent())); - if (PointeeType.getUnqualifiedType() != ClassTy) + QualType PointeeType = ParamRefType->getPointeeType(); + CanQualType ClassTy = Context.getCanonicalTagType(getParent()); + if (!Context.hasSameUnqualifiedType(PointeeType, ClassTy)) return false; // FIXME: other qualifiers? @@ -3056,15 +3078,11 @@ bool CXXConstructorDecl::isSpecializationCopyingObject() const { const ParmVarDecl *Param = getParamDecl(0); ASTContext &Context = getASTContext(); - CanQualType ParamType = Context.getCanonicalType(Param->getType()); + CanQualType ParamType = Param->getType()->getCanonicalTypeUnqualified(); // Is it the same as our class type? - CanQualType ClassTy - = Context.getCanonicalType(Context.getTagDeclType(getParent())); - if (ParamType.getUnqualifiedType() != ClassTy) - return false; - - return true; + CanQualType ClassTy = Context.getCanonicalTagType(getParent()); + return ParamType == ClassTy; } void CXXDestructorDecl::anchor() {} @@ -3201,6 +3219,12 @@ UsingDirectiveDecl *UsingDirectiveDecl::CreateDeserialized(ASTContext &C, SourceLocation(), nullptr, nullptr); } +NamespaceDecl *NamespaceBaseDecl::getNamespace() { + if (auto *Alias = dyn_cast(this)) + return Alias->getNamespace(); + return cast(this); +} + NamespaceDecl *UsingDirectiveDecl::getNominatedNamespace() { if (auto *NA = dyn_cast_or_null(NominatedNamespace)) return NA->getNamespace(); @@ -3211,7 +3235,7 @@ NamespaceDecl::NamespaceDecl(ASTContext &C, DeclContext *DC, bool Inline, SourceLocation StartLoc, SourceLocation IdLoc, IdentifierInfo *Id, NamespaceDecl *PrevDecl, bool Nested) - : NamedDecl(Namespace, DC, IdLoc, Id), DeclContext(Namespace), + : NamespaceBaseDecl(Namespace, DC, IdLoc, Id), DeclContext(Namespace), redeclarable_base(C), LocStart(StartLoc) { setInline(Inline); setNested(Nested); @@ -3258,13 +3282,11 @@ NamespaceAliasDecl *NamespaceAliasDecl::getMostRecentDeclImpl() { return getMostRecentDecl(); } -NamespaceAliasDecl *NamespaceAliasDecl::Create(ASTContext &C, DeclContext *DC, - SourceLocation UsingLoc, - SourceLocation AliasLoc, - IdentifierInfo *Alias, - NestedNameSpecifierLoc QualifierLoc, - SourceLocation IdentLoc, - NamedDecl *Namespace) { +NamespaceAliasDecl *NamespaceAliasDecl::Create( + ASTContext &C, DeclContext *DC, SourceLocation UsingLoc, + SourceLocation AliasLoc, IdentifierInfo *Alias, + NestedNameSpecifierLoc QualifierLoc, SourceLocation IdentLoc, + NamespaceBaseDecl *Namespace) { // FIXME: Preserve the aliased namespace as written. if (auto *NS = dyn_cast_or_null(Namespace)) Namespace = NS->getFirstDecl(); @@ -3357,7 +3379,7 @@ ConstructorUsingShadowDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID) { } CXXRecordDecl *ConstructorUsingShadowDecl::getNominatedBaseClass() const { - return getIntroducer()->getQualifier()->getAsRecordDecl(); + return getIntroducer()->getQualifier().getAsRecordDecl(); } void BaseUsingDecl::anchor() {} diff --git a/clang/lib/AST/DeclPrinter.cpp b/clang/lib/AST/DeclPrinter.cpp index 9273f5816d5ac..ca1d601370f23 100644 --- a/clang/lib/AST/DeclPrinter.cpp +++ b/clang/lib/AST/DeclPrinter.cpp @@ -202,8 +202,7 @@ void Decl::printGroup(Decl** Begin, unsigned NumDecls, } Decl** End = Begin + NumDecls; - TagDecl* TD = dyn_cast(*Begin); - if (TD) + if (isa(*Begin)) ++Begin; PrintingPolicy SubPolicy(Policy); @@ -211,13 +210,9 @@ void Decl::printGroup(Decl** Begin, unsigned NumDecls, bool isFirst = true; for ( ; Begin != End; ++Begin) { if (isFirst) { - if(TD) - SubPolicy.IncludeTagDefinition = true; - SubPolicy.SuppressSpecifiers = false; isFirst = false; } else { - if (!isFirst) Out << ", "; - SubPolicy.IncludeTagDefinition = false; + Out << ", "; SubPolicy.SuppressSpecifiers = true; } @@ -487,10 +482,12 @@ void DeclPrinter::VisitDeclContext(DeclContext *DC, bool Indent) { QualType CurDeclType = getDeclType(*D); if (!Decls.empty() && !CurDeclType.isNull()) { QualType BaseType = GetBaseType(CurDeclType); - if (!BaseType.isNull() && isa(BaseType) && - cast(BaseType)->getOwnedTagDecl() == Decls[0]) { - Decls.push_back(*D); - continue; + if (const auto *TT = dyn_cast_or_null(BaseType); + TT && TT->isTagOwned()) { + if (TT->getOriginalDecl() == Decls[0]) { + Decls.push_back(*D); + continue; + } } } @@ -662,16 +659,6 @@ static void printExplicitSpecifier(ExplicitSpecifier ES, llvm::raw_ostream &Out, Out << Proto; } -static void MaybePrintTagKeywordIfSupressingScopes(PrintingPolicy &Policy, - QualType T, - llvm::raw_ostream &Out) { - StringRef prefix = T->isClassType() ? "class " - : T->isStructureType() ? "struct " - : T->isUnionType() ? "union " - : ""; - Out << prefix; -} - void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) { if (!D->getDescribedFunctionTemplate() && !D->isFunctionTemplateSpecialization()) { @@ -721,11 +708,8 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) { Proto += D->getQualifiedNameAsString(); } else { llvm::raw_string_ostream OS(Proto); - if (!Policy.SuppressScope) { - if (const NestedNameSpecifier *NS = D->getQualifier()) { - NS->print(OS, Policy); - } - } + if (!Policy.SuppressScope) + D->getQualifier().print(OS, Policy); D->getNameInfo().printName(OS, Policy); } @@ -833,10 +817,6 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) { Out << Proto << " -> "; Proto.clear(); } - if (!Policy.SuppressTagKeyword && Policy.SuppressScope && - !Policy.SuppressUnwrittenScope) - MaybePrintTagKeywordIfSupressingScopes(Policy, AFT->getReturnType(), - Out); AFT->getReturnType().print(Out, Policy, Proto); Proto.clear(); } @@ -995,10 +975,6 @@ void DeclPrinter::VisitVarDecl(VarDecl *D) { } } - if (!Policy.SuppressTagKeyword && Policy.SuppressScope && - !Policy.SuppressUnwrittenScope) - MaybePrintTagKeywordIfSupressingScopes(Policy, T, Out); - printDeclType(T, (isa(D) && Policy.CleanUglifiedParameters && D->getIdentifier()) ? D->getIdentifier()->deuglifiedName() @@ -1028,7 +1004,6 @@ void DeclPrinter::VisitVarDecl(VarDecl *D) { } PrintingPolicy SubPolicy(Policy); SubPolicy.SuppressSpecifiers = false; - SubPolicy.IncludeTagDefinition = false; Init->printPretty(Out, nullptr, SubPolicy, Indentation, "\n", &Context); if ((D->getInitStyle() == VarDecl::CallInit) && !isa(Init)) Out << ")"; @@ -1086,15 +1061,13 @@ void DeclPrinter::VisitNamespaceDecl(NamespaceDecl *D) { void DeclPrinter::VisitUsingDirectiveDecl(UsingDirectiveDecl *D) { Out << "using namespace "; - if (D->getQualifier()) - D->getQualifier()->print(Out, Policy); + D->getQualifier().print(Out, Policy); Out << *D->getNominatedNamespaceAsWritten(); } void DeclPrinter::VisitNamespaceAliasDecl(NamespaceAliasDecl *D) { Out << "namespace " << *D << " = "; - if (D->getQualifier()) - D->getQualifier()->print(Out, Policy); + D->getQualifier().print(Out, Policy); Out << *D->getAliasedNamespace(); } @@ -1115,8 +1088,7 @@ void DeclPrinter::VisitCXXRecordDecl(CXXRecordDecl *D) { Out << ' '; if (D->getIdentifier()) { - if (auto *NNS = D->getQualifier()) - NNS->print(Out, Policy); + D->getQualifier().print(Out, Policy); Out << *D; if (auto *S = dyn_cast(D)) { @@ -1748,7 +1720,7 @@ void DeclPrinter::VisitUsingDecl(UsingDecl *D) { Out << "using "; if (D->hasTypename()) Out << "typename "; - D->getQualifier()->print(Out, Policy); + D->getQualifier().print(Out, Policy); // Use the correct record name when the using declaration is used for // inheriting constructors. @@ -1770,14 +1742,14 @@ void DeclPrinter::VisitUsingEnumDecl(UsingEnumDecl *D) { void DeclPrinter::VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D) { Out << "using typename "; - D->getQualifier()->print(Out, Policy); + D->getQualifier().print(Out, Policy); Out << D->getDeclName(); } void DeclPrinter::VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D) { if (!D->isAccessDeclaration()) Out << "using "; - D->getQualifier()->print(Out, Policy); + D->getQualifier().print(Out, Policy); Out << D->getDeclName(); } diff --git a/clang/lib/AST/DeclTemplate.cpp b/clang/lib/AST/DeclTemplate.cpp index 5035f2d33b0a1..7786e17cfca3d 100644 --- a/clang/lib/AST/DeclTemplate.cpp +++ b/clang/lib/AST/DeclTemplate.cpp @@ -630,7 +630,8 @@ ClassTemplateDecl::findPartialSpecialization(QualType T) { ASTContext &Context = getASTContext(); for (ClassTemplatePartialSpecializationDecl &P : getPartialSpecializations()) { - if (Context.hasSameType(P.getInjectedSpecializationType(), T)) + if (Context.hasSameType(P.getCanonicalInjectedSpecializationType(Context), + T)) return P.getMostRecentDecl(); } @@ -649,28 +650,20 @@ ClassTemplateDecl::findPartialSpecInstantiatedFromMember( return nullptr; } -QualType -ClassTemplateDecl::getInjectedClassNameSpecialization() { +CanQualType ClassTemplateDecl::getCanonicalInjectedSpecializationType( + const ASTContext &Ctx) const { Common *CommonPtr = getCommonPtr(); - if (!CommonPtr->InjectedClassNameType.isNull()) - return CommonPtr->InjectedClassNameType; - - // C++0x [temp.dep.type]p2: - // The template argument list of a primary template is a template argument - // list in which the nth template argument has the value of the nth template - // parameter of the class template. If the nth template parameter is a - // template parameter pack (14.5.3), the nth template argument is a pack - // expansion (14.5.3) whose pattern is the name of the template parameter - // pack. - ASTContext &Context = getASTContext(); - TemplateName Name = Context.getQualifiedTemplateName( - /*NNS=*/nullptr, /*TemplateKeyword=*/false, TemplateName(this)); - auto TemplateArgs = getTemplateParameters()->getInjectedTemplateArgs(Context); - CommonPtr->InjectedClassNameType = - Context.getTemplateSpecializationType(Name, - /*SpecifiedArgs=*/TemplateArgs, - /*CanonicalArgs=*/{}); - return CommonPtr->InjectedClassNameType; + + if (CommonPtr->CanonInjectedTST.isNull()) { + SmallVector CanonicalArgs( + getTemplateParameters()->getInjectedTemplateArgs(Ctx)); + Ctx.canonicalizeTemplateArguments(CanonicalArgs); + CommonPtr->CanonInjectedTST = + CanQualType::CreateUnsafe(Ctx.getCanonicalTemplateSpecializationType( + TemplateName(const_cast(getCanonicalDecl())), + CanonicalArgs)); + } + return CommonPtr->CanonInjectedTST; } //===----------------------------------------------------------------------===// @@ -993,7 +986,6 @@ ClassTemplateSpecializationDecl *ClassTemplateSpecializationDecl::Create( auto *Result = new (Context, DC) ClassTemplateSpecializationDecl( Context, ClassTemplateSpecialization, TK, DC, StartLoc, IdLoc, SpecializedTemplate, Args, StrictPackMatch, PrevDecl); - Result->setMayHaveOutOfDateDef(false); // If the template decl is incomplete, copy the external lexical storage from // the base template. This allows instantiations of incomplete types to @@ -1003,17 +995,14 @@ ClassTemplateSpecializationDecl *ClassTemplateSpecializationDecl::Create( Result->setHasExternalLexicalStorage( SpecializedTemplate->getTemplatedDecl()->hasExternalLexicalStorage()); - Context.getTypeDeclType(Result, PrevDecl); return Result; } ClassTemplateSpecializationDecl * ClassTemplateSpecializationDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID) { - auto *Result = - new (C, ID) ClassTemplateSpecializationDecl(C, ClassTemplateSpecialization); - Result->setMayHaveOutOfDateDef(false); - return Result; + return new (C, ID) + ClassTemplateSpecializationDecl(C, ClassTemplateSpecialization); } void ClassTemplateSpecializationDecl::getNameForDiagnostic( @@ -1175,13 +1164,15 @@ ClassTemplatePartialSpecializationDecl::ClassTemplatePartialSpecializationDecl( ASTContext &Context, TagKind TK, DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, TemplateParameterList *Params, ClassTemplateDecl *SpecializedTemplate, ArrayRef Args, + CanQualType CanonInjectedTST, ClassTemplatePartialSpecializationDecl *PrevDecl) : ClassTemplateSpecializationDecl( Context, ClassTemplatePartialSpecialization, TK, DC, StartLoc, IdLoc, // Tracking StrictPackMatch for Partial // Specializations is not needed. SpecializedTemplate, Args, /*StrictPackMatch=*/false, PrevDecl), - TemplateParams(Params), InstantiatedFromMember(nullptr, false) { + TemplateParams(Params), InstantiatedFromMember(nullptr, false), + CanonInjectedTST(CanonInjectedTST) { if (AdoptTemplateParameterList(Params, this)) setInvalidDecl(); } @@ -1191,24 +1182,31 @@ ClassTemplatePartialSpecializationDecl::Create( ASTContext &Context, TagKind TK, DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, TemplateParameterList *Params, ClassTemplateDecl *SpecializedTemplate, ArrayRef Args, - QualType CanonInjectedType, + CanQualType CanonInjectedTST, ClassTemplatePartialSpecializationDecl *PrevDecl) { auto *Result = new (Context, DC) ClassTemplatePartialSpecializationDecl( Context, TK, DC, StartLoc, IdLoc, Params, SpecializedTemplate, Args, - PrevDecl); + CanonInjectedTST, PrevDecl); Result->setSpecializationKind(TSK_ExplicitSpecialization); - Result->setMayHaveOutOfDateDef(false); - - Context.getInjectedClassNameType(Result, CanonInjectedType); return Result; } ClassTemplatePartialSpecializationDecl * ClassTemplatePartialSpecializationDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID) { - auto *Result = new (C, ID) ClassTemplatePartialSpecializationDecl(C); - Result->setMayHaveOutOfDateDef(false); - return Result; + return new (C, ID) ClassTemplatePartialSpecializationDecl(C); +} + +CanQualType +ClassTemplatePartialSpecializationDecl::getCanonicalInjectedSpecializationType( + const ASTContext &Ctx) const { + if (CanonInjectedTST.isNull()) { + CanonInjectedTST = + CanQualType::CreateUnsafe(Ctx.getCanonicalTemplateSpecializationType( + TemplateName(getSpecializedTemplate()->getCanonicalDecl()), + getTemplateArgs().asArray())); + } + return CanonInjectedTST; } SourceRange ClassTemplatePartialSpecializationDecl::getSourceRange() const { diff --git a/clang/lib/AST/DeclarationName.cpp b/clang/lib/AST/DeclarationName.cpp index ae5fcf6e86adf..6c7b995d57567 100644 --- a/clang/lib/AST/DeclarationName.cpp +++ b/clang/lib/AST/DeclarationName.cpp @@ -115,12 +115,12 @@ static void printCXXConstructorDestructorName(QualType ClassType, Policy.adjustForCPlusPlus(); if (const RecordType *ClassRec = ClassType->getAs()) { - ClassRec->getDecl()->printName(OS, Policy); + ClassRec->getOriginalDecl()->printName(OS, Policy); return; } if (Policy.SuppressTemplateArgsInCXXConstructors) { if (auto *InjTy = ClassType->getAs()) { - InjTy->getDecl()->printName(OS, Policy); + InjTy->getOriginalDecl()->printName(OS, Policy); return; } } @@ -184,7 +184,7 @@ void DeclarationName::print(raw_ostream &OS, OS << "operator "; QualType Type = getCXXNameType(); if (const RecordType *Rec = Type->getAs()) { - OS << *Rec->getDecl(); + OS << *Rec->getOriginalDecl(); return; } // We know we're printing C++ here, ensure we print 'bool' properly. diff --git a/clang/lib/AST/DynamicRecursiveASTVisitor.cpp b/clang/lib/AST/DynamicRecursiveASTVisitor.cpp index b478e7a39ea18..8821cd332e918 100644 --- a/clang/lib/AST/DynamicRecursiveASTVisitor.cpp +++ b/clang/lib/AST/DynamicRecursiveASTVisitor.cpp @@ -115,8 +115,12 @@ template struct Impl : RecursiveASTVisitor> { bool TraverseAST(ASTContext &AST) { return Visitor.TraverseAST(AST); } bool TraverseAttr(Attr *At) { return Visitor.TraverseAttr(At); } bool TraverseDecl(Decl *D) { return Visitor.TraverseDecl(D); } - bool TraverseType(QualType T) { return Visitor.TraverseType(T); } - bool TraverseTypeLoc(TypeLoc TL) { return Visitor.TraverseTypeLoc(TL); } + bool TraverseType(QualType T, bool TraverseQualifier = true) { + return Visitor.TraverseType(T, TraverseQualifier); + } + bool TraverseTypeLoc(TypeLoc TL, bool TraverseQualifier = true) { + return Visitor.TraverseTypeLoc(TL, TraverseQualifier); + } bool TraverseStmt(Stmt *S) { return Visitor.TraverseStmt(S); } bool TraverseConstructorInitializer(CXXCtorInitializer *Init) { @@ -172,7 +176,7 @@ template struct Impl : RecursiveASTVisitor> { return Visitor.TraverseLambdaCapture(LE, C, Init); } - bool TraverseNestedNameSpecifier(NestedNameSpecifier *NNS) { + bool TraverseNestedNameSpecifier(NestedNameSpecifier NNS) { return Visitor.TraverseNestedNameSpecifier(NNS); } @@ -241,8 +245,8 @@ template struct Impl : RecursiveASTVisitor> { // Types. #define ABSTRACT_TYPE(CLASS, BASE) #define TYPE(CLASS, BASE) \ - bool Traverse##CLASS##Type(CLASS##Type *T) { \ - return Visitor.Traverse##CLASS##Type(T); \ + bool Traverse##CLASS##Type(CLASS##Type *T, bool TraverseQualifier) { \ + return Visitor.Traverse##CLASS##Type(T, TraverseQualifier); \ } #include "clang/AST/TypeNodes.inc" @@ -255,8 +259,8 @@ template struct Impl : RecursiveASTVisitor> { // TypeLocs. #define ABSTRACT_TYPELOC(CLASS, BASE) #define TYPELOC(CLASS, BASE) \ - bool Traverse##CLASS##TypeLoc(CLASS##TypeLoc TL) { \ - return Visitor.Traverse##CLASS##TypeLoc(TL); \ + bool Traverse##CLASS##TypeLoc(CLASS##TypeLoc TL, bool TraverseQualifier) { \ + return Visitor.Traverse##CLASS##TypeLoc(TL, TraverseQualifier); \ } #include "clang/AST/TypeLocNodes.def" @@ -297,7 +301,6 @@ FORWARD_TO_BASE(TraverseAttr, Attr, *) FORWARD_TO_BASE(TraverseConstructorInitializer, CXXCtorInitializer, *) FORWARD_TO_BASE(TraverseDecl, Decl, *) FORWARD_TO_BASE(TraverseStmt, Stmt, *) -FORWARD_TO_BASE(TraverseNestedNameSpecifier, NestedNameSpecifier, *) FORWARD_TO_BASE(TraverseTemplateInstantiations, ClassTemplateDecl, *) FORWARD_TO_BASE(TraverseTemplateInstantiations, VarTemplateDecl, *) FORWARD_TO_BASE(TraverseTemplateInstantiations, FunctionTemplateDecl, *) @@ -314,8 +317,22 @@ FORWARD_TO_BASE_EXACT(TraverseTemplateArgument, const TemplateArgument &) FORWARD_TO_BASE_EXACT(TraverseTemplateArguments, ArrayRef) FORWARD_TO_BASE_EXACT(TraverseTemplateArgumentLoc, const TemplateArgumentLoc &) FORWARD_TO_BASE_EXACT(TraverseTemplateName, TemplateName) -FORWARD_TO_BASE_EXACT(TraverseType, QualType) -FORWARD_TO_BASE_EXACT(TraverseTypeLoc, TypeLoc) +FORWARD_TO_BASE_EXACT(TraverseNestedNameSpecifier, NestedNameSpecifier) + +template +bool DynamicRecursiveASTVisitorBase::TraverseType( + QualType T, bool TraverseQualifier) { + return Impl(*this).RecursiveASTVisitor>::TraverseType( + T, TraverseQualifier); +} + +template +bool DynamicRecursiveASTVisitorBase::TraverseTypeLoc( + TypeLoc TL, bool TraverseQualifier) { + return Impl(*this).RecursiveASTVisitor>::TraverseTypeLoc( + TL, TraverseQualifier); +} + FORWARD_TO_BASE_EXACT(TraverseTypeConstraint, const TypeConstraint *) FORWARD_TO_BASE_EXACT(TraverseObjCProtocolLoc, ObjCProtocolLoc) FORWARD_TO_BASE_EXACT(TraverseNestedNameSpecifierLoc, NestedNameSpecifierLoc) @@ -354,13 +371,25 @@ bool DynamicRecursiveASTVisitorBase::dataTraverseNode( // Declare Traverse*() and friends for all concrete Type classes. #define ABSTRACT_TYPE(CLASS, BASE) #define TYPE(CLASS, BASE) \ - FORWARD_TO_BASE(Traverse##CLASS##Type, CLASS##Type, *) \ + template \ + bool DynamicRecursiveASTVisitorBase::Traverse##CLASS##Type( \ + MaybeConst *T, bool TraverseQualifier) { \ + return Impl(*this) \ + .RecursiveASTVisitor>::Traverse##CLASS##Type( \ + const_cast(T), TraverseQualifier); \ + } \ FORWARD_TO_BASE(WalkUpFrom##CLASS##Type, CLASS##Type, *) #include "clang/AST/TypeNodes.inc" #define ABSTRACT_TYPELOC(CLASS, BASE) #define TYPELOC(CLASS, BASE) \ - FORWARD_TO_BASE_EXACT(Traverse##CLASS##TypeLoc, CLASS##TypeLoc) + template \ + bool DynamicRecursiveASTVisitorBase::Traverse##CLASS##TypeLoc( \ + CLASS##TypeLoc TL, bool TraverseQualifier) { \ + return Impl(*this) \ + .RecursiveASTVisitor>::Traverse##CLASS##TypeLoc( \ + TL, TraverseQualifier); \ + } #include "clang/AST/TypeLocNodes.def" #define TYPELOC(CLASS, BASE) \ diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp index 36fd5ee271e03..ca312c35508f5 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -75,8 +75,7 @@ const CXXRecordDecl *Expr::getBestDynamicClassType() const { return nullptr; const RecordType *Ty = DerivedType->castAs(); - Decl *D = Ty->getDecl(); - return cast(D); + return cast(Ty->getOriginalDecl())->getDefinitionOrSelf(); } const Expr *Expr::skipRValueSubobjectAdjustments( @@ -92,7 +91,9 @@ const Expr *Expr::skipRValueSubobjectAdjustments( E->getType()->isRecordType()) { E = CE->getSubExpr(); const auto *Derived = - cast(E->getType()->castAs()->getDecl()); + cast( + E->getType()->castAs()->getOriginalDecl()) + ->getDefinitionOrSelf(); Adjustments.push_back(SubobjectAdjustment(CE, Derived)); continue; } @@ -268,7 +269,7 @@ QualType Expr::getEnumCoercedType(const ASTContext &Ctx) const { if (const auto *ECD = getEnumConstantDecl()) { const auto *ED = cast(ECD->getDeclContext()); if (ED->isCompleteDefinition()) - return Ctx.getTypeDeclType(ED); + return Ctx.getCanonicalTagType(ED); } return getType(); } @@ -2031,7 +2032,8 @@ CXXBaseSpecifier **CastExpr::path_buffer() { const FieldDecl *CastExpr::getTargetFieldForToUnionCast(QualType unionType, QualType opType) { - auto RD = unionType->castAs()->getDecl(); + auto RD = + unionType->castAs()->getOriginalDecl()->getDefinitionOrSelf(); return getTargetFieldForToUnionCast(RD, opType); } @@ -3222,7 +3224,7 @@ static const Expr *skipTemporaryBindingsNoOpCastsAndParens(const Expr *E) { /// isTemporaryObject - Determines if this expression produces a /// temporary of the given class type. bool Expr::isTemporaryObject(ASTContext &C, const CXXRecordDecl *TempTy) const { - if (!C.hasSameUnqualifiedType(getType(), C.getTypeDeclType(TempTy))) + if (!C.hasSameUnqualifiedType(getType(), C.getCanonicalTagType(TempTy))) return false; const Expr *E = skipTemporaryBindingsNoOpCastsAndParens(this); @@ -3404,7 +3406,10 @@ bool Expr::isConstantInitializer(ASTContext &Ctx, bool IsForRef, if (ILE->getType()->isRecordType()) { unsigned ElementNo = 0; - RecordDecl *RD = ILE->getType()->castAs()->getDecl(); + RecordDecl *RD = ILE->getType() + ->castAs() + ->getOriginalDecl() + ->getDefinitionOrSelf(); // In C++17, bases were added to the list of members used by aggregate // initialization. @@ -4047,8 +4052,10 @@ Expr::isNullPointerConstant(ASTContext &Ctx, return NPCK_CXX11_nullptr; if (const RecordType *UT = getType()->getAsUnionType()) - if (!Ctx.getLangOpts().CPlusPlus11 && - UT && UT->getDecl()->hasAttr()) + if (!Ctx.getLangOpts().CPlusPlus11 && UT && + UT->getOriginalDecl() + ->getMostRecentDecl() + ->hasAttr()) if (const CompoundLiteralExpr *CLE = dyn_cast(this)){ const Expr *InitExpr = CLE->getInitializer(); if (const InitListExpr *ILE = dyn_cast(InitExpr)) diff --git a/clang/lib/AST/ExprCXX.cpp b/clang/lib/AST/ExprCXX.cpp index 5833a6405125d..21640c87ab424 100644 --- a/clang/lib/AST/ExprCXX.cpp +++ b/clang/lib/AST/ExprCXX.cpp @@ -1307,7 +1307,7 @@ LambdaExpr *LambdaExpr::Create(const ASTContext &Context, CXXRecordDecl *Class, bool ContainsUnexpandedParameterPack) { // Determine the type of the expression (i.e., the type of the // function object we're creating). - QualType T = Context.getTypeDeclType(Class); + CanQualType T = Context.getCanonicalTagType(Class); unsigned Size = totalSizeToAlloc(CaptureInits.size() + 1); void *Mem = Context.Allocate(Size); @@ -1675,10 +1675,9 @@ CXXRecordDecl *UnresolvedMemberExpr::getNamingClass() { // It can't be dependent: after all, we were actually able to do the // lookup. CXXRecordDecl *Record = nullptr; - auto *NNS = getQualifier(); - if (NNS && NNS->getKind() != NestedNameSpecifier::Super) { - const Type *T = getQualifier()->getAsType(); - assert(T && "qualifier in member expression does not name type"); + if (NestedNameSpecifier Qualifier = getQualifier(); + Qualifier.getKind() == NestedNameSpecifier::Kind::Type) { + const Type *T = getQualifier().getAsType(); Record = T->getAsCXXRecordDecl(); assert(Record && "qualifier in member expression does not name record"); } diff --git a/clang/lib/AST/ExprConcepts.cpp b/clang/lib/AST/ExprConcepts.cpp index ac0e566fe6e72..36f910da49bfb 100644 --- a/clang/lib/AST/ExprConcepts.cpp +++ b/clang/lib/AST/ExprConcepts.cpp @@ -41,10 +41,10 @@ ConceptSpecializationExpr::ConceptSpecializationExpr( assert(!Loc->getNestedNameSpecifierLoc() || (!Loc->getNestedNameSpecifierLoc() .getNestedNameSpecifier() - ->isInstantiationDependent() && + .isInstantiationDependent() && !Loc->getNestedNameSpecifierLoc() .getNestedNameSpecifier() - ->containsUnexpandedParameterPack())); + .containsUnexpandedParameterPack())); assert((!isValueDependent() || isInstantiationDependent()) && "should not be value-dependent"); } diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 60c658a8d8f99..fb8b89c355ed9 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -400,7 +400,7 @@ namespace { assert(!Invalid && "invalid designator has no subobject type"); return MostDerivedPathLength == Entries.size() ? MostDerivedType - : Ctx.getRecordType(getAsBaseClass(Entries.back())); + : Ctx.getCanonicalTagType(getAsBaseClass(Entries.back())); } /// Update this designator to refer to the first element within this array. @@ -2617,7 +2617,8 @@ static bool CheckEvaluationResult(CheckEvaluationResultKind CERK, Value.getUnionValue(), Kind, Value.getUnionField(), CheckedTemps); } if (Value.isStruct()) { - RecordDecl *RD = Type->castAs()->getDecl(); + RecordDecl *RD = + Type->castAs()->getOriginalDecl()->getDefinitionOrSelf(); if (const CXXRecordDecl *CD = dyn_cast(RD)) { unsigned BaseIndex = 0; for (const CXXBaseSpecifier &BS : CD->bases()) { @@ -4103,7 +4104,7 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj, } // Next subobject is a class, struct or union field. - RecordDecl *RD = ObjType->castAs()->getDecl(); + RecordDecl *RD = ObjType->castAs()->getOriginalDecl(); if (RD->isUnion()) { const FieldDecl *UnionField = O->getUnionField(); if (!UnionField || @@ -4138,7 +4139,7 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj, const CXXRecordDecl *Base = getAsBaseClass(Sub.Entries[I]); O = &O->getStructBase(getBaseIndex(Derived, Base)); - ObjType = getSubobjectType(ObjType, Info.Ctx.getRecordType(Base)); + ObjType = getSubobjectType(ObjType, Info.Ctx.getCanonicalTagType(Base)); } } } @@ -6295,7 +6296,7 @@ static bool HandleDynamicCast(EvalInfo &Info, const ExplicitCastExpr *E, const CXXRecordDecl *C = E->getTypeAsWritten()->getPointeeCXXRecordDecl(); assert(C && "dynamic_cast target is not void pointer nor class"); - CanQualType CQT = Info.Ctx.getCanonicalType(Info.Ctx.getRecordType(C)); + CanQualType CQT = Info.Ctx.getCanonicalTagType(C); auto RuntimeCheckFailed = [&] (CXXBasePaths *Paths) { // C++ [expr.dynamic.cast]p9: @@ -6321,7 +6322,7 @@ static bool HandleDynamicCast(EvalInfo &Info, const ExplicitCastExpr *E, } Info.FFDiag(E, diag::note_constexpr_dynamic_cast_to_reference_failed) << DiagKind << Ptr.Designator.getType(Info.Ctx) - << Info.Ctx.getRecordType(DynType->Type) + << Info.Ctx.getCanonicalTagType(DynType->Type) << E->getType().getUnqualifiedType(); return false; }; @@ -6818,8 +6819,8 @@ static bool HandleConstructorCall(const Expr *E, const LValue &This, // FIXME: This immediately starts the lifetime of all members of // an anonymous struct. It would be preferable to strictly start // member lifetime in initialization order. - Success &= - handleDefaultInitValue(Info.Ctx.getRecordType(CD), *Value); + Success &= handleDefaultInitValue(Info.Ctx.getCanonicalTagType(CD), + *Value); } // Store Subobject as its parent before updating it for the last element // in the chain. @@ -7717,7 +7718,8 @@ class BufferToAPValueConverter { } std::optional visit(const EnumType *Ty, CharUnits Offset) { - QualType RepresentationType = Ty->getDecl()->getIntegerType(); + QualType RepresentationType = + Ty->getOriginalDecl()->getDefinitionOrSelf()->getIntegerType(); assert(!RepresentationType.isNull() && "enum forward decl should be caught by Sema"); const auto *AsBuiltin = @@ -8451,7 +8453,7 @@ class ExprEvaluatorBase if (auto *DD = dyn_cast(FD)) { assert(This && "no 'this' pointer for destructor call"); return HandleDestruction(Info, E, *This, - Info.Ctx.getRecordType(DD->getParent())) && + Info.Ctx.getCanonicalTagType(DD->getParent())) && CallScope.destroy(); } @@ -8512,8 +8514,10 @@ class ExprEvaluatorBase const FieldDecl *FD = dyn_cast(E->getMemberDecl()); if (!FD) return Error(E); assert(!FD->getType()->isReferenceType() && "prvalue reference?"); - assert(BaseTy->castAs()->getDecl()->getCanonicalDecl() == - FD->getParent()->getCanonicalDecl() && "record / field mismatch"); + assert( + BaseTy->castAs()->getOriginalDecl()->getCanonicalDecl() == + FD->getParent()->getCanonicalDecl() && + "record / field mismatch"); // Note: there is no lvalue base here. But this case should only ever // happen in C or in C++98, where we cannot be evaluating a constexpr @@ -8740,8 +8744,10 @@ class LValueExprEvaluatorBase const ValueDecl *MD = E->getMemberDecl(); if (const FieldDecl *FD = dyn_cast(E->getMemberDecl())) { - assert(BaseTy->castAs()->getDecl()->getCanonicalDecl() == - FD->getParent()->getCanonicalDecl() && "record / field mismatch"); + assert( + BaseTy->castAs()->getOriginalDecl()->getCanonicalDecl() == + FD->getParent()->getCanonicalDecl() && + "record / field mismatch"); (void)BaseTy; if (!HandleLValueMember(this->Info, E, Result, FD)) return false; @@ -9180,8 +9186,8 @@ bool LValueExprEvaluator::VisitCXXTypeidExpr(const CXXTypeidExpr *E) { if (!DynType) return false; - TypeInfo = - TypeInfoLValue(Info.Ctx.getRecordType(DynType->Type).getTypePtr()); + TypeInfo = TypeInfoLValue( + Info.Ctx.getCanonicalTagType(DynType->Type).getTypePtr()); } return Success(APValue::LValueBase::getTypeInfo(TypeInfo, E->getType())); @@ -10718,7 +10724,8 @@ static bool HandleClassZeroInitialization(EvalInfo &Info, const Expr *E, } bool RecordExprEvaluator::ZeroInitialization(const Expr *E, QualType T) { - const RecordDecl *RD = T->castAs()->getDecl(); + const RecordDecl *RD = + T->castAs()->getOriginalDecl()->getDefinitionOrSelf(); if (RD->isInvalidDecl()) return false; if (RD->isUnion()) { // C++11 [dcl.init]p5: If T is a (possibly cv-qualified) union type, the @@ -10787,8 +10794,10 @@ bool RecordExprEvaluator::VisitInitListExpr(const InitListExpr *E) { bool RecordExprEvaluator::VisitCXXParenListOrInitListExpr( const Expr *ExprToVisit, ArrayRef Args) { - const RecordDecl *RD = - ExprToVisit->getType()->castAs()->getDecl(); + const RecordDecl *RD = ExprToVisit->getType() + ->castAs() + ->getOriginalDecl() + ->getDefinitionOrSelf(); if (RD->isInvalidDecl()) return false; const ASTRecordLayout &Layout = Info.Ctx.getASTRecordLayout(RD); auto *CXXRD = dyn_cast(RD); @@ -11008,7 +11017,10 @@ bool RecordExprEvaluator::VisitCXXStdInitializerListExpr( Result = APValue(APValue::UninitStruct(), 0, 2); Array.moveInto(Result.getStructField(0)); - RecordDecl *Record = E->getType()->castAs()->getDecl(); + RecordDecl *Record = E->getType() + ->castAs() + ->getOriginalDecl() + ->getDefinitionOrSelf(); RecordDecl::field_iterator Field = Record->field_begin(); assert(Field != Record->field_end() && Info.Ctx.hasSameType(Field->getType()->getPointeeType(), @@ -12781,7 +12793,10 @@ static bool convertUnsignedAPIntToCharUnits(const llvm::APInt &Int, static void addFlexibleArrayMemberInitSize(EvalInfo &Info, const QualType &T, const LValue &LV, CharUnits &Size) { if (!T.isNull() && T->isStructureType() && - T->getAsStructureType()->getDecl()->hasFlexibleArrayMember()) + T->getAsStructureType() + ->getOriginalDecl() + ->getDefinitionOrSelf() + ->hasFlexibleArrayMember()) if (const auto *V = LV.getLValueBase().dyn_cast()) if (const auto *VD = dyn_cast(V)) if (VD->hasInit()) @@ -15028,7 +15043,7 @@ bool IntExprEvaluator::VisitOffsetOfExpr(const OffsetOfExpr *OOE) { const RecordType *RT = CurrentType->getAs(); if (!RT) return Error(OOE); - RecordDecl *RD = RT->getDecl(); + RecordDecl *RD = RT->getOriginalDecl()->getDefinitionOrSelf(); if (RD->isInvalidDecl()) return false; const ASTRecordLayout &RL = Info.Ctx.getASTRecordLayout(RD); unsigned i = MemberDecl->getFieldIndex(); @@ -15050,7 +15065,7 @@ bool IntExprEvaluator::VisitOffsetOfExpr(const OffsetOfExpr *OOE) { const RecordType *RT = CurrentType->getAs(); if (!RT) return Error(OOE); - RecordDecl *RD = RT->getDecl(); + RecordDecl *RD = RT->getOriginalDecl()->getDefinitionOrSelf(); if (RD->isInvalidDecl()) return false; const ASTRecordLayout &RL = Info.Ctx.getASTRecordLayout(RD); @@ -15061,7 +15076,8 @@ bool IntExprEvaluator::VisitOffsetOfExpr(const OffsetOfExpr *OOE) { return Error(OOE); // Add the offset to the base. - Result += RL.getBaseClassOffset(cast(BaseRT->getDecl())); + Result += RL.getBaseClassOffset(cast( + BaseRT->getOriginalDecl()->getDefinitionOrSelf())); break; } } @@ -15240,7 +15256,7 @@ bool IntExprEvaluator::VisitCastExpr(const CastExpr *E) { if (Info.Ctx.getLangOpts().CPlusPlus && DestType->isEnumeralType()) { const EnumType *ET = dyn_cast(DestType.getCanonicalType()); - const EnumDecl *ED = ET->getDecl(); + const EnumDecl *ED = ET->getOriginalDecl()->getDefinitionOrSelf(); // Check that the value is within the range of the enumeration values. // // This corressponds to [expr.static.cast]p10 which says: @@ -17913,7 +17929,8 @@ bool Expr::isPotentialConstantExpr(const FunctionDecl *FD, // Fabricate an arbitrary expression on the stack and pretend that it // is a temporary being used as the 'this' pointer. LValue This; - ImplicitValueInitExpr VIE(RD ? Info.Ctx.getRecordType(RD) : Info.Ctx.IntTy); + ImplicitValueInitExpr VIE(RD ? Info.Ctx.getCanonicalTagType(RD) + : Info.Ctx.IntTy); This.set({&VIE, Info.CurrentCall->Index}); ArrayRef Args; diff --git a/clang/lib/AST/FormatString.cpp b/clang/lib/AST/FormatString.cpp index 5d3b56fc4e713..ffeca9190fc7e 100644 --- a/clang/lib/AST/FormatString.cpp +++ b/clang/lib/AST/FormatString.cpp @@ -353,10 +353,11 @@ ArgType::matchesType(ASTContext &C, QualType argTy) const { // If the enum is incomplete we know nothing about the underlying type. // Assume that it's 'int'. Do not use the underlying type for a scoped // enumeration. - if (!ETy->getDecl()->isComplete()) + const EnumDecl *ED = ETy->getOriginalDecl()->getDefinitionOrSelf(); + if (!ED->isComplete()) return NoMatch; if (ETy->isUnscopedEnumerationType()) - argTy = ETy->getDecl()->getIntegerType(); + argTy = ED->getIntegerType(); } if (const auto *BT = argTy->getAs()) { @@ -398,10 +399,11 @@ ArgType::matchesType(ASTContext &C, QualType argTy) const { // If the enum is incomplete we know nothing about the underlying type. // Assume that it's 'int'. Do not use the underlying type for a scoped // enumeration as that needs an exact match. - if (!ETy->getDecl()->isComplete()) + const EnumDecl *ED = ETy->getOriginalDecl()->getDefinitionOrSelf(); + if (!ED->isComplete()) argTy = C.IntTy; else if (ETy->isUnscopedEnumerationType()) - argTy = ETy->getDecl()->getIntegerType(); + argTy = ED->getIntegerType(); } if (argTy->isSaturatedFixedPointType()) diff --git a/clang/lib/AST/InheritViz.cpp b/clang/lib/AST/InheritViz.cpp index 1dafed837a356..c03492c64b161 100644 --- a/clang/lib/AST/InheritViz.cpp +++ b/clang/lib/AST/InheritViz.cpp @@ -89,8 +89,8 @@ void InheritanceHierarchyWriter::WriteNode(QualType Type, bool FromVirtual) { Out << " \"];\n"; // Display the base classes. - const auto *Decl = - static_cast(Type->castAs()->getDecl()); + const auto *Decl = static_cast( + Type->castAs()->getOriginalDecl()); for (const auto &Base : Decl->bases()) { QualType CanonBaseType = Context.getCanonicalType(Base.getType()); @@ -133,7 +133,7 @@ InheritanceHierarchyWriter::WriteNodeReference(QualType Type, /// viewInheritance - Display the inheritance hierarchy of this C++ /// class using GraphViz. void CXXRecordDecl::viewInheritance(ASTContext& Context) const { - QualType Self = Context.getTypeDeclType(this); + QualType Self = Context.getCanonicalTagType(this); int FD; SmallString<128> Filename; diff --git a/clang/lib/AST/ItaniumCXXABI.cpp b/clang/lib/AST/ItaniumCXXABI.cpp index 6ceedd657fe7e..43a8bcd9443ff 100644 --- a/clang/lib/AST/ItaniumCXXABI.cpp +++ b/clang/lib/AST/ItaniumCXXABI.cpp @@ -42,10 +42,10 @@ namespace { /// /// Returns the name of anonymous union VarDecl or nullptr if it is not found. static const IdentifierInfo *findAnonymousUnionVarDeclName(const VarDecl& VD) { - const RecordType *RT = VD.getType()->getAs(); - assert(RT && "type of VarDecl is expected to be RecordType."); - assert(RT->getDecl()->isUnion() && "RecordType is expected to be a union."); - if (const FieldDecl *FD = RT->getDecl()->findFirstNamedDataMember()) { + const auto *RT = VD.getType()->castAs(); + const RecordDecl *RD = RT->getOriginalDecl()->getDefinitionOrSelf(); + assert(RD->isUnion() && "RecordType is expected to be a union."); + if (const FieldDecl *FD = RD->findFirstNamedDataMember()) { return FD->getIdentifier(); } diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp index 8a1d4e8313e28..a2f964a71b90c 100644 --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -463,9 +463,7 @@ class CXXNameMangler { void mangleVendorType(StringRef Name); private: - bool mangleSubstitution(const NamedDecl *ND); - bool mangleSubstitution(NestedNameSpecifier *NNS); bool mangleSubstitution(QualType T); bool mangleSubstitution(TemplateName Template); bool mangleSubstitution(uintptr_t Ptr); @@ -479,21 +477,15 @@ class CXXNameMangler { addSubstitution(reinterpret_cast(ND)); } - void addSubstitution(NestedNameSpecifier *NNS) { - NNS = Context.getASTContext().getCanonicalNestedNameSpecifier(NNS); - - addSubstitution(reinterpret_cast(NNS)); - } void addSubstitution(QualType T); void addSubstitution(TemplateName Template); void addSubstitution(uintptr_t Ptr); // Destructive copy substitutions from other mangler. void extendSubstitutions(CXXNameMangler* Other); - void mangleUnresolvedPrefix(NestedNameSpecifier *qualifier, + void mangleUnresolvedPrefix(NestedNameSpecifier Qualifier, bool recursive = false); - void mangleUnresolvedName(NestedNameSpecifier *qualifier, - DeclarationName name, + void mangleUnresolvedName(NestedNameSpecifier Qualifier, DeclarationName name, const TemplateArgumentLoc *TemplateArgs, unsigned NumTemplateArgs, unsigned KnownArity = UnknownArity); @@ -542,7 +534,7 @@ class CXXNameMangler { void mangleNestedNameWithClosurePrefix(GlobalDecl GD, const NamedDecl *PrefixND, const AbiTagList *AdditionalAbiTags); - void manglePrefix(NestedNameSpecifier *qualifier); + void manglePrefix(NestedNameSpecifier Qualifier); void manglePrefix(const DeclContext *DC, bool NoFunction=false); void manglePrefix(QualType type); void mangleTemplatePrefix(GlobalDecl GD, bool NoFunction=false); @@ -588,12 +580,10 @@ class CXXNameMangler { void mangleMemberExprBase(const Expr *base, bool isArrow); void mangleMemberExpr(const Expr *base, bool isArrow, - NestedNameSpecifier *qualifier, - NamedDecl *firstQualifierLookup, - DeclarationName name, + NestedNameSpecifier Qualifier, + NamedDecl *firstQualifierLookup, DeclarationName name, const TemplateArgumentLoc *TemplateArgs, - unsigned NumTemplateArgs, - unsigned knownArity); + unsigned NumTemplateArgs, unsigned knownArity); void mangleCastExpression(const Expr *E, StringRef CastEncoding); void mangleInitListElements(const InitListExpr *InitList); void mangleRequirement(SourceLocation RequiresExprLoc, @@ -1331,6 +1321,21 @@ void CXXNameMangler::manglePrefix(QualType type) { mangleTemplateArgs(Template, DTST->template_arguments()); addSubstitution(QualType(DTST, 0)); } + } else if (const auto *DNT = type->getAs()) { + // Clang 14 and before did not consider this substitutable. + bool Clang14Compat = isCompatibleWith(LangOptions::ClangABI::Ver14); + if (!Clang14Compat && mangleSubstitution(QualType(DNT, 0))) + return; + + // Member expressions can have these without prefixes, but that + // should end up in mangleUnresolvedPrefix instead. + assert(DNT->getQualifier()); + manglePrefix(DNT->getQualifier()); + + mangleSourceName(DNT->getIdentifier()); + + if (!Clang14Compat) + addSubstitution(QualType(DNT, 0)); } else { // We use the QualType mangle type variant here because it handles // substitutions. @@ -1342,7 +1347,7 @@ void CXXNameMangler::manglePrefix(QualType type) { /// /// \param recursive - true if this is being called recursively, /// i.e. if there is more prefix "to the right". -void CXXNameMangler::mangleUnresolvedPrefix(NestedNameSpecifier *qualifier, +void CXXNameMangler::mangleUnresolvedPrefix(NestedNameSpecifier Qualifier, bool recursive) { // x, ::x @@ -1359,8 +1364,11 @@ void CXXNameMangler::mangleUnresolvedPrefix(NestedNameSpecifier *qualifier, // ::= [gs] sr + E // - switch (qualifier->getKind()) { - case NestedNameSpecifier::Global: + switch (Qualifier.getKind()) { + case NestedNameSpecifier::Kind::Null: + llvm_unreachable("unexpected null nested name specifier"); + + case NestedNameSpecifier::Kind::Global: Out << "gs"; // We want an 'sr' unless this is the entire NNS. @@ -1370,35 +1378,29 @@ void CXXNameMangler::mangleUnresolvedPrefix(NestedNameSpecifier *qualifier, // We never want an 'E' here. return; - case NestedNameSpecifier::Super: + case NestedNameSpecifier::Kind::Super: llvm_unreachable("Can't mangle __super specifier"); - case NestedNameSpecifier::Namespace: - if (qualifier->getPrefix()) - mangleUnresolvedPrefix(qualifier->getPrefix(), - /*recursive*/ true); - else - Out << "sr"; - mangleSourceNameWithAbiTags(qualifier->getAsNamespace()); - break; - case NestedNameSpecifier::NamespaceAlias: - if (qualifier->getPrefix()) - mangleUnresolvedPrefix(qualifier->getPrefix(), + case NestedNameSpecifier::Kind::Namespace: { + auto [Namespace, Prefix] = Qualifier.getAsNamespaceAndPrefix(); + if (Prefix) + mangleUnresolvedPrefix(Prefix, /*recursive*/ true); else Out << "sr"; - mangleSourceNameWithAbiTags(qualifier->getAsNamespaceAlias()); + mangleSourceNameWithAbiTags(Namespace); break; + } - case NestedNameSpecifier::TypeSpec: { - const Type *type = qualifier->getAsType(); + case NestedNameSpecifier::Kind::Type: { + const Type *type = Qualifier.getAsType(); // We only want to use an unresolved-type encoding if this is one of: // - a decltype // - a template type parameter // - a template template parameter with arguments // In all of these cases, we should have no prefix. - if (NestedNameSpecifier *Prefix = qualifier->getPrefix()) { + if (NestedNameSpecifier Prefix = type->getPrefix()) { mangleUnresolvedPrefix(Prefix, /*recursive=*/true); } else { @@ -1411,18 +1413,6 @@ void CXXNameMangler::mangleUnresolvedPrefix(NestedNameSpecifier *qualifier, break; } - - case NestedNameSpecifier::Identifier: - // Member expressions can have these without prefixes. - if (qualifier->getPrefix()) - mangleUnresolvedPrefix(qualifier->getPrefix(), - /*recursive*/ true); - else - Out << "sr"; - - mangleSourceName(qualifier->getAsIdentifier()); - // An Identifier has no type information, so we can't emit abi tags for it. - break; } // If this was the innermost part of the NNS, and we fell out to @@ -1434,10 +1424,11 @@ void CXXNameMangler::mangleUnresolvedPrefix(NestedNameSpecifier *qualifier, /// Mangle an unresolved-name, which is generally used for names which /// weren't resolved to specific entities. void CXXNameMangler::mangleUnresolvedName( - NestedNameSpecifier *qualifier, DeclarationName name, + NestedNameSpecifier Qualifier, DeclarationName name, const TemplateArgumentLoc *TemplateArgs, unsigned NumTemplateArgs, unsigned knownArity) { - if (qualifier) mangleUnresolvedPrefix(qualifier); + if (Qualifier) + mangleUnresolvedPrefix(Qualifier); switch (name.getNameKind()) { // ::= case DeclarationName::Identifier: @@ -1586,7 +1577,10 @@ void CXXNameMangler::mangleUnqualifiedName( if (const VarDecl *VD = dyn_cast(ND)) { // We must have an anonymous union or struct declaration. - const RecordDecl *RD = VD->getType()->castAs()->getDecl(); + const RecordDecl *RD = VD->getType() + ->castAs() + ->getOriginalDecl() + ->getDefinitionOrSelf(); // Itanium C++ ABI 5.1.2: // @@ -2172,53 +2166,22 @@ void CXXNameMangler::mangleLambdaSig(const CXXRecordDecl *Lambda) { Lambda->getLambdaStaticInvoker()); } -void CXXNameMangler::manglePrefix(NestedNameSpecifier *qualifier) { - switch (qualifier->getKind()) { - case NestedNameSpecifier::Global: +void CXXNameMangler::manglePrefix(NestedNameSpecifier Qualifier) { + switch (Qualifier.getKind()) { + case NestedNameSpecifier::Kind::Null: + case NestedNameSpecifier::Kind::Global: // nothing return; - case NestedNameSpecifier::Super: + case NestedNameSpecifier::Kind::Super: llvm_unreachable("Can't mangle __super specifier"); - case NestedNameSpecifier::Namespace: - mangleName(qualifier->getAsNamespace()); + case NestedNameSpecifier::Kind::Namespace: + mangleName(Qualifier.getAsNamespaceAndPrefix().Namespace->getNamespace()); return; - case NestedNameSpecifier::NamespaceAlias: - mangleName(qualifier->getAsNamespaceAlias()->getNamespace()); - return; - - case NestedNameSpecifier::TypeSpec: - if (NestedNameSpecifier *Prefix = qualifier->getPrefix()) { - const auto *DTST = - cast(qualifier->getAsType()); - QualType NewT = getASTContext().getDependentTemplateSpecializationType( - DTST->getKeyword(), - {Prefix, DTST->getDependentTemplateName().getName(), - /*HasTemplateKeyword=*/true}, - DTST->template_arguments(), /*IsCanonical=*/true); - manglePrefix(NewT); - return; - } - manglePrefix(QualType(qualifier->getAsType(), 0)); - return; - - case NestedNameSpecifier::Identifier: - // Clang 14 and before did not consider this substitutable. - bool Clang14Compat = isCompatibleWith(LangOptions::ClangABI::Ver14); - if (!Clang14Compat && mangleSubstitution(qualifier)) - return; - - // Member expressions can have these without prefixes, but that - // should end up in mangleUnresolvedPrefix instead. - assert(qualifier->getPrefix()); - manglePrefix(qualifier->getPrefix()); - - mangleSourceName(qualifier->getAsIdentifier()); - - if (!Clang14Compat) - addSubstitution(qualifier); + case NestedNameSpecifier::Kind::Type: + manglePrefix(QualType(Qualifier.getAsType(), 0)); return; } @@ -2278,8 +2241,7 @@ void CXXNameMangler::mangleTemplatePrefix(TemplateName Template) { if (!Clang11Compat && mangleSubstitution(Template)) return; - if (NestedNameSpecifier *Qualifier = Dependent->getQualifier()) - manglePrefix(Qualifier); + manglePrefix(Dependent->getQualifier()); if (Clang11Compat && mangleSubstitution(Template)) return; @@ -2530,7 +2492,8 @@ bool CXXNameMangler::mangleUnresolvedTypeOrSimpleId(QualType Ty, case Type::Enum: case Type::Record: - mangleSourceNameWithAbiTags(cast(Ty)->getDecl()); + mangleSourceNameWithAbiTags( + cast(Ty)->getOriginalDecl()->getDefinitionOrSelf()); break; case Type::TemplateSpecialization: { @@ -2591,8 +2554,9 @@ bool CXXNameMangler::mangleUnresolvedTypeOrSimpleId(QualType Ty, } case Type::InjectedClassName: - mangleSourceNameWithAbiTags( - cast(Ty)->getDecl()); + mangleSourceNameWithAbiTags(cast(Ty) + ->getOriginalDecl() + ->getDefinitionOrSelf()); break; case Type::DependentName: @@ -2613,9 +2577,6 @@ bool CXXNameMangler::mangleUnresolvedTypeOrSimpleId(QualType Ty, case Type::Using: return mangleUnresolvedTypeOrSimpleId(cast(Ty)->desugar(), Prefix); - case Type::Elaborated: - return mangleUnresolvedTypeOrSimpleId( - cast(Ty)->getNamedType(), Prefix); } return false; @@ -3843,7 +3804,7 @@ void CXXNameMangler::mangleType(const RecordType *T) { mangleType(static_cast(T)); } void CXXNameMangler::mangleType(const TagType *T) { - mangleName(T->getDecl()); + mangleName(T->getOriginalDecl()->getDefinitionOrSelf()); } // ::= @@ -3880,16 +3841,10 @@ void CXXNameMangler::mangleType(const IncompleteArrayType *T) { // ::= M void CXXNameMangler::mangleType(const MemberPointerType *T) { Out << 'M'; - if (auto *RD = T->getMostRecentCXXRecordDecl()) { + if (auto *RD = T->getMostRecentCXXRecordDecl()) mangleCXXRecordDecl(RD); - } else { - NestedNameSpecifier *NNS = T->getQualifier(); - if (auto *II = NNS->getAsIdentifier()) - mangleType(getASTContext().getDependentNameType( - ElaboratedTypeKeyword::None, NNS->getPrefix(), II)); - else - manglePrefix(NNS); - } + else + mangleType(QualType(T->getQualifier().getAsType(), 0)); QualType PointeeType = T->getPointeeType(); if (const FunctionProtoType *FPT = dyn_cast(PointeeType)) { mangleType(FPT); @@ -4476,7 +4431,7 @@ void CXXNameMangler::mangleType(const InjectedClassNameType *T) { // Mangle injected class name types as if the user had written the // specialization out fully. It may not actually be possible to see // this mangling, though. - mangleType(T->getInjectedSpecializationType()); + mangleType(T->getCanonicalInjectedTST()); } void CXXNameMangler::mangleType(const TemplateSpecializationType *T) { @@ -4752,7 +4707,7 @@ void CXXNameMangler::mangleIntegerLiteral(QualType T, void CXXNameMangler::mangleMemberExprBase(const Expr *Base, bool IsArrow) { // Ignore member expressions involving anonymous unions. while (const auto *RT = Base->getType()->getAs()) { - if (!RT->getDecl()->isAnonymousStructOrUnion()) + if (!RT->getOriginalDecl()->isAnonymousStructOrUnion()) break; const auto *ME = dyn_cast(Base); if (!ME) @@ -4773,9 +4728,8 @@ void CXXNameMangler::mangleMemberExprBase(const Expr *Base, bool IsArrow) { } /// Mangles a member expression. -void CXXNameMangler::mangleMemberExpr(const Expr *base, - bool isArrow, - NestedNameSpecifier *qualifier, +void CXXNameMangler::mangleMemberExpr(const Expr *base, bool isArrow, + NestedNameSpecifier Qualifier, NamedDecl *firstQualifierLookup, DeclarationName member, const TemplateArgumentLoc *TemplateArgs, @@ -4785,7 +4739,7 @@ void CXXNameMangler::mangleMemberExpr(const Expr *base, // ::= pt if (base) mangleMemberExprBase(base, isArrow); - mangleUnresolvedName(qualifier, member, TemplateArgs, NumTemplateArgs, arity); + mangleUnresolvedName(Qualifier, member, TemplateArgs, NumTemplateArgs, arity); } /// Look at the callee of the given call expression and determine if @@ -5235,7 +5189,7 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity, const auto *PDE = cast(E); if (const Expr *Base = PDE->getBase()) mangleMemberExprBase(Base, PDE->isArrow()); - NestedNameSpecifier *Qualifier = PDE->getQualifier(); + NestedNameSpecifier Qualifier = PDE->getQualifier(); if (TypeSourceInfo *ScopeInfo = PDE->getScopeTypeInfo()) { if (Qualifier) { mangleUnresolvedPrefix(Qualifier, @@ -5860,7 +5814,8 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity, // externally-visible declaration, so there's no standard mangling for // this, but mangling as a literal of the closure type seems reasonable. Out << "L"; - mangleType(Context.getASTContext().getRecordType(cast(E)->getLambdaClass())); + mangleType(Context.getASTContext().getCanonicalTagType( + cast(E)->getLambdaClass())); Out << "E"; break; } @@ -6533,7 +6488,7 @@ static QualType getLValueType(ASTContext &Ctx, const APValue &LV) { dyn_cast(E.getAsBaseOrMember().getPointer())) T = FD->getType(); else - T = Ctx.getRecordType( + T = Ctx.getCanonicalTagType( cast(E.getAsBaseOrMember().getPointer())); } return T; @@ -6900,7 +6855,7 @@ void CXXNameMangler::mangleValueInTemplateArg(QualType T, const APValue &V, } TypeSoFar = FD->getType(); } else { - TypeSoFar = Ctx.getRecordType(cast(D)); + TypeSoFar = Ctx.getCanonicalTagType(cast(D)); } } } @@ -7010,14 +6965,6 @@ bool CXXNameMangler::mangleSubstitution(const NamedDecl *ND) { return mangleSubstitution(reinterpret_cast(ND)); } -bool CXXNameMangler::mangleSubstitution(NestedNameSpecifier *NNS) { - assert(NNS->getKind() == NestedNameSpecifier::Identifier && - "mangleSubstitution(NestedNameSpecifier *) is only used for " - "identifier nested name specifiers."); - NNS = Context.getASTContext().getCanonicalNestedNameSpecifier(NNS); - return mangleSubstitution(reinterpret_cast(NNS)); -} - /// Determine whether the given type has any qualifiers that are relevant for /// substitutions. static bool hasMangledSubstitutionQualifiers(QualType T) { @@ -7028,7 +6975,7 @@ static bool hasMangledSubstitutionQualifiers(QualType T) { bool CXXNameMangler::mangleSubstitution(QualType T) { if (!hasMangledSubstitutionQualifiers(T)) { if (const RecordType *RT = T->getAs()) - return mangleSubstitution(RT->getDecl()); + return mangleSubstitution(RT->getOriginalDecl()->getDefinitionOrSelf()); } uintptr_t TypePtr = reinterpret_cast(T.getAsOpaquePtr()); @@ -7069,7 +7016,7 @@ bool CXXNameMangler::isSpecializedAs(QualType S, llvm::StringRef Name, return false; const ClassTemplateSpecializationDecl *SD = - dyn_cast(RT->getDecl()); + dyn_cast(RT->getOriginalDecl()); if (!SD || !SD->getIdentifier()->isStr(Name)) return false; @@ -7199,7 +7146,7 @@ bool CXXNameMangler::mangleStandardSubstitution(const NamedDecl *ND) { void CXXNameMangler::addSubstitution(QualType T) { if (!hasMangledSubstitutionQualifiers(T)) { if (const RecordType *RT = T->getAs()) { - addSubstitution(RT->getDecl()); + addSubstitution(RT->getOriginalDecl()->getDefinitionOrSelf()); return; } } diff --git a/clang/lib/AST/JSONNodeDumper.cpp b/clang/lib/AST/JSONNodeDumper.cpp index 64ddb1e739347..b3f12a1cce2ec 100644 --- a/clang/lib/AST/JSONNodeDumper.cpp +++ b/clang/lib/AST/JSONNodeDumper.cpp @@ -395,8 +395,8 @@ llvm::json::Array JSONNodeDumper::createCastPath(const CastExpr *C) { for (auto I = C->path_begin(), E = C->path_end(); I != E; ++I) { const CXXBaseSpecifier *Base = *I; - const auto *RD = - cast(Base->getType()->castAs()->getDecl()); + const auto *RD = cast( + Base->getType()->castAs()->getOriginalDecl()); llvm::json::Object Val{{"name", RD->getName()}}; if (Base->isVirtual()) @@ -606,9 +606,8 @@ void JSONNodeDumper::VisitTypedefType(const TypedefType *TT) { } void JSONNodeDumper::VisitUsingType(const UsingType *TT) { - JOS.attribute("decl", createBareDeclRef(TT->getFoundDecl())); - if (!TT->typeMatchesDecl()) - JOS.attribute("type", createQualType(TT->desugar())); + JOS.attribute("decl", createBareDeclRef(TT->getDecl())); + JOS.attribute("type", createQualType(TT->desugar())); } void JSONNodeDumper::VisitFunctionType(const FunctionType *T) { @@ -759,7 +758,15 @@ void JSONNodeDumper::VisitUnaryTransformType(const UnaryTransformType *UTT) { } void JSONNodeDumper::VisitTagType(const TagType *TT) { - JOS.attribute("decl", createBareDeclRef(TT->getDecl())); + if (NestedNameSpecifier Qualifier = TT->getQualifier()) { + std::string Str; + llvm::raw_string_ostream OS(Str); + Qualifier.print(OS, PrintPolicy, /*ResolveTemplateArguments=*/true); + JOS.attribute("qualifier", Str); + } + JOS.attribute("decl", createBareDeclRef(TT->getOriginalDecl())); + if (TT->isTagOwned()) + JOS.attribute("isTagOwned", true); } void JSONNodeDumper::VisitTemplateTypeParmType( @@ -809,7 +816,7 @@ void JSONNodeDumper::VisitTemplateSpecializationType( void JSONNodeDumper::VisitInjectedClassNameType( const InjectedClassNameType *ICNT) { - JOS.attribute("decl", createBareDeclRef(ICNT->getDecl())); + JOS.attribute("decl", createBareDeclRef(ICNT->getOriginalDecl())); } void JSONNodeDumper::VisitObjCInterfaceType(const ObjCInterfaceType *OIT) { @@ -821,17 +828,6 @@ void JSONNodeDumper::VisitPackExpansionType(const PackExpansionType *PET) { JOS.attribute("numExpansions", *N); } -void JSONNodeDumper::VisitElaboratedType(const ElaboratedType *ET) { - if (const NestedNameSpecifier *NNS = ET->getQualifier()) { - std::string Str; - llvm::raw_string_ostream OS(Str); - NNS->print(OS, PrintPolicy, /*ResolveTemplateArgs*/ true); - JOS.attribute("qualifier", Str); - } - if (const TagDecl *TD = ET->getOwnedTagDecl()) - JOS.attribute("ownedTagDecl", createBareDeclRef(TD)); -} - void JSONNodeDumper::VisitMacroQualifiedType(const MacroQualifiedType *MQT) { JOS.attribute("macroName", MQT->getMacroIdentifier()->getName()); } @@ -902,9 +898,9 @@ void JSONNodeDumper::VisitNamespaceAliasDecl(const NamespaceAliasDecl *NAD) { void JSONNodeDumper::VisitUsingDecl(const UsingDecl *UD) { std::string Name; - if (const NestedNameSpecifier *NNS = UD->getQualifier()) { + if (NestedNameSpecifier Qualifier = UD->getQualifier()) { llvm::raw_string_ostream SOS(Name); - NNS->print(SOS, UD->getASTContext().getPrintingPolicy()); + Qualifier.print(SOS, UD->getASTContext().getPrintingPolicy()); } Name += UD->getNameAsString(); JOS.attribute("name", Name); diff --git a/clang/lib/AST/MicrosoftMangle.cpp b/clang/lib/AST/MicrosoftMangle.cpp index bc47e0506add0..1d17f75b8c53a 100644 --- a/clang/lib/AST/MicrosoftMangle.cpp +++ b/clang/lib/AST/MicrosoftMangle.cpp @@ -1806,17 +1806,16 @@ void MicrosoftCXXNameMangler::mangleTemplateArg(const TemplateDecl *TD, case TemplateArgument::Declaration: { const NamedDecl *ND = TA.getAsDecl(); if (isa(ND) || isa(ND)) { - mangleMemberDataPointer(cast(ND->getDeclContext()) - ->getMostRecentNonInjectedDecl(), - cast(ND), - cast(Parm), - TA.getParamTypeForDecl()); + mangleMemberDataPointer( + cast(ND->getDeclContext())->getMostRecentDecl(), + cast(ND), cast(Parm), + TA.getParamTypeForDecl()); } else if (const FunctionDecl *FD = dyn_cast(ND)) { const CXXMethodDecl *MD = dyn_cast(FD); if (MD && MD->isInstance()) { - mangleMemberFunctionPointer( - MD->getParent()->getMostRecentNonInjectedDecl(), MD, - cast(Parm), TA.getParamTypeForDecl()); + mangleMemberFunctionPointer(MD->getParent()->getMostRecentDecl(), MD, + cast(Parm), + TA.getParamTypeForDecl()); } else { mangleFunctionPointer(FD, cast(Parm), TA.getParamTypeForDecl()); @@ -2022,7 +2021,7 @@ void MicrosoftCXXNameMangler::mangleTemplateArgValue(QualType T, if (RD->isAnonymousStructOrUnion()) continue; } else { - ET = getASTContext().getRecordType(cast(D)); + ET = getASTContext().getCanonicalTagType(cast(D)); // Bug in MSVC: fully qualified name of base class should be used for // mangling to prevent collisions e.g. on base classes with same names // in different namespaces. @@ -3248,11 +3247,11 @@ void MicrosoftCXXNameMangler::mangleTagTypeKind(TagTypeKind TTK) { } void MicrosoftCXXNameMangler::mangleType(const EnumType *T, Qualifiers, SourceRange) { - mangleType(cast(T)->getDecl()); + mangleType(cast(T)->getOriginalDecl()->getDefinitionOrSelf()); } void MicrosoftCXXNameMangler::mangleType(const RecordType *T, Qualifiers, SourceRange) { - mangleType(cast(T)->getDecl()); + mangleType(cast(T)->getOriginalDecl()->getDefinitionOrSelf()); } void MicrosoftCXXNameMangler::mangleType(const TagDecl *TD) { mangleTagTypeKind(TD->getTagKind()); diff --git a/clang/lib/AST/NestedNameSpecifier.cpp b/clang/lib/AST/NestedNameSpecifier.cpp index db1ad89565189..b91aa011dd024 100644 --- a/clang/lib/AST/NestedNameSpecifier.cpp +++ b/clang/lib/AST/NestedNameSpecifier.cpp @@ -15,7 +15,6 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" -#include "clang/AST/DeclTemplate.h" #include "clang/AST/DependenceFlags.h" #include "clang/AST/PrettyPrinter.h" #include "clang/AST/TemplateName.h" @@ -35,416 +34,118 @@ using namespace clang; -NestedNameSpecifier * -NestedNameSpecifier::FindOrInsert(const ASTContext &Context, - const NestedNameSpecifier &Mockup) { +const NamespaceAndPrefixStorage * +NestedNameSpecifier::MakeNamespaceAndPrefixStorage( + const ASTContext &Ctx, const NamespaceBaseDecl *Namespace, + NestedNameSpecifier Prefix) { llvm::FoldingSetNodeID ID; - Mockup.Profile(ID); + NamespaceAndPrefixStorage::Profile(ID, Namespace, Prefix); void *InsertPos = nullptr; - NestedNameSpecifier *NNS - = Context.NestedNameSpecifiers.FindNodeOrInsertPos(ID, InsertPos); - if (!NNS) { - NNS = - new (Context, alignof(NestedNameSpecifier)) NestedNameSpecifier(Mockup); - Context.NestedNameSpecifiers.InsertNode(NNS, InsertPos); + NamespaceAndPrefixStorage *S = + Ctx.NamespaceAndPrefixStorages.FindNodeOrInsertPos(ID, InsertPos); + if (!S) { + S = new (Ctx, alignof(NamespaceAndPrefixStorage)) + NamespaceAndPrefixStorage(Namespace, Prefix); + Ctx.NamespaceAndPrefixStorages.InsertNode(S, InsertPos); } - - return NNS; -} - -NestedNameSpecifier *NestedNameSpecifier::Create(const ASTContext &Context, - NestedNameSpecifier *Prefix, - const IdentifierInfo *II) { - assert(II && "Identifier cannot be NULL"); - assert((!Prefix || Prefix->isDependent()) && "Prefix must be dependent"); - - NestedNameSpecifier Mockup; - Mockup.Prefix.setPointer(Prefix); - Mockup.Prefix.setInt(StoredIdentifier); - Mockup.Specifier = const_cast(II); - return FindOrInsert(Context, Mockup); -} - -NestedNameSpecifier * -NestedNameSpecifier::Create(const ASTContext &Context, - NestedNameSpecifier *Prefix, - const NamespaceDecl *NS) { - assert(NS && "Namespace cannot be NULL"); - assert((!Prefix || - (Prefix->getAsType() == nullptr && - Prefix->getAsIdentifier() == nullptr)) && - "Broken nested name specifier"); - NestedNameSpecifier Mockup; - Mockup.Prefix.setPointer(Prefix); - Mockup.Prefix.setInt(StoredDecl); - Mockup.Specifier = const_cast(NS); - return FindOrInsert(Context, Mockup); -} - -NestedNameSpecifier * -NestedNameSpecifier::Create(const ASTContext &Context, - NestedNameSpecifier *Prefix, - const NamespaceAliasDecl *Alias) { - assert(Alias && "Namespace alias cannot be NULL"); - assert((!Prefix || - (Prefix->getAsType() == nullptr && - Prefix->getAsIdentifier() == nullptr)) && - "Broken nested name specifier"); - NestedNameSpecifier Mockup; - Mockup.Prefix.setPointer(Prefix); - Mockup.Prefix.setInt(StoredDecl); - Mockup.Specifier = const_cast(Alias); - return FindOrInsert(Context, Mockup); -} - -NestedNameSpecifier *NestedNameSpecifier::Create(const ASTContext &Context, - NestedNameSpecifier *Prefix, - const Type *T) { - assert(T && "Type cannot be NULL"); - NestedNameSpecifier Mockup; - Mockup.Prefix.setPointer(Prefix); - Mockup.Prefix.setInt(StoredTypeSpec); - Mockup.Specifier = const_cast(T); - return FindOrInsert(Context, Mockup); -} - -NestedNameSpecifier *NestedNameSpecifier::Create(const ASTContext &Context, - const IdentifierInfo *II) { - assert(II && "Identifier cannot be NULL"); - NestedNameSpecifier Mockup; - Mockup.Prefix.setPointer(nullptr); - Mockup.Prefix.setInt(StoredIdentifier); - Mockup.Specifier = const_cast(II); - return FindOrInsert(Context, Mockup); -} - -NestedNameSpecifier * -NestedNameSpecifier::GlobalSpecifier(const ASTContext &Context) { - if (!Context.GlobalNestedNameSpecifier) - Context.GlobalNestedNameSpecifier = - new (Context, alignof(NestedNameSpecifier)) NestedNameSpecifier(); - return Context.GlobalNestedNameSpecifier; -} - -NestedNameSpecifier * -NestedNameSpecifier::SuperSpecifier(const ASTContext &Context, - CXXRecordDecl *RD) { - NestedNameSpecifier Mockup; - Mockup.Prefix.setPointer(nullptr); - Mockup.Prefix.setInt(StoredDecl); - Mockup.Specifier = RD; - return FindOrInsert(Context, Mockup); + return S; } -NestedNameSpecifier::SpecifierKind NestedNameSpecifier::getKind() const { - if (!Specifier) - return Global; - - switch (Prefix.getInt()) { - case StoredIdentifier: - return Identifier; - - case StoredDecl: { - NamedDecl *ND = static_cast(Specifier); - if (isa(ND)) - return Super; - return isa(ND) ? Namespace : NamespaceAlias; - } - - case StoredTypeSpec: - return TypeSpec; - } - - llvm_unreachable("Invalid NNS Kind!"); -} - -/// Retrieve the namespace stored in this nested name specifier. -NamespaceDecl *NestedNameSpecifier::getAsNamespace() const { - if (Prefix.getInt() == StoredDecl) - return dyn_cast(static_cast(Specifier)); - - return nullptr; -} - -/// Retrieve the namespace alias stored in this nested name specifier. -NamespaceAliasDecl *NestedNameSpecifier::getAsNamespaceAlias() const { - if (Prefix.getInt() == StoredDecl) - return dyn_cast(static_cast(Specifier)); - - return nullptr; -} - -/// Retrieve the record declaration stored in this nested name specifier. -CXXRecordDecl *NestedNameSpecifier::getAsRecordDecl() const { - switch (Prefix.getInt()) { - case StoredIdentifier: - return nullptr; - - case StoredDecl: - return dyn_cast(static_cast(Specifier)); - - case StoredTypeSpec: - return getAsType()->getAsCXXRecordDecl(); +bool NestedNameSpecifier::isFullyQualified() const { + switch (getKind()) { + case NestedNameSpecifier::Kind::Global: + return true; + case NestedNameSpecifier::Kind::Null: + case NestedNameSpecifier::Kind::Super: + return false; + case NestedNameSpecifier::Kind::Namespace: + return getAsNamespaceAndPrefix().Prefix.isFullyQualified(); + case NestedNameSpecifier::Kind::Type: + return getAsType()->getPrefix().isFullyQualified(); } - llvm_unreachable("Invalid NNS Kind!"); } NestedNameSpecifierDependence NestedNameSpecifier::getDependence() const { switch (getKind()) { - case Identifier: { - // Identifier specifiers always represent dependent types - auto F = NestedNameSpecifierDependence::Dependent | - NestedNameSpecifierDependence::Instantiation; - // Prefix can contain unexpanded template parameters. - if (getPrefix()) - return F | getPrefix()->getDependence(); - return F; - } - - case Namespace: - case NamespaceAlias: - case Global: - return NestedNameSpecifierDependence::None; - - case Super: { - CXXRecordDecl *RD = static_cast(Specifier); - for (const auto &Base : RD->bases()) - if (Base.getType()->isDependentType()) - // FIXME: must also be instantiation-dependent. - return NestedNameSpecifierDependence::Dependent; + case Kind::Null: + case Kind::Global: + case Kind::Namespace: return NestedNameSpecifierDependence::None; + case Kind::Super: { + CXXRecordDecl *RD = getAsSuper(); + return RD->isDependentContext() + ? NestedNameSpecifierDependence::DependentInstantiation | + NestedNameSpecifierDependence::Dependent + : NestedNameSpecifierDependence::None; } - - case TypeSpec: { - NestedNameSpecifierDependence Dep = - toNestedNameSpecifierDependendence(getAsType()->getDependence()); - if (NestedNameSpecifier *Prefix = getPrefix()) - Dep |= - Prefix->getDependence() & ~NestedNameSpecifierDependence::Dependent; - return Dep; - } + case Kind::Type: + return toNestedNameSpecifierDependence(getAsType()->getDependence()); } llvm_unreachable("Invalid NNS Kind!"); } -bool NestedNameSpecifier::isDependent() const { - return getDependence() & NestedNameSpecifierDependence::Dependent; -} - -bool NestedNameSpecifier::isInstantiationDependent() const { - return getDependence() & NestedNameSpecifierDependence::Instantiation; -} - -bool NestedNameSpecifier::containsUnexpandedParameterPack() const { - return getDependence() & NestedNameSpecifierDependence::UnexpandedPack; -} - -bool NestedNameSpecifier::containsErrors() const { - return getDependence() & NestedNameSpecifierDependence::Error; -} - -const Type * -NestedNameSpecifier::translateToType(const ASTContext &Context) const { - NestedNameSpecifier *Prefix = getPrefix(); - switch (getKind()) { - case SpecifierKind::Identifier: - return Context - .getDependentNameType(ElaboratedTypeKeyword::None, Prefix, - getAsIdentifier()) - .getTypePtr(); - case SpecifierKind::TypeSpec: { - const Type *T = getAsType(); - switch (T->getTypeClass()) { - case Type::DependentTemplateSpecialization: { - const auto *DT = cast(T); - const DependentTemplateStorage &DTN = DT->getDependentTemplateName(); - return Context - .getDependentTemplateSpecializationType( - ElaboratedTypeKeyword::None, - {Prefix, DTN.getName(), DTN.hasTemplateKeyword()}, - DT->template_arguments()) - .getTypePtr(); - } - case Type::Record: - case Type::TemplateSpecialization: - case Type::Using: - case Type::Enum: - case Type::Typedef: - case Type::UnresolvedUsing: - return Context - .getElaboratedType(ElaboratedTypeKeyword::None, Prefix, - QualType(T, 0)) - .getTypePtr(); - default: - assert(Prefix == nullptr && "unexpected type with elaboration"); - return T; - } - } - case SpecifierKind::Global: - case SpecifierKind::Namespace: - case SpecifierKind::NamespaceAlias: - case SpecifierKind::Super: - // These are not representable as types. - return nullptr; - } - llvm_unreachable("Unhandled SpecifierKind enum"); -} - /// Print this nested name specifier to the given output /// stream. void NestedNameSpecifier::print(raw_ostream &OS, const PrintingPolicy &Policy, bool ResolveTemplateArguments, bool PrintFinalScopeResOp) const { - if (getPrefix()) - getPrefix()->print(OS, Policy); - switch (getKind()) { - case Identifier: - OS << getAsIdentifier()->getName(); - break; - - case Namespace: - if (getAsNamespace()->isAnonymousNamespace()) - return; - - OS << getAsNamespace()->getName(); - break; - - case NamespaceAlias: - OS << getAsNamespaceAlias()->getName(); + case Kind::Namespace: { + auto [Namespace, Prefix] = getAsNamespaceAndPrefix(); + Prefix.print(OS, Policy); + if (const auto *NS = dyn_cast(Namespace)) { + assert(!NS->isAnonymousNamespace()); + OS << NS->getName(); + } else { + OS << cast(Namespace)->getName(); + } break; - - case Global: + } + case Kind::Global: OS << "::"; return; - - case Super: + case Kind::Super: OS << "__super"; break; - - case TypeSpec: { + case Kind::Type: { PrintingPolicy InnerPolicy(Policy); - InnerPolicy.SuppressScope = true; InnerPolicy.SuppressTagKeyword = true; QualType(getAsType(), 0).print(OS, InnerPolicy); break; } + case Kind::Null: + return; } - if (PrintFinalScopeResOp) OS << "::"; } -LLVM_DUMP_METHOD void NestedNameSpecifier::dump(const LangOptions &LO) const { - dump(llvm::errs(), LO); +LLVM_DUMP_METHOD void NestedNameSpecifier::dump(llvm::raw_ostream *OS, + const LangOptions *LO) const { + print(OS ? *OS : llvm::errs(), LO ? *LO : LangOptions()); } -LLVM_DUMP_METHOD void NestedNameSpecifier::dump() const { dump(llvm::errs()); } - +LLVM_DUMP_METHOD void NestedNameSpecifier::dump(const LangOptions &LO) const { + dump(/*OS=*/nullptr, &LO); +} LLVM_DUMP_METHOD void NestedNameSpecifier::dump(llvm::raw_ostream &OS) const { - LangOptions LO; - dump(OS, LO); + dump(&OS); } - LLVM_DUMP_METHOD void NestedNameSpecifier::dump(llvm::raw_ostream &OS, const LangOptions &LO) const { - print(OS, PrintingPolicy(LO)); + dump(&OS, &LO); } -unsigned -NestedNameSpecifierLoc::getLocalDataLength(NestedNameSpecifier *Qualifier) { - assert(Qualifier && "Expected a non-NULL qualifier"); - - // Location of the trailing '::'. - unsigned Length = sizeof(SourceLocation::UIntTy); - - switch (Qualifier->getKind()) { - case NestedNameSpecifier::Global: - // Nothing more to add. - break; - - case NestedNameSpecifier::Identifier: - case NestedNameSpecifier::Namespace: - case NestedNameSpecifier::NamespaceAlias: - case NestedNameSpecifier::Super: - // The location of the identifier or namespace name. - Length += sizeof(SourceLocation::UIntTy); - break; - - case NestedNameSpecifier::TypeSpec: - // The "void*" that points at the TypeLoc data. - // Note: the 'template' keyword is part of the TypeLoc. - Length += sizeof(void *); - break; - } - - return Length; -} - -unsigned -NestedNameSpecifierLoc::getDataLength(NestedNameSpecifier *Qualifier) { - unsigned Length = 0; - for (; Qualifier; Qualifier = Qualifier->getPrefix()) - Length += getLocalDataLength(Qualifier); - return Length; -} - -/// Load a (possibly unaligned) source location from a given address -/// and offset. -static SourceLocation LoadSourceLocation(void *Data, unsigned Offset) { - SourceLocation::UIntTy Raw; - memcpy(&Raw, static_cast(Data) + Offset, sizeof(Raw)); - return SourceLocation::getFromRawEncoding(Raw); -} - -/// Load a (possibly unaligned) pointer from a given address and -/// offset. -static void *LoadPointer(void *Data, unsigned Offset) { - void *Result; - memcpy(&Result, static_cast(Data) + Offset, sizeof(void*)); - return Result; -} - -SourceRange NestedNameSpecifierLoc::getLocalSourceRange() const { +SourceLocation NestedNameSpecifierLoc::getBeginLoc() const { if (!Qualifier) - return SourceRange(); - - unsigned Offset = getDataLength(Qualifier->getPrefix()); - switch (Qualifier->getKind()) { - case NestedNameSpecifier::Global: - return LoadSourceLocation(Data, Offset); - - case NestedNameSpecifier::Identifier: - case NestedNameSpecifier::Namespace: - case NestedNameSpecifier::NamespaceAlias: - case NestedNameSpecifier::Super: - return SourceRange( - LoadSourceLocation(Data, Offset), - LoadSourceLocation(Data, Offset + sizeof(SourceLocation::UIntTy))); - - case NestedNameSpecifier::TypeSpec: { - // The "void*" that points at the TypeLoc data. - // Note: the 'template' keyword is part of the TypeLoc. - void *TypeData = LoadPointer(Data, Offset); - TypeLoc TL(Qualifier->getAsType(), TypeData); - return SourceRange(TL.getBeginLoc(), - LoadSourceLocation(Data, Offset + sizeof(void*))); - } - } - - llvm_unreachable("Invalid NNS Kind!"); -} + return SourceLocation(); -TypeLoc NestedNameSpecifierLoc::getTypeLoc() const { - if (Qualifier->getKind() != NestedNameSpecifier::TypeSpec) - return TypeLoc(); - - // The "void*" that points at the TypeLoc data. - unsigned Offset = getDataLength(Qualifier->getPrefix()); - void *TypeData = LoadPointer(Data, Offset); - return TypeLoc(Qualifier->getAsType(), TypeData); + NestedNameSpecifierLoc First = *this; + while (NestedNameSpecifierLoc Prefix = First.getAsNamespaceAndPrefix().Prefix) + First = Prefix; + return First.getLocalSourceRange().getBegin(); } static void Append(char *Start, char *End, char *&Buffer, unsigned &BufferSize, @@ -546,10 +247,10 @@ operator=(const NestedNameSpecifierLocBuilder &Other) { return *this; } -void NestedNameSpecifierLocBuilder::Extend(ASTContext &Context, TypeLoc TL, - SourceLocation ColonColonLoc) { - Representation = - NestedNameSpecifier::Create(Context, Representation, TL.getTypePtr()); +void NestedNameSpecifierLocBuilder::Make(ASTContext &Context, TypeLoc TL, + SourceLocation ColonColonLoc) { + assert(!Representation); + Representation = NestedNameSpecifier(TL.getTypePtr()); // Push source-location info into the buffer. SavePointer(TL.getOpaqueData(), Buffer, BufferSize, BufferCapacity); @@ -557,44 +258,20 @@ void NestedNameSpecifierLocBuilder::Extend(ASTContext &Context, TypeLoc TL, } void NestedNameSpecifierLocBuilder::Extend(ASTContext &Context, - IdentifierInfo *Identifier, - SourceLocation IdentifierLoc, - SourceLocation ColonColonLoc) { - Representation = NestedNameSpecifier::Create(Context, Representation, - Identifier); - - // Push source-location info into the buffer. - SaveSourceLocation(IdentifierLoc, Buffer, BufferSize, BufferCapacity); - SaveSourceLocation(ColonColonLoc, Buffer, BufferSize, BufferCapacity); -} - -void NestedNameSpecifierLocBuilder::Extend(ASTContext &Context, - NamespaceDecl *Namespace, + const NamespaceBaseDecl *Namespace, SourceLocation NamespaceLoc, SourceLocation ColonColonLoc) { - Representation = NestedNameSpecifier::Create(Context, Representation, - Namespace); + Representation = NestedNameSpecifier(Context, Namespace, Representation); // Push source-location info into the buffer. SaveSourceLocation(NamespaceLoc, Buffer, BufferSize, BufferCapacity); SaveSourceLocation(ColonColonLoc, Buffer, BufferSize, BufferCapacity); } -void NestedNameSpecifierLocBuilder::Extend(ASTContext &Context, - NamespaceAliasDecl *Alias, - SourceLocation AliasLoc, - SourceLocation ColonColonLoc) { - Representation = NestedNameSpecifier::Create(Context, Representation, Alias); - - // Push source-location info into the buffer. - SaveSourceLocation(AliasLoc, Buffer, BufferSize, BufferCapacity); - SaveSourceLocation(ColonColonLoc, Buffer, BufferSize, BufferCapacity); -} - void NestedNameSpecifierLocBuilder::MakeGlobal(ASTContext &Context, SourceLocation ColonColonLoc) { assert(!Representation && "Already have a nested-name-specifier!?"); - Representation = NestedNameSpecifier::GlobalSpecifier(Context); + Representation = NestedNameSpecifier::getGlobal(); // Push source-location info into the buffer. SaveSourceLocation(ColonColonLoc, Buffer, BufferSize, BufferCapacity); @@ -604,51 +281,39 @@ void NestedNameSpecifierLocBuilder::MakeSuper(ASTContext &Context, CXXRecordDecl *RD, SourceLocation SuperLoc, SourceLocation ColonColonLoc) { - Representation = NestedNameSpecifier::SuperSpecifier(Context, RD); + Representation = NestedNameSpecifier(RD); // Push source-location info into the buffer. SaveSourceLocation(SuperLoc, Buffer, BufferSize, BufferCapacity); SaveSourceLocation(ColonColonLoc, Buffer, BufferSize, BufferCapacity); } -void NestedNameSpecifierLocBuilder::MakeTrivial(ASTContext &Context, - NestedNameSpecifier *Qualifier, +void NestedNameSpecifierLocBuilder::PushTrivial(ASTContext &Context, + NestedNameSpecifier Qualifier, SourceRange R) { - Representation = Qualifier; - // Construct bogus (but well-formed) source information for the // nested-name-specifier. - BufferSize = 0; - SmallVector Stack; - for (NestedNameSpecifier *NNS = Qualifier; NNS; NNS = NNS->getPrefix()) - Stack.push_back(NNS); - while (!Stack.empty()) { - NestedNameSpecifier *NNS = Stack.pop_back_val(); - switch (NNS->getKind()) { - case NestedNameSpecifier::Identifier: - case NestedNameSpecifier::Namespace: - case NestedNameSpecifier::NamespaceAlias: - SaveSourceLocation(R.getBegin(), Buffer, BufferSize, BufferCapacity); - break; - - case NestedNameSpecifier::TypeSpec: { - TypeSourceInfo *TSInfo - = Context.getTrivialTypeSourceInfo(QualType(NNS->getAsType(), 0), - R.getBegin()); - SavePointer(TSInfo->getTypeLoc().getOpaqueData(), Buffer, BufferSize, - BufferCapacity); - break; - } - - case NestedNameSpecifier::Global: - case NestedNameSpecifier::Super: - break; - } - - // Save the location of the '::'. - SaveSourceLocation(Stack.empty()? R.getEnd() : R.getBegin(), - Buffer, BufferSize, BufferCapacity); + switch (Qualifier.getKind()) { + case NestedNameSpecifier::Kind::Null: + return; + case NestedNameSpecifier::Kind::Namespace: { + auto [_1, Prefix] = Qualifier.getAsNamespaceAndPrefix(); + PushTrivial(Context, Prefix, R.getBegin()); + SaveSourceLocation(R.getBegin(), Buffer, BufferSize, BufferCapacity); + break; + } + case NestedNameSpecifier::Kind::Type: { + TypeSourceInfo *TSInfo = Context.getTrivialTypeSourceInfo( + QualType(Qualifier.getAsType(), 0), R.getBegin()); + SavePointer(TSInfo->getTypeLoc().getOpaqueData(), Buffer, BufferSize, + BufferCapacity); + break; + } + case NestedNameSpecifier::Kind::Global: + case NestedNameSpecifier::Kind::Super: + break; } + SaveSourceLocation(R.getEnd(), Buffer, BufferSize, BufferCapacity); } void NestedNameSpecifierLocBuilder::Adopt(NestedNameSpecifierLoc Other) { @@ -656,7 +321,7 @@ void NestedNameSpecifierLocBuilder::Adopt(NestedNameSpecifierLoc Other) { free(Buffer); if (!Other) { - Representation = nullptr; + Representation = std::nullopt; BufferSize = 0; return; } diff --git a/clang/lib/AST/ODRHash.cpp b/clang/lib/AST/ODRHash.cpp index 7fdfcfa3014f3..2f64d76af02cf 100644 --- a/clang/lib/AST/ODRHash.cpp +++ b/clang/lib/AST/ODRHash.cpp @@ -111,37 +111,28 @@ void ODRHash::AddDeclarationNameInfoImpl(DeclarationNameInfo NameInfo) { } } -void ODRHash::AddNestedNameSpecifier(const NestedNameSpecifier *NNS) { - assert(NNS && "Expecting non-null pointer."); - const auto *Prefix = NNS->getPrefix(); - AddBoolean(Prefix); - if (Prefix) { - AddNestedNameSpecifier(Prefix); - } - auto Kind = NNS->getKind(); - ID.AddInteger(Kind); +void ODRHash::AddNestedNameSpecifier(NestedNameSpecifier NNS) { + auto Kind = NNS.getKind(); + ID.AddInteger(llvm::to_underlying(Kind)); switch (Kind) { - case NestedNameSpecifier::Identifier: - AddIdentifierInfo(NNS->getAsIdentifier()); - break; - case NestedNameSpecifier::Namespace: - AddDecl(NNS->getAsNamespace()); - break; - case NestedNameSpecifier::NamespaceAlias: - AddDecl(NNS->getAsNamespaceAlias()); + case NestedNameSpecifier::Kind::Namespace: { + auto [Namespace, Prefix] = NNS.getAsNamespaceAndPrefix(); + AddDecl(Namespace); + AddNestedNameSpecifier(Prefix); break; - case NestedNameSpecifier::TypeSpec: - AddType(NNS->getAsType()); + } + case NestedNameSpecifier::Kind::Type: + AddType(NNS.getAsType()); break; - case NestedNameSpecifier::Global: - case NestedNameSpecifier::Super: + case NestedNameSpecifier::Kind::Null: + case NestedNameSpecifier::Kind::Global: + case NestedNameSpecifier::Kind::Super: break; } } void ODRHash::AddDependentTemplateName(const DependentTemplateStorage &Name) { - if (NestedNameSpecifier *NNS = Name.getQualifier()) - AddNestedNameSpecifier(NNS); + AddNestedNameSpecifier(Name.getQualifier()); if (IdentifierOrOverloadedOperator IO = Name.getName(); const IdentifierInfo *II = IO.getIdentifier()) AddIdentifierInfo(II); @@ -159,8 +150,7 @@ void ODRHash::AddTemplateName(TemplateName Name) { break; case TemplateName::QualifiedTemplate: { QualifiedTemplateName *QTN = Name.getAsQualifiedTemplateName(); - if (NestedNameSpecifier *NNS = QTN->getQualifier()) - AddNestedNameSpecifier(NNS); + AddNestedNameSpecifier(QTN->getQualifier()); AddBoolean(QTN->hasTemplateKeyword()); AddTemplateName(QTN->getUnderlyingTemplate()); break; @@ -892,11 +882,8 @@ class ODRTypeVisitor : public TypeVisitor { } } - void AddNestedNameSpecifier(const NestedNameSpecifier *NNS) { - Hash.AddBoolean(NNS); - if (NNS) { - Hash.AddNestedNameSpecifier(NNS); - } + void AddNestedNameSpecifier(NestedNameSpecifier NNS) { + Hash.AddNestedNameSpecifier(NNS); } void AddIdentifierInfo(const IdentifierInfo *II) { @@ -910,52 +897,33 @@ class ODRTypeVisitor : public TypeVisitor { ID.AddInteger(Quals.getAsOpaqueValue()); } - // Return the RecordType if the typedef only strips away a keyword. - // Otherwise, return the original type. - static const Type *RemoveTypedef(const Type *T) { + // Handle typedefs which only strip away a keyword. + bool handleTypedef(const Type *T) { const auto *TypedefT = dyn_cast(T); - if (!TypedefT) { - return T; - } - - const TypedefNameDecl *D = TypedefT->getDecl(); - QualType UnderlyingType = D->getUnderlyingType(); - - if (UnderlyingType.hasLocalQualifiers()) { - return T; - } - - const auto *ElaboratedT = dyn_cast(UnderlyingType); - if (!ElaboratedT) { - return T; - } + if (!TypedefT) + return false; - if (ElaboratedT->getQualifier() != nullptr) { - return T; - } + QualType UnderlyingType = TypedefT->desugar(); - QualType NamedType = ElaboratedT->getNamedType(); - if (NamedType.hasLocalQualifiers()) { - return T; - } + if (UnderlyingType.hasLocalQualifiers()) + return false; - const auto *RecordT = dyn_cast(NamedType); - if (!RecordT) { - return T; - } + const auto *TagT = dyn_cast(UnderlyingType); + if (!TagT || TagT->getQualifier()) + return false; - const IdentifierInfo *TypedefII = TypedefT->getDecl()->getIdentifier(); - const IdentifierInfo *RecordII = RecordT->getDecl()->getIdentifier(); - if (!TypedefII || !RecordII || - TypedefII->getName() != RecordII->getName()) { - return T; - } + if (TypedefT->getDecl()->getIdentifier() != + TagT->getOriginalDecl()->getIdentifier()) + return false; - return RecordT; + ID.AddInteger(TagT->getTypeClass()); + VisitTagType(TagT, /*ElaboratedOverride=*/TypedefT); + return true; } void Visit(const Type *T) { - T = RemoveTypedef(T); + if (handleTypedef(T)) + return; ID.AddInteger(T->getTypeClass()); Inherited::Visit(T); } @@ -1091,7 +1059,7 @@ class ODRTypeVisitor : public TypeVisitor { } void VisitInjectedClassNameType(const InjectedClassNameType *T) { - AddDecl(T->getDecl()); + AddDecl(T->getOriginalDecl()->getDefinitionOrSelf()); VisitType(T); } @@ -1189,14 +1157,17 @@ class ODRTypeVisitor : public TypeVisitor { VisitType(T); } - void VisitTagType(const TagType *T) { - AddDecl(T->getDecl()); + void VisitTagType(const TagType *T, + const TypedefType *ElaboratedOverride = nullptr) { + ID.AddInteger(llvm::to_underlying( + ElaboratedOverride ? ElaboratedTypeKeyword::None : T->getKeyword())); + AddNestedNameSpecifier(ElaboratedOverride + ? ElaboratedOverride->getQualifier() + : T->getQualifier()); + AddDecl(T->getOriginalDecl()->getDefinitionOrSelf()); VisitType(T); } - void VisitRecordType(const RecordType *T) { VisitTagType(T); } - void VisitEnumType(const EnumType *T) { VisitTagType(T); } - void VisitTemplateSpecializationType(const TemplateSpecializationType *T) { ID.AddInteger(T->template_arguments().size()); for (const auto &TA : T->template_arguments()) { @@ -1214,6 +1185,8 @@ class ODRTypeVisitor : public TypeVisitor { } void VisitTypedefType(const TypedefType *T) { + ID.AddInteger(llvm::to_underlying(T->getKeyword())); + AddNestedNameSpecifier(T->getQualifier()); AddDecl(T->getDecl()); VisitType(T); } @@ -1250,12 +1223,6 @@ class ODRTypeVisitor : public TypeVisitor { VisitTypeWithKeyword(T); } - void VisitElaboratedType(const ElaboratedType *T) { - AddNestedNameSpecifier(T->getQualifier()); - AddQualType(T->getNamedType()); - VisitTypeWithKeyword(T); - } - void VisitUnaryTransformType(const UnaryTransformType *T) { AddQualType(T->getUnderlyingType()); AddQualType(T->getBaseType()); @@ -1333,7 +1300,7 @@ void ODRHash::AddStructuralValue(const APValue &Value) { TypeSoFar = FD->getType(); } else { TypeSoFar = - D->getASTContext().getRecordType(cast(D)); + D->getASTContext().getCanonicalTagType(cast(D)); } } } diff --git a/clang/lib/AST/OpenMPClause.cpp b/clang/lib/AST/OpenMPClause.cpp index de8b5996818de..588b0dcc6d7b8 100644 --- a/clang/lib/AST/OpenMPClause.cpp +++ b/clang/lib/AST/OpenMPClause.cpp @@ -2350,17 +2350,16 @@ void OMPClausePrinter::VisitOMPReductionClause(OMPReductionClause *Node) { if (Node->getModifierLoc().isValid()) OS << getOpenMPSimpleClauseTypeName(OMPC_reduction, Node->getModifier()) << ", "; - NestedNameSpecifier *QualifierLoc = + NestedNameSpecifier Qualifier = Node->getQualifierLoc().getNestedNameSpecifier(); OverloadedOperatorKind OOK = Node->getNameInfo().getName().getCXXOverloadedOperator(); - if (QualifierLoc == nullptr && OOK != OO_None) { + if (!Qualifier && OOK != OO_None) { // Print reduction identifier in C format OS << getOperatorSpelling(OOK); } else { // Use C++ format - if (QualifierLoc != nullptr) - QualifierLoc->print(OS, Policy); + Qualifier.print(OS, Policy); OS << Node->getNameInfo(); } OS << ":"; @@ -2373,17 +2372,16 @@ void OMPClausePrinter::VisitOMPTaskReductionClause( OMPTaskReductionClause *Node) { if (!Node->varlist_empty()) { OS << "task_reduction("; - NestedNameSpecifier *QualifierLoc = + NestedNameSpecifier Qualifier = Node->getQualifierLoc().getNestedNameSpecifier(); OverloadedOperatorKind OOK = Node->getNameInfo().getName().getCXXOverloadedOperator(); - if (QualifierLoc == nullptr && OOK != OO_None) { + if (!Qualifier && OOK != OO_None) { // Print reduction identifier in C format OS << getOperatorSpelling(OOK); } else { // Use C++ format - if (QualifierLoc != nullptr) - QualifierLoc->print(OS, Policy); + Qualifier.print(OS, Policy); OS << Node->getNameInfo(); } OS << ":"; @@ -2395,17 +2393,16 @@ void OMPClausePrinter::VisitOMPTaskReductionClause( void OMPClausePrinter::VisitOMPInReductionClause(OMPInReductionClause *Node) { if (!Node->varlist_empty()) { OS << "in_reduction("; - NestedNameSpecifier *QualifierLoc = + NestedNameSpecifier Qualifier = Node->getQualifierLoc().getNestedNameSpecifier(); OverloadedOperatorKind OOK = Node->getNameInfo().getName().getCXXOverloadedOperator(); - if (QualifierLoc == nullptr && OOK != OO_None) { + if (!Qualifier && OOK != OO_None) { // Print reduction identifier in C format OS << getOperatorSpelling(OOK); } else { // Use C++ format - if (QualifierLoc != nullptr) - QualifierLoc->print(OS, Policy); + Qualifier.print(OS, Policy); OS << Node->getNameInfo(); } OS << ":"; @@ -2508,10 +2505,9 @@ template static void PrintMapper(raw_ostream &OS, T *Node, const PrintingPolicy &Policy) { OS << '('; - NestedNameSpecifier *MapperNNS = + NestedNameSpecifier MapperNNS = Node->getMapperQualifierLoc().getNestedNameSpecifier(); - if (MapperNNS) - MapperNNS->print(OS, Policy); + MapperNNS.print(OS, Policy); OS << Node->getMapperIdInfo() << ')'; } diff --git a/clang/lib/AST/ParentMapContext.cpp b/clang/lib/AST/ParentMapContext.cpp index 68dfe4d5d22cb..acc011cb2faa4 100644 --- a/clang/lib/AST/ParentMapContext.cpp +++ b/clang/lib/AST/ParentMapContext.cpp @@ -438,10 +438,12 @@ class ParentMapContext::ParentMap::ASTVisitor DeclNode, DeclNode, [&] { return VisitorBase::TraverseDecl(DeclNode); }, &Map.PointerParents); } - bool TraverseTypeLoc(TypeLoc TypeLocNode) { + bool TraverseTypeLoc(TypeLoc TypeLocNode, bool TraverseQualifier = true) { return TraverseNode( TypeLocNode, DynTypedNode::create(TypeLocNode), - [&] { return VisitorBase::TraverseTypeLoc(TypeLocNode); }, + [&] { + return VisitorBase::TraverseTypeLoc(TypeLocNode, TraverseQualifier); + }, &Map.OtherParents); } bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNSLocNode) { diff --git a/clang/lib/AST/PrintfFormatString.cpp b/clang/lib/AST/PrintfFormatString.cpp index 293164ddac8f8..4aece07ef9613 100644 --- a/clang/lib/AST/PrintfFormatString.cpp +++ b/clang/lib/AST/PrintfFormatString.cpp @@ -791,7 +791,7 @@ bool PrintfSpecifier::fixType(QualType QT, const LangOptions &LangOpt, // If it's an enum, get its underlying type. if (const EnumType *ETy = QT->getAs()) - QT = ETy->getDecl()->getIntegerType(); + QT = ETy->getOriginalDecl()->getDefinitionOrSelf()->getIntegerType(); const BuiltinType *BT = QT->getAs(); if (!BT) { diff --git a/clang/lib/AST/QualTypeNames.cpp b/clang/lib/AST/QualTypeNames.cpp index 39703d6d7b882..9e31a8ca5d085 100644 --- a/clang/lib/AST/QualTypeNames.cpp +++ b/clang/lib/AST/QualTypeNames.cpp @@ -24,10 +24,9 @@ namespace TypeName { /// is requested. /// \param[in] WithGlobalNsPrefix - Indicate whether the global namespace /// specifier "::" should be prepended or not. -static NestedNameSpecifier *createNestedNameSpecifier( - const ASTContext &Ctx, - const NamespaceDecl *Namesp, - bool WithGlobalNsPrefix); +static NestedNameSpecifier +createNestedNameSpecifier(const ASTContext &Ctx, const NamespaceDecl *Namesp, + bool WithGlobalNsPrefix); /// Create a NestedNameSpecifier for TagDecl and its enclosing /// scopes. @@ -39,22 +38,24 @@ static NestedNameSpecifier *createNestedNameSpecifier( /// qualified names. /// \param[in] WithGlobalNsPrefix - Indicate whether the global namespace /// specifier "::" should be prepended or not. -static NestedNameSpecifier *createNestedNameSpecifier( - const ASTContext &Ctx, const TypeDecl *TD, - bool FullyQualify, bool WithGlobalNsPrefix); +static NestedNameSpecifier createNestedNameSpecifier(const ASTContext &Ctx, + const TypeDecl *TD, + bool FullyQualify, + bool WithGlobalNsPrefix); -static NestedNameSpecifier *createNestedNameSpecifierForScopeOf( - const ASTContext &Ctx, const Decl *decl, - bool FullyQualified, bool WithGlobalNsPrefix); +static NestedNameSpecifier +createNestedNameSpecifierForScopeOf(const ASTContext &Ctx, const Decl *decl, + bool FullyQualified, + bool WithGlobalNsPrefix); -static NestedNameSpecifier *getFullyQualifiedNestedNameSpecifier( - const ASTContext &Ctx, NestedNameSpecifier *scope, bool WithGlobalNsPrefix); +static NestedNameSpecifier getFullyQualifiedNestedNameSpecifier( + const ASTContext &Ctx, NestedNameSpecifier NNS, bool WithGlobalNsPrefix); static bool getFullyQualifiedTemplateName(const ASTContext &Ctx, TemplateName &TName, bool WithGlobalNsPrefix) { bool Changed = false; - NestedNameSpecifier *NNS = nullptr; + NestedNameSpecifier NNS = std::nullopt; TemplateDecl *ArgTDecl = TName.getAsTemplateDecl(); // ArgTDecl won't be NULL because we asserted that this isn't a @@ -65,13 +66,13 @@ static bool getFullyQualifiedTemplateName(const ASTContext &Ctx, if (QTName && !QTName->hasTemplateKeyword() && (NNS = QTName->getQualifier())) { - NestedNameSpecifier *QNNS = getFullyQualifiedNestedNameSpecifier( - Ctx, NNS, WithGlobalNsPrefix); + NestedNameSpecifier QNNS = + getFullyQualifiedNestedNameSpecifier(Ctx, NNS, WithGlobalNsPrefix); if (QNNS != NNS) { Changed = true; NNS = QNNS; } else { - NNS = nullptr; + NNS = std::nullopt; } } else { NNS = createNestedNameSpecifierForScopeOf( @@ -116,76 +117,81 @@ static bool getFullyQualifiedTemplateArgument(const ASTContext &Ctx, } static const Type *getFullyQualifiedTemplateType(const ASTContext &Ctx, - const Type *TypePtr, + const TagType *TSTRecord, + ElaboratedTypeKeyword Keyword, + NestedNameSpecifier Qualifier, bool WithGlobalNsPrefix) { - // DependentTemplateTypes exist within template declarations and - // definitions. Therefore we shouldn't encounter them at the end of - // a translation unit. If we do, the caller has made an error. - assert(!isa(TypePtr)); - // In case of template specializations, iterate over the arguments - // and fully qualify them as well. - if (const auto *TST = dyn_cast(TypePtr)) { - bool MightHaveChanged = false; - SmallVector FQArgs; - // Cheap to copy and potentially modified by - // getFullyQualifedTemplateArgument. - for (TemplateArgument Arg : TST->template_arguments()) { - MightHaveChanged |= getFullyQualifiedTemplateArgument( - Ctx, Arg, WithGlobalNsPrefix); - FQArgs.push_back(Arg); - } + // We are asked to fully qualify and we have a Record Type, + // which can point to a template instantiation with no sugar in any of + // its template argument, however we still need to fully qualify them. + + const auto *TD = TSTRecord->getOriginalDecl(); + const auto *TSTDecl = dyn_cast(TD); + if (!TSTDecl) + return Ctx.getTagType(Keyword, Qualifier, TD, /*OwnsTag=*/false) + .getTypePtr(); + + const TemplateArgumentList &TemplateArgs = TSTDecl->getTemplateArgs(); + + bool MightHaveChanged = false; + SmallVector FQArgs; + for (unsigned int I = 0, E = TemplateArgs.size(); I != E; ++I) { + // cheap to copy and potentially modified by + // getFullyQualifedTemplateArgument + TemplateArgument Arg(TemplateArgs[I]); + MightHaveChanged |= + getFullyQualifiedTemplateArgument(Ctx, Arg, WithGlobalNsPrefix); + FQArgs.push_back(Arg); + } - // If a fully qualified arg is different from the unqualified arg, - // allocate new type in the AST. - if (MightHaveChanged) { - QualType QT = Ctx.getTemplateSpecializationType( - TST->getTemplateName(), FQArgs, - /*CanonicalArgs=*/{}, TST->desugar()); - // getTemplateSpecializationType returns a fully qualified - // version of the specialization itself, so no need to qualify - // it. - return QT.getTypePtr(); - } - } else if (const auto *TSTRecord = dyn_cast(TypePtr)) { - // We are asked to fully qualify and we have a Record Type, - // which can point to a template instantiation with no sugar in any of - // its template argument, however we still need to fully qualify them. - - if (const auto *TSTDecl = - dyn_cast(TSTRecord->getDecl())) { - const TemplateArgumentList &TemplateArgs = TSTDecl->getTemplateArgs(); - - bool MightHaveChanged = false; - SmallVector FQArgs; - for (unsigned int I = 0, E = TemplateArgs.size(); I != E; ++I) { - // cheap to copy and potentially modified by - // getFullyQualifedTemplateArgument - TemplateArgument Arg(TemplateArgs[I]); - MightHaveChanged |= getFullyQualifiedTemplateArgument( - Ctx, Arg, WithGlobalNsPrefix); - FQArgs.push_back(Arg); - } + if (!MightHaveChanged) + return Ctx.getTagType(Keyword, Qualifier, TD, /*OwnsTag=*/false) + .getTypePtr(); + // If a fully qualified arg is different from the unqualified arg, + // allocate new type in the AST. + TemplateName TN = Ctx.getQualifiedTemplateName( + Qualifier, /*TemplateKeyword=*/false, + TemplateName(TSTDecl->getSpecializedTemplate())); + QualType QT = Ctx.getTemplateSpecializationType( + Keyword, TN, FQArgs, + /*CanonicalArgs=*/{}, TSTRecord->getCanonicalTypeInternal()); + // getTemplateSpecializationType returns a fully qualified + // version of the specialization itself, so no need to qualify + // it. + return QT.getTypePtr(); +} - // If a fully qualified arg is different from the unqualified arg, - // allocate new type in the AST. - if (MightHaveChanged) { - TemplateName TN(TSTDecl->getSpecializedTemplate()); - QualType QT = Ctx.getTemplateSpecializationType( - TN, FQArgs, - /*CanonicalArgs=*/{}, TSTRecord->getCanonicalTypeInternal()); - // getTemplateSpecializationType returns a fully qualified - // version of the specialization itself, so no need to qualify - // it. - return QT.getTypePtr(); - } - } +static const Type * +getFullyQualifiedTemplateType(const ASTContext &Ctx, + const TemplateSpecializationType *TST, + bool WithGlobalNsPrefix) { + TemplateName TName = TST->getTemplateName(); + bool MightHaveChanged = + getFullyQualifiedTemplateName(Ctx, TName, WithGlobalNsPrefix); + SmallVector FQArgs; + // Cheap to copy and potentially modified by + // getFullyQualifedTemplateArgument. + for (TemplateArgument Arg : TST->template_arguments()) { + MightHaveChanged |= + getFullyQualifiedTemplateArgument(Ctx, Arg, WithGlobalNsPrefix); + FQArgs.push_back(Arg); } - return TypePtr; + + if (!MightHaveChanged) + return TST; + + QualType NewQT = + Ctx.getTemplateSpecializationType(TST->getKeyword(), TName, FQArgs, + /*CanonicalArgs=*/{}, TST->desugar()); + // getTemplateSpecializationType returns a fully qualified + // version of the specialization itself, so no need to qualify + // it. + return NewQT.getTypePtr(); } -static NestedNameSpecifier *createOuterNNS(const ASTContext &Ctx, const Decl *D, - bool FullyQualify, - bool WithGlobalNsPrefix) { +static NestedNameSpecifier createOuterNNS(const ASTContext &Ctx, const Decl *D, + bool FullyQualify, + bool WithGlobalNsPrefix) { const DeclContext *DC = D->getDeclContext(); if (const auto *NS = dyn_cast(DC)) { while (NS && NS->isInline()) { @@ -195,80 +201,63 @@ static NestedNameSpecifier *createOuterNNS(const ASTContext &Ctx, const Decl *D, if (NS && NS->getDeclName()) { return createNestedNameSpecifier(Ctx, NS, WithGlobalNsPrefix); } - return nullptr; // no starting '::', no anonymous - } else if (const auto *TD = dyn_cast(DC)) { - return createNestedNameSpecifier(Ctx, TD, FullyQualify, WithGlobalNsPrefix); - } else if (const auto *TDD = dyn_cast(DC)) { - return createNestedNameSpecifier( - Ctx, TDD, FullyQualify, WithGlobalNsPrefix); - } else if (WithGlobalNsPrefix && DC->isTranslationUnit()) { - return NestedNameSpecifier::GlobalSpecifier(Ctx); + return std::nullopt; // no starting '::', no anonymous } - return nullptr; // no starting '::' if |WithGlobalNsPrefix| is false + if (const auto *TD = dyn_cast(DC)) + return createNestedNameSpecifier(Ctx, TD, FullyQualify, WithGlobalNsPrefix); + if (const auto *TDD = dyn_cast(DC)) + return createNestedNameSpecifier(Ctx, TDD, FullyQualify, + WithGlobalNsPrefix); + if (WithGlobalNsPrefix && DC->isTranslationUnit()) + return NestedNameSpecifier::getGlobal(); + return std::nullopt; // no starting '::' if |WithGlobalNsPrefix| is false } /// Return a fully qualified version of this name specifier. -static NestedNameSpecifier *getFullyQualifiedNestedNameSpecifier( - const ASTContext &Ctx, NestedNameSpecifier *Scope, - bool WithGlobalNsPrefix) { - switch (Scope->getKind()) { - case NestedNameSpecifier::Global: - case NestedNameSpecifier::Super: - // Already fully qualified - return Scope; - case NestedNameSpecifier::Namespace: - return TypeName::createNestedNameSpecifier( - Ctx, Scope->getAsNamespace(), WithGlobalNsPrefix); - case NestedNameSpecifier::NamespaceAlias: - // Namespace aliases are only valid for the duration of the - // scope where they were introduced, and therefore are often - // invalid at the end of the TU. So use the namespace name more - // likely to be valid at the end of the TU. - return TypeName::createNestedNameSpecifier( - Ctx, - Scope->getAsNamespaceAlias()->getNamespace()->getCanonicalDecl(), - WithGlobalNsPrefix); - case NestedNameSpecifier::Identifier: - // A function or some other construct that makes it un-namable - // at the end of the TU. Skip the current component of the name, - // but use the name of it's prefix. - return getFullyQualifiedNestedNameSpecifier( - Ctx, Scope->getPrefix(), WithGlobalNsPrefix); - case NestedNameSpecifier::TypeSpec: { - const Type *Type = Scope->getAsType(); - // Find decl context. - const TagDecl *TD = nullptr; - if (const TagType *TagDeclType = Type->getAs()) { - TD = TagDeclType->getDecl(); - } else { - TD = Type->getAsCXXRecordDecl(); - } - if (TD) { - return TypeName::createNestedNameSpecifier(Ctx, TD, - true /*FullyQualified*/, - WithGlobalNsPrefix); - } else if (const auto *TDD = dyn_cast(Type)) { - return TypeName::createNestedNameSpecifier(Ctx, TDD->getDecl(), - true /*FullyQualified*/, - WithGlobalNsPrefix); - } +static NestedNameSpecifier getFullyQualifiedNestedNameSpecifier( + const ASTContext &Ctx, NestedNameSpecifier Scope, bool WithGlobalNsPrefix) { + switch (Scope.getKind()) { + case NestedNameSpecifier::Kind::Null: + llvm_unreachable("can't fully qualify the empty nested name specifier"); + case NestedNameSpecifier::Kind::Global: + case NestedNameSpecifier::Kind::Super: + // Already fully qualified + return Scope; + case NestedNameSpecifier::Kind::Namespace: + return TypeName::createNestedNameSpecifier( + Ctx, Scope.getAsNamespaceAndPrefix().Namespace->getNamespace(), + WithGlobalNsPrefix); + case NestedNameSpecifier::Kind::Type: { + const Type *Type = Scope.getAsType(); + // Find decl context. + const TypeDecl *TD; + if (const TagType *TagDeclType = Type->getAs()) + TD = TagDeclType->getOriginalDecl(); + else if (const auto *D = dyn_cast(Type)) + TD = D->getDecl(); + else return Scope; - } + return TypeName::createNestedNameSpecifier(Ctx, TD, /*FullyQualify=*/true, + WithGlobalNsPrefix); + } } llvm_unreachable("bad NNS kind"); } /// Create a nested name specifier for the declaring context of /// the type. -static NestedNameSpecifier *createNestedNameSpecifierForScopeOf( - const ASTContext &Ctx, const Decl *Decl, - bool FullyQualified, bool WithGlobalNsPrefix) { +static NestedNameSpecifier +createNestedNameSpecifierForScopeOf(const ASTContext &Ctx, const Decl *Decl, + bool FullyQualified, + bool WithGlobalNsPrefix) { assert(Decl); const DeclContext *DC = Decl->getDeclContext()->getRedeclContext(); const auto *Outer = dyn_cast(DC); const auto *OuterNS = dyn_cast(DC); - if (Outer && !(OuterNS && OuterNS->isAnonymousNamespace())) { + if (OuterNS && OuterNS->isAnonymousNamespace()) + OuterNS = dyn_cast(OuterNS->getParent()); + if (Outer) { if (const auto *CxxDecl = dyn_cast(DC)) { if (ClassTemplateDecl *ClassTempl = CxxDecl->getDescribedClassTemplate()) { @@ -297,76 +286,80 @@ static NestedNameSpecifier *createNestedNameSpecifierForScopeOf( Ctx, TD, FullyQualified, WithGlobalNsPrefix); } else if (isa(Outer)) { // Context is the TU. Nothing needs to be done. - return nullptr; + return std::nullopt; } else { // Decl's context was neither the TU, a namespace, nor a // TagDecl, which means it is a type local to a scope, and not // accessible at the end of the TU. - return nullptr; + return std::nullopt; } } else if (WithGlobalNsPrefix && DC->isTranslationUnit()) { - return NestedNameSpecifier::GlobalSpecifier(Ctx); + return NestedNameSpecifier::getGlobal(); } - return nullptr; + return std::nullopt; } /// Create a nested name specifier for the declaring context of /// the type. -static NestedNameSpecifier *createNestedNameSpecifierForScopeOf( - const ASTContext &Ctx, const Type *TypePtr, - bool FullyQualified, bool WithGlobalNsPrefix) { - if (!TypePtr) return nullptr; +static NestedNameSpecifier +createNestedNameSpecifierForScopeOf(const ASTContext &Ctx, const Type *TypePtr, + bool FullyQualified, + bool WithGlobalNsPrefix) { + if (!TypePtr) + return std::nullopt; Decl *Decl = nullptr; // There are probably other cases ... if (const auto *TDT = dyn_cast(TypePtr)) { Decl = TDT->getDecl(); } else if (const auto *TagDeclType = dyn_cast(TypePtr)) { - Decl = TagDeclType->getDecl(); + Decl = TagDeclType->getOriginalDecl(); } else if (const auto *TST = dyn_cast(TypePtr)) { Decl = TST->getTemplateName().getAsTemplateDecl(); } else { Decl = TypePtr->getAsCXXRecordDecl(); } - if (!Decl) return nullptr; + if (!Decl) + return std::nullopt; return createNestedNameSpecifierForScopeOf( Ctx, Decl, FullyQualified, WithGlobalNsPrefix); } -NestedNameSpecifier *createNestedNameSpecifier(const ASTContext &Ctx, - const NamespaceDecl *Namespace, - bool WithGlobalNsPrefix) { +static NestedNameSpecifier +createNestedNameSpecifier(const ASTContext &Ctx, const NamespaceDecl *Namespace, + bool WithGlobalNsPrefix) { while (Namespace && Namespace->isInline()) { // Ignore inline namespace; Namespace = dyn_cast(Namespace->getDeclContext()); } - if (!Namespace) return nullptr; + if (!Namespace) + return std::nullopt; - bool FullyQualified = true; // doesn't matter, DeclContexts are namespaces - return NestedNameSpecifier::Create( - Ctx, - createOuterNNS(Ctx, Namespace, FullyQualified, WithGlobalNsPrefix), - Namespace); + bool FullyQualify = true; // doesn't matter, DeclContexts are namespaces + return NestedNameSpecifier( + Ctx, Namespace, + createOuterNNS(Ctx, Namespace, FullyQualify, WithGlobalNsPrefix)); } -NestedNameSpecifier *createNestedNameSpecifier(const ASTContext &Ctx, - const TypeDecl *TD, - bool FullyQualify, - bool WithGlobalNsPrefix) { - const Type *TypePtr = TD->getTypeForDecl(); - if (isa(TypePtr) || - isa(TypePtr)) { +NestedNameSpecifier createNestedNameSpecifier(const ASTContext &Ctx, + const TypeDecl *TD, + bool FullyQualify, + bool WithGlobalNsPrefix) { + const Type *TypePtr = Ctx.getTypeDeclType(TD).getTypePtr(); + if (auto *RD = dyn_cast(TypePtr)) { // We are asked to fully qualify and we have a Record Type (which // may point to a template specialization) or Template // Specialization Type. We need to fully qualify their arguments. - - TypePtr = getFullyQualifiedTemplateType(Ctx, TypePtr, WithGlobalNsPrefix); + TypePtr = getFullyQualifiedTemplateType( + Ctx, RD, ElaboratedTypeKeyword::None, + createOuterNNS(Ctx, TD, FullyQualify, WithGlobalNsPrefix), + WithGlobalNsPrefix); + } else if (auto *TST = dyn_cast(TypePtr)) { + TypePtr = getFullyQualifiedTemplateType(Ctx, TST, WithGlobalNsPrefix); } - - return NestedNameSpecifier::Create( - Ctx, createOuterNNS(Ctx, TD, FullyQualify, WithGlobalNsPrefix), TypePtr); + return NestedNameSpecifier(TypePtr); } /// Return the fully qualified type, including fully-qualified @@ -390,7 +383,7 @@ QualType getFullyQualifiedType(QualType QT, const ASTContext &Ctx, Qualifiers Quals = QT.getQualifiers(); // Fully qualify the pointee and class types. QT = getFullyQualifiedType(QT->getPointeeType(), Ctx, WithGlobalNsPrefix); - NestedNameSpecifier *Qualifier = getFullyQualifiedNestedNameSpecifier( + NestedNameSpecifier Qualifier = getFullyQualifiedNestedNameSpecifier( Ctx, MPT->getQualifier(), WithGlobalNsPrefix); QT = Ctx.getMemberPointerType(QT, Qualifier, MPT->getMostRecentCXXRecordDecl()); @@ -443,45 +436,48 @@ QualType getFullyQualifiedType(QualType QT, const ASTContext &Ctx, QT = Ctx.getQualifiedType(QT, Quals); } - NestedNameSpecifier *Prefix = nullptr; + if (const auto *TST = + dyn_cast(QT.getTypePtr())) { + + const Type *T = getFullyQualifiedTemplateType(Ctx, TST, WithGlobalNsPrefix); + if (T == TST) + return QT; + return Ctx.getQualifiedType(T, QT.getQualifiers()); + } + // Local qualifiers are attached to the QualType outside of the // elaborated type. Retrieve them before descending into the // elaborated type. Qualifiers PrefixQualifiers = QT.getLocalQualifiers(); QT = QualType(QT.getTypePtr(), 0); - ElaboratedTypeKeyword Keyword = ElaboratedTypeKeyword::None; - if (const auto *ETypeInput = dyn_cast(QT.getTypePtr())) { - QT = ETypeInput->getNamedType(); - assert(!QT.hasLocalQualifiers()); - Keyword = ETypeInput->getKeyword(); - } // We don't consider the alias introduced by `using a::X` as a new type. // The qualified name is still a::X. if (const auto *UT = QT->getAs()) { - QT = Ctx.getQualifiedType(UT->getUnderlyingType(), PrefixQualifiers); + QT = Ctx.getQualifiedType(UT->desugar(), PrefixQualifiers); return getFullyQualifiedType(QT, Ctx, WithGlobalNsPrefix); } // Create a nested name specifier if needed. - Prefix = createNestedNameSpecifierForScopeOf(Ctx, QT.getTypePtr(), - true /*FullyQualified*/, - WithGlobalNsPrefix); + NestedNameSpecifier Prefix = createNestedNameSpecifierForScopeOf( + Ctx, QT.getTypePtr(), true /*FullyQualified*/, WithGlobalNsPrefix); // In case of template specializations iterate over the arguments and // fully qualify them as well. - if (isa(QT.getTypePtr()) || - isa(QT.getTypePtr())) { + if (const auto *TT = dyn_cast(QT.getTypePtr())) { // We are asked to fully qualify and we have a Record Type (which // may point to a template specialization) or Template // Specialization Type. We need to fully qualify their arguments. const Type *TypePtr = getFullyQualifiedTemplateType( - Ctx, QT.getTypePtr(), WithGlobalNsPrefix); + Ctx, TT, TT->getKeyword(), Prefix, WithGlobalNsPrefix); QT = QualType(TypePtr, 0); - } - if (Prefix || Keyword != ElaboratedTypeKeyword::None) { - QT = Ctx.getElaboratedType(Keyword, Prefix, QT); + } else if (const auto *TT = dyn_cast(QT.getTypePtr())) { + QT = Ctx.getTypedefType( + TT->getKeyword(), Prefix, TT->getDecl(), + getFullyQualifiedType(TT->desugar(), Ctx, WithGlobalNsPrefix)); + } else { + assert(!Prefix && "Unhandled type node"); } QT = Ctx.getQualifiedType(QT, PrefixQualifiers); return QT; diff --git a/clang/lib/AST/RecordLayoutBuilder.cpp b/clang/lib/AST/RecordLayoutBuilder.cpp index 6d819031cbef4..8ea4e660c08bb 100644 --- a/clang/lib/AST/RecordLayoutBuilder.cpp +++ b/clang/lib/AST/RecordLayoutBuilder.cpp @@ -2012,8 +2012,7 @@ void ItaniumRecordLayoutBuilder::LayoutField(const FieldDecl *D, } else if (const BuiltinType *BTy = BaseTy->getAs()) { performBuiltinTypeAlignmentUpgrade(BTy); } else if (const RecordType *RT = BaseTy->getAs()) { - const RecordDecl *RD = RT->getDecl(); - assert(RD && "Expected non-null RecordDecl."); + const RecordDecl *RD = RT->getOriginalDecl(); const ASTRecordLayout &FieldRecord = Context.getASTRecordLayout(RD); PreferredAlign = FieldRecord.getPreferredAlignment(); } @@ -2128,7 +2127,8 @@ void ItaniumRecordLayoutBuilder::LayoutField(const FieldDecl *D, // TODO: Takes no account the alignment of the outer struct if (FieldOffset % OriginalFieldAlign != 0) Diag(D->getLocation(), diag::warn_unaligned_access) - << Context.getTypeDeclType(RD) << D->getName() << D->getType(); + << Context.getCanonicalTagType(RD) << D->getName() + << D->getType(); } } @@ -2193,8 +2193,7 @@ void ItaniumRecordLayoutBuilder::FinishLayout(const NamedDecl *D) { InBits = false; } Diag(RD->getLocation(), diag::warn_padded_struct_size) - << Context.getTypeDeclType(RD) - << PadSize + << Context.getCanonicalTagType(RD) << PadSize << (InBits ? 1 : 0); // (byte|bit) } @@ -2212,7 +2211,7 @@ void ItaniumRecordLayoutBuilder::FinishLayout(const NamedDecl *D) { Context.getLangOpts().getClangABICompat() <= LangOptions::ClangABI::Ver15)) Diag(D->getLocation(), diag::warn_unnecessary_packed) - << Context.getTypeDeclType(RD); + << Context.getCanonicalTagType(RD); } } @@ -2306,7 +2305,7 @@ static void CheckFieldPadding(const ASTContext &Context, bool IsUnion, Context.getDiagnostics().Report(D->getLocation(), Diagnostic) << getPaddingDiagFromTagKind(D->getParent()->getTagKind()) - << Context.getTypeDeclType(D->getParent()) << PadSize + << Context.getCanonicalTagType(D->getParent()) << PadSize << (InBits ? 1 : 0) // (byte|bit) << D->getIdentifier(); } else { @@ -2315,7 +2314,7 @@ static void CheckFieldPadding(const ASTContext &Context, bool IsUnion, Context.getDiagnostics().Report(D->getLocation(), Diagnostic) << getPaddingDiagFromTagKind(D->getParent()->getTagKind()) - << Context.getTypeDeclType(D->getParent()) << PadSize + << Context.getCanonicalTagType(D->getParent()) << PadSize << (InBits ? 1 : 0); // (byte|bit) } } @@ -2723,7 +2722,7 @@ MicrosoftRecordLayoutBuilder::getAdjustedElementInfo( else { if (auto RT = FD->getType()->getBaseElementTypeUnsafe()->getAs()) { - auto const &Layout = Context.getASTRecordLayout(RT->getDecl()); + auto const &Layout = Context.getASTRecordLayout(RT->getOriginalDecl()); EndsWithZeroSizedObject = Layout.endsWithZeroSizedObject(); FieldRequiredAlignment = std::max(FieldRequiredAlignment, Layout.getRequiredAlignment()); @@ -3282,7 +3281,7 @@ void MicrosoftRecordLayoutBuilder::finalizeLayout(const RecordDecl *RD) { Context.getDiagnostics().Report(RD->getLocation(), diag::warn_padded_struct_size) - << Context.getTypeDeclType(RD) << PadSize + << Context.getCanonicalTagType(RD) << PadSize << (InBits ? 1 : 0); // (byte|bit) } } @@ -3640,7 +3639,7 @@ static void DumpRecordLayout(raw_ostream &OS, const RecordDecl *RD, auto CXXRD = dyn_cast(RD); PrintOffset(OS, Offset, IndentLevel); - OS << C.getTypeDeclType(const_cast(RD)); + OS << C.getCanonicalTagType(const_cast(RD)); if (Description) OS << ' ' << Description; if (CXXRD && CXXRD->isEmpty()) @@ -3705,8 +3704,8 @@ static void DumpRecordLayout(raw_ostream &OS, const RecordDecl *RD, // Recursively dump fields of record type. if (auto RT = Field->getType()->getAs()) { - DumpRecordLayout(OS, RT->getDecl(), C, FieldOffset, IndentLevel, - Field->getName().data(), + DumpRecordLayout(OS, RT->getOriginalDecl()->getDefinitionOrSelf(), C, + FieldOffset, IndentLevel, Field->getName().data(), /*PrintSizeInfo=*/false, /*IncludeVirtualBases=*/true); continue; @@ -3789,7 +3788,7 @@ void ASTContext::DumpRecordLayout(const RecordDecl *RD, raw_ostream &OS, // in libFrontend. const ASTRecordLayout &Info = getASTRecordLayout(RD); - OS << "Type: " << getTypeDeclType(RD) << "\n"; + OS << "Type: " << getCanonicalTagType(RD) << "\n"; OS << "\nLayout: "; OS << "getAs()) { // Don't try to fix incomplete enums. - if (!ETy->getDecl()->isComplete()) + const EnumDecl *ED = ETy->getOriginalDecl()->getDefinitionOrSelf(); + if (!ED->isComplete()) return false; - PT = ETy->getDecl()->getIntegerType(); + PT = ED->getIntegerType(); } const BuiltinType *BT = PT->getAs(); diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp index be02bdde38a3d..698c864c77c83 100644 --- a/clang/lib/AST/StmtPrinter.cpp +++ b/clang/lib/AST/StmtPrinter.cpp @@ -454,10 +454,7 @@ void StmtPrinter::VisitMSDependentExistsStmt(MSDependentExistsStmt *Node) { else OS << "__if_not_exists ("; - if (NestedNameSpecifier *Qualifier - = Node->getQualifierLoc().getNestedNameSpecifier()) - Qualifier->print(OS, Policy); - + Node->getQualifierLoc().getNestedNameSpecifier().print(OS, Policy); OS << Node->getNameInfo() << ") "; PrintRawCompoundStmt(Node->getSubStmt()); @@ -1309,8 +1306,7 @@ void StmtPrinter::VisitDeclRefExpr(DeclRefExpr *Node) { TPOD->printAsExpr(OS, Policy); return; } - if (NestedNameSpecifier *Qualifier = Node->getQualifier()) - Qualifier->print(OS, Policy); + Node->getQualifier().print(OS, Policy); if (Node->hasTemplateKeyword()) OS << "template "; @@ -1359,8 +1355,7 @@ void StmtPrinter::VisitDeclRefExpr(DeclRefExpr *Node) { void StmtPrinter::VisitDependentScopeDeclRefExpr( DependentScopeDeclRefExpr *Node) { - if (NestedNameSpecifier *Qualifier = Node->getQualifier()) - Qualifier->print(OS, Policy); + Node->getQualifier().print(OS, Policy); if (Node->hasTemplateKeyword()) OS << "template "; OS << Node->getNameInfo(); @@ -1369,8 +1364,7 @@ void StmtPrinter::VisitDependentScopeDeclRefExpr( } void StmtPrinter::VisitUnresolvedLookupExpr(UnresolvedLookupExpr *Node) { - if (Node->getQualifier()) - Node->getQualifier()->print(OS, Policy); + Node->getQualifier().print(OS, Policy); if (Node->hasTemplateKeyword()) OS << "template "; OS << Node->getNameInfo(); @@ -1778,8 +1772,7 @@ void StmtPrinter::VisitMemberExpr(MemberExpr *Node) { if (FD->isAnonymousStructOrUnion()) return; - if (NestedNameSpecifier *Qualifier = Node->getQualifier()) - Qualifier->print(OS, Policy); + Node->getQualifier().print(OS, Policy); if (Node->hasTemplateKeyword()) OS << "template "; OS << Node->getMemberNameInfo(); @@ -2177,9 +2170,7 @@ void StmtPrinter::VisitMSPropertyRefExpr(MSPropertyRefExpr *Node) { OS << "->"; else OS << "."; - if (NestedNameSpecifier *Qualifier = - Node->getQualifierLoc().getNestedNameSpecifier()) - Qualifier->print(OS, Policy); + Node->getQualifierLoc().getNestedNameSpecifier().print(OS, Policy); OS << Node->getPropertyDecl()->getDeclName(); } @@ -2509,8 +2500,7 @@ void StmtPrinter::VisitCXXPseudoDestructorExpr(CXXPseudoDestructorExpr *E) { OS << "->"; else OS << '.'; - if (E->getQualifier()) - E->getQualifier()->print(OS, Policy); + E->getQualifier().print(OS, Policy); OS << "~"; if (const IdentifierInfo *II = E->getDestroyedTypeIdentifier()) @@ -2572,8 +2562,7 @@ void StmtPrinter::VisitCXXDependentScopeMemberExpr( PrintExpr(Node->getBase()); OS << (Node->isArrow() ? "->" : "."); } - if (NestedNameSpecifier *Qualifier = Node->getQualifier()) - Qualifier->print(OS, Policy); + Node->getQualifier().print(OS, Policy); if (Node->hasTemplateKeyword()) OS << "template "; OS << Node->getMemberNameInfo(); @@ -2586,8 +2575,7 @@ void StmtPrinter::VisitUnresolvedMemberExpr(UnresolvedMemberExpr *Node) { PrintExpr(Node->getBase()); OS << (Node->isArrow() ? "->" : "."); } - if (NestedNameSpecifier *Qualifier = Node->getQualifier()) - Qualifier->print(OS, Policy); + Node->getQualifier().print(OS, Policy); if (Node->hasTemplateKeyword()) OS << "template "; OS << Node->getMemberNameInfo(); @@ -2678,8 +2666,7 @@ void StmtPrinter::VisitCXXParenListInitExpr(CXXParenListInitExpr *Node) { void StmtPrinter::VisitConceptSpecializationExpr(ConceptSpecializationExpr *E) { NestedNameSpecifierLoc NNS = E->getNestedNameSpecifierLoc(); - if (NNS) - NNS.getNestedNameSpecifier()->print(OS, Policy); + NNS.getNestedNameSpecifier().print(OS, Policy); if (E->getTemplateKWLoc().isValid()) OS << "template "; OS << E->getFoundDecl()->getName(); diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp index c61450e19f1b6..59a18395d109c 100644 --- a/clang/lib/AST/StmtProfile.cpp +++ b/clang/lib/AST/StmtProfile.cpp @@ -65,7 +65,7 @@ namespace { /// Visit a nested-name-specifier that occurs within an expression /// or statement. - virtual void VisitNestedNameSpecifier(NestedNameSpecifier *NNS) = 0; + virtual void VisitNestedNameSpecifier(NestedNameSpecifier NNS) = 0; /// Visit a template name that occurs within an expression or /// statement. @@ -167,10 +167,10 @@ namespace { ID.AddPointer(II); } - void VisitNestedNameSpecifier(NestedNameSpecifier *NNS) override { + void VisitNestedNameSpecifier(NestedNameSpecifier NNS) override { if (Canonical) - NNS = Context.getCanonicalNestedNameSpecifier(NNS); - ID.AddPointer(NNS); + NNS = NNS.getCanonical(); + NNS.Profile(ID); } void VisitTemplateName(TemplateName Name) override { @@ -226,11 +226,10 @@ namespace { void VisitTemplateName(TemplateName Name) override { Hash.AddTemplateName(Name); } - void VisitNestedNameSpecifier(NestedNameSpecifier *NNS) override { - ID.AddBoolean(NNS); - if (NNS) { + void VisitNestedNameSpecifier(NestedNameSpecifier NNS) override { + ID.AddBoolean(bool(NNS)); + if (NNS) Hash.AddNestedNameSpecifier(NNS); - } } }; } diff --git a/clang/lib/AST/TemplateBase.cpp b/clang/lib/AST/TemplateBase.cpp index 7c89dea4629cc..700675840fd96 100644 --- a/clang/lib/AST/TemplateBase.cpp +++ b/clang/lib/AST/TemplateBase.cpp @@ -57,7 +57,7 @@ static void printIntegral(const TemplateArgument &TemplArg, raw_ostream &Out, if (Policy.UseEnumerators) { if (const EnumType *ET = T->getAs()) { - for (const EnumConstantDecl *ECD : ET->getDecl()->enumerators()) { + for (const EnumConstantDecl *ECD : ET->getOriginalDecl()->enumerators()) { // In Sema::CheckTemplateArugment, enum template arguments value are // extended to the size of the integer underlying the enum type. This // may create a size difference between the enum value and template @@ -585,6 +585,29 @@ void TemplateArgument::print(const PrintingPolicy &Policy, raw_ostream &Out, // TemplateArgumentLoc Implementation //===----------------------------------------------------------------------===// +TemplateArgumentLoc::TemplateArgumentLoc(ASTContext &Ctx, + const TemplateArgument &Argument, + SourceLocation TemplateKWLoc, + NestedNameSpecifierLoc QualifierLoc, + SourceLocation TemplateNameLoc, + SourceLocation EllipsisLoc) + : Argument(Argument), + LocInfo(Ctx, TemplateKWLoc, QualifierLoc, TemplateNameLoc, EllipsisLoc) { + assert(Argument.getKind() == TemplateArgument::Template || + Argument.getKind() == TemplateArgument::TemplateExpansion); + assert(QualifierLoc.getNestedNameSpecifier() == + Argument.getAsTemplateOrTemplatePattern().getQualifier()); +} + +NestedNameSpecifierLoc TemplateArgumentLoc::getTemplateQualifierLoc() const { + if (Argument.getKind() != TemplateArgument::Template && + Argument.getKind() != TemplateArgument::TemplateExpansion) + return NestedNameSpecifierLoc(); + return NestedNameSpecifierLoc( + Argument.getAsTemplateOrTemplatePattern().getQualifier(), + LocInfo.getTemplate()->QualifierLocData); +} + SourceRange TemplateArgumentLoc::getSourceRange() const { switch (Argument.getKind()) { case TemplateArgument::Expression: @@ -691,10 +714,11 @@ const StreamingDiagnostic &clang::operator<<(const StreamingDiagnostic &DB, } clang::TemplateArgumentLocInfo::TemplateArgumentLocInfo( - ASTContext &Ctx, NestedNameSpecifierLoc QualifierLoc, - SourceLocation TemplateNameLoc, SourceLocation EllipsisLoc) { + ASTContext &Ctx, SourceLocation TemplateKWLoc, + NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateNameLoc, + SourceLocation EllipsisLoc) { TemplateTemplateArgLocInfo *Template = new (Ctx) TemplateTemplateArgLocInfo; - Template->Qualifier = QualifierLoc.getNestedNameSpecifier(); + Template->TemplateKwLoc = TemplateKWLoc; Template->QualifierLocData = QualifierLoc.getOpaqueData(); Template->TemplateNameLoc = TemplateNameLoc; Template->EllipsisLoc = EllipsisLoc; diff --git a/clang/lib/AST/TemplateName.cpp b/clang/lib/AST/TemplateName.cpp index 5b7abc4d038a9..28d54760a1f4a 100644 --- a/clang/lib/AST/TemplateName.cpp +++ b/clang/lib/AST/TemplateName.cpp @@ -289,10 +289,30 @@ QualifiedTemplateName *TemplateName::getAsQualifiedTemplateName() const { return dyn_cast_if_present(Storage); } +QualifiedTemplateName * +TemplateName::getAsAdjustedQualifiedTemplateName() const { + for (std::optional Cur = *this; Cur; + Cur = Cur->desugar(/*IgnoreDeduced=*/true)) + if (QualifiedTemplateName *N = Cur->getAsQualifiedTemplateName()) + return N; + return nullptr; +} + DependentTemplateName *TemplateName::getAsDependentTemplateName() const { return Storage.dyn_cast(); } +NestedNameSpecifier TemplateName::getQualifier() const { + for (std::optional Cur = *this; Cur; + Cur = Cur->desugar(/*IgnoreDeduced=*/true)) { + if (DependentTemplateName *N = Cur->getAsDependentTemplateName()) + return N->getQualifier(); + if (QualifiedTemplateName *N = Cur->getAsQualifiedTemplateName()) + return N->getQualifier(); + } + return std::nullopt; +} + UsingShadowDecl *TemplateName::getAsUsingShadowDecl() const { if (Decl *D = Storage.dyn_cast()) if (UsingShadowDecl *USD = dyn_cast(D)) @@ -303,24 +323,21 @@ UsingShadowDecl *TemplateName::getAsUsingShadowDecl() const { } DependentTemplateStorage::DependentTemplateStorage( - NestedNameSpecifier *Qualifier, IdentifierOrOverloadedOperator Name, + NestedNameSpecifier Qualifier, IdentifierOrOverloadedOperator Name, bool HasTemplateKeyword) : Qualifier(Qualifier, HasTemplateKeyword), Name(Name) { - assert((!Qualifier || Qualifier->isDependent()) && + assert((!Qualifier || Qualifier.isDependent()) && "Qualifier must be dependent"); } TemplateNameDependence DependentTemplateStorage::getDependence() const { - auto D = TemplateNameDependence::DependentInstantiation; - if (NestedNameSpecifier *Qualifier = getQualifier()) - D |= toTemplateNameDependence(Qualifier->getDependence()); - return D; + return toTemplateNameDependence(getQualifier().getDependence()) | + TemplateNameDependence::DependentInstantiation; } void DependentTemplateStorage::print(raw_ostream &OS, const PrintingPolicy &Policy) const { - if (NestedNameSpecifier *NNS = getQualifier()) - NNS->print(OS, Policy); + getQualifier().print(OS, Policy); if (hasTemplateKeyword()) OS << "template "; @@ -363,16 +380,13 @@ TemplateNameDependence TemplateName::getDependence() const { case NameKind::QualifiedTemplate: { QualifiedTemplateName *S = getAsQualifiedTemplateName(); TemplateNameDependence D = S->getUnderlyingTemplate().getDependence(); - if (NestedNameSpecifier *NNS = S->getQualifier()) - D |= toTemplateNameDependence(NNS->getDependence()); + D |= toTemplateNameDependence(S->getQualifier().getDependence()); return D; } case NameKind::DependentTemplate: { DependentTemplateName *S = getAsDependentTemplateName(); - auto D = TemplateNameDependence::DependentInstantiation; - if (NestedNameSpecifier *Qualifier = S->getQualifier()) - D |= toTemplateNameDependence(Qualifier->getDependence()); - return D; + return toTemplateNameDependence(S->getQualifier().getDependence()) | + TemplateNameDependence::DependentInstantiation; } case NameKind::SubstTemplateTemplateParm: { auto *S = getAsSubstTemplateTemplateParm(); @@ -434,7 +448,7 @@ void TemplateName::print(raw_ostream &OS, const PrintingPolicy &Policy, Template = cast(Template->getCanonicalDecl()); if (handleAnonymousTTP(Template, OS)) return; - if (Qual == Qualified::None) + if (Qual == Qualified::None || Policy.SuppressScope) OS << *Template; else Template->printQualifiedName(OS, Policy); @@ -443,9 +457,8 @@ void TemplateName::print(raw_ostream &OS, const PrintingPolicy &Policy, QTN->getUnderlyingTemplate().print(OS, Policy, Qual); return; } - if (NestedNameSpecifier *NNS = QTN->getQualifier(); - Qual != Qualified::None && NNS) - NNS->print(OS, Policy); + if (Qual != Qualified::None) + QTN->getQualifier().print(OS, Policy); if (QTN->hasTemplateKeyword()) OS << "template "; diff --git a/clang/lib/AST/TextNodeDumper.cpp b/clang/lib/AST/TextNodeDumper.cpp index 9d7c2757d6ee4..bd4f3cacc481d 100644 --- a/clang/lib/AST/TextNodeDumper.cpp +++ b/clang/lib/AST/TextNodeDumper.cpp @@ -1034,39 +1034,34 @@ void clang::TextNodeDumper::dumpTemplateSpecializationKind( } } -void clang::TextNodeDumper::dumpNestedNameSpecifier(const NestedNameSpecifier *NNS) { +void clang::TextNodeDumper::dumpNestedNameSpecifier(NestedNameSpecifier NNS) { if (!NNS) return; AddChild([=] { OS << "NestedNameSpecifier"; - switch (NNS->getKind()) { - case NestedNameSpecifier::Identifier: - OS << " Identifier"; - OS << " '" << NNS->getAsIdentifier()->getName() << "'"; - break; - case NestedNameSpecifier::Namespace: + switch (NNS.getKind()) { + case NestedNameSpecifier::Kind::Namespace: { + auto [Namespace, Prefix] = NNS.getAsNamespaceAndPrefix(); OS << " "; // "Namespace" is printed as the decl kind. - dumpBareDeclRef(NNS->getAsNamespace()); - break; - case NestedNameSpecifier::NamespaceAlias: - OS << " "; // "NamespaceAlias" is printed as the decl kind. - dumpBareDeclRef(NNS->getAsNamespaceAlias()); + dumpBareDeclRef(Namespace); + dumpNestedNameSpecifier(Prefix); break; - case NestedNameSpecifier::TypeSpec: + } + case NestedNameSpecifier::Kind::Type: OS << " TypeSpec"; - dumpType(QualType(NNS->getAsType(), 0)); + dumpType(QualType(NNS.getAsType(), 0)); break; - case NestedNameSpecifier::Global: + case NestedNameSpecifier::Kind::Global: OS << " Global"; break; - case NestedNameSpecifier::Super: + case NestedNameSpecifier::Kind::Super: OS << " Super"; break; + case NestedNameSpecifier::Kind::Null: + llvm_unreachable("unexpected null nested name specifier"); } - - dumpNestedNameSpecifier(NNS->getPrefix()); }); } @@ -1402,8 +1397,8 @@ static void dumpBasePath(raw_ostream &OS, const CastExpr *Node) { if (!First) OS << " -> "; - const auto *RD = - cast(Base->getType()->castAs()->getDecl()); + const auto *RD = cast( + Base->getType()->castAs()->getOriginalDecl()); if (Base->isVirtual()) OS << "virtual "; @@ -2113,19 +2108,32 @@ void TextNodeDumper::VisitFunctionProtoType(const FunctionProtoType *T) { } void TextNodeDumper::VisitUnresolvedUsingType(const UnresolvedUsingType *T) { + if (ElaboratedTypeKeyword K = T->getKeyword(); + K != ElaboratedTypeKeyword::None) + OS << ' ' << TypeWithKeyword::getKeywordName(K); + dumpNestedNameSpecifier(T->getQualifier()); dumpDeclRef(T->getDecl()); } void TextNodeDumper::VisitUsingType(const UsingType *T) { - dumpDeclRef(T->getFoundDecl()); - if (!T->typeMatchesDecl()) - OS << " divergent"; + if (ElaboratedTypeKeyword K = T->getKeyword(); + K != ElaboratedTypeKeyword::None) + OS << ' ' << TypeWithKeyword::getKeywordName(K); + dumpNestedNameSpecifier(T->getQualifier()); + dumpDeclRef(T->getDecl()); + dumpType(T->desugar()); } void TextNodeDumper::VisitTypedefType(const TypedefType *T) { + if (ElaboratedTypeKeyword K = T->getKeyword(); + K != ElaboratedTypeKeyword::None) + OS << ' ' << TypeWithKeyword::getKeywordName(K); + dumpNestedNameSpecifier(T->getQualifier()); dumpDeclRef(T->getDecl()); - if (!T->typeMatchesDecl()) + if (!T->typeMatchesDecl()) { OS << " divergent"; + dumpType(T->desugar()); + } } void TextNodeDumper::VisitUnaryTransformType(const UnaryTransformType *T) { @@ -2139,7 +2147,17 @@ void TextNodeDumper::VisitUnaryTransformType(const UnaryTransformType *T) { } void TextNodeDumper::VisitTagType(const TagType *T) { - dumpDeclRef(T->getDecl()); + if (T->isCanonicalUnqualified()) + OS << " canonical"; + if (T->isTagOwned()) + OS << " owns_tag"; + if (T->isInjected()) + OS << " injected"; + if (ElaboratedTypeKeyword K = T->getKeyword(); + K != ElaboratedTypeKeyword::None) + OS << ' ' << TypeWithKeyword::getKeywordName(K); + dumpNestedNameSpecifier(T->getQualifier()); + dumpDeclRef(T->getOriginalDecl()); } void TextNodeDumper::VisitTemplateTypeParmType(const TemplateTypeParmType *T) { @@ -2183,12 +2201,15 @@ void TextNodeDumper::VisitTemplateSpecializationType( const TemplateSpecializationType *T) { if (T->isTypeAlias()) OS << " alias"; + if (ElaboratedTypeKeyword K = T->getKeyword(); + K != ElaboratedTypeKeyword::None) + OS << ' ' << TypeWithKeyword::getKeywordName(K); dumpTemplateName(T->getTemplateName(), "name"); } void TextNodeDumper::VisitInjectedClassNameType( const InjectedClassNameType *T) { - dumpDeclRef(T->getDecl()); + dumpDeclRef(T->getOriginalDecl()); } void TextNodeDumper::VisitObjCInterfaceType(const ObjCInterfaceType *T) { @@ -2779,8 +2800,7 @@ void TextNodeDumper::VisitTemplateTemplateParmDecl( void TextNodeDumper::VisitUsingDecl(const UsingDecl *D) { OS << ' '; - if (D->getQualifier()) - D->getQualifier()->print(OS, D->getASTContext().getPrintingPolicy()); + D->getQualifier().print(OS, D->getASTContext().getPrintingPolicy()); OS << D->getDeclName(); dumpNestedNameSpecifier(D->getQualifier()); } @@ -2793,16 +2813,14 @@ void TextNodeDumper::VisitUsingEnumDecl(const UsingEnumDecl *D) { void TextNodeDumper::VisitUnresolvedUsingTypenameDecl( const UnresolvedUsingTypenameDecl *D) { OS << ' '; - if (D->getQualifier()) - D->getQualifier()->print(OS, D->getASTContext().getPrintingPolicy()); + D->getQualifier().print(OS, D->getASTContext().getPrintingPolicy()); OS << D->getDeclName(); } void TextNodeDumper::VisitUnresolvedUsingValueDecl( const UnresolvedUsingValueDecl *D) { OS << ' '; - if (D->getQualifier()) - D->getQualifier()->print(OS, D->getASTContext().getPrintingPolicy()); + D->getQualifier().print(OS, D->getASTContext().getPrintingPolicy()); OS << D->getDeclName(); dumpType(D->getType()); } diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp index e5a1ab2ff8906..1ad42c2a3836e 100644 --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -109,12 +109,14 @@ bool Qualifiers::isTargetAddressSpaceSupersetOf(LangAS A, LangAS B, const IdentifierInfo *QualType::getBaseTypeIdentifier() const { const Type *ty = getTypePtr(); NamedDecl *ND = nullptr; + if (const auto *DNT = ty->getAs()) + return DNT->getIdentifier(); if (ty->isPointerOrReferenceType()) return ty->getPointeeType().getBaseTypeIdentifier(); - else if (ty->isRecordType()) - ND = ty->castAs()->getDecl(); + if (ty->isRecordType()) + ND = ty->castAs()->getOriginalDecl(); else if (ty->isEnumeralType()) - ND = ty->castAs()->getDecl(); + ND = ty->castAs()->getOriginalDecl(); else if (ty->getTypeClass() == Type::Typedef) ND = ty->castAs()->getDecl(); else if (ty->isArrayType()) @@ -671,13 +673,13 @@ const Type *Type::getUnqualifiedDesugaredType() const { bool Type::isClassType() const { if (const auto *RT = getAs()) - return RT->getDecl()->isClass(); + return RT->getOriginalDecl()->isClass(); return false; } bool Type::isStructureType() const { if (const auto *RT = getAs()) - return RT->getDecl()->isStruct(); + return RT->getOriginalDecl()->isStruct(); return false; } @@ -685,7 +687,7 @@ bool Type::isStructureTypeWithFlexibleArrayMember() const { const auto *RT = getAs(); if (!RT) return false; - const auto *Decl = RT->getDecl(); + const auto *Decl = RT->getOriginalDecl()->getDefinitionOrSelf(); if (!Decl->isStruct()) return false; return Decl->hasFlexibleArrayMember(); @@ -693,19 +695,21 @@ bool Type::isStructureTypeWithFlexibleArrayMember() const { bool Type::isObjCBoxableRecordType() const { if (const auto *RT = getAs()) - return RT->getDecl()->hasAttr(); + return RT->getOriginalDecl() + ->getDefinitionOrSelf() + ->hasAttr(); return false; } bool Type::isInterfaceType() const { if (const auto *RT = getAs()) - return RT->getDecl()->isInterface(); + return RT->getOriginalDecl()->isInterface(); return false; } bool Type::isStructureOrClassType() const { if (const auto *RT = getAs()) { - RecordDecl *RD = RT->getDecl(); + RecordDecl *RD = RT->getOriginalDecl(); return RD->isStruct() || RD->isClass() || RD->isInterface(); } return false; @@ -719,7 +723,7 @@ bool Type::isVoidPointerType() const { bool Type::isUnionType() const { if (const auto *RT = getAs()) - return RT->getDecl()->isUnion(); + return RT->getOriginalDecl()->isUnion(); return false; } @@ -736,7 +740,7 @@ bool Type::isComplexIntegerType() const { bool Type::isScopedEnumeralType() const { if (const auto *ET = getAs()) - return ET->getDecl()->isScoped(); + return ET->getOriginalDecl()->isScoped(); return false; } @@ -770,13 +774,13 @@ QualType Type::getPointeeType() const { const RecordType *Type::getAsStructureType() const { // If this is directly a structure type, return it. if (const auto *RT = dyn_cast(this)) { - if (RT->getDecl()->isStruct()) + if (RT->getOriginalDecl()->isStruct()) return RT; } // If the canonical form of this type isn't the right kind, reject it. if (const auto *RT = dyn_cast(CanonicalType)) { - if (!RT->getDecl()->isStruct()) + if (!RT->getOriginalDecl()->isStruct()) return nullptr; // If this is a typedef for a structure type, strip the typedef off without @@ -789,13 +793,13 @@ const RecordType *Type::getAsStructureType() const { const RecordType *Type::getAsUnionType() const { // If this is directly a union type, return it. if (const auto *RT = dyn_cast(this)) { - if (RT->getDecl()->isUnion()) + if (RT->getOriginalDecl()->isUnion()) return RT; } // If the canonical form of this type isn't the right kind, reject it. if (const auto *RT = dyn_cast(CanonicalType)) { - if (!RT->getDecl()->isUnion()) + if (!RT->getOriginalDecl()->isUnion()) return nullptr; // If this is a typedef for a union type, strip the typedef off without @@ -1272,9 +1276,6 @@ struct SimpleTransformVisitor : public TypeVisitor { TRIVIAL_TYPE_CLASS(Record) TRIVIAL_TYPE_CLASS(Enum) - // FIXME: Non-trivial to implement, but important for C++ - SUGARED_TYPE_CLASS(Elaborated) - QualType VisitAttributedType(const AttributedType *T) { QualType modifiedType = recurse(T->getModifiedType()); if (modifiedType.isNull()) @@ -1921,25 +1922,32 @@ const CXXRecordDecl *Type::getPointeeCXXRecordDecl() const { return nullptr; if (const auto *RT = PointeeType->getAs()) - return dyn_cast(RT->getDecl()); + return dyn_cast( + RT->getOriginalDecl()->getDefinitionOrSelf()); return nullptr; } CXXRecordDecl *Type::getAsCXXRecordDecl() const { - return dyn_cast_or_null(getAsTagDecl()); + const auto *TT = dyn_cast(CanonicalType); + if (!isa_and_present(TT)) + return nullptr; + auto *TD = TT->getOriginalDecl(); + if (!isa(TT) && !isa(TD)) + return nullptr; + return cast(TD)->getDefinitionOrSelf(); } RecordDecl *Type::getAsRecordDecl() const { - return dyn_cast_or_null(getAsTagDecl()); + const auto *TT = dyn_cast(CanonicalType); + if (!isa_and_present(TT)) + return nullptr; + return cast(TT->getOriginalDecl())->getDefinitionOrSelf(); } TagDecl *Type::getAsTagDecl() const { - if (const auto *TT = getAs()) - return TT->getDecl(); - if (const auto *Injected = getAs()) - return Injected->getDecl(); - + if (const auto *TT = dyn_cast(CanonicalType)) + return TT->getOriginalDecl()->getDefinitionOrSelf(); return nullptr; } @@ -1951,6 +1959,35 @@ Type::getAsNonAliasTemplateSpecializationType() const { return TST; } +NestedNameSpecifier Type::getPrefix() const { + switch (getTypeClass()) { + case Type::DependentName: + return cast(this)->getQualifier(); + case Type::TemplateSpecialization: { + QualifiedTemplateName *S = cast(this) + ->getTemplateName() + .getAsAdjustedQualifiedTemplateName(); + return S ? S->getQualifier() : std::nullopt; + } + case Type::DependentTemplateSpecialization: + return cast(this) + ->getDependentTemplateName() + .getQualifier(); + case Type::Enum: + case Type::Record: + case Type::InjectedClassName: + return cast(this)->getQualifier(); + case Type::Typedef: + return cast(this)->getQualifier(); + case Type::UnresolvedUsing: + return cast(this)->getQualifier(); + case Type::Using: + return cast(this)->getQualifier(); + default: + return std::nullopt; + } +} + bool Type::hasAttr(attr::Kind AK) const { const Type *Cur = this; while (const auto *AT = Cur->getAs()) { @@ -1989,10 +2026,6 @@ class GetContainedDeducedTypeVisitor return Visit(T->getReplacementType()); } - Type *VisitElaboratedType(const ElaboratedType *T) { - return Visit(T->getNamedType()); - } - Type *VisitPointerType(const PointerType *T) { return Visit(T->getPointeeType()); } @@ -2114,7 +2147,7 @@ bool Type::isIntegralType(const ASTContext &Ctx) const { // Complete enum types are integral in C. if (!Ctx.getLangOpts().CPlusPlus) if (const auto *ET = dyn_cast(CanonicalType)) - return ET->getDecl()->isComplete(); + return IsEnumDeclComplete(ET->getOriginalDecl()); return isBitIntType(); } @@ -2131,7 +2164,7 @@ bool Type::isIntegralOrUnscopedEnumerationType() const { bool Type::isUnscopedEnumerationType() const { if (const auto *ET = dyn_cast(CanonicalType)) - return !ET->getDecl()->isScoped(); + return !ET->getOriginalDecl()->isScoped(); return false; } @@ -2216,8 +2249,10 @@ bool Type::isSignedIntegerType() const { if (const EnumType *ET = dyn_cast(CanonicalType)) { // Incomplete enum types are not treated as integer types. // FIXME: In C++, enum types are never integer types. - if (ET->getDecl()->isComplete() && !ET->getDecl()->isScoped()) - return ET->getDecl()->getIntegerType()->isSignedIntegerType(); + const auto *ED = ET->getOriginalDecl()->getDefinitionOrSelf(); + if (!ED->isComplete() || ED->isScoped()) + return false; + return ED->getIntegerType()->isSignedIntegerType(); } if (const auto *IT = dyn_cast(CanonicalType)) @@ -2232,9 +2267,12 @@ bool Type::isSignedIntegerOrEnumerationType() const { if (const auto *BT = dyn_cast(CanonicalType)) return BT->isSignedInteger(); - if (const auto *ET = dyn_cast(CanonicalType); - ET && ET->getDecl()->isComplete()) - return ET->getDecl()->getIntegerType()->isSignedIntegerType(); + if (const auto *ET = dyn_cast(CanonicalType)) { + const auto *ED = ET->getOriginalDecl()->getDefinitionOrSelf(); + if (!ED->isComplete()) + return false; + return ED->getIntegerType()->isSignedIntegerType(); + } if (const auto *IT = dyn_cast(CanonicalType)) return IT->isSigned(); @@ -2261,8 +2299,10 @@ bool Type::isUnsignedIntegerType() const { if (const auto *ET = dyn_cast(CanonicalType)) { // Incomplete enum types are not treated as integer types. // FIXME: In C++, enum types are never integer types. - if (ET->getDecl()->isComplete() && !ET->getDecl()->isScoped()) - return ET->getDecl()->getIntegerType()->isUnsignedIntegerType(); + const auto *ED = ET->getOriginalDecl()->getDefinitionOrSelf(); + if (!ED->isComplete() || ED->isScoped()) + return false; + return ED->getIntegerType()->isUnsignedIntegerType(); } if (const auto *IT = dyn_cast(CanonicalType)) @@ -2277,9 +2317,12 @@ bool Type::isUnsignedIntegerOrEnumerationType() const { if (const auto *BT = dyn_cast(CanonicalType)) return BT->isUnsignedInteger(); - if (const auto *ET = dyn_cast(CanonicalType); - ET && ET->getDecl()->isComplete()) - return ET->getDecl()->getIntegerType()->isUnsignedIntegerType(); + if (const auto *ET = dyn_cast(CanonicalType)) { + const auto *ED = ET->getOriginalDecl()->getDefinitionOrSelf(); + if (!ED->isComplete()) + return false; + return ED->getIntegerType()->isUnsignedIntegerType(); + } if (const auto *IT = dyn_cast(CanonicalType)) return IT->isUnsigned(); @@ -2328,8 +2371,10 @@ bool Type::isRealType() const { if (const auto *BT = dyn_cast(CanonicalType)) return BT->getKind() >= BuiltinType::Bool && BT->getKind() <= BuiltinType::Ibm128; - if (const auto *ET = dyn_cast(CanonicalType)) - return ET->getDecl()->isComplete() && !ET->getDecl()->isScoped(); + if (const auto *ET = dyn_cast(CanonicalType)) { + const auto *ED = ET->getOriginalDecl(); + return !ED->isScoped() && ED->getDefinitionOrSelf()->isComplete(); + } return isBitIntType(); } @@ -2337,14 +2382,16 @@ bool Type::isArithmeticType() const { if (const auto *BT = dyn_cast(CanonicalType)) return BT->getKind() >= BuiltinType::Bool && BT->getKind() <= BuiltinType::Ibm128; - if (const auto *ET = dyn_cast(CanonicalType)) + if (const auto *ET = dyn_cast(CanonicalType)) { // GCC allows forward declaration of enum types (forbid by C99 6.7.2.3p2). // If a body isn't seen by the time we get here, return false. // // C++0x: Enumerations are not arithmetic types. For now, just return // false for scoped enumerations since that will disable any // unwanted implicit conversions. - return !ET->getDecl()->isScoped() && ET->getDecl()->isComplete(); + const auto *ED = ET->getOriginalDecl(); + return !ED->isScoped() && ED->getDefinitionOrSelf()->isComplete(); + } return isa(CanonicalType) || isBitIntType(); } @@ -2352,8 +2399,8 @@ bool Type::hasBooleanRepresentation() const { if (const auto *VT = dyn_cast(CanonicalType)) return VT->getElementType()->isBooleanType(); if (const auto *ET = dyn_cast(CanonicalType)) { - return ET->getDecl()->isComplete() && - ET->getDecl()->getIntegerType()->isBooleanType(); + const auto *ED = ET->getOriginalDecl()->getDefinitionOrSelf(); + return ED->isComplete() && ED->getIntegerType()->isBooleanType(); } if (const auto *IT = dyn_cast(CanonicalType)) return IT->getNumBits() == 1; @@ -2385,7 +2432,10 @@ Type::ScalarTypeKind Type::getScalarTypeKind() const { } else if (isa(T)) { return STK_MemberPointer; } else if (isa(T)) { - assert(cast(T)->getDecl()->isComplete()); + assert(cast(T) + ->getOriginalDecl() + ->getDefinitionOrSelf() + ->isComplete()); return STK_Integral; } else if (const auto *CT = dyn_cast(T)) { if (CT->getElementType()->isRealFloatingType()) @@ -2409,7 +2459,8 @@ Type::ScalarTypeKind Type::getScalarTypeKind() const { /// includes union types. bool Type::isAggregateType() const { if (const auto *Record = dyn_cast(CanonicalType)) { - if (const auto *ClassDecl = dyn_cast(Record->getDecl())) + if (const auto *ClassDecl = dyn_cast( + Record->getOriginalDecl()->getDefinitionOrSelf())) return ClassDecl->isAggregate(); return true; @@ -2443,7 +2494,8 @@ bool Type::isIncompleteType(NamedDecl **Def) const { // be completed. return isVoidType(); case Enum: { - EnumDecl *EnumD = cast(CanonicalType)->getDecl(); + EnumDecl *EnumD = + cast(CanonicalType)->getOriginalDecl()->getDefinitionOrSelf(); if (Def) *Def = EnumD; return !EnumD->isComplete(); @@ -2451,13 +2503,17 @@ bool Type::isIncompleteType(NamedDecl **Def) const { case Record: { // A tagged type (struct/union/enum/class) is incomplete if the decl is a // forward declaration, but not a full definition (C99 6.2.5p22). - RecordDecl *Rec = cast(CanonicalType)->getDecl(); + RecordDecl *Rec = cast(CanonicalType) + ->getOriginalDecl() + ->getDefinitionOrSelf(); if (Def) *Def = Rec; return !Rec->isCompleteDefinition(); } case InjectedClassName: { - CXXRecordDecl *Rec = cast(CanonicalType)->getDecl(); + CXXRecordDecl *Rec = cast(CanonicalType) + ->getOriginalDecl() + ->getDefinitionOrSelf(); if (!Rec->isBeingDefined()) return false; if (Def) @@ -2739,9 +2795,9 @@ bool QualType::isCXX98PODType(const ASTContext &Context) const { return true; case Type::Record: - if (const auto *ClassDecl = - dyn_cast(cast(CanonicalType)->getDecl())) - return ClassDecl->isPOD(); + if (const auto *ClassDecl = dyn_cast( + cast(CanonicalType)->getOriginalDecl())) + return ClassDecl->getDefinitionOrSelf()->isPOD(); // C struct/union is POD. return true; @@ -2782,7 +2838,8 @@ bool QualType::isTrivialType(const ASTContext &Context) const { if (CanonicalType->isScalarType() || CanonicalType->isVectorType()) return true; if (const auto *RT = CanonicalType->getAs()) { - if (const auto *ClassDecl = dyn_cast(RT->getDecl())) { + if (const auto *ClassDecl = + dyn_cast(RT->getOriginalDecl())) { // C++20 [class]p6: // A trivial class is a class that is trivially copyable, and // has one or more eligible default constructors such that each is @@ -2841,14 +2898,17 @@ static bool isTriviallyCopyableTypeImpl(const QualType &type, return true; if (const auto *RT = CanonicalType->getAs()) { - if (const auto *ClassDecl = dyn_cast(RT->getDecl())) { + if (const auto *ClassDecl = + dyn_cast(RT->getOriginalDecl())) { if (IsCopyConstructible) { return ClassDecl->isTriviallyCopyConstructible(); } else { return ClassDecl->isTriviallyCopyable(); } } - return !RT->getDecl()->isNonTrivialToPrimitiveCopy(); + return !RT->getOriginalDecl() + ->getDefinitionOrSelf() + ->isNonTrivialToPrimitiveCopy(); } // No other types can match. return false; @@ -2938,7 +2998,9 @@ QualType::PrimitiveDefaultInitializeKind QualType::isNonTrivialToPrimitiveDefaultInitialize() const { if (const auto *RT = getTypePtr()->getBaseElementTypeUnsafe()->getAs()) - if (RT->getDecl()->isNonTrivialToPrimitiveDefaultInitialize()) + if (RT->getOriginalDecl() + ->getDefinitionOrSelf() + ->isNonTrivialToPrimitiveDefaultInitialize()) return PDIK_Struct; switch (getQualifiers().getObjCLifetime()) { @@ -2954,7 +3016,9 @@ QualType::isNonTrivialToPrimitiveDefaultInitialize() const { QualType::PrimitiveCopyKind QualType::isNonTrivialToPrimitiveCopy() const { if (const auto *RT = getTypePtr()->getBaseElementTypeUnsafe()->getAs()) - if (RT->getDecl()->isNonTrivialToPrimitiveCopy()) + if (RT->getOriginalDecl() + ->getDefinitionOrSelf() + ->isNonTrivialToPrimitiveCopy()) return PCK_Struct; Qualifiers Qs = getQualifiers(); @@ -3022,8 +3086,8 @@ bool Type::isLiteralType(const ASTContext &Ctx) const { // -- all non-static data members and base classes of literal types // // We resolve DR1361 by ignoring the second bullet. - if (const auto *ClassDecl = dyn_cast(RT->getDecl())) - return ClassDecl->isLiteral(); + if (const auto *ClassDecl = dyn_cast(RT->getOriginalDecl())) + return ClassDecl->getDefinitionOrSelf()->isLiteral(); return true; } @@ -3076,8 +3140,8 @@ bool Type::isStandardLayoutType() const { if (BaseTy->isScalarType() || BaseTy->isVectorType()) return true; if (const auto *RT = BaseTy->getAs()) { - if (const auto *ClassDecl = dyn_cast(RT->getDecl())) - if (!ClassDecl->isStandardLayout()) + if (const auto *ClassDecl = dyn_cast(RT->getOriginalDecl())) + if (!ClassDecl->getDefinitionOrSelf()->isStandardLayout()) return false; // Default to 'true' for non-C++ class types. @@ -3119,7 +3183,9 @@ bool QualType::isCXX11PODType(const ASTContext &Context) const { if (BaseTy->isScalarType() || BaseTy->isVectorType()) return true; if (const auto *RT = BaseTy->getAs()) { - if (const auto *ClassDecl = dyn_cast(RT->getDecl())) { + if (const auto *ClassDecl = + dyn_cast(RT->getOriginalDecl())) { + ClassDecl = ClassDecl->getDefinitionOrSelf(); // C++11 [class]p10: // A POD struct is a non-union class that is both a trivial class [...] if (!ClassDecl->isTrivial()) @@ -3159,8 +3225,9 @@ bool Type::isNothrowT() const { bool Type::isAlignValT() const { if (const auto *ET = getAs()) { - IdentifierInfo *II = ET->getDecl()->getIdentifier(); - if (II && II->isStr("align_val_t") && ET->getDecl()->isInStdNamespace()) + const auto *ED = ET->getOriginalDecl(); + IdentifierInfo *II = ED->getIdentifier(); + if (II && II->isStr("align_val_t") && ED->isInStdNamespace()) return true; } return false; @@ -3168,8 +3235,9 @@ bool Type::isAlignValT() const { bool Type::isStdByteType() const { if (const auto *ET = getAs()) { - IdentifierInfo *II = ET->getDecl()->getIdentifier(); - if (II && II->isStr("byte") && ET->getDecl()->isInStdNamespace()) + const auto *ED = ET->getOriginalDecl(); + IdentifierInfo *II = ED->getIdentifier(); + if (II && II->isStr("byte") && ED->isInStdNamespace()) return true; } return false; @@ -3188,7 +3256,6 @@ bool Type::isSpecifierType() const { case TemplateTypeParm: case SubstTemplateTypeParm: case TemplateSpecialization: - case Elaborated: case DependentName: case DependentTemplateSpecialization: case ObjCInterface: @@ -3199,8 +3266,7 @@ bool Type::isSpecifierType() const { } } -ElaboratedTypeKeyword -TypeWithKeyword::getKeywordForTypeSpec(unsigned TypeSpec) { +ElaboratedTypeKeyword KeywordHelpers::getKeywordForTypeSpec(unsigned TypeSpec) { switch (TypeSpec) { default: return ElaboratedTypeKeyword::None; @@ -3219,7 +3285,7 @@ TypeWithKeyword::getKeywordForTypeSpec(unsigned TypeSpec) { } } -TagTypeKind TypeWithKeyword::getTagTypeKindForTypeSpec(unsigned TypeSpec) { +TagTypeKind KeywordHelpers::getTagTypeKindForTypeSpec(unsigned TypeSpec) { switch (TypeSpec) { case TST_class: return TagTypeKind::Class; @@ -3237,7 +3303,7 @@ TagTypeKind TypeWithKeyword::getTagTypeKindForTypeSpec(unsigned TypeSpec) { } ElaboratedTypeKeyword -TypeWithKeyword::getKeywordForTagTypeKind(TagTypeKind Kind) { +KeywordHelpers::getKeywordForTagTypeKind(TagTypeKind Kind) { switch (Kind) { case TagTypeKind::Class: return ElaboratedTypeKeyword::Class; @@ -3254,7 +3320,7 @@ TypeWithKeyword::getKeywordForTagTypeKind(TagTypeKind Kind) { } TagTypeKind -TypeWithKeyword::getTagTypeKindForKeyword(ElaboratedTypeKeyword Keyword) { +KeywordHelpers::getTagTypeKindForKeyword(ElaboratedTypeKeyword Keyword) { switch (Keyword) { case ElaboratedTypeKeyword::Class: return TagTypeKind::Class; @@ -3273,7 +3339,7 @@ TypeWithKeyword::getTagTypeKindForKeyword(ElaboratedTypeKeyword Keyword) { llvm_unreachable("Unknown elaborated type keyword."); } -bool TypeWithKeyword::KeywordIsTagTypeKind(ElaboratedTypeKeyword Keyword) { +bool KeywordHelpers::KeywordIsTagTypeKind(ElaboratedTypeKeyword Keyword) { switch (Keyword) { case ElaboratedTypeKeyword::None: case ElaboratedTypeKeyword::Typename: @@ -3288,7 +3354,7 @@ bool TypeWithKeyword::KeywordIsTagTypeKind(ElaboratedTypeKeyword Keyword) { llvm_unreachable("Unknown elaborated type keyword."); } -StringRef TypeWithKeyword::getKeywordName(ElaboratedTypeKeyword Keyword) { +StringRef KeywordHelpers::getKeywordName(ElaboratedTypeKeyword Keyword) { switch (Keyword) { case ElaboratedTypeKeyword::None: return {}; @@ -3338,13 +3404,21 @@ void DependentTemplateSpecializationType::Profile( bool Type::isElaboratedTypeSpecifier() const { ElaboratedTypeKeyword Keyword; - if (const auto *Elab = dyn_cast(this)) - Keyword = Elab->getKeyword(); + if (const auto *TST = dyn_cast(this)) + Keyword = TST->getKeyword(); else if (const auto *DepName = dyn_cast(this)) Keyword = DepName->getKeyword(); else if (const auto *DepTST = dyn_cast(this)) Keyword = DepTST->getKeyword(); + else if (const auto *T = dyn_cast(this)) + Keyword = T->getKeyword(); + else if (const auto *T = dyn_cast(this)) + Keyword = T->getKeyword(); + else if (const auto *T = dyn_cast(this)) + Keyword = T->getKeyword(); + else if (const auto *T = dyn_cast(this)) + Keyword = T->getKeyword(); else return false; @@ -4011,34 +4085,53 @@ StringRef CountAttributedType::getAttributeName(bool WithMacroPrefix) const { #undef ENUMERATE_ATTRS } -TypedefType::TypedefType(TypeClass tc, const TypedefNameDecl *D, - QualType UnderlyingType, bool HasTypeDifferentFromDecl) - : Type(tc, UnderlyingType.getCanonicalType(), - toSemanticDependence(UnderlyingType->getDependence())), +TypedefType::TypedefType(TypeClass TC, ElaboratedTypeKeyword Keyword, + NestedNameSpecifier Qualifier, + const TypedefNameDecl *D, QualType UnderlyingType, + bool HasTypeDifferentFromDecl) + : TypeWithKeyword( + Keyword, TC, UnderlyingType.getCanonicalType(), + toSemanticDependence(UnderlyingType->getDependence()) | + (Qualifier + ? toTypeDependence(Qualifier.getDependence() & + ~NestedNameSpecifierDependence::Dependent) + : TypeDependence{})), Decl(const_cast(D)) { - TypedefBits.hasTypeDifferentFromDecl = HasTypeDifferentFromDecl; - if (!typeMatchesDecl()) - *getTrailingObjects() = UnderlyingType; + if ((TypedefBits.hasQualifier = !!Qualifier)) + *getTrailingObjects() = Qualifier; + if ((TypedefBits.hasTypeDifferentFromDecl = HasTypeDifferentFromDecl)) + *getTrailingObjects() = UnderlyingType; } QualType TypedefType::desugar() const { - return typeMatchesDecl() ? Decl->getUnderlyingType() : *getTrailingObjects(); -} - -UsingType::UsingType(const UsingShadowDecl *Found, QualType Underlying, - QualType Canon) - : Type(Using, Canon, toSemanticDependence(Canon->getDependence())), - Found(const_cast(Found)) { - UsingBits.hasTypeDifferentFromDecl = !Underlying.isNull(); - if (!typeMatchesDecl()) - *getTrailingObjects() = Underlying; -} - -QualType UsingType::getUnderlyingType() const { - return typeMatchesDecl() - ? QualType( - cast(Found->getTargetDecl())->getTypeForDecl(), 0) - : *getTrailingObjects(); + return typeMatchesDecl() ? Decl->getUnderlyingType() + : *getTrailingObjects(); +} + +UnresolvedUsingType::UnresolvedUsingType(ElaboratedTypeKeyword Keyword, + NestedNameSpecifier Qualifier, + const UnresolvedUsingTypenameDecl *D, + const Type *CanonicalType) + : TypeWithKeyword( + Keyword, UnresolvedUsing, QualType(CanonicalType, 0), + TypeDependence::DependentInstantiation | + (Qualifier + ? toTypeDependence(Qualifier.getDependence() & + ~NestedNameSpecifierDependence::Dependent) + : TypeDependence{})), + Decl(const_cast(D)) { + if ((UnresolvedUsingBits.hasQualifier = !!Qualifier)) + *getTrailingObjects() = Qualifier; +} + +UsingType::UsingType(ElaboratedTypeKeyword Keyword, + NestedNameSpecifier Qualifier, const UsingShadowDecl *D, + QualType UnderlyingType) + : TypeWithKeyword(Keyword, Using, UnderlyingType.getCanonicalType(), + toSemanticDependence(UnderlyingType->getDependence())), + D(const_cast(D)), UnderlyingType(UnderlyingType) { + if ((UsingBits.hasQualifier = !!Qualifier)) + *getTrailingObjects() = Qualifier; } QualType MacroQualifiedType::desugar() const { return getUnderlyingType(); } @@ -4212,24 +4305,79 @@ UnaryTransformType::UnaryTransformType(QualType BaseType, : Type(UnaryTransform, CanonicalType, BaseType->getDependence()), BaseType(BaseType), UnderlyingType(UnderlyingType), UKind(UKind) {} -TagType::TagType(TypeClass TC, const TagDecl *D, QualType can) - : Type(TC, can, - D->isDependentType() ? TypeDependence::DependentInstantiation - : TypeDependence::None), - decl(const_cast(D)) {} - -static TagDecl *getInterestingTagDecl(TagDecl *decl) { - for (auto *I : decl->redecls()) { - if (I->isCompleteDefinition() || I->isBeingDefined()) - return I; +TagType::TagType(TypeClass TC, ElaboratedTypeKeyword Keyword, + NestedNameSpecifier Qualifier, const TagDecl *Tag, + bool OwnsTag, bool ISInjected, const Type *CanonicalType) + : TypeWithKeyword( + Keyword, TC, QualType(CanonicalType, 0), + (Tag->isDependentType() ? TypeDependence::DependentInstantiation + : TypeDependence::None) | + (Qualifier + ? toTypeDependence(Qualifier.getDependence() & + ~NestedNameSpecifierDependence::Dependent) + : TypeDependence{})), + decl(const_cast(Tag)) { + if ((TagTypeBits.HasQualifier = !!Qualifier)) + getTrailingQualifier() = Qualifier; + TagTypeBits.OwnsTag = !!OwnsTag; + TagTypeBits.IsInjected = ISInjected; +} + +void *TagType::getTrailingPointer() const { + switch (getTypeClass()) { + case Type::Enum: + return const_cast(cast(this) + 1); + case Type::Record: + return const_cast(cast(this) + 1); + case Type::InjectedClassName: + return const_cast( + cast(this) + 1); + default: + llvm_unreachable("unexpected type class"); } - // If there's no definition (not even in progress), return what we have. - return decl; } -TagDecl *TagType::getDecl() const { return getInterestingTagDecl(decl); } +NestedNameSpecifier &TagType::getTrailingQualifier() const { + assert(TagTypeBits.HasQualifier); + return *reinterpret_cast(llvm::alignAddr( + getTrailingPointer(), llvm::Align::Of())); +} + +NestedNameSpecifier TagType::getQualifier() const { + return TagTypeBits.HasQualifier ? getTrailingQualifier() : std::nullopt; +} -bool TagType::isBeingDefined() const { return getDecl()->isBeingDefined(); } +ClassTemplateDecl *TagType::getTemplateDecl() const { + auto *Decl = dyn_cast(decl); + if (!Decl) + return nullptr; + if (auto *RD = dyn_cast(Decl)) + return RD->getSpecializedTemplate(); + return Decl->getDescribedClassTemplate(); +} + +TemplateName TagType::getTemplateName(const ASTContext &Ctx) const { + auto *TD = getTemplateDecl(); + if (!TD) + return TemplateName(); + if (isCanonicalUnqualified()) + return TemplateName(TD); + return Ctx.getQualifiedTemplateName(getQualifier(), /*TemplateKeyword=*/false, + TemplateName(TD)); +} + +ArrayRef +TagType::getTemplateArgs(const ASTContext &Ctx) const { + auto *Decl = dyn_cast(decl); + if (!Decl) + return {}; + + if (auto *RD = dyn_cast(Decl)) + return RD->getTemplateArgs().asArray(); + if (ClassTemplateDecl *TD = Decl->getDescribedClassTemplate()) + return TD->getTemplateParameters()->getInjectedTemplateArgs(Ctx); + return {}; +} bool RecordType::hasConstFields() const { std::vector RecordTypeList; @@ -4237,8 +4385,10 @@ bool RecordType::hasConstFields() const { unsigned NextToCheckIndex = 0; while (RecordTypeList.size() > NextToCheckIndex) { - for (FieldDecl *FD : - RecordTypeList[NextToCheckIndex]->getDecl()->fields()) { + for (FieldDecl *FD : RecordTypeList[NextToCheckIndex] + ->getOriginalDecl() + ->getDefinitionOrSelf() + ->fields()) { QualType FieldTy = FD->getType(); if (FieldTy.isConstQualified()) return true; @@ -4253,6 +4403,19 @@ bool RecordType::hasConstFields() const { return false; } +InjectedClassNameType::InjectedClassNameType(ElaboratedTypeKeyword Keyword, + NestedNameSpecifier Qualifier, + const TagDecl *TD, bool IsInjected, + CanQualType CanonicalInjectedTST, + const Type *CanonicalType) + : TagType(TypeClass::InjectedClassName, Keyword, Qualifier, TD, + /*OwnsTag=*/false, IsInjected, CanonicalType), + CanonicalInjectedTST(CanonicalInjectedTST) {} + +CanQualType InjectedClassNameType::getCanonicalInjectedTST() const { + return CanQualType::CreateUnsafe(CanonicalInjectedTST); +} + AttributedType::AttributedType(QualType canon, const Attr *attr, QualType modified, QualType equivalent) : AttributedType(canon, attr->getKind(), attr, modified, equivalent) {} @@ -4340,10 +4503,6 @@ bool AttributedType::isCallingConv() const { llvm_unreachable("invalid attr kind"); } -CXXRecordDecl *InjectedClassNameType::getDecl() const { - return cast(getInterestingTagDecl(Decl)); -} - IdentifierInfo *TemplateTypeParmType::getIdentifier() const { return isCanonicalUnqualified() ? nullptr : getDecl()->getIdentifier(); } @@ -4467,16 +4626,17 @@ bool TemplateSpecializationType::anyInstantiationDependentTemplateArguments( } TemplateSpecializationType::TemplateSpecializationType( - TemplateName T, bool IsAlias, ArrayRef Args, - QualType Underlying) - : Type(TemplateSpecialization, - Underlying.isNull() ? QualType(this, 0) - : Underlying.getCanonicalType(), - (Underlying.isNull() - ? TypeDependence::DependentInstantiation - : toSemanticDependence(Underlying->getDependence())) | - (toTypeDependence(T.getDependence()) & - TypeDependence::UnexpandedPack)), + ElaboratedTypeKeyword Keyword, TemplateName T, bool IsAlias, + ArrayRef Args, QualType Underlying) + : TypeWithKeyword( + Keyword, TemplateSpecialization, + Underlying.isNull() ? QualType(this, 0) + : Underlying.getCanonicalType(), + (Underlying.isNull() + ? TypeDependence::DependentInstantiation + : toSemanticDependence(Underlying->getDependence())) | + (toTypeDependence(T.getDependence()) & + TypeDependence::UnexpandedPack)), Template(T) { TemplateSpecializationTypeBits.NumArgs = Args.size(); TemplateSpecializationTypeBits.TypeAlias = IsAlias; @@ -4699,7 +4859,8 @@ static CachedProperties computeCachedProperties(const Type *T) { case Type::Record: case Type::Enum: { - const TagDecl *Tag = cast(T)->getDecl(); + const TagDecl *Tag = + cast(T)->getOriginalDecl()->getDefinitionOrSelf(); // C++ [basic.link]p8: // - it is a class or enumeration type that is named (or has a name @@ -4726,12 +4887,9 @@ static CachedProperties computeCachedProperties(const Type *T) { case Type::MemberPointer: { const auto *MPT = cast(T); CachedProperties Cls = [&] { - if (auto *RD = MPT->getMostRecentCXXRecordDecl()) - return Cache::get(QualType(RD->getTypeForDecl(), 0)); - if (const Type *T = MPT->getQualifier()->getAsType()) - return Cache::get(T); - // Treat as a dependent type. - return CachedProperties(Linkage::External, false); + if (MPT->isSugared()) + MPT = cast(MPT->getCanonicalTypeInternal()); + return Cache::get(MPT->getQualifier().getAsType()); }(); return merge(Cls, Cache::get(MPT->getPointeeType())); } @@ -4811,7 +4969,8 @@ LinkageInfo LinkageComputer::computeTypeLinkageInfo(const Type *T) { case Type::Record: case Type::Enum: - return getDeclLinkageAndVisibility(cast(T)->getDecl()); + return getDeclLinkageAndVisibility( + cast(T)->getOriginalDecl()->getDefinitionOrSelf()); case Type::Complex: return computeTypeLinkageInfo(cast(T)->getElementType()); @@ -4827,8 +4986,8 @@ LinkageInfo LinkageComputer::computeTypeLinkageInfo(const Type *T) { LinkageInfo LV; if (auto *D = MPT->getMostRecentCXXRecordDecl()) { LV.merge(getDeclLinkageAndVisibility(D)); - } else if (auto *Ty = MPT->getQualifier()->getAsType()) { - LV.merge(computeTypeLinkageInfo(Ty)); + } else { + LV.merge(computeTypeLinkageInfo(MPT->getQualifier().getAsType())); } LV.merge(computeTypeLinkageInfo(MPT->getPointeeType())); return LV; @@ -5014,7 +5173,7 @@ bool Type::canHaveNullability(bool ResultIfUnknown) const { llvm_unreachable("unknown builtin type"); case Type::Record: { - const RecordDecl *RD = cast(type)->getDecl(); + const RecordDecl *RD = cast(type)->getOriginalDecl(); // For template specializations, look only at primary template attributes. // This is a consistent regardless of whether the instantiation is known. if (const auto *CTSD = dyn_cast(RD)) @@ -5212,14 +5371,18 @@ bool Type::isCARCBridgableType() const { /// Check if the specified type is the CUDA device builtin surface type. bool Type::isCUDADeviceBuiltinSurfaceType() const { if (const auto *RT = getAs()) - return RT->getDecl()->hasAttr(); + return RT->getOriginalDecl() + ->getMostRecentDecl() + ->hasAttr(); return false; } /// Check if the specified type is the CUDA device builtin texture type. bool Type::isCUDADeviceBuiltinTextureType() const { if (const auto *RT = getAs()) - return RT->getDecl()->hasAttr(); + return RT->getOriginalDecl() + ->getMostRecentDecl() + ->hasAttr(); return false; } @@ -5283,7 +5446,7 @@ QualType::DestructionKind QualType::isDestructedTypeImpl(QualType type) { } if (const auto *RT = type->getBaseElementTypeUnsafe()->getAs()) { - const RecordDecl *RD = RT->getDecl(); + const RecordDecl *RD = RT->getOriginalDecl(); if (const auto *CXXRD = dyn_cast(RD)) { /// Check if this is a C++ object with a non-trivial destructor. if (CXXRD->hasDefinition() && !CXXRD->hasTrivialDestructor()) @@ -5291,7 +5454,7 @@ QualType::DestructionKind QualType::isDestructedTypeImpl(QualType type) { } else { /// Check if this is a C struct that is non-trivial to destroy or an array /// that contains such a struct. - if (RD->isNonTrivialToPrimitiveDestroy()) + if (RD->getDefinitionOrSelf()->isNonTrivialToPrimitiveDestroy()) return DK_nontrivial_c_struct; } } @@ -5301,16 +5464,16 @@ QualType::DestructionKind QualType::isDestructedTypeImpl(QualType type) { bool MemberPointerType::isSugared() const { CXXRecordDecl *D1 = getMostRecentCXXRecordDecl(), - *D2 = getQualifier()->getAsRecordDecl(); + *D2 = getQualifier().getAsRecordDecl(); assert(!D1 == !D2); return D1 != D2 && D1->getCanonicalDecl() != D2->getCanonicalDecl(); } void MemberPointerType::Profile(llvm::FoldingSetNodeID &ID, QualType Pointee, - const NestedNameSpecifier *Qualifier, + const NestedNameSpecifier Qualifier, const CXXRecordDecl *Cls) { ID.AddPointer(Pointee.getAsOpaquePtr()); - ID.AddPointer(Qualifier); + Qualifier.Profile(ID); if (Cls) ID.AddPointer(Cls->getCanonicalDecl()); } @@ -5318,14 +5481,14 @@ void MemberPointerType::Profile(llvm::FoldingSetNodeID &ID, QualType Pointee, CXXRecordDecl *MemberPointerType::getCXXRecordDecl() const { return dyn_cast(getCanonicalTypeInternal()) ->getQualifier() - ->getAsRecordDecl(); + .getAsRecordDecl(); } CXXRecordDecl *MemberPointerType::getMostRecentCXXRecordDecl() const { auto *RD = getCXXRecordDecl(); if (!RD) return nullptr; - return RD->getMostRecentNonInjectedDecl(); + return RD->getMostRecentDecl(); } void clang::FixedPointValueToString(SmallVectorImpl &Str, diff --git a/clang/lib/AST/TypeLoc.cpp b/clang/lib/AST/TypeLoc.cpp index 5c45c596538f8..83099a74aa7b5 100644 --- a/clang/lib/AST/TypeLoc.cpp +++ b/clang/lib/AST/TypeLoc.cpp @@ -195,15 +195,6 @@ SourceLocation TypeLoc::getBeginLoc() const { TypeLoc LeftMost = Cur; while (true) { switch (Cur.getTypeLocClass()) { - case Elaborated: - if (Cur.getLocalSourceRange().getBegin().isValid()) { - LeftMost = Cur; - break; - } - Cur = Cur.getNextTypeLoc(); - if (Cur.isNull()) - break; - continue; case FunctionProto: if (Cur.castAs().getTypePtr() ->hasTrailingReturn()) { @@ -275,7 +266,6 @@ SourceLocation TypeLoc::getEndLoc() const { Last = Cur; break; case Qualified: - case Elaborated: break; } Cur = Cur.getNextTypeLoc(); @@ -313,9 +303,8 @@ bool TypeSpecTypeLoc::isKind(const TypeLoc &TL) { } bool TagTypeLoc::isDefinition() const { - TagDecl *D = getDecl(); - return D->isCompleteDefinition() && - (D->getIdentifier() == nullptr || D->getLocation() == getNameLoc()); + return getTypePtr()->isTagOwned() && + getOriginalDecl()->isCompleteDefinition(); } // Reimplemented to account for GNU/C++ extension @@ -482,6 +471,134 @@ TypeLoc TypeLoc::findExplicitQualifierLoc() const { return {}; } +NestedNameSpecifierLoc TypeLoc::getPrefix() const { + switch (getTypeLocClass()) { + case TypeLoc::DependentName: + return castAs().getQualifierLoc(); + case TypeLoc::TemplateSpecialization: + return castAs().getQualifierLoc(); + case TypeLoc::DependentTemplateSpecialization: + return castAs().getQualifierLoc(); + case TypeLoc::DeducedTemplateSpecialization: + return castAs().getQualifierLoc(); + case TypeLoc::Enum: + case TypeLoc::Record: + case TypeLoc::InjectedClassName: + return castAs().getQualifierLoc(); + case TypeLoc::Typedef: + return castAs().getQualifierLoc(); + case TypeLoc::UnresolvedUsing: + return castAs().getQualifierLoc(); + case TypeLoc::Using: + return castAs().getQualifierLoc(); + default: + return NestedNameSpecifierLoc(); + } +} + +SourceLocation TypeLoc::getNonPrefixBeginLoc() const { + switch (getTypeLocClass()) { + case TypeLoc::TemplateSpecialization: { + auto TL = castAs(); + SourceLocation Loc = TL.getTemplateKeywordLoc(); + if (!Loc.isValid()) + Loc = TL.getTemplateNameLoc(); + return Loc; + } + case TypeLoc::DependentTemplateSpecialization: { + auto TL = castAs(); + SourceLocation Loc = TL.getTemplateKeywordLoc(); + if (!Loc.isValid()) + Loc = TL.getTemplateNameLoc(); + return Loc; + } + case TypeLoc::DeducedTemplateSpecialization: { + auto TL = castAs(); + SourceLocation Loc = TL.getTemplateKeywordLoc(); + if (!Loc.isValid()) + Loc = TL.getTemplateNameLoc(); + return Loc; + } + case TypeLoc::DependentName: + return castAs().getNameLoc(); + case TypeLoc::Enum: + case TypeLoc::Record: + case TypeLoc::InjectedClassName: + return castAs().getNameLoc(); + case TypeLoc::Typedef: + return castAs().getNameLoc(); + case TypeLoc::UnresolvedUsing: + return castAs().getNameLoc(); + case TypeLoc::Using: + return castAs().getNameLoc(); + default: + return getBeginLoc(); + } +} + +SourceLocation TypeLoc::getNonElaboratedBeginLoc() const { + // For elaborated types (e.g. `struct a::A`) we want the portion after the + // `struct` but including the namespace qualifier, `a::`. + switch (getTypeLocClass()) { + case TypeLoc::Qualified: + return castAs() + .getUnqualifiedLoc() + .getNonElaboratedBeginLoc(); + case TypeLoc::TemplateSpecialization: { + auto T = castAs(); + if (NestedNameSpecifierLoc QualifierLoc = T.getQualifierLoc()) + return QualifierLoc.getBeginLoc(); + return T.getTemplateNameLoc(); + } + case TypeLoc::DependentTemplateSpecialization: { + auto T = castAs(); + if (NestedNameSpecifierLoc QualifierLoc = T.getQualifierLoc()) + return QualifierLoc.getBeginLoc(); + return T.getTemplateNameLoc(); + } + case TypeLoc::DeducedTemplateSpecialization: { + auto T = castAs(); + if (NestedNameSpecifierLoc QualifierLoc = T.getQualifierLoc()) + return QualifierLoc.getBeginLoc(); + return T.getTemplateNameLoc(); + } + case TypeLoc::DependentName: { + auto T = castAs(); + if (NestedNameSpecifierLoc QualifierLoc = T.getQualifierLoc()) + return QualifierLoc.getBeginLoc(); + return T.getNameLoc(); + } + case TypeLoc::Enum: + case TypeLoc::Record: + case TypeLoc::InjectedClassName: { + auto T = castAs(); + if (NestedNameSpecifierLoc QualifierLoc = T.getQualifierLoc()) + return QualifierLoc.getBeginLoc(); + return T.getNameLoc(); + } + case TypeLoc::Typedef: { + auto T = castAs(); + if (NestedNameSpecifierLoc QualifierLoc = T.getQualifierLoc()) + return QualifierLoc.getBeginLoc(); + return T.getNameLoc(); + } + case TypeLoc::UnresolvedUsing: { + auto T = castAs(); + if (NestedNameSpecifierLoc QualifierLoc = T.getQualifierLoc()) + return QualifierLoc.getBeginLoc(); + return T.getNameLoc(); + } + case TypeLoc::Using: { + auto T = castAs(); + if (NestedNameSpecifierLoc QualifierLoc = T.getQualifierLoc()) + return QualifierLoc.getBeginLoc(); + return T.getNameLoc(); + } + default: + return getBeginLoc(); + } +} + void ObjCTypeParamTypeLoc::initializeLocal(ASTContext &Context, SourceLocation Loc) { setNameLoc(Loc); @@ -555,9 +672,9 @@ static void initializeElaboratedKeyword(TL T, SourceLocation Loc) { : SourceLocation()); } -static NestedNameSpecifierLoc -initializeQualifier(ASTContext &Context, NestedNameSpecifier *Qualifier, - SourceLocation Loc) { +static NestedNameSpecifierLoc initializeQualifier(ASTContext &Context, + NestedNameSpecifier Qualifier, + SourceLocation Loc) { if (!Qualifier) return NestedNameSpecifierLoc(); NestedNameSpecifierLocBuilder Builder; @@ -565,15 +682,6 @@ initializeQualifier(ASTContext &Context, NestedNameSpecifier *Qualifier, return Builder.getWithLocInContext(Context); } -void ElaboratedTypeLoc::initializeLocal(ASTContext &Context, - SourceLocation Loc) { - if (isEmpty()) - return; - initializeElaboratedKeyword(*this, Loc); - setQualifierLoc( - initializeQualifier(Context, getTypePtr()->getQualifier(), Loc)); -} - void DependentNameTypeLoc::initializeLocal(ASTContext &Context, SourceLocation Loc) { initializeElaboratedKeyword(*this, Loc); @@ -596,6 +704,78 @@ DependentTemplateSpecializationTypeLoc::initializeLocal(ASTContext &Context, Context, getTypePtr()->template_arguments(), getArgInfos(), Loc); } +void TemplateSpecializationTypeLoc::set(SourceLocation ElaboratedKeywordLoc, + NestedNameSpecifierLoc QualifierLoc, + SourceLocation TemplateKeywordLoc, + SourceLocation NameLoc, + SourceLocation LAngleLoc, + SourceLocation RAngleLoc) { + TemplateSpecializationLocInfo &Data = *getLocalData(); + + Data.ElaboratedKWLoc = ElaboratedKeywordLoc; + SourceLocation BeginLoc = ElaboratedKeywordLoc; + + getLocalData()->QualifierData = QualifierLoc.getOpaqueData(); + + assert(QualifierLoc.getNestedNameSpecifier() == + getTypePtr()->getTemplateName().getQualifier()); + Data.QualifierData = QualifierLoc ? QualifierLoc.getOpaqueData() : nullptr; + if (QualifierLoc && !BeginLoc.isValid()) + BeginLoc = QualifierLoc.getBeginLoc(); + + Data.TemplateKWLoc = TemplateKeywordLoc; + if (!BeginLoc.isValid()) + BeginLoc = TemplateKeywordLoc; + + Data.NameLoc = NameLoc; + if (!BeginLoc.isValid()) + BeginLoc = NameLoc; + + Data.LAngleLoc = LAngleLoc; + Data.SR = SourceRange(BeginLoc, RAngleLoc); +} + +void TemplateSpecializationTypeLoc::set(SourceLocation ElaboratedKeywordLoc, + NestedNameSpecifierLoc QualifierLoc, + SourceLocation TemplateKeywordLoc, + SourceLocation NameLoc, + const TemplateArgumentListInfo &TAL) { + set(ElaboratedKeywordLoc, QualifierLoc, TemplateKeywordLoc, NameLoc, + TAL.getLAngleLoc(), TAL.getRAngleLoc()); + MutableArrayRef ArgInfos = getArgLocInfos(); + assert(TAL.size() == ArgInfos.size()); + for (unsigned I = 0, N = TAL.size(); I != N; ++I) + ArgInfos[I] = TAL[I].getLocInfo(); +} + +void TemplateSpecializationTypeLoc::initializeLocal(ASTContext &Context, + SourceLocation Loc) { + QualifiedTemplateName *Name = + getTypePtr()->getTemplateName().getAsAdjustedQualifiedTemplateName(); + + SourceLocation ElaboratedKeywordLoc = + getTypePtr()->getKeyword() != ElaboratedTypeKeyword::None + ? Loc + : SourceLocation(); + + NestedNameSpecifierLoc QualifierLoc; + if (NestedNameSpecifier Qualifier = + Name ? Name->getQualifier() : std::nullopt) { + NestedNameSpecifierLocBuilder Builder; + Builder.MakeTrivial(Context, Qualifier, Loc); + QualifierLoc = Builder.getWithLocInContext(Context); + } + + TemplateArgumentListInfo TAL(Loc, Loc); + set(ElaboratedKeywordLoc, QualifierLoc, + /*TemplateKeywordLoc=*/Name && Name->hasTemplateKeyword() + ? Loc + : SourceLocation(), + /*NameLoc=*/Loc, /*LAngleLoc=*/Loc, /*RAngleLoc=*/Loc); + initializeArgLocs(Context, getTypePtr()->template_arguments(), getArgInfos(), + Loc); +} + void TemplateSpecializationTypeLoc::initializeArgLocs( ASTContext &Context, ArrayRef Args, TemplateArgumentLocInfo *ArgInfos, SourceLocation Loc) { @@ -631,7 +811,7 @@ void TemplateSpecializationTypeLoc::initializeArgLocs( Builder.MakeTrivial(Context, QTN->getQualifier(), Loc); ArgInfos[i] = TemplateArgumentLocInfo( - Context, Builder.getWithLocInContext(Context), Loc, + Context, Loc, Builder.getWithLocInContext(Context), Loc, Args[i].getKind() == TemplateArgument::Template ? SourceLocation() : Loc); break; @@ -693,10 +873,6 @@ namespace { // Only these types can contain the desired 'auto' type. - TypeLoc VisitElaboratedTypeLoc(ElaboratedTypeLoc T) { - return Visit(T.getNamedTypeLoc()); - } - TypeLoc VisitQualifiedTypeLoc(QualifiedTypeLoc T) { return Visit(T.getUnqualifiedLoc()); } diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp index d18723d807c6a..adaeeb59e8133 100644 --- a/clang/lib/AST/TypePrinter.cpp +++ b/clang/lib/AST/TypePrinter.cpp @@ -133,7 +133,7 @@ class TypePrinter { void printAfter(QualType T, raw_ostream &OS); void AppendScope(DeclContext *DC, raw_ostream &OS, DeclarationName NameInScope); - void printTag(TagDecl *T, raw_ostream &OS); + void printTagType(const TagType *T, raw_ostream &OS); void printFunctionAfter(const FunctionType::ExtInfo &Info, raw_ostream &OS); #define ABSTRACT_TYPE(CLASS, PARENT) #define TYPE(CLASS, PARENT) \ @@ -230,7 +230,6 @@ bool TypePrinter::canPrefixQualifiers(const Type *T, case Type::UnaryTransform: case Type::Record: case Type::Enum: - case Type::Elaborated: case Type::TemplateTypeParm: case Type::SubstTemplateTypeParmPack: case Type::DeducedTemplateSpecialization: @@ -503,11 +502,7 @@ void TypePrinter::printMemberPointerBefore(const MemberPointerType *T, // FIXME: this should include vectors, but vectors use attributes I guess. if (isa(T->getPointeeType())) OS << '('; - - PrintingPolicy InnerPolicy(Policy); - InnerPolicy.IncludeTagDefinition = false; - T->getQualifier()->print(OS, InnerPolicy); - + T->getQualifier().print(OS, Policy); OS << "*"; } @@ -1210,29 +1205,50 @@ void TypePrinter::printTypeSpec(NamedDecl *D, raw_ostream &OS) { void TypePrinter::printUnresolvedUsingBefore(const UnresolvedUsingType *T, raw_ostream &OS) { - printTypeSpec(T->getDecl(), OS); + OS << TypeWithKeyword::getKeywordName(T->getKeyword()); + if (T->getKeyword() != ElaboratedTypeKeyword::None) + OS << ' '; + auto *D = T->getDecl(); + if (Policy.FullyQualifiedName || T->isCanonicalUnqualified()) { + AppendScope(D->getDeclContext(), OS, D->getDeclName()); + } else { + T->getQualifier().print(OS, Policy); + } + OS << D->getIdentifier()->getName(); + spaceBeforePlaceHolder(OS); } void TypePrinter::printUnresolvedUsingAfter(const UnresolvedUsingType *T, raw_ostream &OS) {} void TypePrinter::printUsingBefore(const UsingType *T, raw_ostream &OS) { - // After `namespace b { using a::X }`, is the type X within B a::X or b::X? - // - // - b::X is more formally correct given the UsingType model - // - b::X makes sense if "re-exporting" a symbol in a new namespace - // - a::X makes sense if "importing" a symbol for convenience - // - // The "importing" use seems much more common, so we print a::X. - // This could be a policy option, but the right choice seems to rest more - // with the intent of the code than the caller. - printTypeSpec(T->getFoundDecl()->getUnderlyingDecl(), OS); + OS << TypeWithKeyword::getKeywordName(T->getKeyword()); + if (T->getKeyword() != ElaboratedTypeKeyword::None) + OS << ' '; + auto *D = T->getDecl(); + if (Policy.FullyQualifiedName) { + AppendScope(D->getDeclContext(), OS, D->getDeclName()); + } else { + T->getQualifier().print(OS, Policy); + } + OS << D->getIdentifier()->getName(); + spaceBeforePlaceHolder(OS); } void TypePrinter::printUsingAfter(const UsingType *T, raw_ostream &OS) {} void TypePrinter::printTypedefBefore(const TypedefType *T, raw_ostream &OS) { - printTypeSpec(T->getDecl(), OS); + OS << TypeWithKeyword::getKeywordName(T->getKeyword()); + if (T->getKeyword() != ElaboratedTypeKeyword::None) + OS << ' '; + auto *D = T->getDecl(); + if (Policy.FullyQualifiedName) { + AppendScope(D->getDeclContext(), OS, D->getDeclName()); + } else { + T->getQualifier().print(OS, Policy); + } + OS << D->getIdentifier()->getName(); + spaceBeforePlaceHolder(OS); } void TypePrinter::printMacroQualifiedBefore(const MacroQualifiedType *T, @@ -1353,14 +1369,53 @@ void TypePrinter::printAutoAfter(const AutoType *T, raw_ostream &OS) { void TypePrinter::printDeducedTemplateSpecializationBefore( const DeducedTemplateSpecializationType *T, raw_ostream &OS) { - // If the type has been deduced, print the deduced type. + if (ElaboratedTypeKeyword Keyword = T->getKeyword(); + T->getKeyword() != ElaboratedTypeKeyword::None) + OS << KeywordHelpers::getKeywordName(Keyword) << ' '; + + TemplateName Name = T->getTemplateName(); + + // If the type has been deduced, print the template arguments, as if this was + // printing the deduced type, but including elaboration and template name + // qualification. + // FIXME: There should probably be a policy which controls this. + // We would probably want to do this on diagnostics, but not on -ast-print. + ArrayRef Args; + TemplateDecl *DeducedTD = nullptr; if (!T->getDeducedType().isNull()) { - printBefore(T->getDeducedType(), OS); - } else { + if (const auto *TST = + dyn_cast(T->getDeducedType())) { + DeducedTD = TST->getTemplateName().getAsTemplateDecl( + /*IgnoreDeduced=*/true); + Args = TST->template_arguments(); + } else { + // Should only get here for canonical types. + const auto *CD = cast( + cast(T->getDeducedType())->getOriginalDecl()); + DeducedTD = CD->getSpecializedTemplate(); + Args = CD->getTemplateArgs().asArray(); + } + + // FIXME: Workaround for alias template CTAD not producing guides which + // include the alias template specialization type. + // Purposefully disregard qualification when building this TemplateName; + // any qualification we might have, might not make sense in the + // context this was deduced. + if (!declaresSameEntity(DeducedTD, Name.getAsTemplateDecl( + /*IgnoreDeduced=*/true))) + Name = TemplateName(DeducedTD); + } + + { IncludeStrongLifetimeRAII Strong(Policy); - T->getTemplateName().print(OS, Policy); - spaceBeforePlaceHolder(OS); + Name.print(OS, Policy); + } + if (DeducedTD) { + printTemplateArgumentList(OS, Args, Policy, + DeducedTD->getTemplateParameters()); } + + spaceBeforePlaceHolder(OS); } void TypePrinter::printDeducedTemplateSpecializationAfter( @@ -1470,30 +1525,37 @@ void TypePrinter::AppendScope(DeclContext *DC, raw_ostream &OS, } } -void TypePrinter::printTag(TagDecl *D, raw_ostream &OS) { - if (Policy.IncludeTagDefinition) { - PrintingPolicy SubPolicy = Policy; - SubPolicy.IncludeTagDefinition = false; - D->print(OS, SubPolicy, Indentation); +void TypePrinter::printTagType(const TagType *T, raw_ostream &OS) { + TagDecl *D = T->getOriginalDecl(); + + if (Policy.IncludeTagDefinition && T->isTagOwned()) { + D->print(OS, Policy, Indentation); spaceBeforePlaceHolder(OS); return; } bool HasKindDecoration = false; - // We don't print tags unless this is an elaborated type. - // In C, we just assume every RecordType is an elaborated type. - if (!Policy.SuppressTagKeyword && !D->getTypedefNameForAnonDecl()) { - HasKindDecoration = true; - OS << D->getKindName(); - OS << ' '; + if (T->isCanonicalUnqualified()) { + if (!Policy.SuppressTagKeyword && !D->getTypedefNameForAnonDecl()) { + HasKindDecoration = true; + OS << D->getKindName(); + OS << ' '; + } + } else { + OS << TypeWithKeyword::getKeywordName(T->getKeyword()); + if (T->getKeyword() != ElaboratedTypeKeyword::None) + OS << ' '; } - // Compute the full nested-name-specifier for this type. - // In C, this will always be empty except when the type - // being printed is anonymous within other Record. - if (!Policy.SuppressScope) + if (!Policy.FullyQualifiedName && !T->isCanonicalUnqualified()) { + T->getQualifier().print(OS, Policy); + } else if (!Policy.SuppressScope) { + // Compute the full nested-name-specifier for this type. + // In C, this will always be empty except when the type + // being printed is anonymous within other Record. AppendScope(D->getDeclContext(), OS, D->getDeclName()); + } if (const IdentifierInfo *II = D->getIdentifier()) OS << II->getName(); @@ -1568,9 +1630,11 @@ void TypePrinter::printTag(TagDecl *D, raw_ostream &OS) { void TypePrinter::printRecordBefore(const RecordType *T, raw_ostream &OS) { // Print the preferred name if we have one for this type. if (Policy.UsePreferredNames) { - for (const auto *PNA : T->getDecl()->specific_attrs()) { + for (const auto *PNA : T->getOriginalDecl() + ->getMostRecentDecl() + ->specific_attrs()) { if (!declaresSameEntity(PNA->getTypedefType()->getAsCXXRecordDecl(), - T->getDecl())) + T->getOriginalDecl())) continue; // Find the outermost typedef or alias template. QualType T = PNA->getTypedefType(); @@ -1584,17 +1648,44 @@ void TypePrinter::printRecordBefore(const RecordType *T, raw_ostream &OS) { } } - printTag(T->getDecl(), OS); + printTagType(T, OS); } void TypePrinter::printRecordAfter(const RecordType *T, raw_ostream &OS) {} void TypePrinter::printEnumBefore(const EnumType *T, raw_ostream &OS) { - printTag(T->getDecl(), OS); + printTagType(T, OS); } void TypePrinter::printEnumAfter(const EnumType *T, raw_ostream &OS) {} +void TypePrinter::printInjectedClassNameBefore(const InjectedClassNameType *T, + raw_ostream &OS) { + const ASTContext &Ctx = T->getOriginalDecl()->getASTContext(); + IncludeStrongLifetimeRAII Strong(Policy); + T->getTemplateName(Ctx).print(OS, Policy); + if (Policy.PrintInjectedClassNameWithArguments) { + auto *Decl = T->getOriginalDecl(); + // FIXME: Use T->getTemplateArgs(Ctx) when that supports as-written + // arguments. + if (auto *RD = dyn_cast(Decl)) { + printTemplateArgumentList(OS, RD->getTemplateArgsAsWritten()->arguments(), + Policy, + T->getTemplateDecl()->getTemplateParameters()); + } else { + ClassTemplateDecl *TD = Decl->getDescribedClassTemplate(); + assert(TD); + printTemplateArgumentList( + OS, TD->getTemplateParameters()->getInjectedTemplateArgs(Ctx), Policy, + T->getTemplateDecl()->getTemplateParameters()); + } + } + spaceBeforePlaceHolder(OS); +} + +void TypePrinter::printInjectedClassNameAfter(const InjectedClassNameType *T, + raw_ostream &OS) {} + void TypePrinter::printTemplateTypeParmBefore(const TemplateTypeParmType *T, raw_ostream &OS) { TemplateTypeParmDecl *D = T->getDecl(); @@ -1661,6 +1752,10 @@ void TypePrinter::printTemplateId(const TemplateSpecializationType *T, raw_ostream &OS, bool FullyQualify) { IncludeStrongLifetimeRAII Strong(Policy); + if (ElaboratedTypeKeyword K = T->getKeyword(); + K != ElaboratedTypeKeyword::None) + OS << TypeWithKeyword::getKeywordName(K) << ' '; + TemplateDecl *TD = T->getTemplateName().getAsTemplateDecl(/*IgnoreDeduced=*/true); // FIXME: Null TD never exercised in test suite. @@ -1670,7 +1765,10 @@ void TypePrinter::printTemplateId(const TemplateSpecializationType *T, OS << TD->getName(); } else { - T->getTemplateName().print(OS, Policy, TemplateName::Qualified::None); + T->getTemplateName().print(OS, Policy, + !Policy.SuppressScope + ? TemplateName::Qualified::AsWritten + : TemplateName::Qualified::None); } DefaultTemplateArgsPolicyRAII TemplateArgs(Policy); @@ -1689,77 +1787,6 @@ void TypePrinter::printTemplateSpecializationAfter( const TemplateSpecializationType *T, raw_ostream &OS) {} -void TypePrinter::printInjectedClassNameBefore(const InjectedClassNameType *T, - raw_ostream &OS) { - if (Policy.PrintInjectedClassNameWithArguments) - return printTemplateSpecializationBefore(T->getInjectedTST(), OS); - - IncludeStrongLifetimeRAII Strong(Policy); - T->getTemplateName().print(OS, Policy); - spaceBeforePlaceHolder(OS); -} - -void TypePrinter::printInjectedClassNameAfter(const InjectedClassNameType *T, - raw_ostream &OS) {} - -void TypePrinter::printElaboratedBefore(const ElaboratedType *T, - raw_ostream &OS) { - if (Policy.IncludeTagDefinition && T->getOwnedTagDecl()) { - TagDecl *OwnedTagDecl = T->getOwnedTagDecl(); - assert(OwnedTagDecl->getTypeForDecl() == T->getNamedType().getTypePtr() && - "OwnedTagDecl expected to be a declaration for the type"); - PrintingPolicy SubPolicy = Policy; - SubPolicy.IncludeTagDefinition = false; - OwnedTagDecl->print(OS, SubPolicy, Indentation); - spaceBeforePlaceHolder(OS); - return; - } - - if (Policy.SuppressElaboration) { - printBefore(T->getNamedType(), OS); - return; - } - - // The tag definition will take care of these. - if (!Policy.IncludeTagDefinition) - { - OS << TypeWithKeyword::getKeywordName(T->getKeyword()); - if (T->getKeyword() != ElaboratedTypeKeyword::None) - OS << " "; - NestedNameSpecifier *Qualifier = T->getQualifier(); - if (!Policy.SuppressTagKeyword && Policy.SuppressScope && - !Policy.SuppressUnwrittenScope) { - bool OldTagKeyword = Policy.SuppressTagKeyword; - bool OldSupressScope = Policy.SuppressScope; - Policy.SuppressTagKeyword = true; - Policy.SuppressScope = false; - printBefore(T->getNamedType(), OS); - Policy.SuppressTagKeyword = OldTagKeyword; - Policy.SuppressScope = OldSupressScope; - return; - } - if (Qualifier) - Qualifier->print(OS, Policy); - } - - ElaboratedTypePolicyRAII PolicyRAII(Policy); - printBefore(T->getNamedType(), OS); -} - -void TypePrinter::printElaboratedAfter(const ElaboratedType *T, - raw_ostream &OS) { - if (Policy.IncludeTagDefinition && T->getOwnedTagDecl()) - return; - - if (Policy.SuppressElaboration) { - printAfter(T->getNamedType(), OS); - return; - } - - ElaboratedTypePolicyRAII PolicyRAII(Policy); - printAfter(T->getNamedType(), OS); -} - void TypePrinter::printParenBefore(const ParenType *T, raw_ostream &OS) { if (!HasEmptyPlaceHolder && !isa(T->getInnerType())) { printBefore(T->getInnerType(), OS); @@ -1781,9 +1808,7 @@ void TypePrinter::printDependentNameBefore(const DependentNameType *T, OS << TypeWithKeyword::getKeywordName(T->getKeyword()); if (T->getKeyword() != ElaboratedTypeKeyword::None) OS << " "; - - T->getQualifier()->print(OS, Policy); - + T->getQualifier().print(OS, Policy); OS << T->getIdentifier()->getName(); spaceBeforePlaceHolder(OS); } diff --git a/clang/lib/AST/VTTBuilder.cpp b/clang/lib/AST/VTTBuilder.cpp index de011848a721e..85101aee97e66 100644 --- a/clang/lib/AST/VTTBuilder.cpp +++ b/clang/lib/AST/VTTBuilder.cpp @@ -64,7 +64,9 @@ void VTTBuilder::LayoutSecondaryVTTs(BaseSubobject Base) { continue; const auto *BaseDecl = - cast(I.getType()->castAs()->getDecl()); + cast( + I.getType()->castAs()->getOriginalDecl()) + ->getDefinitionOrSelf(); const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(RD); CharUnits BaseOffset = Base.getBaseOffset() + @@ -90,7 +92,9 @@ VTTBuilder::LayoutSecondaryVirtualPointers(BaseSubobject Base, for (const auto &I : RD->bases()) { const auto *BaseDecl = - cast(I.getType()->castAs()->getDecl()); + cast( + I.getType()->castAs()->getOriginalDecl()) + ->getDefinitionOrSelf(); // Itanium C++ ABI 2.6.2: // Secondary virtual pointers are present for all bases with either @@ -154,7 +158,9 @@ void VTTBuilder::LayoutVirtualVTTs(const CXXRecordDecl *RD, VisitedVirtualBasesSetTy &VBases) { for (const auto &I : RD->bases()) { const auto *BaseDecl = - cast(I.getType()->castAs()->getDecl()); + cast( + I.getType()->castAs()->getOriginalDecl()) + ->getDefinitionOrSelf(); // Check if this is a virtual base. if (I.isVirtual()) { diff --git a/clang/lib/AST/VTableBuilder.cpp b/clang/lib/AST/VTableBuilder.cpp index 0001745a6ff22..6cec526ba8443 100644 --- a/clang/lib/AST/VTableBuilder.cpp +++ b/clang/lib/AST/VTableBuilder.cpp @@ -313,10 +313,12 @@ ComputeReturnAdjustmentBaseOffset(ASTContext &Context, } const CXXRecordDecl *DerivedRD = - cast(cast(CanDerivedReturnType)->getDecl()); + cast( + cast(CanDerivedReturnType)->getOriginalDecl()) + ->getDefinitionOrSelf(); - const CXXRecordDecl *BaseRD = - cast(cast(CanBaseReturnType)->getDecl()); + const CXXRecordDecl *BaseRD = cast( + cast(CanBaseReturnType)->getOriginalDecl()); return ComputeBaseOffset(Context, BaseRD, DerivedRD); } diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 758012f894a41..ce12e1e8fccad 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -591,12 +591,12 @@ class TreeTransform { /// By default, transforms the template name by transforming the declarations /// and nested-name-specifiers that occur within the template name. /// Subclasses may override this function to provide alternate behavior. - TemplateName - TransformTemplateName(CXXScopeSpec &SS, TemplateName Name, - SourceLocation NameLoc, - QualType ObjectType = QualType(), - NamedDecl *FirstQualifierInScope = nullptr, - bool AllowInjectedClassName = false); + TemplateName TransformTemplateName(NestedNameSpecifierLoc &QualifierLoc, + SourceLocation TemplateKWLoc, + TemplateName Name, SourceLocation NameLoc, + QualType ObjectType = QualType(), + NamedDecl *FirstQualifierInScope = nullptr, + bool AllowInjectedClassName = false); /// Transform the given template argument. /// @@ -693,20 +693,17 @@ class TreeTransform { StmtResult TransformSEHHandler(Stmt *Handler); - QualType - TransformTemplateSpecializationType(TypeLocBuilder &TLB, - TemplateSpecializationTypeLoc TL, - TemplateName Template); - - QualType - TransformDependentTemplateSpecializationType(TypeLocBuilder &TLB, - DependentTemplateSpecializationTypeLoc TL, + QualType TransformTemplateSpecializationType(TypeLocBuilder &TLB, + TemplateSpecializationTypeLoc TL, TemplateName Template, CXXScopeSpec &SS); QualType TransformDependentTemplateSpecializationType( TypeLocBuilder &TLB, DependentTemplateSpecializationTypeLoc TL, - CXXScopeSpec &SS); + QualType ObjectType, NamedDecl *UnqualLookup, + bool AllowInjectedClassName); + + QualType TransformTagType(TypeLocBuilder &TLB, TagTypeLoc TL); /// Transforms the parameters of a function type into the /// given vectors. @@ -1016,16 +1013,22 @@ class TreeTransform { /// Rebuild an unresolved typename type, given the decl that /// the UnresolvedUsingTypenameDecl was transformed to. - QualType RebuildUnresolvedUsingType(SourceLocation NameLoc, Decl *D); + QualType RebuildUnresolvedUsingType(ElaboratedTypeKeyword Keyword, + NestedNameSpecifier Qualifier, + SourceLocation NameLoc, Decl *D); /// Build a new type found via an alias. - QualType RebuildUsingType(UsingShadowDecl *Found, QualType Underlying) { - return SemaRef.Context.getUsingType(Found, Underlying); + QualType RebuildUsingType(ElaboratedTypeKeyword Keyword, + NestedNameSpecifier Qualifier, UsingShadowDecl *D, + QualType UnderlyingType) { + return SemaRef.Context.getUsingType(Keyword, Qualifier, D, UnderlyingType); } /// Build a new typedef type. - QualType RebuildTypedefType(TypedefNameDecl *Typedef) { - return SemaRef.Context.getTypeDeclType(Typedef); + QualType RebuildTypedefType(ElaboratedTypeKeyword Keyword, + NestedNameSpecifier Qualifier, + TypedefNameDecl *Typedef) { + return SemaRef.Context.getTypedefType(Keyword, Qualifier, Typedef); } /// Build a new MacroDefined type. @@ -1034,14 +1037,14 @@ class TreeTransform { return SemaRef.Context.getMacroQualifiedType(T, MacroII); } - /// Build a new class/struct/union type. - QualType RebuildRecordType(RecordDecl *Record) { - return SemaRef.Context.getTypeDeclType(Record); + /// Build a new class/struct/union/enum type. + QualType RebuildTagType(ElaboratedTypeKeyword Keyword, + NestedNameSpecifier Qualifier, TagDecl *Tag) { + return SemaRef.Context.getTagType(Keyword, Qualifier, Tag, + /*OwnsTag=*/false); } - - /// Build a new Enum type. - QualType RebuildEnumType(EnumDecl *Enum) { - return SemaRef.Context.getTypeDeclType(Enum); + QualType RebuildCanonicalTagType(TagDecl *Tag) { + return SemaRef.Context.getCanonicalTagType(Tag); } /// Build a new typeof(expr) type. @@ -1090,10 +1093,10 @@ class TreeTransform { /// By default, builds a new DeducedTemplateSpecializationType with the given /// deduced type. - QualType RebuildDeducedTemplateSpecializationType(TemplateName Template, - QualType Deduced) { + QualType RebuildDeducedTemplateSpecializationType( + ElaboratedTypeKeyword Keyword, TemplateName Template, QualType Deduced) { return SemaRef.Context.getDeducedTemplateSpecializationType( - Template, Deduced, /*IsDependent*/ false); + Keyword, Template, Deduced, /*IsDependent*/ false); } /// Build a new template specialization type. @@ -1101,7 +1104,8 @@ class TreeTransform { /// By default, performs semantic analysis when building the template /// specialization type. Subclasses may override this routine to provide /// different behavior. - QualType RebuildTemplateSpecializationType(TemplateName Template, + QualType RebuildTemplateSpecializationType(ElaboratedTypeKeyword Keyword, + TemplateName Template, SourceLocation TemplateLoc, TemplateArgumentListInfo &Args); @@ -1113,41 +1117,22 @@ class TreeTransform { return SemaRef.BuildParenType(InnerType); } - /// Build a new qualified name type. - /// - /// By default, builds a new ElaboratedType type from the keyword, - /// the nested-name-specifier and the named type. - /// Subclasses may override this routine to provide different behavior. - QualType RebuildElaboratedType(SourceLocation KeywordLoc, - ElaboratedTypeKeyword Keyword, - NestedNameSpecifierLoc QualifierLoc, - QualType Named) { - return SemaRef.Context.getElaboratedType(Keyword, - QualifierLoc.getNestedNameSpecifier(), - Named); - } - /// Build a new typename type that refers to a template-id. /// /// By default, builds a new DependentNameType type from the /// nested-name-specifier and the given type. Subclasses may override /// this routine to provide different behavior. QualType RebuildDependentTemplateSpecializationType( - ElaboratedTypeKeyword Keyword, NestedNameSpecifier *NNS, - SourceLocation TemplateKWLoc, TemplateName Name, SourceLocation NameLoc, - TemplateArgumentListInfo &Args, bool AllowInjectedClassName) { + ElaboratedTypeKeyword Keyword, SourceLocation TemplateKWLoc, + TemplateName Name, SourceLocation NameLoc, TemplateArgumentListInfo &Args, + bool AllowInjectedClassName) { // If it's still dependent, make a dependent specialization. if (const DependentTemplateStorage *S = Name.getAsDependentTemplateName()) return SemaRef.Context.getDependentTemplateSpecializationType( Keyword, *S, Args.arguments()); - // Otherwise, make an elaborated type wrapping a non-dependent - // specialization. - QualType T = - getDerived().RebuildTemplateSpecializationType(Name, NameLoc, Args); - if (T.isNull()) - return QualType(); - return SemaRef.Context.getElaboratedType(Keyword, NNS, T); + return getDerived().RebuildTemplateSpecializationType(Keyword, Name, + NameLoc, Args); } /// Build a new typename type that refers to an identifier. @@ -1164,7 +1149,7 @@ class TreeTransform { CXXScopeSpec SS; SS.Adopt(QualifierLoc); - if (QualifierLoc.getNestedNameSpecifier()->isDependent()) { + if (QualifierLoc.getNestedNameSpecifier().isDependent()) { // If the name is still dependent, just build a new dependent name type. if (!SemaRef.computeDeclContext(SS)) return SemaRef.Context.getDependentNameType(Keyword, @@ -1234,19 +1219,14 @@ class TreeTransform { } return QualType(); } - if (!SemaRef.isAcceptableTagRedeclaration(Tag, Kind, /*isDefinition*/false, IdLoc, Id)) { SemaRef.Diag(KeywordLoc, diag::err_use_with_wrong_tag) << Id; SemaRef.Diag(Tag->getLocation(), diag::note_previous_use); return QualType(); } - - // Build the elaborated-type-specifier type. - QualType T = SemaRef.Context.getTypeDeclType(Tag); - return SemaRef.Context.getElaboratedType(Keyword, - QualifierLoc.getNestedNameSpecifier(), - T); + return getDerived().RebuildTagType( + Keyword, QualifierLoc.getNestedNameSpecifier(), Tag); } /// Build a new pack expansion type. @@ -1299,7 +1279,6 @@ class TreeTransform { SourceLocation TemplateKWLoc, const IdentifierInfo &Name, SourceLocation NameLoc, QualType ObjectType, - NamedDecl *FirstQualifierInScope, bool AllowInjectedClassName); /// Build a new template name given a nested name specifier and the @@ -1319,7 +1298,6 @@ class TreeTransform { SourceLocation TemplateKWLoc, IdentifierOrOverloadedOperator IO, SourceLocation NameLoc, QualType ObjectType, - NamedDecl *FirstQualifierInScope, bool AllowInjectedClassName); /// Build a new template name given a template template parameter pack @@ -4008,8 +3986,8 @@ class TreeTransform { SemaRef.Context, TemplateArgument(Pattern.getArgument().getAsTemplate(), NumExpansions), - Pattern.getTemplateQualifierLoc(), Pattern.getTemplateNameLoc(), - EllipsisLoc); + Pattern.getTemplateKWLoc(), Pattern.getTemplateQualifierLoc(), + Pattern.getTemplateNameLoc(), EllipsisLoc); case TemplateArgument::Null: case TemplateArgument::Integral: @@ -4254,23 +4232,29 @@ class TreeTransform { } private: - TypeLoc TransformTypeInObjectScope(TypeLoc TL, - QualType ObjectType, - NamedDecl *FirstQualifierInScope, - CXXScopeSpec &SS); + QualType TransformTypeInObjectScope(TypeLocBuilder &TLB, TypeLoc TL, + QualType ObjectType, + NamedDecl *FirstQualifierInScope); TypeSourceInfo *TransformTypeInObjectScope(TypeSourceInfo *TSInfo, QualType ObjectType, - NamedDecl *FirstQualifierInScope, - CXXScopeSpec &SS); + NamedDecl *FirstQualifierInScope) { + if (getDerived().AlreadyTransformed(TSInfo->getType())) + return TSInfo; - TypeSourceInfo *TransformTSIInObjectScope(TypeLoc TL, QualType ObjectType, - NamedDecl *FirstQualifierInScope, - CXXScopeSpec &SS); + TypeLocBuilder TLB; + QualType T = TransformTypeInObjectScope(TLB, TSInfo->getTypeLoc(), + ObjectType, FirstQualifierInScope); + if (T.isNull()) + return nullptr; + return TLB.getTypeSourceInfo(SemaRef.Context, T); + } QualType TransformDependentNameType(TypeLocBuilder &TLB, DependentNameTypeLoc TL, - bool DeducibleTSTContext); + bool DeducibleTSTContext, + QualType ObjectType = QualType(), + NamedDecl *UnqualLookup = nullptr); llvm::SmallVector TransformOpenACCClauseList(OpenACCDirectiveKind DirKind, @@ -4599,7 +4583,7 @@ NestedNameSpecifierLoc TreeTransform::TransformNestedNameSpecifierLoc( auto insertNNS = [&Qualifiers](NestedNameSpecifierLoc NNS) { for (NestedNameSpecifierLoc Qualifier = NNS; Qualifier; - Qualifier = Qualifier.getPrefix()) + Qualifier = Qualifier.getAsNamespaceAndPrefix().Prefix) Qualifiers.push_back(Qualifier); }; insertNNS(NNS); @@ -4607,86 +4591,86 @@ NestedNameSpecifierLoc TreeTransform::TransformNestedNameSpecifierLoc( CXXScopeSpec SS; while (!Qualifiers.empty()) { NestedNameSpecifierLoc Q = Qualifiers.pop_back_val(); - NestedNameSpecifier *QNNS = Q.getNestedNameSpecifier(); - - switch (QNNS->getKind()) { - case NestedNameSpecifier::Identifier: { - Sema::NestedNameSpecInfo IdInfo(QNNS->getAsIdentifier(), - Q.getLocalBeginLoc(), Q.getLocalEndLoc(), - ObjectType); - if (SemaRef.BuildCXXNestedNameSpecifier(/*Scope=*/nullptr, IdInfo, false, - SS, FirstQualifierInScope, false)) - return NestedNameSpecifierLoc(); - break; - } + NestedNameSpecifier QNNS = Q.getNestedNameSpecifier(); - case NestedNameSpecifier::Namespace: { - NamespaceDecl *NS = - cast_or_null(getDerived().TransformDecl( - Q.getLocalBeginLoc(), QNNS->getAsNamespace())); - SS.Extend(SemaRef.Context, NS, Q.getLocalBeginLoc(), Q.getLocalEndLoc()); - break; - } + switch (QNNS.getKind()) { + case NestedNameSpecifier::Kind::Null: + llvm_unreachable("unexpected null nested name specifier"); - case NestedNameSpecifier::NamespaceAlias: { - NamespaceAliasDecl *Alias = - cast_or_null(getDerived().TransformDecl( - Q.getLocalBeginLoc(), QNNS->getAsNamespaceAlias())); - SS.Extend(SemaRef.Context, Alias, Q.getLocalBeginLoc(), - Q.getLocalEndLoc()); + case NestedNameSpecifier::Kind::Namespace: { + auto *NS = cast(getDerived().TransformDecl( + Q.getLocalBeginLoc(), const_cast( + QNNS.getAsNamespaceAndPrefix().Namespace))); + SS.Extend(SemaRef.Context, NS, Q.getLocalBeginLoc(), Q.getLocalEndLoc()); break; } - case NestedNameSpecifier::Global: + case NestedNameSpecifier::Kind::Global: // There is no meaningful transformation that one could perform on the // global scope. SS.MakeGlobal(SemaRef.Context, Q.getBeginLoc()); break; - case NestedNameSpecifier::Super: { - CXXRecordDecl *RD = - cast_or_null(getDerived().TransformDecl( - SourceLocation(), QNNS->getAsRecordDecl())); + case NestedNameSpecifier::Kind::Super: { + CXXRecordDecl *RD = cast_or_null( + getDerived().TransformDecl(SourceLocation(), QNNS.getAsRecordDecl())); SS.MakeSuper(SemaRef.Context, RD, Q.getBeginLoc(), Q.getEndLoc()); break; } - case NestedNameSpecifier::TypeSpec: { - TypeLoc TL = TransformTypeInObjectScope(Q.getTypeLoc(), ObjectType, - FirstQualifierInScope, SS); - - if (!TL) - return NestedNameSpecifierLoc(); + case NestedNameSpecifier::Kind::Type: { + assert(SS.isEmpty()); + TypeLoc TL = Q.castAsTypeLoc(); + + if (auto DNT = TL.getAs()) { + NestedNameSpecifierLoc QualifierLoc = DNT.getQualifierLoc(); + if (QualifierLoc) { + QualifierLoc = getDerived().TransformNestedNameSpecifierLoc( + QualifierLoc, ObjectType, FirstQualifierInScope); + if (!QualifierLoc) + return NestedNameSpecifierLoc(); + ObjectType = QualType(); + FirstQualifierInScope = nullptr; + } + SS.Adopt(QualifierLoc); + Sema::NestedNameSpecInfo IdInfo( + const_cast(DNT.getTypePtr()->getIdentifier()), + DNT.getNameLoc(), Q.getLocalEndLoc(), ObjectType); + if (SemaRef.BuildCXXNestedNameSpecifier(/*Scope=*/nullptr, IdInfo, + false, SS, + FirstQualifierInScope, false)) + return NestedNameSpecifierLoc(); + return SS.getWithLocInContext(SemaRef.Context); + } QualType T = TL.getType(); + TypeLocBuilder TLB; + if (!getDerived().AlreadyTransformed(T)) { + T = TransformTypeInObjectScope(TLB, TL, ObjectType, + FirstQualifierInScope); + if (T.isNull()) + return NestedNameSpecifierLoc(); + TL = TLB.getTypeLocInContext(SemaRef.Context, T); + } + if (T->isDependentType() || T->isRecordType() || (SemaRef.getLangOpts().CPlusPlus11 && T->isEnumeralType())) { if (T->isEnumeralType()) SemaRef.Diag(TL.getBeginLoc(), diag::warn_cxx98_compat_enum_nested_name_spec); - - if (const auto ETL = TL.getAs()) { - SS.Adopt(ETL.getQualifierLoc()); - TL = ETL.getNamedTypeLoc(); - } - - SS.Extend(SemaRef.Context, TL, Q.getLocalEndLoc()); + SS.Make(SemaRef.Context, TL, Q.getLocalEndLoc()); break; } // If the nested-name-specifier is an invalid type def, don't emit an // error because a previous error should have already been emitted. TypedefTypeLoc TTL = TL.getAsAdjusted(); - if (!TTL || !TTL.getTypedefNameDecl()->isInvalidDecl()) { + if (!TTL || !TTL.getDecl()->isInvalidDecl()) { SemaRef.Diag(TL.getBeginLoc(), diag::err_nested_name_spec_non_tag) << T << SS.getRange(); } return NestedNameSpecifierLoc(); } } - - // The qualifier-in-scope and object type only apply to the leftmost entity. - FirstQualifierInScope = nullptr; - ObjectType = QualType(); } // Don't rebuild the nested-name-specifier if we don't have to. @@ -4772,30 +4756,32 @@ template TemplateName TreeTransform::RebuildTemplateName( CXXScopeSpec &SS, SourceLocation TemplateKWLoc, IdentifierOrOverloadedOperator IO, SourceLocation NameLoc, - QualType ObjectType, NamedDecl *FirstQualifierInScope, - bool AllowInjectedClassName) { - if (const IdentifierInfo *II = IO.getIdentifier()) { + QualType ObjectType, bool AllowInjectedClassName) { + if (const IdentifierInfo *II = IO.getIdentifier()) return getDerived().RebuildTemplateName(SS, TemplateKWLoc, *II, NameLoc, - ObjectType, FirstQualifierInScope, - AllowInjectedClassName); - } + ObjectType, AllowInjectedClassName); return getDerived().RebuildTemplateName(SS, TemplateKWLoc, IO.getOperator(), NameLoc, ObjectType, AllowInjectedClassName); } -template -TemplateName -TreeTransform::TransformTemplateName(CXXScopeSpec &SS, - TemplateName Name, - SourceLocation NameLoc, - QualType ObjectType, - NamedDecl *FirstQualifierInScope, - bool AllowInjectedClassName) { +template +TemplateName TreeTransform::TransformTemplateName( + NestedNameSpecifierLoc &QualifierLoc, SourceLocation TemplateKWLoc, + TemplateName Name, SourceLocation NameLoc, QualType ObjectType, + NamedDecl *FirstQualifierInScope, bool AllowInjectedClassName) { if (QualifiedTemplateName *QTN = Name.getAsQualifiedTemplateName()) { + // FIXME: Preserve UsingTemplateName. TemplateDecl *Template = QTN->getUnderlyingTemplate().getAsTemplateDecl(); assert(Template && "qualified template name must refer to a template"); + if (QualifierLoc) { + QualifierLoc = getDerived().TransformNestedNameSpecifierLoc( + QualifierLoc, ObjectType, FirstQualifierInScope); + if (!QualifierLoc) + return TemplateName(); + } + TemplateDecl *TransTemplate = cast_or_null(getDerived().TransformDecl(NameLoc, Template)); @@ -4803,41 +4789,67 @@ TreeTransform::TransformTemplateName(CXXScopeSpec &SS, return TemplateName(); if (!getDerived().AlwaysRebuild() && - SS.getScopeRep() == QTN->getQualifier() && + QualifierLoc.getNestedNameSpecifier() == QTN->getQualifier() && TransTemplate == Template) return Name; - + CXXScopeSpec SS; + SS.Adopt(QualifierLoc); return getDerived().RebuildTemplateName(SS, QTN->hasTemplateKeyword(), TransTemplate); } if (DependentTemplateName *DTN = Name.getAsDependentTemplateName()) { - if (SS.getScopeRep()) { - // These apply to the scope specifier, not the template. + if (QualifierLoc) { + QualifierLoc = getDerived().TransformNestedNameSpecifierLoc( + QualifierLoc, ObjectType, FirstQualifierInScope); + if (!QualifierLoc) + return TemplateName(); + // The qualifier-in-scope and object type only apply to the leftmost + // entity. ObjectType = QualType(); - FirstQualifierInScope = nullptr; } if (!getDerived().AlwaysRebuild() && - SS.getScopeRep() == DTN->getQualifier() && + QualifierLoc.getNestedNameSpecifier() == DTN->getQualifier() && ObjectType.isNull()) return Name; - // FIXME: Preserve the location of the "template" keyword. - SourceLocation TemplateKWLoc = NameLoc; - return getDerived().RebuildTemplateName( - SS, TemplateKWLoc, DTN->getName(), NameLoc, ObjectType, + CXXScopeSpec SS; + SS.Adopt(QualifierLoc); + return getDerived().RebuildTemplateName(SS, TemplateKWLoc, DTN->getName(), + NameLoc, ObjectType, + AllowInjectedClassName); + } + + if (SubstTemplateTemplateParmStorage *S = + Name.getAsSubstTemplateTemplateParm()) { + TemplateName NewName = getDerived().TransformTemplateName( + QualifierLoc, TemplateKWLoc, S->getReplacement(), NameLoc, ObjectType, FirstQualifierInScope, AllowInjectedClassName); + if (NewName.isNull()) + return TemplateName(); + Decl *AssociatedDecl = + getDerived().TransformDecl(NameLoc, S->getAssociatedDecl()); + if (!getDerived().AlwaysRebuild() && NewName == S->getReplacement() && + AssociatedDecl == S->getAssociatedDecl()) + return Name; + return SemaRef.Context.getSubstTemplateTemplateParm( + NewName, AssociatedDecl, S->getIndex(), S->getPackIndex(), + S->getFinal()); } - // FIXME: Try to preserve more of the TemplateName. + assert(!Name.getAsDeducedTemplateName() && + "DeducedTemplateName should not escape partial ordering"); + if (TemplateDecl *Template = Name.getAsTemplateDecl()) { + assert(!QualifierLoc && "missed a Qualified Template"); TemplateDecl *TransTemplate = cast_or_null(getDerived().TransformDecl(NameLoc, Template)); if (!TransTemplate) return TemplateName(); + CXXScopeSpec SS; return getDerived().RebuildTemplateName(SS, /*TemplateKeyword=*/false, TransTemplate); } @@ -4929,21 +4941,16 @@ bool TreeTransform::TransformTemplateArgument( case TemplateArgument::Template: { NestedNameSpecifierLoc QualifierLoc = Input.getTemplateQualifierLoc(); - if (QualifierLoc) { - QualifierLoc = getDerived().TransformNestedNameSpecifierLoc(QualifierLoc); - if (!QualifierLoc) - return true; - } - CXXScopeSpec SS; - SS.Adopt(QualifierLoc); TemplateName Template = getDerived().TransformTemplateName( - SS, Arg.getAsTemplate(), Input.getTemplateNameLoc()); + QualifierLoc, Input.getTemplateKWLoc(), Arg.getAsTemplate(), + Input.getTemplateNameLoc()); if (Template.isNull()) return true; Output = TemplateArgumentLoc(SemaRef.Context, TemplateArgument(Template), - QualifierLoc, Input.getTemplateNameLoc()); + Input.getTemplateKWLoc(), QualifierLoc, + Input.getTemplateNameLoc()); return false; } @@ -5380,85 +5387,35 @@ QualType TreeTransform::RebuildQualifiedType(QualType T, return SemaRef.BuildQualifiedType(T, Loc, Quals); } -template -TypeLoc -TreeTransform::TransformTypeInObjectScope(TypeLoc TL, - QualType ObjectType, - NamedDecl *UnqualLookup, - CXXScopeSpec &SS) { - if (getDerived().AlreadyTransformed(TL.getType())) - return TL; - - TypeSourceInfo *TSI = - TransformTSIInObjectScope(TL, ObjectType, UnqualLookup, SS); - if (TSI) - return TSI->getTypeLoc(); - return TypeLoc(); -} - -template -TypeSourceInfo * -TreeTransform::TransformTypeInObjectScope(TypeSourceInfo *TSInfo, - QualType ObjectType, - NamedDecl *UnqualLookup, - CXXScopeSpec &SS) { - if (getDerived().AlreadyTransformed(TSInfo->getType())) - return TSInfo; - - return TransformTSIInObjectScope(TSInfo->getTypeLoc(), ObjectType, - UnqualLookup, SS); -} - template -TypeSourceInfo *TreeTransform::TransformTSIInObjectScope( - TypeLoc TL, QualType ObjectType, NamedDecl *UnqualLookup, - CXXScopeSpec &SS) { - QualType T = TL.getType(); - assert(!getDerived().AlreadyTransformed(T)); - - TypeLocBuilder TLB; - QualType Result; - - if (isa(T)) { - TemplateSpecializationTypeLoc SpecTL = - TL.castAs(); - - TemplateName Template = getDerived().TransformTemplateName( - SS, SpecTL.getTypePtr()->getTemplateName(), SpecTL.getTemplateNameLoc(), - ObjectType, UnqualLookup, /*AllowInjectedClassName*/true); - if (Template.isNull()) - return nullptr; +QualType TreeTransform::TransformTypeInObjectScope( + TypeLocBuilder &TLB, TypeLoc TL, QualType ObjectType, + NamedDecl *UnqualLookup) { + assert(!getDerived().AlreadyTransformed(TL.getType())); - Result = getDerived().TransformTemplateSpecializationType(TLB, SpecTL, - Template); - } else if (isa(T)) { - DependentTemplateSpecializationTypeLoc SpecTL = - TL.castAs(); - - const IdentifierInfo *II = SpecTL.getTypePtr() - ->getDependentTemplateName() - .getName() - .getIdentifier(); - TemplateName Template = getDerived().RebuildTemplateName( - SS, SpecTL.getTemplateKeywordLoc(), *II, SpecTL.getTemplateNameLoc(), - ObjectType, UnqualLookup, - /*AllowInjectedClassName*/ true); - if (Template.isNull()) - return nullptr; - - Result = getDerived().TransformDependentTemplateSpecializationType(TLB, - SpecTL, - Template, - SS); - } else { - // Nothing special needs to be done for these. - Result = getDerived().TransformType(TLB, TL); + switch (TL.getTypeLocClass()) { + case TypeLoc::DependentTemplateSpecialization: + return getDerived().TransformDependentTemplateSpecializationType( + TLB, TL.castAs(), ObjectType, + UnqualLookup, /*AllowInjectedClassName=*/true); + case TypeLoc::DependentName: { + return getDerived().TransformDependentNameType( + TLB, TL.castAs(), /*DeducedTSTContext=*/false, + ObjectType, UnqualLookup); + } + case TypeLoc::Typedef: + case TypeLoc::TemplateSpecialization: + case TypeLoc::SubstTemplateTypeParm: + case TypeLoc::PackIndexing: + case TypeLoc::Enum: + case TypeLoc::Record: + case TypeLoc::InjectedClassName: + case TypeLoc::TemplateTypeParm: + case TypeLoc::Decltype: + return getDerived().TransformType(TLB, TL); + default: + llvm_unreachable("unexpected type class"); } - - if (Result.isNull()) - return nullptr; - - return TLB.getTypeSourceInfo(SemaRef.Context, Result); } template static inline @@ -6694,23 +6651,38 @@ QualType TreeTransform::TransformFunctionNoProtoType( template QualType TreeTransform::TransformUnresolvedUsingType( TypeLocBuilder &TLB, UnresolvedUsingTypeLoc TL) { + const UnresolvedUsingType *T = TL.getTypePtr(); - Decl *D = getDerived().TransformDecl(TL.getNameLoc(), T->getDecl()); + bool Changed = false; + + NestedNameSpecifierLoc QualifierLoc = TL.getQualifierLoc(); + if (NestedNameSpecifierLoc OldQualifierLoc = QualifierLoc) { + QualifierLoc = getDerived().TransformNestedNameSpecifierLoc(QualifierLoc); + if (!QualifierLoc) + return QualType(); + Changed |= QualifierLoc != OldQualifierLoc; + } + + auto *D = getDerived().TransformDecl(TL.getNameLoc(), T->getDecl()); if (!D) return QualType(); + Changed |= D != T->getDecl(); QualType Result = TL.getType(); - if (getDerived().AlwaysRebuild() || D != T->getDecl()) { - Result = getDerived().RebuildUnresolvedUsingType(TL.getNameLoc(), D); + if (getDerived().AlwaysRebuild() || Changed) { + Result = getDerived().RebuildUnresolvedUsingType( + T->getKeyword(), QualifierLoc.getNestedNameSpecifier(), TL.getNameLoc(), + D); if (Result.isNull()) return QualType(); } - // We might get an arbitrary type spec type back. We should at - // least always get a type spec type, though. - TypeSpecTypeLoc NewTL = TLB.pushTypeSpec(Result); - NewTL.setNameLoc(TL.getNameLoc()); - + if (isa(Result)) + TLB.push(Result).set(TL.getElaboratedKeywordLoc(), + QualifierLoc, TL.getNameLoc()); + else + TLB.push(Result).set(TL.getElaboratedKeywordLoc(), + QualifierLoc, TL.getNameLoc()); return Result; } @@ -6718,25 +6690,37 @@ template QualType TreeTransform::TransformUsingType(TypeLocBuilder &TLB, UsingTypeLoc TL) { const UsingType *T = TL.getTypePtr(); + bool Changed = false; - auto *Found = cast_or_null(getDerived().TransformDecl( - TL.getLocalSourceRange().getBegin(), T->getFoundDecl())); - if (!Found) + NestedNameSpecifierLoc QualifierLoc = TL.getQualifierLoc(); + if (NestedNameSpecifierLoc OldQualifierLoc = QualifierLoc) { + QualifierLoc = getDerived().TransformNestedNameSpecifierLoc(QualifierLoc); + if (!QualifierLoc) + return QualType(); + Changed |= QualifierLoc != OldQualifierLoc; + } + + auto *D = cast_or_null( + getDerived().TransformDecl(TL.getNameLoc(), T->getDecl())); + if (!D) return QualType(); + Changed |= D != T->getDecl(); - QualType Underlying = getDerived().TransformType(T->desugar()); - if (Underlying.isNull()) + QualType UnderlyingType = getDerived().TransformType(T->desugar()); + if (UnderlyingType.isNull()) return QualType(); + Changed |= UnderlyingType != T->desugar(); QualType Result = TL.getType(); - if (getDerived().AlwaysRebuild() || Found != T->getFoundDecl() || - Underlying != T->getUnderlyingType()) { - Result = getDerived().RebuildUsingType(Found, Underlying); + if (getDerived().AlwaysRebuild() || Changed) { + Result = getDerived().RebuildUsingType( + T->getKeyword(), QualifierLoc.getNestedNameSpecifier(), D, + UnderlyingType); if (Result.isNull()) return QualType(); } - - TLB.pushTypeSpec(Result).setNameLoc(TL.getNameLoc()); + TLB.push(Result).set(TL.getElaboratedKeywordLoc(), QualifierLoc, + TL.getNameLoc()); return Result; } @@ -6744,23 +6728,34 @@ template QualType TreeTransform::TransformTypedefType(TypeLocBuilder &TLB, TypedefTypeLoc TL) { const TypedefType *T = TL.getTypePtr(); - TypedefNameDecl *Typedef - = cast_or_null(getDerived().TransformDecl(TL.getNameLoc(), - T->getDecl())); + bool Changed = false; + + NestedNameSpecifierLoc QualifierLoc = TL.getQualifierLoc(); + if (NestedNameSpecifierLoc OldQualifierLoc = QualifierLoc) { + QualifierLoc = getDerived().TransformNestedNameSpecifierLoc(QualifierLoc); + if (!QualifierLoc) + return QualType(); + Changed |= QualifierLoc != OldQualifierLoc; + } + + auto *Typedef = cast_or_null( + getDerived().TransformDecl(TL.getNameLoc(), T->getDecl())); if (!Typedef) return QualType(); + Changed |= Typedef != T->getDecl(); + + // FIXME: Transform the UnderlyingType if different from decl. QualType Result = TL.getType(); - if (getDerived().AlwaysRebuild() || - Typedef != T->getDecl()) { - Result = getDerived().RebuildTypedefType(Typedef); + if (getDerived().AlwaysRebuild() || Changed) { + Result = getDerived().RebuildTypedefType( + T->getKeyword(), QualifierLoc.getNestedNameSpecifier(), Typedef); if (Result.isNull()) return QualType(); } - TypedefTypeLoc NewTL = TLB.push(Result); - NewTL.setNameLoc(TL.getNameLoc()); - + TLB.push(Result).set(TL.getElaboratedKeywordLoc(), + QualifierLoc, TL.getNameLoc()); return Result; } @@ -6996,9 +6991,10 @@ QualType TreeTransform::TransformDeducedTemplateSpecializationType( TypeLocBuilder &TLB, DeducedTemplateSpecializationTypeLoc TL) { const DeducedTemplateSpecializationType *T = TL.getTypePtr(); - CXXScopeSpec SS; + NestedNameSpecifierLoc QualifierLoc = TL.getQualifierLoc(); TemplateName TemplateName = getDerived().TransformTemplateName( - SS, T->getTemplateName(), TL.getTemplateNameLoc()); + QualifierLoc, /*TemplateKELoc=*/SourceLocation(), T->getTemplateName(), + TL.getTemplateNameLoc()); if (TemplateName.isNull()) return QualType(); @@ -7011,76 +7007,71 @@ QualType TreeTransform::TransformDeducedTemplateSpecializationType( } QualType Result = getDerived().RebuildDeducedTemplateSpecializationType( - TemplateName, NewDeduced); + T->getKeyword(), TemplateName, NewDeduced); if (Result.isNull()) return QualType(); - DeducedTemplateSpecializationTypeLoc NewTL = - TLB.push(Result); + auto NewTL = TLB.push(Result); + NewTL.setElaboratedKWLoc(TL.getElaboratedKWLoc()); NewTL.setTemplateNameLoc(TL.getTemplateNameLoc()); - + NewTL.setQualifierLoc(QualifierLoc); return Result; } -template -QualType TreeTransform::TransformRecordType(TypeLocBuilder &TLB, - RecordTypeLoc TL) { - const RecordType *T = TL.getTypePtr(); - RecordDecl *Record - = cast_or_null(getDerived().TransformDecl(TL.getNameLoc(), - T->getDecl())); - if (!Record) +template +QualType TreeTransform::TransformTagType(TypeLocBuilder &TLB, + TagTypeLoc TL) { + const TagType *T = TL.getTypePtr(); + + NestedNameSpecifierLoc QualifierLoc = TL.getQualifierLoc(); + if (QualifierLoc) { + QualifierLoc = getDerived().TransformNestedNameSpecifierLoc(QualifierLoc); + if (!QualifierLoc) + return QualType(); + } + + auto *TD = cast_or_null( + getDerived().TransformDecl(TL.getNameLoc(), T->getOriginalDecl())); + if (!TD) return QualType(); QualType Result = TL.getType(); - if (getDerived().AlwaysRebuild() || - Record != T->getDecl()) { - Result = getDerived().RebuildRecordType(Record); + if (getDerived().AlwaysRebuild() || QualifierLoc != TL.getQualifierLoc() || + TD != T->getOriginalDecl()) { + if (T->isCanonicalUnqualified()) + Result = getDerived().RebuildCanonicalTagType(TD); + else + Result = getDerived().RebuildTagType( + T->getKeyword(), QualifierLoc.getNestedNameSpecifier(), TD); if (Result.isNull()) return QualType(); } - RecordTypeLoc NewTL = TLB.push(Result); + TagTypeLoc NewTL = TLB.push(Result); + NewTL.setElaboratedKeywordLoc(TL.getElaboratedKeywordLoc()); + NewTL.setQualifierLoc(QualifierLoc); NewTL.setNameLoc(TL.getNameLoc()); return Result; } -template +template QualType TreeTransform::TransformEnumType(TypeLocBuilder &TLB, EnumTypeLoc TL) { - const EnumType *T = TL.getTypePtr(); - EnumDecl *Enum - = cast_or_null(getDerived().TransformDecl(TL.getNameLoc(), - T->getDecl())); - if (!Enum) - return QualType(); - - QualType Result = TL.getType(); - if (getDerived().AlwaysRebuild() || - Enum != T->getDecl()) { - Result = getDerived().RebuildEnumType(Enum); - if (Result.isNull()) - return QualType(); - } - - EnumTypeLoc NewTL = TLB.push(Result); - NewTL.setNameLoc(TL.getNameLoc()); + return getDerived().TransformTagType(TLB, TL); +} - return Result; +template +QualType TreeTransform::TransformRecordType(TypeLocBuilder &TLB, + RecordTypeLoc TL) { + return getDerived().TransformTagType(TLB, TL); } template QualType TreeTransform::TransformInjectedClassNameType( TypeLocBuilder &TLB, InjectedClassNameTypeLoc TL) { - Decl *D = getDerived().TransformDecl(TL.getNameLoc(), - TL.getTypePtr()->getDecl()); - if (!D) return QualType(); - - QualType T = SemaRef.Context.getTypeDeclType(cast(D)); - TLB.pushTypeSpec(T).setNameLoc(TL.getNameLoc()); - return T; + return getDerived().TransformTagType(TLB, TL); } template @@ -7141,24 +7132,6 @@ QualType TreeTransform::TransformSubstTemplateTypeParmPackType( return TransformTypeSpecType(TLB, TL); } -template -QualType TreeTransform::TransformTemplateSpecializationType( - TypeLocBuilder &TLB, - TemplateSpecializationTypeLoc TL) { - const TemplateSpecializationType *T = TL.getTypePtr(); - - // The nested-name-specifier never matters in a TemplateSpecializationType, - // because we can't have a dependent nested-name-specifier anyway. - CXXScopeSpec SS; - TemplateName Template - = getDerived().TransformTemplateName(SS, T->getTemplateName(), - TL.getTemplateNameLoc()); - if (Template.isNull()) - return QualType(); - - return getDerived().TransformTemplateSpecializationType(TLB, TL, Template); -} - template QualType TreeTransform::TransformAtomicType(TypeLocBuilder &TLB, AtomicTypeLoc TL) { @@ -7392,9 +7365,16 @@ QualType TreeTransform::TransformAutoType(TypeLocBuilder &TLB, template QualType TreeTransform::TransformTemplateSpecializationType( - TypeLocBuilder &TLB, - TemplateSpecializationTypeLoc TL, - TemplateName Template) { + TypeLocBuilder &TLB, TemplateSpecializationTypeLoc TL) { + const TemplateSpecializationType *T = TL.getTypePtr(); + + NestedNameSpecifierLoc QualifierLoc = TL.getQualifierLoc(); + TemplateName Template = getDerived().TransformTemplateName( + QualifierLoc, TL.getTemplateKeywordLoc(), T->getTemplateName(), + TL.getTemplateNameLoc()); + if (Template.isNull()) + return QualType(); + TemplateArgumentListInfo NewTemplateArgs; NewTemplateArgs.setLAngleLoc(TL.getLAngleLoc()); NewTemplateArgs.setRAngleLoc(TL.getRAngleLoc()); @@ -7409,10 +7389,9 @@ QualType TreeTransform::TransformTemplateSpecializationType( // original template changed. If the template changed, and even if the // arguments didn't change, these arguments might not correspond to their // respective parameters, therefore needing conversions. - QualType Result = - getDerived().RebuildTemplateSpecializationType(Template, - TL.getTemplateNameLoc(), - NewTemplateArgs); + QualType Result = getDerived().RebuildTemplateSpecializationType( + TL.getTypePtr()->getKeyword(), Template, TL.getTemplateNameLoc(), + NewTemplateArgs); if (!Result.isNull()) { // Specializations of template template parameters are represented as @@ -7422,8 +7401,8 @@ QualType TreeTransform::TransformTemplateSpecializationType( if (isa(Result)) { DependentTemplateSpecializationTypeLoc NewTL = TLB.push(Result); - NewTL.setElaboratedKeywordLoc(SourceLocation()); - NewTL.setQualifierLoc(NestedNameSpecifierLoc()); + NewTL.setElaboratedKeywordLoc(TL.getElaboratedKeywordLoc()); + NewTL.setQualifierLoc(QualifierLoc); NewTL.setTemplateKeywordLoc(TL.getTemplateKeywordLoc()); NewTL.setTemplateNameLoc(TL.getTemplateNameLoc()); NewTL.setLAngleLoc(TL.getLAngleLoc()); @@ -7432,132 +7411,14 @@ QualType TreeTransform::TransformTemplateSpecializationType( NewTL.setArgLocInfo(i, NewTemplateArgs[i].getLocInfo()); return Result; } - - TemplateSpecializationTypeLoc NewTL - = TLB.push(Result); - NewTL.setTemplateKeywordLoc(TL.getTemplateKeywordLoc()); - NewTL.setTemplateNameLoc(TL.getTemplateNameLoc()); - NewTL.setLAngleLoc(TL.getLAngleLoc()); - NewTL.setRAngleLoc(TL.getRAngleLoc()); - for (unsigned i = 0, e = NewTemplateArgs.size(); i != e; ++i) - NewTL.setArgLocInfo(i, NewTemplateArgs[i].getLocInfo()); + TLB.push(Result).set( + TL.getElaboratedKeywordLoc(), QualifierLoc, TL.getTemplateKeywordLoc(), + TL.getTemplateNameLoc(), NewTemplateArgs); } return Result; } -template -QualType TreeTransform::TransformDependentTemplateSpecializationType( - TypeLocBuilder &TLB, - DependentTemplateSpecializationTypeLoc TL, - TemplateName Template, - CXXScopeSpec &SS) { - TemplateArgumentListInfo NewTemplateArgs; - NewTemplateArgs.setLAngleLoc(TL.getLAngleLoc()); - NewTemplateArgs.setRAngleLoc(TL.getRAngleLoc()); - typedef TemplateArgumentLocContainerIterator< - DependentTemplateSpecializationTypeLoc> ArgIterator; - if (getDerived().TransformTemplateArguments(ArgIterator(TL, 0), - ArgIterator(TL, TL.getNumArgs()), - NewTemplateArgs)) - return QualType(); - - // FIXME: maybe don't rebuild if all the template arguments are the same. - - if (DependentTemplateName *DTN = Template.getAsDependentTemplateName()) { - assert(DTN->getQualifier() == SS.getScopeRep()); - QualType Result = getSema().Context.getDependentTemplateSpecializationType( - TL.getTypePtr()->getKeyword(), *DTN, NewTemplateArgs.arguments()); - - DependentTemplateSpecializationTypeLoc NewTL - = TLB.push(Result); - NewTL.setElaboratedKeywordLoc(TL.getElaboratedKeywordLoc()); - NewTL.setQualifierLoc(SS.getWithLocInContext(SemaRef.Context)); - NewTL.setTemplateKeywordLoc(TL.getTemplateKeywordLoc()); - NewTL.setTemplateNameLoc(TL.getTemplateNameLoc()); - NewTL.setLAngleLoc(TL.getLAngleLoc()); - NewTL.setRAngleLoc(TL.getRAngleLoc()); - for (unsigned i = 0, e = NewTemplateArgs.size(); i != e; ++i) - NewTL.setArgLocInfo(i, NewTemplateArgs[i].getLocInfo()); - return Result; - } - - QualType Result - = getDerived().RebuildTemplateSpecializationType(Template, - TL.getTemplateNameLoc(), - NewTemplateArgs); - - if (!Result.isNull()) { - /// FIXME: Wrap this in an elaborated-type-specifier? - TemplateSpecializationTypeLoc NewTL - = TLB.push(Result); - NewTL.setTemplateKeywordLoc(TL.getTemplateKeywordLoc()); - NewTL.setTemplateNameLoc(TL.getTemplateNameLoc()); - NewTL.setLAngleLoc(TL.getLAngleLoc()); - NewTL.setRAngleLoc(TL.getRAngleLoc()); - for (unsigned i = 0, e = NewTemplateArgs.size(); i != e; ++i) - NewTL.setArgLocInfo(i, NewTemplateArgs[i].getLocInfo()); - } - - return Result; -} - -template -QualType -TreeTransform::TransformElaboratedType(TypeLocBuilder &TLB, - ElaboratedTypeLoc TL) { - const ElaboratedType *T = TL.getTypePtr(); - - NestedNameSpecifierLoc QualifierLoc; - // NOTE: the qualifier in an ElaboratedType is optional. - if (TL.getQualifierLoc()) { - QualifierLoc - = getDerived().TransformNestedNameSpecifierLoc(TL.getQualifierLoc()); - if (!QualifierLoc) - return QualType(); - } - - QualType NamedT = getDerived().TransformType(TLB, TL.getNamedTypeLoc()); - if (NamedT.isNull()) - return QualType(); - - // C++0x [dcl.type.elab]p2: - // If the identifier resolves to a typedef-name or the simple-template-id - // resolves to an alias template specialization, the - // elaborated-type-specifier is ill-formed. - if (T->getKeyword() != ElaboratedTypeKeyword::None && - T->getKeyword() != ElaboratedTypeKeyword::Typename) { - if (const TemplateSpecializationType *TST = - NamedT->getAs()) { - TemplateName Template = TST->getTemplateName(); - if (TypeAliasTemplateDecl *TAT = dyn_cast_or_null( - Template.getAsTemplateDecl())) { - SemaRef.Diag(TL.getNamedTypeLoc().getBeginLoc(), - diag::err_tag_reference_non_tag) - << TAT << NonTagKind::TypeAliasTemplate - << ElaboratedType::getTagTypeKindForKeyword(T->getKeyword()); - SemaRef.Diag(TAT->getLocation(), diag::note_declared_at); - } - } - } - - QualType Result = TL.getType(); - if (getDerived().AlwaysRebuild() || - QualifierLoc != TL.getQualifierLoc() || - NamedT != T->getNamedType()) { - Result = getDerived().RebuildElaboratedType(TL.getElaboratedKeywordLoc(), - T->getKeyword(), - QualifierLoc, NamedT); - if (Result.isNull()) - return QualType(); - } - - ElaboratedTypeLoc NewTL = TLB.push(Result); - NewTL.setElaboratedKeywordLoc(TL.getElaboratedKeywordLoc()); - NewTL.setQualifierLoc(QualifierLoc); - return Result; -} - template QualType TreeTransform::TransformAttributedType(TypeLocBuilder &TLB, AttributedTypeLoc TL) { @@ -7748,15 +7609,22 @@ QualType TreeTransform::TransformDependentNameType( return TransformDependentNameType(TLB, TL, false); } -template +template QualType TreeTransform::TransformDependentNameType( - TypeLocBuilder &TLB, DependentNameTypeLoc TL, bool DeducedTSTContext) { + TypeLocBuilder &TLB, DependentNameTypeLoc TL, bool DeducedTSTContext, + QualType ObjectType, NamedDecl *UnqualLookup) { const DependentNameType *T = TL.getTypePtr(); - NestedNameSpecifierLoc QualifierLoc - = getDerived().TransformNestedNameSpecifierLoc(TL.getQualifierLoc()); - if (!QualifierLoc) - return QualType(); + NestedNameSpecifierLoc QualifierLoc = TL.getQualifierLoc(); + if (QualifierLoc) { + QualifierLoc = getDerived().TransformNestedNameSpecifierLoc( + QualifierLoc, ObjectType, UnqualLookup); + if (!QualifierLoc) + return QualType(); + } else { + assert((ObjectType.isNull() && !UnqualLookup) && + "must be transformed by TransformNestedNameSpecifierLoc"); + } QualType Result = getDerived().RebuildDependentNameType(T->getKeyword(), @@ -7768,13 +7636,19 @@ QualType TreeTransform::TransformDependentNameType( if (Result.isNull()) return QualType(); - if (const ElaboratedType* ElabT = Result->getAs()) { - QualType NamedT = ElabT->getNamedType(); - TLB.pushTypeSpec(NamedT).setNameLoc(TL.getNameLoc()); - - ElaboratedTypeLoc NewTL = TLB.push(Result); + if (isa(Result)) { + auto NewTL = TLB.push(Result); NewTL.setElaboratedKeywordLoc(TL.getElaboratedKeywordLoc()); NewTL.setQualifierLoc(QualifierLoc); + NewTL.setNameLoc(TL.getNameLoc()); + } else if (isa(Result)) { + auto NewTL = TLB.push(Result); + NewTL.setElaboratedKWLoc(TL.getElaboratedKeywordLoc()); + NewTL.setTemplateNameLoc(TL.getNameLoc()); + NewTL.setQualifierLoc(QualifierLoc); + } else if (isa(Result)) { + TLB.push(Result).set(TL.getElaboratedKeywordLoc(), + QualifierLoc, TL.getNameLoc()); } else { DependentNameTypeLoc NewTL = TLB.push(Result); NewTL.setElaboratedKeywordLoc(TL.getElaboratedKeywordLoc()); @@ -7784,33 +7658,34 @@ QualType TreeTransform::TransformDependentNameType( return Result; } -template -QualType TreeTransform:: - TransformDependentTemplateSpecializationType(TypeLocBuilder &TLB, - DependentTemplateSpecializationTypeLoc TL) { - NestedNameSpecifierLoc QualifierLoc; - if (TL.getQualifierLoc()) { - QualifierLoc - = getDerived().TransformNestedNameSpecifierLoc(TL.getQualifierLoc()); - if (!QualifierLoc) - return QualType(); - } - - CXXScopeSpec SS; - SS.Adopt(QualifierLoc); - return getDerived().TransformDependentTemplateSpecializationType(TLB, TL, SS); +template +QualType TreeTransform::TransformDependentTemplateSpecializationType( + TypeLocBuilder &TLB, DependentTemplateSpecializationTypeLoc TL) { + return getDerived().TransformDependentTemplateSpecializationType( + TLB, TL, QualType(), nullptr, false); } template QualType TreeTransform::TransformDependentTemplateSpecializationType( TypeLocBuilder &TLB, DependentTemplateSpecializationTypeLoc TL, - CXXScopeSpec &SS) { + QualType ObjectType, NamedDecl *UnqualLookup, bool AllowInjectedClassName) { const DependentTemplateSpecializationType *T = TL.getTypePtr(); - TemplateArgumentListInfo NewTemplateArgs; - NewTemplateArgs.setLAngleLoc(TL.getLAngleLoc()); - NewTemplateArgs.setRAngleLoc(TL.getRAngleLoc()); + NestedNameSpecifierLoc QualifierLoc = TL.getQualifierLoc(); + if (QualifierLoc) { + QualifierLoc = getDerived().TransformNestedNameSpecifierLoc( + QualifierLoc, ObjectType, UnqualLookup); + if (!QualifierLoc) + return QualType(); + // These only apply to the leftmost prefix. + ObjectType = QualType(); + UnqualLookup = nullptr; + } + CXXScopeSpec SS; + SS.Adopt(QualifierLoc); + TemplateArgumentListInfo NewTemplateArgs(TL.getLAngleLoc(), + TL.getRAngleLoc()); auto ArgsRange = llvm::make_range>({TL, 0}, {TL, TL.getNumArgs()}); @@ -7827,43 +7702,27 @@ QualType TreeTransform::TransformDependentTemplateSpecializationType( QualType Result = TL.getType(); if (getDerived().AlwaysRebuild() || SS.getScopeRep() != DTN.getQualifier() || - TemplateArgumentsChanged) { + TemplateArgumentsChanged || !ObjectType.isNull()) { TemplateName Name = getDerived().RebuildTemplateName( SS, TL.getTemplateKeywordLoc(), DTN.getName(), TL.getTemplateNameLoc(), - /*ObjectType=*/QualType(), /*FirstQualifierInScope=*/nullptr, - /*AllowInjectedClassName=*/false); + ObjectType, AllowInjectedClassName); if (Name.isNull()) return QualType(); Result = getDerived().RebuildDependentTemplateSpecializationType( - T->getKeyword(), SS.getScopeRep(), TL.getTemplateKeywordLoc(), Name, + T->getKeyword(), TL.getTemplateKeywordLoc(), Name, TL.getTemplateNameLoc(), NewTemplateArgs, /*AllowInjectedClassName=*/false); if (Result.isNull()) return QualType(); } - NestedNameSpecifierLoc QualifierLoc = SS.getWithLocInContext(SemaRef.Context); - if (const ElaboratedType *ElabT = dyn_cast(Result)) { - QualType NamedT = ElabT->getNamedType(); - - // Copy information relevant to the template specialization. - TemplateSpecializationTypeLoc NamedTL - = TLB.push(NamedT); - NamedTL.setTemplateKeywordLoc(TL.getTemplateKeywordLoc()); - NamedTL.setTemplateNameLoc(TL.getTemplateNameLoc()); - NamedTL.setLAngleLoc(TL.getLAngleLoc()); - NamedTL.setRAngleLoc(TL.getRAngleLoc()); - for (unsigned I = 0, E = NewTemplateArgs.size(); I != E; ++I) - NamedTL.setArgLocInfo(I, NewTemplateArgs[I].getLocInfo()); - - // Copy information relevant to the elaborated type. - ElaboratedTypeLoc NewTL = TLB.push(Result); - NewTL.setElaboratedKeywordLoc(TL.getElaboratedKeywordLoc()); - NewTL.setQualifierLoc(QualifierLoc); + QualifierLoc = SS.getWithLocInContext(SemaRef.Context); + if (isa(Result)) { + TLB.push(Result).set( + TL.getElaboratedKeywordLoc(), QualifierLoc, TL.getTemplateKeywordLoc(), + TL.getTemplateNameLoc(), NewTemplateArgs); } else { - assert(isa(Result)); - DependentTemplateSpecializationTypeLoc SpecTL - = TLB.push(Result); + auto SpecTL = TLB.push(Result); SpecTL.setElaboratedKeywordLoc(TL.getElaboratedKeywordLoc()); SpecTL.setQualifierLoc(QualifierLoc); SpecTL.setTemplateKeywordLoc(TL.getTemplateKeywordLoc()); @@ -8584,14 +8443,18 @@ TreeTransform::TransformDeclStmt(DeclStmt *S) { DeclChanged = true; if (LSI) { - if (auto *TD = dyn_cast(Transformed)) - LSI->ContainsUnexpandedParameterPack |= - getSema() - .getASTContext() - .getTypeDeclType(TD) - .getSingleStepDesugaredType(getSema().getASTContext()) - ->containsUnexpandedParameterPack(); - + if (auto *TD = dyn_cast(Transformed)) { + if (auto *TN = dyn_cast(TD)) { + LSI->ContainsUnexpandedParameterPack |= + TN->getUnderlyingType()->containsUnexpandedParameterPack(); + } else { + LSI->ContainsUnexpandedParameterPack |= + getSema() + .getASTContext() + .getTypeDeclType(TD) + ->containsUnexpandedParameterPack(); + } + } if (auto *VD = dyn_cast(Transformed)) LSI->ContainsUnexpandedParameterPack |= VD->getType()->containsUnexpandedParameterPack(); @@ -14295,7 +14158,7 @@ TreeTransform::TransformCXXTypeidExpr(CXXTypeidExpr *E) { auto EvalCtx = Sema::ExpressionEvaluationContext::Unevaluated; if (E->isGLValue()) if (auto *RecordT = Op->getType()->getAs()) - if (cast(RecordT->getDecl())->isPolymorphic()) + if (cast(RecordT->getOriginalDecl())->isPolymorphic()) EvalCtx = SemaRef.ExprEvalContexts.back().Context; EnterExpressionEvaluationContext Unevaluated(SemaRef, EvalCtx, @@ -14535,7 +14398,8 @@ TreeTransform::TransformCXXNewExpr(CXXNewExpr *E) { QualType ElementType = SemaRef.Context.getBaseElementType(E->getAllocatedType()); if (const RecordType *RecordT = ElementType->getAs()) { - CXXRecordDecl *Record = cast(RecordT->getDecl()); + CXXRecordDecl *Record = cast(RecordT->getOriginalDecl()) + ->getDefinitionOrSelf(); if (CXXDestructorDecl *Destructor = SemaRef.LookupDestructor(Record)) { SemaRef.MarkFunctionReferenced(E->getBeginLoc(), Destructor); } @@ -14605,7 +14469,9 @@ TreeTransform::TransformCXXDeleteExpr(CXXDeleteExpr *E) { QualType Destroyed = SemaRef.Context.getBaseElementType( E->getDestroyedType()); if (const RecordType *DestroyedRec = Destroyed->getAs()) { - CXXRecordDecl *Record = cast(DestroyedRec->getDecl()); + CXXRecordDecl *Record = + cast(DestroyedRec->getOriginalDecl()) + ->getDefinitionOrSelf(); SemaRef.MarkFunctionReferenced(E->getBeginLoc(), SemaRef.LookupDestructor(Record)); } @@ -14649,9 +14515,9 @@ TreeTransform::TransformCXXPseudoDestructorExpr( PseudoDestructorTypeStorage Destroyed; if (E->getDestroyedTypeInfo()) { - TypeSourceInfo *DestroyedTypeInfo - = getDerived().TransformTypeInObjectScope(E->getDestroyedTypeInfo(), - ObjectType, nullptr, SS); + TypeSourceInfo *DestroyedTypeInfo = getDerived().TransformTypeInObjectScope( + E->getDestroyedTypeInfo(), ObjectType, + /*FirstQualifierInScope=*/nullptr); if (!DestroyedTypeInfo) return ExprError(); Destroyed = DestroyedTypeInfo; @@ -14675,9 +14541,8 @@ TreeTransform::TransformCXXPseudoDestructorExpr( TypeSourceInfo *ScopeTypeInfo = nullptr; if (E->getScopeTypeInfo()) { - CXXScopeSpec EmptySS; ScopeTypeInfo = getDerived().TransformTypeInObjectScope( - E->getScopeTypeInfo(), ObjectType, nullptr, EmptySS); + E->getScopeTypeInfo(), ObjectType, nullptr); if (!ScopeTypeInfo) return ExprError(); } @@ -15798,10 +15663,6 @@ TreeTransform::TransformLambdaExpr(LambdaExpr *E) { // parameters are dependent. DependencyKind = getDerived().ComputeLambdaDependency(&LSICopy); Class->setLambdaDependencyKind(DependencyKind); - // Clean up the type cache created previously. Then, we re-create a type for - // such Decl with the new DependencyKind. - Class->setTypeForDecl(nullptr); - getSema().Context.getTypeDeclType(Class); return getDerived().RebuildLambdaExpr(E->getBeginLoc(), Body.get()->getEndLoc(), &LSICopy); @@ -17304,9 +17165,10 @@ QualType TreeTransform::RebuildFunctionNoProtoType(QualType T) { return SemaRef.Context.getFunctionNoProtoType(T); } -template -QualType TreeTransform::RebuildUnresolvedUsingType(SourceLocation Loc, - Decl *D) { +template +QualType TreeTransform::RebuildUnresolvedUsingType( + ElaboratedTypeKeyword Keyword, NestedNameSpecifier Qualifier, + SourceLocation NameLoc, Decl *D) { assert(D && "no decl found"); if (D->isInvalidDecl()) return QualType(); @@ -17316,7 +17178,7 @@ QualType TreeTransform::RebuildUnresolvedUsingType(SourceLocation Loc, // UsingDecls, but they must each have exactly one type, and it must be // the same type in every case. But we must have at least one expansion! if (UPD->expansions().empty()) { - getSema().Diag(Loc, diag::err_using_pack_expansion_empty) + getSema().Diag(NameLoc, diag::err_using_pack_expansion_empty) << UPD->isCXXClassMember() << UPD; return QualType(); } @@ -17327,10 +17189,11 @@ QualType TreeTransform::RebuildUnresolvedUsingType(SourceLocation Loc, QualType FallbackT; QualType T; for (auto *E : UPD->expansions()) { - QualType ThisT = RebuildUnresolvedUsingType(Loc, E); + QualType ThisT = + RebuildUnresolvedUsingType(Keyword, Qualifier, NameLoc, E); if (ThisT.isNull()) continue; - else if (ThisT->getAs()) + if (ThisT->getAs()) FallbackT = ThisT; else if (T.isNull()) T = ThisT; @@ -17339,7 +17202,8 @@ QualType TreeTransform::RebuildUnresolvedUsingType(SourceLocation Loc, "mismatched resolved types in using pack expansion"); } return T.isNull() ? FallbackT : T; - } else if (auto *Using = dyn_cast(D)) { + } + if (auto *Using = dyn_cast(D)) { assert(Using->hasTypename() && "UnresolvedUsingTypenameDecl transformed to non-typename using"); @@ -17347,17 +17211,14 @@ QualType TreeTransform::RebuildUnresolvedUsingType(SourceLocation Loc, assert(++Using->shadow_begin() == Using->shadow_end()); UsingShadowDecl *Shadow = *Using->shadow_begin(); - if (SemaRef.DiagnoseUseOfDecl(Shadow->getTargetDecl(), Loc)) + if (SemaRef.DiagnoseUseOfDecl(Shadow->getTargetDecl(), NameLoc)) return QualType(); - return SemaRef.Context.getUsingType( - Shadow, SemaRef.Context.getTypeDeclType( - cast(Shadow->getTargetDecl()))); - } else { - assert(isa(D) && - "UnresolvedUsingTypenameDecl transformed to non-using decl"); - return SemaRef.Context.getTypeDeclType( - cast(D)); + return SemaRef.Context.getUsingType(Keyword, Qualifier, Shadow); } + assert(isa(D) && + "UnresolvedUsingTypenameDecl transformed to non-using decl"); + return SemaRef.Context.getUnresolvedUsingType( + Keyword, Qualifier, cast(D)); } template @@ -17393,12 +17254,12 @@ QualType TreeTransform::RebuildUnaryTransformType(QualType BaseType, return SemaRef.BuildUnaryTransformType(BaseType, UKind, Loc); } -template +template QualType TreeTransform::RebuildTemplateSpecializationType( - TemplateName Template, - SourceLocation TemplateNameLoc, - TemplateArgumentListInfo &TemplateArgs) { - return SemaRef.CheckTemplateIdType(Template, TemplateNameLoc, TemplateArgs); + ElaboratedTypeKeyword Keyword, TemplateName Template, + SourceLocation TemplateNameLoc, TemplateArgumentListInfo &TemplateArgs) { + return SemaRef.CheckTemplateIdType(Keyword, Template, TemplateNameLoc, + TemplateArgs); } template @@ -17441,15 +17302,10 @@ TreeTransform::RebuildTemplateName(CXXScopeSpec &SS, TemplateName(Template)); } -template -TemplateName -TreeTransform::RebuildTemplateName(CXXScopeSpec &SS, - SourceLocation TemplateKWLoc, - const IdentifierInfo &Name, - SourceLocation NameLoc, - QualType ObjectType, - NamedDecl *FirstQualifierInScope, - bool AllowInjectedClassName) { +template +TemplateName TreeTransform::RebuildTemplateName( + CXXScopeSpec &SS, SourceLocation TemplateKWLoc, const IdentifierInfo &Name, + SourceLocation NameLoc, QualType ObjectType, bool AllowInjectedClassName) { UnqualifiedId TemplateName; TemplateName.setIdentifier(&Name, NameLoc); Sema::TemplateTy Template; @@ -17591,15 +17447,16 @@ TreeTransform::RebuildCXXPseudoDestructorExpr(Expr *Base, NameInfo.setNamedTypeInfo(DestroyedType); // The scope type is now known to be a valid nested name specifier - // component. Tack it on to the end of the nested name specifier. + // component. Tack it on to the nested name specifier. if (ScopeType) { - if (!ScopeType->getType()->getAs()) { + if (!isa(ScopeType->getType().getCanonicalType())) { getSema().Diag(ScopeType->getTypeLoc().getBeginLoc(), diag::err_expected_class_or_namespace) << ScopeType->getType() << getSema().getLangOpts().CPlusPlus; return ExprError(); } - SS.Extend(SemaRef.Context, ScopeType->getTypeLoc(), CCLoc); + SS.clear(); + SS.Make(SemaRef.Context, ScopeType->getTypeLoc(), CCLoc); } SourceLocation TemplateKWLoc; // FIXME: retrieve it from caller.