Skip to content

Commit e48d8f9

Browse files
authored
[Clang] Correctly initialize placeholder fields from their initializers (#114196)
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 a165bbd commit e48d8f9

File tree

8 files changed

+67
-17
lines changed

8 files changed

+67
-17
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -591,6 +591,7 @@ Bug Fixes to C++ Support
591591
- Clang now correctly ignores previous partial specializations of member templates explicitly specialized for
592592
an implicitly instantiated class template specialization. (#GH51051)
593593
- Fixed an assertion failure caused by invalid enum forward declarations. (#GH112208)
594+
- Name independent data members were not correctly initialized from default member initializers. (#GH114069)
594595

595596
Bug Fixes to AST Handling
596597
^^^^^^^^^^^^^^^^^^^^^^^^^

clang/include/clang/AST/ASTContext.h

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

1044-
FieldDecl *getInstantiatedFromUnnamedFieldDecl(FieldDecl *Field);
1044+
FieldDecl *getInstantiatedFromUnnamedFieldDecl(FieldDecl *Field) const;
10451045

10461046
void setInstantiatedFromUnnamedFieldDecl(FieldDecl *Inst, FieldDecl *Tmpl);
10471047

clang/lib/AST/ASTContext.cpp

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

1595-
FieldDecl *ASTContext::getInstantiatedFromUnnamedFieldDecl(FieldDecl *Field) {
1595+
FieldDecl *
1596+
ASTContext::getInstantiatedFromUnnamedFieldDecl(FieldDecl *Field) const {
15961597
return InstantiatedFromUnnamedFieldDecl.lookup(Field);
15971598
}
15981599

15991600
void ASTContext::setInstantiatedFromUnnamedFieldDecl(FieldDecl *Inst,
16001601
FieldDecl *Tmpl) {
1601-
assert(!Inst->getDeclName() && "Instantiated field decl is not unnamed");
1602-
assert(!Tmpl->getDeclName() && "Template field decl is not unnamed");
1602+
assert((!Inst->getDeclName() || Inst->isPlaceholderVar(getLangOpts())) &&
1603+
"Instantiated field decl is not unnamed");
1604+
assert((!Inst->getDeclName() || Inst->isPlaceholderVar(getLangOpts())) &&
1605+
"Template field decl is not unnamed");
16031606
assert(!InstantiatedFromUnnamedFieldDecl[Inst] &&
16041607
"Already noted what unnamed field was instantiated from");
16051608

clang/lib/Sema/SemaExpr.cpp

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5560,6 +5560,24 @@ 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(
5572+
Lookup, [](auto &&L) { return isa<FieldDecl>(*L); });
5573+
if (Rng.empty())
5574+
return nullptr;
5575+
// FIXME: this breaks clang/test/Modules/pr28812.cpp
5576+
// assert(std::distance(Rng.begin(), Rng.end()) <= 1
5577+
// && "Duplicated instantiation pattern for field decl");
5578+
return cast<FieldDecl>(*Rng.begin());
5579+
}
5580+
55635581
ExprResult Sema::BuildCXXDefaultInitExpr(SourceLocation Loc, FieldDecl *Field) {
55645582
assert(Field->hasInClassInitializer());
55655583

@@ -5588,15 +5606,8 @@ ExprResult Sema::BuildCXXDefaultInitExpr(SourceLocation Loc, FieldDecl *Field) {
55885606
// Maybe we haven't instantiated the in-class initializer. Go check the
55895607
// pattern FieldDecl to see if it has one.
55905608
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-
}
5609+
FieldDecl *Pattern =
5610+
FindFieldDeclInstantiationPattern(getASTContext(), Field);
56005611
assert(Pattern && "We must have set the Pattern!");
56015612
if (!Pattern->hasInClassInitializer() ||
56025613
InstantiateInClassInitializer(Loc, Field, Pattern,

clang/lib/Sema/SemaTemplateInstantiateDecl.cpp

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

1355-
if (!Field->getDeclName()) {
1355+
if (!Field->getDeclName() || Field->isPlaceholderVar(SemaRef.getLangOpts())) {
13561356
// Keep track of where this decl came from.
13571357
SemaRef.Context.setInstantiatedFromUnnamedFieldDecl(Field, D);
13581358
}

clang/lib/Serialization/ASTReaderDecl.cpp

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

1550-
if (!FD->getDeclName()) {
1550+
if (!FD->getDeclName() ||
1551+
FD->isPlaceholderVar(Reader.getContext().getLangOpts())) {
15511552
if (auto *Tmpl = readDeclAs<FieldDecl>())
15521553
Reader.getContext().setInstantiatedFromUnnamedFieldDecl(FD, Tmpl);
15531554
}

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)