Skip to content

Commit a9e9ea5

Browse files
committed
[Clang] Correctly initialize placeholder fields from their initializers
We made the incorrect assumption that names of fields are unique when creating their default initializers. We fix that by keeping track of the instantiaation pattern for field decls that are placeholder vars, like we already do for unamed fields. Fixes #114069
1 parent e61a7dc commit a9e9ea5

File tree

8 files changed

+68
-17
lines changed

8 files changed

+68
-17
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -574,6 +574,7 @@ Bug Fixes to C++ Support
574574
(#GH95854).
575575
- Fixed an assertion failure when evaluating an invalid expression in an array initializer. (#GH112140)
576576
- Fixed an assertion failure in range calculations for conditional throw expressions. (#GH111854)
577+
- Name independent data members were not correctly initialized from default member initializers. (#GH114069)
577578

578579
Bug Fixes to AST Handling
579580
^^^^^^^^^^^^^^^^^^^^^^^^^

clang/include/clang/AST/ASTContext.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1037,7 +1037,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
10371037
void setInstantiatedFromUsingShadowDecl(UsingShadowDecl *Inst,
10381038
UsingShadowDecl *Pattern);
10391039

1040-
FieldDecl *getInstantiatedFromUnnamedFieldDecl(FieldDecl *Field);
1040+
FieldDecl *getInstantiatedFromUnnamedFieldDecl(FieldDecl *Field) const;
10411041

10421042
void setInstantiatedFromUnnamedFieldDecl(FieldDecl *Inst, FieldDecl *Tmpl);
10431043

clang/lib/AST/ASTContext.cpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1583,14 +1583,17 @@ ASTContext::setInstantiatedFromUsingShadowDecl(UsingShadowDecl *Inst,
15831583
InstantiatedFromUsingShadowDecl[Inst] = Pattern;
15841584
}
15851585

1586-
FieldDecl *ASTContext::getInstantiatedFromUnnamedFieldDecl(FieldDecl *Field) {
1586+
FieldDecl *
1587+
ASTContext::getInstantiatedFromUnnamedFieldDecl(FieldDecl *Field) const {
15871588
return InstantiatedFromUnnamedFieldDecl.lookup(Field);
15881589
}
15891590

15901591
void ASTContext::setInstantiatedFromUnnamedFieldDecl(FieldDecl *Inst,
15911592
FieldDecl *Tmpl) {
1592-
assert(!Inst->getDeclName() && "Instantiated field decl is not unnamed");
1593-
assert(!Tmpl->getDeclName() && "Template field decl is not unnamed");
1593+
assert((!Inst->getDeclName() || Inst->isPlaceholderVar(getLangOpts())) &&
1594+
"Instantiated field decl is not unnamed");
1595+
assert((!Inst->getDeclName() || Inst->isPlaceholderVar(getLangOpts())) &&
1596+
"Template field decl is not unnamed");
15941597
assert(!InstantiatedFromUnnamedFieldDecl[Inst] &&
15951598
"Already noted what unnamed field was instantiated from");
15961599

clang/lib/Sema/SemaExpr.cpp

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5560,6 +5560,25 @@ ExprResult Sema::BuildCXXDefaultArgExpr(SourceLocation CallLoc,
55605560
Init, InitializationContext->Context);
55615561
}
55625562

5563+
static FieldDecl *FindFieldDeclInstantiationPattern(const ASTContext &Ctx,
5564+
FieldDecl *Field) {
5565+
if (FieldDecl *Pattern = Ctx.getInstantiatedFromUnnamedFieldDecl(Field))
5566+
return Pattern;
5567+
auto *ParentRD = cast<CXXRecordDecl>(Field->getParent());
5568+
CXXRecordDecl *ClassPattern = ParentRD->getTemplateInstantiationPattern();
5569+
DeclContext::lookup_result Lookup =
5570+
ClassPattern->lookup(Field->getDeclName());
5571+
auto Rng = llvm::make_filter_range(Lookup, [] (auto && L) {
5572+
return isa<FieldDecl>(*L);
5573+
});
5574+
// FIXME: this breaks clang/test/Modules/pr28812.cpp
5575+
// assert(std::distance(Rng.begin(), Rng.end()) <= 1
5576+
// && "Duplicated instantiation pattern for field decl");
5577+
if(Rng.empty())
5578+
return nullptr;
5579+
return cast<FieldDecl>(*Rng.begin());
5580+
}
5581+
55635582
ExprResult Sema::BuildCXXDefaultInitExpr(SourceLocation Loc, FieldDecl *Field) {
55645583
assert(Field->hasInClassInitializer());
55655584

@@ -5588,15 +5607,8 @@ ExprResult Sema::BuildCXXDefaultInitExpr(SourceLocation Loc, FieldDecl *Field) {
55885607
// Maybe we haven't instantiated the in-class initializer. Go check the
55895608
// pattern FieldDecl to see if it has one.
55905609
if (isTemplateInstantiation(ParentRD->getTemplateSpecializationKind())) {
5591-
CXXRecordDecl *ClassPattern = ParentRD->getTemplateInstantiationPattern();
5592-
DeclContext::lookup_result Lookup =
5593-
ClassPattern->lookup(Field->getDeclName());
5594-
5595-
FieldDecl *Pattern = nullptr;
5596-
for (auto *L : Lookup) {
5597-
if ((Pattern = dyn_cast<FieldDecl>(L)))
5598-
break;
5599-
}
5610+
FieldDecl *Pattern =
5611+
FindFieldDeclInstantiationPattern(getASTContext(), Field);
56005612
assert(Pattern && "We must have set the Pattern!");
56015613
if (!Pattern->hasInClassInitializer() ||
56025614
InstantiateInClassInitializer(Loc, Field, Pattern,

clang/lib/Sema/SemaTemplateInstantiateDecl.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1346,7 +1346,7 @@ Decl *TemplateDeclInstantiator::VisitFieldDecl(FieldDecl *D) {
13461346
if (Invalid)
13471347
Field->setInvalidDecl();
13481348

1349-
if (!Field->getDeclName()) {
1349+
if (!Field->getDeclName() || Field->isPlaceholderVar(SemaRef.getLangOpts())) {
13501350
// Keep track of where this decl came from.
13511351
SemaRef.Context.setInstantiatedFromUnnamedFieldDecl(Field, D);
13521352
}

clang/lib/Serialization/ASTReaderDecl.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1539,7 +1539,8 @@ void ASTDeclReader::VisitFieldDecl(FieldDecl *FD) {
15391539
else if (Bits & 1)
15401540
FD->setBitWidth(Record.readExpr());
15411541

1542-
if (!FD->getDeclName()) {
1542+
if (!FD->getDeclName() ||
1543+
FD->isPlaceholderVar(Reader.getContext().getLangOpts())) {
15431544
if (auto *Tmpl = readDeclAs<FieldDecl>())
15441545
Reader.getContext().setInstantiatedFromUnnamedFieldDecl(FD, Tmpl);
15451546
}

clang/lib/Serialization/ASTWriterDecl.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1038,7 +1038,7 @@ void ASTDeclWriter::VisitFieldDecl(FieldDecl *D) {
10381038
else if (D->BitField)
10391039
Record.AddStmt(D->getBitWidth());
10401040

1041-
if (!D->getDeclName())
1041+
if (!D->getDeclName() || D->isPlaceholderVar(Writer.getLangOpts()))
10421042
Record.AddDeclRef(Context.getInstantiatedFromUnnamedFieldDecl(D));
10431043

10441044
if (D->getDeclContext() == D->getLexicalDeclContext() &&

clang/test/SemaCXX/cxx2c-placeholder-vars.cpp

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %clang -cc1 -fsyntax-only -verify -std=c++2c -Wunused-parameter -Wunused -Wpre-c++26-compat %s
1+
// RUN: %clang_cc1 -fsyntax-only -verify -ast-dump -std=c++2c -Wunused-parameter -Wunused -Wpre-c++26-compat %s | FileCheck %s
22

33
void static_var() {
44
static int _; // expected-note {{previous definition is here}} \
@@ -254,3 +254,37 @@ namespace Bases {
254254
}
255255
};
256256
}
257+
258+
namespace GH114069 {
259+
260+
template <class T>
261+
struct A {
262+
T _ = 1;
263+
T _ = 2;
264+
T : 1;
265+
T a = 3;
266+
T _ = 4;
267+
};
268+
269+
void f() {
270+
[[maybe_unused]] A<int> a;
271+
}
272+
273+
// CHECK: NamespaceDecl {{.*}} GH114069
274+
// CHECK: ClassTemplateSpecializationDecl {{.*}} struct A definition
275+
// CHECK: CXXConstructorDecl {{.*}} implicit used constexpr A 'void () noexcept'
276+
// CHECK-NEXT: CXXCtorInitializer Field {{.*}} '_' 'int'
277+
// CHECK-NEXT: CXXDefaultInitExpr {{.*}} 'int' has rewritten init
278+
// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 1
279+
// CHECK-NEXT: CXXCtorInitializer Field {{.*}} '_' 'int'
280+
// CHECK-NEXT: CXXDefaultInitExpr {{.*}} 'int' has rewritten init
281+
// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 2
282+
// CHECK-NEXT: CXXCtorInitializer Field {{.*}} 'a' 'int'
283+
// CHECK-NEXT: CXXDefaultInitExpr {{.*}} 'int' has rewritten init
284+
// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 3
285+
// CHECK-NEXT: CXXCtorInitializer Field {{.*}} '_' 'int'
286+
// CHECK-NEXT: CXXDefaultInitExpr {{.*}} 'int' has rewritten init
287+
// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 4
288+
// CHECK-NEXT: CompoundStmt {{.*}}
289+
290+
}

0 commit comments

Comments
 (0)