From 374aefc8116013196137309777baec6bd64a2483 Mon Sep 17 00:00:00 2001 From: Matheus Izvekov Date: Thu, 10 Jul 2025 14:03:40 -0300 Subject: [PATCH] [PATCH 1/4] [clang] Improve nested name specifier AST representation This is a major change on how we represent nested name qualifications in the AST. * The nested name specifier itself and how it's stored is changed. The prefixes for types are handled within the type hierarchy, which makes canonicalization for them super cheap, no memory allocation required. Also translating a type into nested name specifier form becomes a no-op. An identifier is stored as a DependentNameType. The nested name specifier gains a lightweight handle class, to be used instead of passing around pointers, which is similar to what is implemented for TemplateName. There is still one free bit available, and this handle can be used within a PointerUnion and PointerIntPair, which should keep bit-packing aficionados happy. * The ElaboratedType node is removed, all type nodes in which it could previously apply to can now store the elaborated keyword and name qualifier, tail allocating when present. * TagTypes can now point to the exact declaration found when producing these, as opposed to the previous situation of there only existing one TagType per entity. This increases the amount of type sugar retained, and can have several applications, for example in tracking module ownership, and other tools which care about source file origins, such as IWYU. These TagTypes are lazily allocated, in order to limit the increase in AST size. This patch offers a great performance benefit. It greatly improves compilation time for [stdexec](https://github.com/NVIDIA/stdexec). For one datapoint, for `test_on2.cpp` in that project, which is the slowest compiling test, this patch improves `-c` compilation time by about 7.2%, with the `-fsyntax-only` improvement being at ~12%. This has great results on compile-time-tracker as well: ![image](https://github.com/user-attachments/assets/700dce98-2cab-4aa8-97d1-b038c0bee831) This patch also further enables other optimziations in the future, and will reduce the performance impact of template specialization resugaring when that lands. It has some other miscelaneous drive-by fixes. About the review: Yes the patch is huge, sorry about that. Part of the reason is that I started by the nested name specifier part, before the ElaboratedType part, but that had a huge performance downside, as ElaboratedType is a big performance hog. I didn't have the steam to go back and change the patch after the fact. There is also a lot of internal API changes, and it made sense to remove ElaboratedType in one go, versus removing it from one type at a time, as that would present much more churn to the users. Also, the nested name specifier having a different API avoids missing changes related to how prefixes work now, which could make existing code compile but not work. How to review: The important changes are all in `clang/include/clang/AST` and `clang/lib/AST`, with also important changes in `clang/lib/Sema/TreeTransform.h`. The rest and bulk of the changes are mostly consequences of the changes in API. PS: TagType::getDecl is renamed to `getOriginalDecl` in this patch, just for easier to rebasing. I plan to rename it back after this lands. Fixes #136624 Fixes #147000 --- clang/include/clang/AST/ASTConcept.h | 9 +- clang/include/clang/AST/ASTContext.h | 201 ++- clang/include/clang/AST/ASTImporter.h | 2 +- clang/include/clang/AST/ASTNodeTraverser.h | 23 +- clang/include/clang/AST/ASTTypeTraits.h | 15 +- clang/include/clang/AST/AbstractBasicReader.h | 44 +- clang/include/clang/AST/AbstractBasicWriter.h | 38 +- clang/include/clang/AST/CanonicalType.h | 11 +- clang/include/clang/AST/Decl.h | 97 +- clang/include/clang/AST/DeclBase.h | 10 - clang/include/clang/AST/DeclCXX.h | 93 +- clang/include/clang/AST/DeclObjC.h | 3 + clang/include/clang/AST/DeclTemplate.h | 44 +- clang/include/clang/AST/DependenceFlags.h | 2 +- .../clang/AST/DynamicRecursiveASTVisitor.h | 13 +- clang/include/clang/AST/Expr.h | 4 +- clang/include/clang/AST/ExprCXX.h | 8 +- clang/include/clang/AST/JSONNodeDumper.h | 1 - clang/include/clang/AST/NestedNameSpecifier.h | 692 ++++------ .../clang/AST/NestedNameSpecifierBase.h | 585 +++++++++ clang/include/clang/AST/ODRHash.h | 2 +- clang/include/clang/AST/PrettyPrinter.h | 11 +- clang/include/clang/AST/PropertiesBase.td | 6 +- clang/include/clang/AST/RecursiveASTVisitor.h | 282 +++-- clang/include/clang/AST/TemplateBase.h | 40 +- clang/include/clang/AST/TemplateName.h | 30 +- clang/include/clang/AST/TextNodeDumper.h | 2 +- clang/include/clang/AST/Type.h | 770 ++++++------ clang/include/clang/AST/TypeLoc.h | 408 +++--- clang/include/clang/AST/TypeProperties.td | 140 +-- clang/lib/AST/APValue.cpp | 3 +- clang/lib/AST/ASTConcept.cpp | 11 +- clang/lib/AST/ASTContext.cpp | 1112 +++++++++-------- clang/lib/AST/ASTDiagnostic.cpp | 49 +- clang/lib/AST/ASTDumper.cpp | 4 +- clang/lib/AST/ASTImporter.cpp | 308 ++--- clang/lib/AST/ASTImporterLookupTable.cpp | 16 +- clang/lib/AST/ASTStructuralEquivalence.cpp | 181 ++- clang/lib/AST/ASTTypeTraits.cpp | 36 +- clang/lib/AST/ByteCode/Compiler.cpp | 9 +- clang/lib/AST/ByteCode/Context.cpp | 2 +- clang/lib/AST/ByteCode/Descriptor.cpp | 8 +- clang/lib/AST/ByteCode/Interp.cpp | 8 +- clang/lib/AST/ByteCode/Interp.h | 5 +- clang/lib/AST/ByteCode/InterpBuiltin.cpp | 7 +- clang/lib/AST/ByteCode/InterpFrame.cpp | 2 +- clang/lib/AST/ByteCode/Pointer.cpp | 7 +- clang/lib/AST/ByteCode/Program.cpp | 7 +- clang/lib/AST/ByteCode/Record.cpp | 2 +- clang/lib/AST/CXXInheritance.cpp | 16 +- clang/lib/AST/Comment.cpp | 2 - clang/lib/AST/CommentSema.cpp | 14 +- clang/lib/AST/ComparisonCategories.cpp | 2 +- clang/lib/AST/ComputeDependence.cpp | 26 +- clang/lib/AST/Decl.cpp | 115 +- clang/lib/AST/DeclBase.cpp | 40 +- clang/lib/AST/DeclCXX.cpp | 134 +- clang/lib/AST/DeclPrinter.cpp | 60 +- clang/lib/AST/DeclTemplate.cpp | 72 +- clang/lib/AST/DeclarationName.cpp | 6 +- clang/lib/AST/DynamicRecursiveASTVisitor.cpp | 53 +- clang/lib/AST/Expr.cpp | 25 +- clang/lib/AST/ExprCXX.cpp | 9 +- clang/lib/AST/ExprConcepts.cpp | 4 +- clang/lib/AST/ExprConstant.cpp | 69 +- clang/lib/AST/FormatString.cpp | 10 +- clang/lib/AST/InheritViz.cpp | 6 +- clang/lib/AST/ItaniumCXXABI.cpp | 8 +- clang/lib/AST/ItaniumMangle.cpp | 205 ++- clang/lib/AST/JSONNodeDumper.cpp | 36 +- clang/lib/AST/MicrosoftMangle.cpp | 21 +- clang/lib/AST/NestedNameSpecifier.cpp | 523 ++------ clang/lib/AST/ODRHash.cpp | 127 +- clang/lib/AST/OpenMPClause.cpp | 26 +- clang/lib/AST/ParentMapContext.cpp | 6 +- clang/lib/AST/PrintfFormatString.cpp | 2 +- clang/lib/AST/QualTypeNames.cpp | 370 +++--- clang/lib/AST/RecordLayoutBuilder.cpp | 27 +- clang/lib/AST/ScanfFormatString.cpp | 5 +- clang/lib/AST/StmtPrinter.cpp | 33 +- clang/lib/AST/StmtProfile.cpp | 15 +- clang/lib/AST/TemplateBase.cpp | 32 +- clang/lib/AST/TemplateName.cpp | 49 +- clang/lib/AST/TextNodeDumper.cpp | 82 +- clang/lib/AST/Type.cpp | 471 ++++--- clang/lib/AST/TypeLoc.cpp | 236 +++- clang/lib/AST/TypePrinter.cpp | 261 ++-- clang/lib/AST/VTTBuilder.cpp | 12 +- clang/lib/AST/VTableBuilder.cpp | 8 +- clang/lib/Sema/TreeTransform.h | 983 +++++++-------- 90 files changed, 4908 insertions(+), 4656 deletions(-) create mode 100644 clang/include/clang/AST/NestedNameSpecifierBase.h 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.