-
Notifications
You must be signed in to change notification settings - Fork 14.9k
[clang] fix uniquing of some TagTypes created from the injected class name #155347
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
… name 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: #147835 (comment) Since this regression was never released, there are no release notes.
@llvm/pr-subscribers-clang Author: Matheus Izvekov (mizvekov) ChangesThis 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: #147835 (comment) 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:
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
|
This commit breaks some of our internal tests that were working fine with the original #147835 I don't have the repro yet and I am not sure of an easy way to extract it from internal code. Pasting logs that I have right now in case you could figure anything out from this:
|
I don't think that helps, however the patch is a bit simple, so you could maybe sort of reverse engineer what could have gone wrong from it. For example, before this patch we would have produced non-identical CXXRecordTypes from basically the same information. |
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: #147835 (comment)
Since this regression was never released, there are no release notes.