llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang Author: Matheus Izvekov (mizvekov) <details> <summary>Changes</summary> This fixes a bug in the fast path for the creation of TagTypes from injected class names. The creation of TagTypes has a fast path which, when there is no elaboration, uses storage in the declaration itself for memoizing the resuling type node, instead of using the folding set. This memoizing would fail when the type was created from the injected class name, as we would look for the node in the injected declaration but store it in the non-injected one, so a different type would be created each time. This regression was reported here: https://github.com/llvm/llvm-project/pull/147835#discussion_r2299248995 Since this regression was never released, there are no release notes. --- Full diff: https://github.com/llvm/llvm-project/pull/155347.diff 2 Files Affected: - (modified) clang/lib/AST/ASTContext.cpp (+20-21) - (modified) clang/test/AST/ast-dump-decl.cpp (+16-1) ``````````diff diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 036df53063568..edd512fa78e46 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -5474,18 +5474,15 @@ TagType *ASTContext::getTagTypeInternal(ElaboratedTypeKeyword Keyword, return T; } -static bool getNonInjectedClassName(const TagDecl *&TD) { +static const TagDecl *getNonInjectedClassName(const TagDecl *TD) { if (const auto *RD = dyn_cast<CXXRecordDecl>(TD); - RD && RD->isInjectedClassName()) { - TD = cast<TagDecl>(RD->getDeclContext()); - return true; - } - return false; + RD && RD->isInjectedClassName()) + return cast<TagDecl>(RD->getDeclContext()); + return TD; } CanQualType ASTContext::getCanonicalTagType(const TagDecl *TD) const { - ::getNonInjectedClassName(TD); - TD = TD->getCanonicalDecl(); + TD = ::getNonInjectedClassName(TD)->getCanonicalDecl(); if (TD->TypeForDecl) return TD->TypeForDecl->getCanonicalTypeUnqualified(); @@ -5501,40 +5498,42 @@ CanQualType ASTContext::getCanonicalTagType(const TagDecl *TD) const { QualType ASTContext::getTagType(ElaboratedTypeKeyword Keyword, NestedNameSpecifier Qualifier, const TagDecl *TD, bool OwnsTag) const { + + const TagDecl *NonInjectedTD = ::getNonInjectedClassName(TD); + bool IsInjected = TD != NonInjectedTD; + ElaboratedTypeKeyword PreferredKeyword = - getLangOpts().CPlusPlus - ? ElaboratedTypeKeyword::None - : KeywordHelpers::getKeywordForTagTypeKind(TD->getTagKind()); + getLangOpts().CPlusPlus ? ElaboratedTypeKeyword::None + : KeywordHelpers::getKeywordForTagTypeKind( + NonInjectedTD->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 *CanonicalType = getCanonicalTagType(NonInjectedTD).getTypePtr(); const Type *T = getTagTypeInternal(Keyword, - /*Qualifier=*/std::nullopt, TD, + /*Qualifier=*/std::nullopt, NonInjectedTD, /*OwnsTag=*/false, IsInjected, CanonicalType, /*WithFoldingSetNode=*/false); TD->TypeForDecl = T; return QualType(T, 0); } - bool IsInjected = ::getNonInjectedClassName(TD); - llvm::FoldingSetNodeID ID; - TagTypeFoldingSetPlaceholder::Profile(ID, Keyword, Qualifier, TD, OwnsTag, - IsInjected); + TagTypeFoldingSetPlaceholder::Profile(ID, Keyword, Qualifier, NonInjectedTD, + OwnsTag, IsInjected); void *InsertPos = nullptr; if (TagTypeFoldingSetPlaceholder *T = TagTypes.FindNodeOrInsertPos(ID, InsertPos)) return QualType(T->getTagType(), 0); - const Type *CanonicalType = getCanonicalTagType(TD).getTypePtr(); - TagType *T = getTagTypeInternal(Keyword, Qualifier, TD, OwnsTag, IsInjected, - CanonicalType, /*WithFoldingSetNode=*/true); + const Type *CanonicalType = getCanonicalTagType(NonInjectedTD).getTypePtr(); + TagType *T = + getTagTypeInternal(Keyword, Qualifier, NonInjectedTD, OwnsTag, IsInjected, + CanonicalType, /*WithFoldingSetNode=*/true); TagTypes.InsertNode(TagTypeFoldingSetPlaceholder::fromTagType(T), InsertPos); return QualType(T, 0); } diff --git a/clang/test/AST/ast-dump-decl.cpp b/clang/test/AST/ast-dump-decl.cpp index dca0e9b9ca10a..6cada93c8b93b 100644 --- a/clang/test/AST/ast-dump-decl.cpp +++ b/clang/test/AST/ast-dump-decl.cpp @@ -973,5 +973,20 @@ namespace TestConstexprVariableTemplateWithInitializer { // CHECK-NEXT: `-VarDecl 0x{{.+}} <col:25, col:48> col:37 call_init 'const T' constexpr callinit{{$}} // CHECK-NEXT: `-ParenListExpr 0x{{.+}} <col:46, col:48> 'NULL TYPE'{{$}} // CHECK-NEXT: `-IntegerLiteral 0x{{.+}} <col:47> 'int' 0{{$}} - } + +namespace TestInjectedClassName { + struct A { + using T1 = A; + using T2 = A; + }; + // CHECK-LABEL: Dumping TestInjectedClassName: + // CHECK: CXXRecordDecl [[TestInjectedClassName_RD:0x[^ ]+]] {{.*}} struct A definition + // CHECK: CXXRecordDecl {{.*}} implicit referenced struct A + // CHECK-NEXT: |-TypeAliasDecl {{.*}} T1 'A' + // CHECK-NEXT: | `-RecordType [[TestInjectedClassName_RT:0x[^ ]+]] 'A' injected + // CHECK-NEXT: | `-CXXRecord [[TestInjectedClassName_RD]] 'A' + // CHECK-NEXT: `-TypeAliasDecl {{.*}} T2 'A' + // CHECK-NEXT: `-RecordType [[TestInjectedClassName_RT]] 'A' injected + // CHECK-NEXT: `-CXXRecord [[TestInjectedClassName_RD]] 'A' +} // namespace InjectedClassName `````````` </details> https://github.com/llvm/llvm-project/pull/155347 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits