diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 9231f2cae9bfa..480c2bea8311a 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -50,12 +50,16 @@ ABI Changes in This Version AST Dumping Potentially Breaking Changes ---------------------------------------- +- How nested name specifiers are dumped and printed changes, keeping track of clang AST changes. Clang Frontend Potentially Breaking Changes ------------------------------------------- Clang Python Bindings Potentially Breaking Changes -------------------------------------------------- +- TypeKind ``ELABORATED`` is not used anymore, per clang AST changes removing + ElaboratedTypes. The value becomes unused, and all the existing users should + expect the former underlying type to be reported instead. What's New in Clang |release|? ============================== @@ -91,13 +95,13 @@ Non-comprehensive list of changes in this release ------------------------------------------------- - Added ``__builtin_elementwise_minnumnum`` and ``__builtin_elementwise_maxnumnum``. -- Trapping UBSan (e.g. ``-fsanitize-trap=undefined``) now emits a string describing the reason for - trapping into the generated debug info. This feature allows debuggers (e.g. LLDB) to display - the reason for trapping if the trap is reached. The string is currently encoded in the debug - info as an artificial frame that claims to be inlined at the trap location. The function used - for the artificial frame is an artificial function whose name encodes the reason for trapping. - The encoding used is currently the same as ``__builtin_verbose_trap`` but might change in the future. - This feature is enabled by default but can be disabled by compiling with +- Trapping UBSan (e.g. ``-fsanitize-trap=undefined``) now emits a string describing the reason for + trapping into the generated debug info. This feature allows debuggers (e.g. LLDB) to display + the reason for trapping if the trap is reached. The string is currently encoded in the debug + info as an artificial frame that claims to be inlined at the trap location. The function used + for the artificial frame is an artificial function whose name encodes the reason for trapping. + The encoding used is currently the same as ``__builtin_verbose_trap`` but might change in the future. + This feature is enabled by default but can be disabled by compiling with ``-fno-sanitize-annotate-debug-info-traps``. New Compiler Flags @@ -123,7 +127,7 @@ Improvements to Clang's diagnostics Moved the warning for a missing (though implied) attribute on a redeclaration into this group. Added a new warning in this group for the case where the attribute is missing/implicit on an override of a virtual method. -- Fixed fix-it hint for fold expressions. Clang now correctly places the suggested right +- Fixed fix-it hint for fold expressions. Clang now correctly places the suggested right parenthesis when diagnosing malformed fold expressions. (#GH151787) Improvements to Clang's time-trace @@ -163,6 +167,9 @@ Bug Fixes to C++ Support Bug Fixes to AST Handling ^^^^^^^^^^^^^^^^^^^^^^^^^ +- Fix incorrect name qualifiers applied to alias CTAD. (#GH136624) +- Fixed ElaboratedTypes appearing within NestedNameSpecifier, which was not a + legal representation. This is fixed because ElaboratedTypes don't exist anymore. (#GH43179) (#GH68670) (#GH92757) Miscellaneous Bug Fixes ^^^^^^^^^^^^^^^^^^^^^^^ @@ -232,6 +239,8 @@ Fixed Point Support in Clang AST Matchers ------------ +- Removed elaboratedType matchers, and related nested name specifier changes, + following the corresponding changes in the clang AST. - Ensure ``hasBitWidth`` doesn't crash on bit widths that are dependent on template parameters. @@ -256,7 +265,7 @@ New features Crash and bug fixes ^^^^^^^^^^^^^^^^^^^ -- Fixed a crash in the static analyzer that when the expression in an +- Fixed a crash in the static analyzer that when the expression in an ``[[assume(expr)]]`` attribute was enclosed in parentheses. (#GH151529) Improvements diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h index 99f54305d8ed6..fcc10498ae331 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::DenseMap @@ -1386,8 +1387,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: @@ -1767,34 +1766,53 @@ 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; - return getTypeDeclTypeSlow(Decl); - } + /// Use the normal 'getFooBarType' constructors to obtain these types. + QualType getTypeDeclType(const TagDecl *) const = delete; + QualType getTypeDeclType(const TypedefDecl *) const = delete; + QualType getTypeDeclType(const TypeAliasDecl *) const = delete; + QualType getTypeDeclType(const UnresolvedUsingTypenameDecl *) const = delete; - QualType getUsingType(const UsingShadowDecl *Found, - QualType Underlying) const; + CanQualType getCanonicalTypeDeclType(const TypeDecl *TD) 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. @@ -1843,10 +1861,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, @@ -1886,18 +1905,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, @@ -1908,9 +1929,6 @@ 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, const IdentifierInfo *Name) const; @@ -1999,21 +2017,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 /// . /// @@ -2089,7 +2103,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); @@ -2186,10 +2202,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 @@ -2202,7 +2219,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(); } @@ -2214,7 +2232,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(); } @@ -2226,7 +2245,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(); } @@ -2238,12 +2258,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; } @@ -2308,7 +2329,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 @@ -2318,7 +2340,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()); } PointerAuthQualifier getObjCMemberSelTypePtrAuth(); @@ -2332,7 +2355,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 @@ -2351,7 +2375,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. @@ -2365,7 +2390,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 @@ -2379,16 +2405,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); } /// Retrieve the implicitly-predeclared 'struct type_info' declaration. @@ -3159,7 +3186,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, @@ -3167,7 +3194,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 @@ -3185,23 +3212,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/ASTNodeTraverser.h b/clang/include/clang/AST/ASTNodeTraverser.h index 8ebabb2bde10d..1d846a1f9df35 100644 --- a/clang/include/clang/AST/ASTNodeTraverser.h +++ b/clang/include/clang/AST/ASTNodeTraverser.h @@ -510,7 +510,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 +772,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..d63cbf405fba1 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. diff --git a/clang/include/clang/AST/AbstractBasicReader.h b/clang/include/clang/AST/AbstractBasicReader.h index 0a2db9e205c7c..8f5fdc9d93c78 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( diff --git a/clang/include/clang/AST/AbstractBasicWriter.h b/clang/include/clang/AST/AbstractBasicWriter.h index c105bbbe45c92..fbbaba5f7327b 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); diff --git a/clang/include/clang/AST/CanonicalType.h b/clang/include/clang/AST/CanonicalType.h index 35db68971e029..10dab7fbdfa77 100644 --- a/clang/include/clang/AST/CanonicalType.h +++ b/clang/include/clang/AST/CanonicalType.h @@ -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 08fe1f881503b..f95a98d88adb9 100644 --- a/clang/include/clang/AST/Decl.h +++ b/clang/include/clang/AST/Decl.h @@ -3528,8 +3528,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; } @@ -3635,6 +3641,10 @@ class TypedefNameDecl : public TypeDecl, public Redeclarable { return isTransparentTagSlow(); } + // These types are created lazily, use the ASTContext methods to obtain them. + 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) { @@ -3754,14 +3764,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; @@ -3842,12 +3844,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. @@ -3888,6 +3884,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()); } @@ -3958,6 +3967,10 @@ class TagDecl : public TypeDecl, return getExtInfo()->TemplParamLists[i]; } + // These types are created lazily, use the ASTContext methods to obtain them. + const Type *getTypeForDecl() const = delete; + void setTypeForDecl(const Type *TD) = delete; + using TypeDecl::printName; void printName(raw_ostream &OS, const PrintingPolicy &Policy) const override; @@ -4087,6 +4100,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, @@ -4469,6 +4486,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. @@ -5299,6 +5320,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 33ae3d604020b..d9b222067c41b 100644 --- a/clang/include/clang/AST/DeclCXX.h +++ b/clang/include/clang/AST/DeclCXX.h @@ -545,20 +545,6 @@ class CXXRecordDecl : public RecordDecl { return const_cast(this)->getMostRecentDecl(); } - CXXRecordDecl *getMostRecentNonInjectedDecl() { - CXXRecordDecl *Recent = 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. @@ -566,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, @@ -1903,6 +1894,20 @@ class CXXRecordDecl : public RecordDecl { /// \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; 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 32de203f2d831..f298ed8b2f640 100644 --- a/clang/include/clang/AST/DeclTemplate.h +++ b/clang/include/clang/AST/DeclTemplate.h @@ -1898,14 +1898,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. @@ -2123,10 +2123,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) @@ -2143,7 +2146,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 * @@ -2160,12 +2163,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. @@ -2247,14 +2244,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; @@ -2289,8 +2282,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; }; @@ -2427,7 +2420,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 @@ -2441,7 +2434,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/DynamicRecursiveASTVisitor.h b/clang/include/clang/AST/DynamicRecursiveASTVisitor.h index 703cca22777ad..0bcd67322c7f6 100644 --- a/clang/include/clang/AST/DynamicRecursiveASTVisitor.h +++ b/clang/include/clang/AST/DynamicRecursiveASTVisitor.h @@ -181,14 +181,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 +273,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 +284,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/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/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/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h index 62991d986e675..05134422797b3 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. @@ -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" } @@ -975,10 +983,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; \ @@ -1087,9 +1098,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())); }) @@ -1115,13 +1135,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())); @@ -1130,13 +1144,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())); }) @@ -1165,22 +1172,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(DependentNameType, - { TRY_TO(TraverseNestedNameSpecifier(T->getQualifier())); }) +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, { + 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 +1260,16 @@ DEF_TRAVERSE_TYPE(PredefinedSugarType, {}) // 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()) \ @@ -1391,9 +1433,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 +1477,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 +1485,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 +1505,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())); }) @@ -1631,8 +1704,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 eb384eae3faa7..2050c4c7eddef 100644 --- a/clang/include/clang/AST/TemplateBase.h +++ b/clang/include/clang/AST/TemplateBase.h @@ -525,6 +525,10 @@ struct TemplateArgumentLocInfo { SourceLocation getTemplateEllipsisLoc() const { return getTemplate()->EllipsisLoc; } + +private: + llvm::PointerUnion + Pointer; }; /// Location wrapper for a TemplateArgument. TemplateArgument is to diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h index 12dce309127e5..2d35c72eb1bdd 100644 --- a/clang/include/clang/AST/Type.h +++ b/clang/include/clang/AST/Type.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 @@ -2305,13 +2329,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; @@ -5767,84 +5792,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; } @@ -5855,16 +6050,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; } }; @@ -6131,71 +6335,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. @@ -6806,34 +7087,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()); @@ -6864,7 +7149,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 @@ -6876,8 +7162,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: @@ -6978,241 +7264,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. /// @@ -9026,8 +9077,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 52ef7ac54145e..5394687f3b372 100644 --- a/clang/include/clang/AST/TypeLoc.h +++ b/clang/include/clang/AST/TypeLoc.h @@ -679,62 +679,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 +844,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 +854,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. @@ -1701,9 +1816,11 @@ struct TemplateNameLocInfo { }; struct TemplateSpecializationLocInfo : TemplateNameLocInfo { + SourceRange SR; + SourceLocation ElaboratedKWLoc; SourceLocation TemplateKWLoc; SourceLocation LAngleLoc; - SourceLocation RAngleLoc; + void *QualifierData; }; class TemplateSpecializationTypeLoc : @@ -1712,54 +1829,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)); + getArgInfos()[i]); } - SourceLocation getTemplateNameLoc() const { - return getLocalData()->NameLoc; - } - - 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 +1889,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 +2450,68 @@ 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(); + return getLocalData()->ElaboratedKWLoc; } void setElaboratedKeywordLoc(SourceLocation Loc) { - if (isEmpty()) { - assert(Loc.isInvalid()); - return; - } 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(); + assert(QualifierLoc.getNestedNameSpecifier() == + getTypePtr() + ->getTemplateName() + .getAsAdjustedQualifiedTemplateName() + ->getQualifier() && + "Inconsistent nested-name-specifier pointer"); + getLocalData()->QualifierData = QualifierLoc.getOpaqueData(); } 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(); - } - - 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 +2822,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 3373e963038f1..388f6dda4a6f0 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/include/clang/Basic/TypeNodes.td b/clang/include/clang/Basic/TypeNodes.td index 971ce541d4831..e4960ec660b90 100644 --- a/clang/include/clang/Basic/TypeNodes.td +++ b/clang/include/clang/Basic/TypeNodes.td @@ -90,7 +90,7 @@ def UnaryTransformType : TypeNode, NeverCanonicalUnlessDependent; def TagType : TypeNode; def RecordType : TypeNode, LeafType; def EnumType : TypeNode, LeafType; -def ElaboratedType : TypeNode, NeverCanonical; +def InjectedClassNameType : TypeNode, AlwaysDependent, LeafType; def AttributedType : TypeNode, NeverCanonical; def BTFTagAttributedType : TypeNode, NeverCanonical; def HLSLAttributedResourceType : TypeNode; @@ -102,7 +102,6 @@ def TemplateSpecializationType : TypeNode, NeverCanonicalUnlessDependent; def DeducedType : TypeNode; def AutoType : TypeNode; def DeducedTemplateSpecializationType : TypeNode; -def InjectedClassNameType : TypeNode, AlwaysDependent, LeafType; def DependentNameType : TypeNode, AlwaysDependent; def DependentTemplateSpecializationType : TypeNode, AlwaysDependent; def PackExpansionType : TypeNode, AlwaysDependent; diff --git a/clang/include/clang/Serialization/TypeBitCodes.def b/clang/include/clang/Serialization/TypeBitCodes.def index 613eb6af2005a..8af32db4c0b39 100644 --- a/clang/include/clang/Serialization/TypeBitCodes.def +++ b/clang/include/clang/Serialization/TypeBitCodes.def @@ -32,7 +32,6 @@ TYPE_BIT_CODE(Enum, ENUM, 20) TYPE_BIT_CODE(ObjCInterface, OBJC_INTERFACE, 21) TYPE_BIT_CODE(ObjCObjectPointer, OBJC_OBJECT_POINTER, 22) TYPE_BIT_CODE(Decltype, DECLTYPE, 23) -TYPE_BIT_CODE(Elaborated, ELABORATED, 24) TYPE_BIT_CODE(SubstTemplateTypeParm, SUBST_TEMPLATE_TYPE_PARM, 25) TYPE_BIT_CODE(UnresolvedUsing, UNRESOLVED_USING, 26) TYPE_BIT_CODE(InjectedClassName, INJECTED_CLASS_NAME, 27) diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 3a16111dd5f7d..3f95baf901ca7 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -2040,8 +2040,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; } @@ -2490,8 +2490,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()); @@ -2543,9 +2542,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()); @@ -2851,7 +2847,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(), @@ -3456,7 +3453,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; } @@ -3740,12 +3737,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)); @@ -5245,7 +5236,6 @@ ASTContext::getPredefinedSugarType(PredefinedSugarType::Kind KD) const { } llvm_unreachable("unexpected kind"); }; - auto *New = new (*this, alignof(PredefinedSugarType)) PredefinedSugarType(KD, &Idents.get(PredefinedSugarType::getName(KD)), getCanonicalType(*this, static_cast(KD))); @@ -5254,153 +5244,301 @@ ASTContext::getPredefinedSugarType(PredefinedSugarType::Kind KD) const { 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 sets, or having the folding setaccept 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); + } + + bool IsInjected = ::getNonInjectedClassName(TD); - if (const EnumDecl *PrevDecl = Decl->getPreviousDecl()) - if (PrevDecl->TypeForDecl) - return QualType(Decl->TypeForDecl = PrevDecl->TypeForDecl, 0); + llvm::FoldingSetNodeID ID; + TagTypeFoldingSetPlaceholder::Profile(ID, Keyword, Qualifier, TD, OwnsTag, + IsInjected); - auto *newType = new (*this, alignof(EnumType)) EnumType(Decl); - Decl->TypeForDecl = newType; - Types.push_back(newType); - return QualType(newType, 0); + 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, @@ -5495,21 +5633,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, @@ -5729,34 +5915,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 @@ -5787,7 +5971,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); @@ -5796,7 +5981,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!"); @@ -5806,7 +5992,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); @@ -5837,42 +6024,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; @@ -6062,7 +6219,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 @@ -6334,11 +6492,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 @@ -6737,20 +6895,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; @@ -6766,14 +6924,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 @@ -6823,15 +6987,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 . @@ -8418,7 +8573,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"); @@ -8433,14 +8588,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; } @@ -8454,7 +8610,7 @@ void ASTContext::setCFConstantStringType(QualType T) { QualType ASTContext::getBlockDescriptorType() const { if (BlockDescriptorType) - return getTagDeclType(BlockDescriptorType); + return getCanonicalTagType(BlockDescriptorType); RecordDecl *RD; // FIXME: Needs the FlagAppleBlock bit. @@ -8484,12 +8640,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. @@ -8523,7 +8679,7 @@ QualType ASTContext::getBlockDescriptorExtendedType() const { RD->completeDefinition(); BlockDescriptorExtendedType = RD; - return getTagDeclType(BlockDescriptorExtendedType); + return getCanonicalTagType(BlockDescriptorExtendedType); } OpenCLTypeKind ASTContext::getOpenCLTypeKind(const Type *T) const { @@ -9900,7 +10056,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"); @@ -9952,14 +10108,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); @@ -10011,7 +10168,7 @@ CreateX86_64ABIBuiltinVaListDecl(const ASTContext *Context) { } VaListTagDecl->completeDefinition(); Context->VaListTagDecl = VaListTagDecl; - QualType VaListTagType = Context->getRecordType(VaListTagDecl); + CanQualType VaListTagType = Context->getCanonicalTagType(VaListTagDecl); // }; @@ -10059,7 +10216,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"); } @@ -10106,7 +10263,7 @@ CreateSystemZBuiltinVaListDecl(const ASTContext *Context) { } VaListTagDecl->completeDefinition(); Context->VaListTagDecl = VaListTagDecl; - QualType VaListTagType = Context->getRecordType(VaListTagDecl); + CanQualType VaListTagType = Context->getCanonicalTagType(VaListTagDecl); // }; @@ -10153,13 +10310,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); @@ -10197,7 +10356,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 = @@ -10319,14 +10478,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); } @@ -13573,7 +13732,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()) @@ -13588,7 +13747,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); @@ -13596,7 +13755,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()); @@ -13611,7 +13770,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()) @@ -13657,7 +13816,7 @@ static TemplateArgument getCommonTemplateArgument(ASTContext &Ctx, } } -static bool getCommonTemplateArguments(ASTContext &Ctx, +static bool getCommonTemplateArguments(const ASTContext &Ctx, SmallVectorImpl &R, ArrayRef Xs, ArrayRef Ys) { @@ -13672,7 +13831,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; @@ -13856,11 +14015,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(); } @@ -13880,8 +14041,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) { @@ -13900,7 +14062,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. @@ -13964,7 +14126,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(); @@ -13982,10 +14144,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) @@ -14217,6 +14377,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), @@ -14244,7 +14405,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: { @@ -14260,7 +14421,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), @@ -14301,7 +14462,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(); @@ -14413,15 +14574,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); @@ -14465,16 +14617,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 @@ -14505,11 +14660,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), @@ -14568,7 +14724,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 2ef0c31ec1bd9..6049bfb64ebbe 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; } @@ -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); @@ -1164,6 +1159,7 @@ class TemplateDiff { 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 8e2927bdc8d6f..e5d4b103a6475 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -949,8 +949,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()); @@ -961,8 +963,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); @@ -1597,13 +1600,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) { @@ -1631,15 +1636,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) { @@ -1658,14 +1665,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) { @@ -1728,36 +1735,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) { @@ -1850,27 +1858,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 @@ -2643,7 +2632,7 @@ Error ASTNodeImporter::ImportDefinition( return Err; ExpectedType ToTypeOrErr = - import(Importer.getFromContext().getTypeDeclType(From)); + import(QualType(Importer.getFromContext().getCanonicalTagType(From))); if (!ToTypeOrErr) return ToTypeOrErr.takeError(); @@ -3428,17 +3417,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, @@ -3458,51 +3436,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 = @@ -3842,17 +3775,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 @@ -6521,16 +6448,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; @@ -10740,7 +10661,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 0e2023f86c19d..fff912d6b83cd 100644 --- a/clang/lib/AST/ASTStructuralEquivalence.cpp +++ b/clang/lib/AST/ASTStructuralEquivalence.cpp @@ -1206,23 +1206,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( @@ -1286,10 +1298,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); @@ -1348,33 +1370,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); @@ -1628,7 +1623,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. @@ -1801,7 +1796,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(); @@ -1903,7 +1898,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(); @@ -1924,7 +1919,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(); @@ -1940,7 +1935,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(); @@ -1962,7 +1957,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); @@ -1975,7 +1970,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); @@ -1989,7 +1984,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); @@ -2001,7 +1996,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) @@ -2013,7 +2008,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(), @@ -2024,7 +2019,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(); @@ -2041,7 +2036,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(); @@ -2101,7 +2096,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(D1->getLocation(), D1->isFixed() @@ -2124,7 +2119,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_incompatible_fixed_underlying_type) @@ -2162,7 +2157,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); @@ -2180,7 +2175,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); @@ -2198,7 +2193,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); @@ -2595,7 +2590,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) @@ -2617,10 +2612,6 @@ 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(); if (RecDecl->getDeclContext() == Owner && !RecDecl->getIdentifier()) { diff --git a/clang/lib/AST/ByteCode/Descriptor.cpp b/clang/lib/AST/ByteCode/Descriptor.cpp index 7403e90ce53db..837a1bbe5ba97 100644 --- a/clang/lib/AST/ByteCode/Descriptor.cpp +++ b/clang/lib/AST/ByteCode/Descriptor.cpp @@ -455,12 +455,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 f2366f674f45b..0d57e379f26a0 100644 --- a/clang/lib/AST/ByteCode/Interp.cpp +++ b/clang/lib/AST/ByteCode/Interp.cpp @@ -2009,7 +2009,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()) { @@ -2017,14 +2017,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 61e776965a006..9bbc99a2b0341 100644 --- a/clang/lib/AST/ByteCode/Interp.h +++ b/clang/lib/AST/ByteCode/Interp.h @@ -1764,10 +1764,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/InterpFrame.cpp b/clang/lib/AST/ByteCode/InterpFrame.cpp index d62a4f6275b50..2eb760048472d 100644 --- a/clang/lib/AST/ByteCode/InterpFrame.cpp +++ b/clang/lib/AST/ByteCode/InterpFrame.cpp @@ -164,7 +164,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 dec2088f1a423..febd2cba5b422 100644 --- a/clang/lib/AST/ByteCode/Pointer.cpp +++ b/clang/lib/AST/ByteCode/Pointer.cpp @@ -728,14 +728,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/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 88520d7940e34..285d01428a83f 100644 --- a/clang/lib/AST/CommentSema.cpp +++ b/clang/lib/AST/CommentSema.cpp @@ -905,17 +905,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 87334d98413e6..b492df98e0ac8 100644 --- a/clang/lib/AST/ComputeDependence.cpp +++ b/clang/lib/AST/ComputeDependence.cpp @@ -820,8 +820,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 +871,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 5471f31fb10e6..7eafdc7572f23 100644 --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -1693,9 +1693,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; @@ -2889,7 +2889,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()) @@ -4836,10 +4836,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()); } @@ -4867,25 +4863,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; } @@ -4919,7 +4906,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. @@ -4963,19 +4950,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 { @@ -5035,7 +5016,7 @@ EnumDecl *EnumDecl::getTemplateInstantiationPattern() const { EnumDecl *ED = getInstantiatedFromMemberEnum(); while (auto *NewED = ED->getInstantiatedFromMemberEnum()) ED = NewED; - return getDefinitionOrSelf(ED); + return ::getDefinitionOrSelf(ED); } } @@ -5125,21 +5106,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::isLambda() const { 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 037a28c4255f4..174c18d3724d2 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()) { @@ -2125,11 +2114,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); @@ -2159,6 +2147,29 @@ bool CXXRecordDecl::isInjectedClassName() const { 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()) @@ -2272,7 +2283,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); } } @@ -2284,7 +2295,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); } @@ -2712,8 +2723,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); } @@ -2733,8 +2743,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); } @@ -2769,7 +2778,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()); } @@ -3027,11 +3036,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? @@ -3066,15 +3073,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() {} @@ -3371,7 +3374,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 f4265dd07bd46..dc4457b4e449b 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()) { @@ -833,10 +820,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 +978,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 +1007,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 +1064,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 +1091,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)) { @@ -1746,7 +1721,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. @@ -1768,14 +1743,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 bc4a299e67f7c..8a6fb3391c13f 100644 --- a/clang/lib/AST/DeclTemplate.cpp +++ b/clang/lib/AST/DeclTemplate.cpp @@ -632,7 +632,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(); } @@ -651,28 +652,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; } //===----------------------------------------------------------------------===// @@ -998,7 +991,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 @@ -1008,17 +1000,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( @@ -1180,13 +1169,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(); } @@ -1196,24 +1187,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/DynamicRecursiveASTVisitor.cpp b/clang/lib/AST/DynamicRecursiveASTVisitor.cpp index b478e7a39ea18..f5c42b8fec1bc 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) { @@ -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" @@ -354,13 +358,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 cd9672d32a013..5bccce27c7dda 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -268,7 +268,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(); } @@ -3221,7 +3221,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); diff --git a/clang/lib/AST/ExprCXX.cpp b/clang/lib/AST/ExprCXX.cpp index a099e97d86c50..74ce7fb5c7164 100644 --- a/clang/lib/AST/ExprCXX.cpp +++ b/clang/lib/AST/ExprCXX.cpp @@ -1319,7 +1319,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); diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 3a47fa87b5f77..018e95719cf55 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -401,7 +401,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. @@ -4144,7 +4144,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)); } } } @@ -6342,7 +6342,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: @@ -6368,7 +6368,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; }; @@ -6865,8 +6865,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. @@ -8507,7 +8507,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(); } @@ -9236,8 +9236,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())); @@ -17985,7 +17985,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/InheritViz.cpp b/clang/lib/AST/InheritViz.cpp index 1dafed837a356..822fbc2ca78e8 100644 --- a/clang/lib/AST/InheritViz.cpp +++ b/clang/lib/AST/InheritViz.cpp @@ -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/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp index 5233648d8f9c8..f75ed4fc9b094 100644 --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -1334,6 +1334,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. @@ -2608,9 +2623,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; @@ -4471,7 +4483,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) { @@ -4780,7 +4792,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 @@ -5855,7 +5867,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; } @@ -6528,7 +6541,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; @@ -6895,7 +6908,7 @@ void CXXNameMangler::mangleValueInTemplateArg(QualType T, const APValue &V, } TypeSoFar = FD->getType(); } else { - TypeSoFar = Ctx.getRecordType(cast(D)); + TypeSoFar = Ctx.getCanonicalTagType(cast(D)); } } } diff --git a/clang/lib/AST/JSONNodeDumper.cpp b/clang/lib/AST/JSONNodeDumper.cpp index 64ddb1e739347..fdbd4479bb995 100644 --- a/clang/lib/AST/JSONNodeDumper.cpp +++ b/clang/lib/AST/JSONNodeDumper.cpp @@ -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( @@ -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()); } diff --git a/clang/lib/AST/MicrosoftMangle.cpp b/clang/lib/AST/MicrosoftMangle.cpp index e6ea0ada2e9ec..a78bf24792d23 100644 --- a/clang/lib/AST/MicrosoftMangle.cpp +++ b/clang/lib/AST/MicrosoftMangle.cpp @@ -1805,17 +1805,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()); @@ -2021,7 +2020,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. diff --git a/clang/lib/AST/NestedNameSpecifier.cpp b/clang/lib/AST/NestedNameSpecifier.cpp index 56f74b92412d2..872983f553e19 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" @@ -614,7 +613,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 bd87d4418484b..9812d26a61f05 100644 --- a/clang/lib/AST/ODRHash.cpp +++ b/clang/lib/AST/ODRHash.cpp @@ -907,52 +907,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); } @@ -1186,14 +1167,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()) { @@ -1211,6 +1195,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); } @@ -1247,12 +1233,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()); @@ -1330,7 +1310,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/QualTypeNames.cpp b/clang/lib/AST/QualTypeNames.cpp index 9731b3a1a3e3b..c77e3dd281b3a 100644 --- a/clang/lib/AST/QualTypeNames.cpp +++ b/clang/lib/AST/QualTypeNames.cpp @@ -434,45 +434,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 760b2fcdc0681..ad1d31a39cea6 100644 --- a/clang/lib/AST/RecordLayoutBuilder.cpp +++ b/clang/lib/AST/RecordLayoutBuilder.cpp @@ -2128,7 +2128,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 +2194,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 +2212,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 +2306,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 +2315,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) } } @@ -3273,7 +3273,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) } } @@ -3631,7 +3631,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()) @@ -3781,7 +3781,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 << "getQualifier()) - Node->getQualifier()->print(OS, Policy); + Node->getQualifier().print(OS, Policy); if (Node->hasTemplateKeyword()) OS << "template "; OS << Node->getNameInfo(); @@ -2509,8 +2508,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()) diff --git a/clang/lib/AST/TextNodeDumper.cpp b/clang/lib/AST/TextNodeDumper.cpp index 6b524cfcd2d71..edc705fa25a5f 100644 --- a/clang/lib/AST/TextNodeDumper.cpp +++ b/clang/lib/AST/TextNodeDumper.cpp @@ -2112,19 +2112,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) { @@ -2138,7 +2151,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) { @@ -2182,6 +2205,9 @@ 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"); } @@ -2792,16 +2818,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 141edc881d683..a944e8fa055d2 100644 --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -109,6 +109,8 @@ 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()) @@ -1272,9 +1274,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()) @@ -1989,10 +1988,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()); } @@ -3188,7 +3183,6 @@ bool Type::isSpecifierType() const { case TemplateTypeParm: case SubstTemplateTypeParm: case TemplateSpecialization: - case Elaborated: case DependentName: case DependentTemplateSpecialization: case ObjCInterface: @@ -3199,8 +3193,7 @@ bool Type::isSpecifierType() const { } } -ElaboratedTypeKeyword -TypeWithKeyword::getKeywordForTypeSpec(unsigned TypeSpec) { +ElaboratedTypeKeyword KeywordHelpers::getKeywordForTypeSpec(unsigned TypeSpec) { switch (TypeSpec) { default: return ElaboratedTypeKeyword::None; @@ -3219,7 +3212,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 +3230,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 +3247,7 @@ TypeWithKeyword::getKeywordForTagTypeKind(TagTypeKind Kind) { } TagTypeKind -TypeWithKeyword::getTagTypeKindForKeyword(ElaboratedTypeKeyword Keyword) { +KeywordHelpers::getTagTypeKindForKeyword(ElaboratedTypeKeyword Keyword) { switch (Keyword) { case ElaboratedTypeKeyword::Class: return TagTypeKind::Class; @@ -3273,7 +3266,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 +3281,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 +3331,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 +4012,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 +4232,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())); +} -bool TagType::isBeingDefined() const { return getDecl()->isBeingDefined(); } +NestedNameSpecifier TagType::getQualifier() const { + return TagTypeBits.HasQualifier ? getTrailingQualifier() : std::nullopt; +} + +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; @@ -4253,6 +4328,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 +4428,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 +4551,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; @@ -4726,12 +4811,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())); } @@ -4827,8 +4909,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; @@ -5291,7 +5373,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; } } @@ -5318,14 +5400,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..8704b7466a4f5 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(); @@ -565,15 +555,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 +577,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 +684,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; @@ -680,6 +733,14 @@ void AutoTypeLoc::initializeLocal(ASTContext &Context, SourceLocation Loc) { } } +void DeducedTemplateSpecializationTypeLoc::initializeLocal(ASTContext &Context, + SourceLocation Loc) { + initializeElaboratedKeyword(*this, Loc); + setQualifierLoc(initializeQualifier( + Context, getTypePtr()->getTemplateName().getQualifier(), Loc)); + setTemplateNameLoc(Loc); +} + namespace { class GetContainedAutoTypeLocVisitor : @@ -693,10 +754,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 deb453fe6ee75..f8082ab5b0db9 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: @@ -504,11 +503,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 << "*"; } @@ -1211,29 +1206,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, @@ -1354,14 +1370,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( @@ -1480,30 +1535,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(); @@ -1594,17 +1656,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(); @@ -1671,6 +1760,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. @@ -1680,7 +1773,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); @@ -1699,77 +1795,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); @@ -1791,9 +1816,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/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp index 0d70321335467..2bf4139c1928b 100644 --- a/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/clang/lib/Sema/SemaTemplateDeduction.cpp @@ -5607,7 +5607,7 @@ static TemplateDeductionResult CheckDeductionConsistency( bool IsDeductionGuide = isa(FTD->getTemplatedDecl()); if (IsDeductionGuide) { if (auto *Injected = P->getAs()) - P = Injected->getInjectedSpecializationType(); + P = Injected->getCanonicalInjectedTST(); } QualType InstP = S.SubstType(P.getCanonicalType(), MLTAL, FTD->getLocation(), FTD->getDeclName(), &IsIncompleteSubstitution); @@ -5627,9 +5627,9 @@ static TemplateDeductionResult CheckDeductionConsistency( auto T2 = S.Context.getUnqualifiedArrayType(A.getNonReferenceType()); if (IsDeductionGuide) { if (auto *Injected = T1->getAs()) - T1 = Injected->getInjectedSpecializationType(); + T1 = Injected->getCanonicalInjectedTST(); if (auto *Injected = T2->getAs()) - T2 = Injected->getInjectedSpecializationType(); + T2 = Injected->getCanonicalInjectedTST(); } if (!S.Context.hasSameType(T1, T2)) return TemplateDeductionResult::NonDeducedMismatch; diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 5ff5fbf52ae25..aab52c6121ba7 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -610,9 +610,9 @@ class TreeTransform { TemplateArgumentLoc &Output, bool Uneval = false); - TemplateArgument - TransformNamedTemplateTemplateArgument(CXXScopeSpec &SS, TemplateName Name, - SourceLocation NameLoc); + TemplateArgument TransformNamedTemplateTemplateArgument( + NestedNameSpecifierLoc &QualifierLoc, SourceLocation TemplateKeywordLoc, + TemplateName Name, SourceLocation NameLoc); /// Transform the given set of template arguments. /// @@ -697,20 +697,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. @@ -1020,16 +1017,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. @@ -1038,14 +1041,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. @@ -1094,10 +1097,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. @@ -1105,7 +1108,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); @@ -1117,41 +1121,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. @@ -1238,19 +1223,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. @@ -1303,7 +1283,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 @@ -1323,7 +1302,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 @@ -4012,8 +3990,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: @@ -4258,23 +4236,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, @@ -4849,8 +4833,10 @@ TreeTransform::TransformTemplateName(CXXScopeSpec &SS, template TemplateArgument TreeTransform::TransformNamedTemplateTemplateArgument( - CXXScopeSpec &SS, TemplateName Name, SourceLocation NameLoc) { - TemplateName TN = getDerived().TransformTemplateName(SS, Name, NameLoc); + NestedNameSpecifierLoc &QualifierLoc, SourceLocation TemplateKeywordLoc, + TemplateName Name, SourceLocation NameLoc) { + TemplateName TN = getDerived().TransformTemplateName( + QualifierLoc, TemplateKeywordLoc, Name, NameLoc); if (TN.isNull()) return TemplateArgument(); return TemplateArgument(TN); @@ -4945,8 +4931,8 @@ bool TreeTransform::TransformTemplateArgument( SS, Arg.getAsTemplate(), Input.getTemplateNameLoc()); if (Out.isNull()) return true; - Output = TemplateArgumentLoc(SemaRef.Context, Out, QualifierLoc, - Input.getTemplateNameLoc()); + Output = TemplateArgumentLoc(SemaRef.Context, Out, Input.getTemplateKWLoc(), + QualifierLoc, Input.getTemplateNameLoc()); return false; } @@ -5380,85 +5366,37 @@ 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(); +QualType TreeTransform::TransformTypeInObjectScope( + TypeLocBuilder &TLB, TypeLoc TL, QualType ObjectType, + NamedDecl *UnqualLookup) { + assert(!getDerived().AlreadyTransformed(TL.getType())); - TemplateName Template = getDerived().TransformTemplateName( - SS, SpecTL.getTypePtr()->getTemplateName(), SpecTL.getTemplateNameLoc(), - ObjectType, UnqualLookup, /*AllowInjectedClassName*/true); - if (Template.isNull()) - return nullptr; - - 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: + case TypeLoc::UnresolvedUsing: + case TypeLoc::Using: + 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 @@ -7011,76 +6949,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.setElaboratedKeywordLoc(TL.getElaboratedKeywordLoc()); 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 +7074,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) { @@ -7415,10 +7330,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 @@ -7428,8 +7342,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()); @@ -7438,132 +7352,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) { @@ -7774,13 +7570,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.setElaboratedKeywordLoc(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()); @@ -8590,14 +8392,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(); @@ -14685,9 +14491,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; @@ -14711,9 +14517,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(); } @@ -15834,10 +15639,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); @@ -17340,9 +17141,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(); @@ -17352,7 +17154,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(); } @@ -17363,10 +17165,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; @@ -17375,7 +17178,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"); @@ -17383,17 +17187,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 @@ -17429,12 +17230,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 @@ -17477,15 +17278,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; @@ -17627,15 +17423,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.