Skip to content

Commit 0a675f5

Browse files
authored
[clang] fix uniquing of some TagTypes created from the injected class name (#155347)
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.
1 parent 07b2ba2 commit 0a675f5

File tree

2 files changed

+36
-22
lines changed

2 files changed

+36
-22
lines changed

clang/lib/AST/ASTContext.cpp

Lines changed: 20 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -5474,18 +5474,15 @@ TagType *ASTContext::getTagTypeInternal(ElaboratedTypeKeyword Keyword,
54745474
return T;
54755475
}
54765476

5477-
static bool getNonInjectedClassName(const TagDecl *&TD) {
5477+
static const TagDecl *getNonInjectedClassName(const TagDecl *TD) {
54785478
if (const auto *RD = dyn_cast<CXXRecordDecl>(TD);
5479-
RD && RD->isInjectedClassName()) {
5480-
TD = cast<TagDecl>(RD->getDeclContext());
5481-
return true;
5482-
}
5483-
return false;
5479+
RD && RD->isInjectedClassName())
5480+
return cast<TagDecl>(RD->getDeclContext());
5481+
return TD;
54845482
}
54855483

54865484
CanQualType ASTContext::getCanonicalTagType(const TagDecl *TD) const {
5487-
::getNonInjectedClassName(TD);
5488-
TD = TD->getCanonicalDecl();
5485+
TD = ::getNonInjectedClassName(TD)->getCanonicalDecl();
54895486
if (TD->TypeForDecl)
54905487
return TD->TypeForDecl->getCanonicalTypeUnqualified();
54915488

@@ -5501,40 +5498,42 @@ CanQualType ASTContext::getCanonicalTagType(const TagDecl *TD) const {
55015498
QualType ASTContext::getTagType(ElaboratedTypeKeyword Keyword,
55025499
NestedNameSpecifier Qualifier,
55035500
const TagDecl *TD, bool OwnsTag) const {
5501+
5502+
const TagDecl *NonInjectedTD = ::getNonInjectedClassName(TD);
5503+
bool IsInjected = TD != NonInjectedTD;
5504+
55045505
ElaboratedTypeKeyword PreferredKeyword =
5505-
getLangOpts().CPlusPlus
5506-
? ElaboratedTypeKeyword::None
5507-
: KeywordHelpers::getKeywordForTagTypeKind(TD->getTagKind());
5506+
getLangOpts().CPlusPlus ? ElaboratedTypeKeyword::None
5507+
: KeywordHelpers::getKeywordForTagTypeKind(
5508+
NonInjectedTD->getTagKind());
55085509

55095510
if (Keyword == PreferredKeyword && !Qualifier && !OwnsTag) {
55105511
if (const Type *T = TD->TypeForDecl; T && !T->isCanonicalUnqualified())
55115512
return QualType(T, 0);
55125513

5513-
bool IsInjected = ::getNonInjectedClassName(TD);
5514-
const Type *CanonicalType = getCanonicalTagType(TD).getTypePtr();
5514+
const Type *CanonicalType = getCanonicalTagType(NonInjectedTD).getTypePtr();
55155515
const Type *T =
55165516
getTagTypeInternal(Keyword,
5517-
/*Qualifier=*/std::nullopt, TD,
5517+
/*Qualifier=*/std::nullopt, NonInjectedTD,
55185518
/*OwnsTag=*/false, IsInjected, CanonicalType,
55195519
/*WithFoldingSetNode=*/false);
55205520
TD->TypeForDecl = T;
55215521
return QualType(T, 0);
55225522
}
55235523

5524-
bool IsInjected = ::getNonInjectedClassName(TD);
5525-
55265524
llvm::FoldingSetNodeID ID;
5527-
TagTypeFoldingSetPlaceholder::Profile(ID, Keyword, Qualifier, TD, OwnsTag,
5528-
IsInjected);
5525+
TagTypeFoldingSetPlaceholder::Profile(ID, Keyword, Qualifier, NonInjectedTD,
5526+
OwnsTag, IsInjected);
55295527

55305528
void *InsertPos = nullptr;
55315529
if (TagTypeFoldingSetPlaceholder *T =
55325530
TagTypes.FindNodeOrInsertPos(ID, InsertPos))
55335531
return QualType(T->getTagType(), 0);
55345532

5535-
const Type *CanonicalType = getCanonicalTagType(TD).getTypePtr();
5536-
TagType *T = getTagTypeInternal(Keyword, Qualifier, TD, OwnsTag, IsInjected,
5537-
CanonicalType, /*WithFoldingSetNode=*/true);
5533+
const Type *CanonicalType = getCanonicalTagType(NonInjectedTD).getTypePtr();
5534+
TagType *T =
5535+
getTagTypeInternal(Keyword, Qualifier, NonInjectedTD, OwnsTag, IsInjected,
5536+
CanonicalType, /*WithFoldingSetNode=*/true);
55385537
TagTypes.InsertNode(TagTypeFoldingSetPlaceholder::fromTagType(T), InsertPos);
55395538
return QualType(T, 0);
55405539
}

clang/test/AST/ast-dump-decl.cpp

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -973,5 +973,20 @@ namespace TestConstexprVariableTemplateWithInitializer {
973973
// CHECK-NEXT: `-VarDecl 0x{{.+}} <col:25, col:48> col:37 call_init 'const T' constexpr callinit{{$}}
974974
// CHECK-NEXT: `-ParenListExpr 0x{{.+}} <col:46, col:48> 'NULL TYPE'{{$}}
975975
// CHECK-NEXT: `-IntegerLiteral 0x{{.+}} <col:47> 'int' 0{{$}}
976-
977976
}
977+
978+
namespace TestInjectedClassName {
979+
struct A {
980+
using T1 = A;
981+
using T2 = A;
982+
};
983+
// CHECK-LABEL: Dumping TestInjectedClassName:
984+
// CHECK: CXXRecordDecl [[TestInjectedClassName_RD:0x[^ ]+]] {{.*}} struct A definition
985+
// CHECK: CXXRecordDecl {{.*}} implicit referenced struct A
986+
// CHECK-NEXT: |-TypeAliasDecl {{.*}} T1 'A'
987+
// CHECK-NEXT: | `-RecordType [[TestInjectedClassName_RT:0x[^ ]+]] 'A' injected
988+
// CHECK-NEXT: | `-CXXRecord [[TestInjectedClassName_RD]] 'A'
989+
// CHECK-NEXT: `-TypeAliasDecl {{.*}} T2 'A'
990+
// CHECK-NEXT: `-RecordType [[TestInjectedClassName_RT]] 'A' injected
991+
// CHECK-NEXT: `-CXXRecord [[TestInjectedClassName_RD]] 'A'
992+
} // namespace InjectedClassName

0 commit comments

Comments
 (0)