Skip to content

Commit af96ed6

Browse files
authored
[clang] Inject IndirectFieldDecl even if name conflicts. (#153140)
This modifies InjectAnonymousStructOrUnionMembers to inject an IndirectFieldDecl and mark it invalid even if its name conflicts with another name in the scope. This resolves a crash on a further diagnostic diag::err_multiple_mem_union_initialization which via findDefaultInitializer relies on these declarations being present. Fixes #149985
1 parent 2c20a9b commit af96ed6

File tree

4 files changed

+75
-36
lines changed

4 files changed

+75
-36
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,9 @@ AST Dumping Potentially Breaking Changes
7777

7878
Clang Frontend Potentially Breaking Changes
7979
-------------------------------------------
80+
- Members of anonymous unions/structs are now injected as ``IndirectFieldDecl``
81+
into the enclosing record even if their names conflict with other names in the
82+
scope. These ``IndirectFieldDecl`` are marked invalid.
8083

8184
Clang Python Bindings Potentially Breaking Changes
8285
--------------------------------------------------
@@ -217,6 +220,8 @@ Bug Fixes to C++ Support
217220
- Fix the dynamic_cast to final class optimization to correctly handle
218221
casts that are guaranteed to fail (#GH137518).
219222
- Fix bug rejecting partial specialization of variable templates with auto NTTPs (#GH118190).
223+
- Fix a crash if errors "member of anonymous [...] redeclares" and
224+
"intializing multiple members of union" coincide (#GH149985).
220225
- Fix a crash when using ``explicit(bool)`` in pre-C++11 language modes. (#GH152729)
221226
- Fix the parsing of variadic member functions when the ellipis immediately follows a default argument.(#GH153445)
222227

clang/lib/Sema/SemaDecl.cpp

Lines changed: 41 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -5503,48 +5503,54 @@ InjectAnonymousStructOrUnionMembers(Sema &SemaRef, Scope *S, DeclContext *Owner,
55035503
if ((isa<FieldDecl>(D) || isa<IndirectFieldDecl>(D)) &&
55045504
cast<NamedDecl>(D)->getDeclName()) {
55055505
ValueDecl *VD = cast<ValueDecl>(D);
5506-
if (CheckAnonMemberRedeclaration(SemaRef, S, Owner, VD->getDeclName(),
5507-
VD->getLocation(), AnonRecord->isUnion(),
5508-
SC)) {
5509-
// C++ [class.union]p2:
5510-
// The names of the members of an anonymous union shall be
5511-
// distinct from the names of any other entity in the
5512-
// scope in which the anonymous union is declared.
5506+
// C++ [class.union]p2:
5507+
// The names of the members of an anonymous union shall be
5508+
// distinct from the names of any other entity in the
5509+
// scope in which the anonymous union is declared.
5510+
5511+
bool FieldInvalid = CheckAnonMemberRedeclaration(
5512+
SemaRef, S, Owner, VD->getDeclName(), VD->getLocation(),
5513+
AnonRecord->isUnion(), SC);
5514+
if (FieldInvalid)
55135515
Invalid = true;
5514-
} else {
5515-
// C++ [class.union]p2:
5516-
// For the purpose of name lookup, after the anonymous union
5517-
// definition, the members of the anonymous union are
5518-
// considered to have been defined in the scope in which the
5519-
// anonymous union is declared.
5520-
unsigned OldChainingSize = Chaining.size();
5521-
if (IndirectFieldDecl *IF = dyn_cast<IndirectFieldDecl>(VD))
5522-
Chaining.append(IF->chain_begin(), IF->chain_end());
5523-
else
5524-
Chaining.push_back(VD);
55255516

5526-
assert(Chaining.size() >= 2);
5527-
NamedDecl **NamedChain =
5528-
new (SemaRef.Context)NamedDecl*[Chaining.size()];
5529-
for (unsigned i = 0; i < Chaining.size(); i++)
5530-
NamedChain[i] = Chaining[i];
5517+
// Inject the IndirectFieldDecl even if invalid, because later
5518+
// diagnostics may depend on it being present, see findDefaultInitializer.
5519+
5520+
// C++ [class.union]p2:
5521+
// For the purpose of name lookup, after the anonymous union
5522+
// definition, the members of the anonymous union are
5523+
// considered to have been defined in the scope in which the
5524+
// anonymous union is declared.
5525+
unsigned OldChainingSize = Chaining.size();
5526+
if (IndirectFieldDecl *IF = dyn_cast<IndirectFieldDecl>(VD))
5527+
Chaining.append(IF->chain_begin(), IF->chain_end());
5528+
else
5529+
Chaining.push_back(VD);
55315530

5532-
IndirectFieldDecl *IndirectField = IndirectFieldDecl::Create(
5533-
SemaRef.Context, Owner, VD->getLocation(), VD->getIdentifier(),
5534-
VD->getType(), {NamedChain, Chaining.size()});
5531+
assert(Chaining.size() >= 2);
5532+
NamedDecl **NamedChain =
5533+
new (SemaRef.Context) NamedDecl *[Chaining.size()];
5534+
for (unsigned i = 0; i < Chaining.size(); i++)
5535+
NamedChain[i] = Chaining[i];
55355536

5536-
for (const auto *Attr : VD->attrs())
5537-
IndirectField->addAttr(Attr->clone(SemaRef.Context));
5537+
IndirectFieldDecl *IndirectField = IndirectFieldDecl::Create(
5538+
SemaRef.Context, Owner, VD->getLocation(), VD->getIdentifier(),
5539+
VD->getType(), {NamedChain, Chaining.size()});
55385540

5539-
IndirectField->setAccess(AS);
5540-
IndirectField->setImplicit();
5541-
SemaRef.PushOnScopeChains(IndirectField, S);
5541+
for (const auto *Attr : VD->attrs())
5542+
IndirectField->addAttr(Attr->clone(SemaRef.Context));
55425543

5543-
// That includes picking up the appropriate access specifier.
5544-
if (AS != AS_none) IndirectField->setAccess(AS);
5544+
IndirectField->setAccess(AS);
5545+
IndirectField->setImplicit();
5546+
IndirectField->setInvalidDecl(FieldInvalid);
5547+
SemaRef.PushOnScopeChains(IndirectField, S);
55455548

5546-
Chaining.resize(OldChainingSize);
5547-
}
5549+
// That includes picking up the appropriate access specifier.
5550+
if (AS != AS_none)
5551+
IndirectField->setAccess(AS);
5552+
5553+
Chaining.resize(OldChainingSize);
55485554
}
55495555
}
55505556

clang/lib/Sema/SemaDeclCXX.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7012,9 +7012,12 @@ void Sema::CheckCompletedCXXClass(Scope *S, CXXRecordDecl *Record) {
70127012
for (DeclContext::lookup_iterator I = R.begin(), E = R.end(); I != E;
70137013
++I) {
70147014
NamedDecl *D = (*I)->getUnderlyingDecl();
7015+
// Invalid IndirectFieldDecls have already been diagnosed with
7016+
// err_anonymous_record_member_redecl in
7017+
// SemaDecl.cpp:CheckAnonMemberRedeclaration.
70157018
if (((isa<FieldDecl>(D) || isa<UnresolvedUsingValueDecl>(D)) &&
70167019
Record->hasUserDeclaredConstructor()) ||
7017-
isa<IndirectFieldDecl>(D)) {
7020+
(isa<IndirectFieldDecl>(D) && !D->isInvalidDecl())) {
70187021
Diag((*I)->getLocation(), diag::err_member_name_of_class)
70197022
<< D->getDeclName();
70207023
break;

clang/test/CXX/class/class.union/class.union.anon/p4.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,28 @@ union U {
88
int y = 1; // expected-error {{initializing multiple members of union}}
99
};
1010
};
11+
12+
namespace GH149985 {
13+
union X {
14+
enum {
15+
csize = 42,
16+
cs = sizeof(int) // expected-note {{previous declaration is here}}
17+
};
18+
struct {
19+
int data; // expected-note {{previous declaration is here}}
20+
union X *cs[csize] = {}; // expected-error {{member of anonymous struct redeclares}} expected-note {{previous initialization is here}}
21+
};
22+
struct {
23+
int data; // expected-error {{member of anonymous struct redeclares}}
24+
union X *ds[2] = {}; // expected-error {{initializing multiple members of union}}
25+
};
26+
};
27+
28+
union U {
29+
int x; // expected-note {{previous declaration is here}}
30+
union {
31+
int x = {}; // expected-error {{member of anonymous union redeclares}} expected-note {{previous initialization is here}}
32+
};
33+
int y = {}; // expected-error {{initializing multiple members of union}}
34+
};
35+
}

0 commit comments

Comments
 (0)