Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,9 @@ AST Dumping Potentially Breaking Changes

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

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

Expand Down
76 changes: 41 additions & 35 deletions clang/lib/Sema/SemaDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5503,48 +5503,54 @@ InjectAnonymousStructOrUnionMembers(Sema &SemaRef, Scope *S, DeclContext *Owner,
if ((isa<FieldDecl>(D) || isa<IndirectFieldDecl>(D)) &&
cast<NamedDecl>(D)->getDeclName()) {
ValueDecl *VD = cast<ValueDecl>(D);
if (CheckAnonMemberRedeclaration(SemaRef, S, Owner, VD->getDeclName(),
VD->getLocation(), AnonRecord->isUnion(),
SC)) {
// C++ [class.union]p2:
// The names of the members of an anonymous union shall be
// distinct from the names of any other entity in the
// scope in which the anonymous union is declared.
// C++ [class.union]p2:
// The names of the members of an anonymous union shall be
// distinct from the names of any other entity in the
// scope in which the anonymous union is declared.

bool FieldInvalid = CheckAnonMemberRedeclaration(
SemaRef, S, Owner, VD->getDeclName(), VD->getLocation(),
AnonRecord->isUnion(), SC);
if (FieldInvalid)
Invalid = true;
} else {
// C++ [class.union]p2:
// For the purpose of name lookup, after the anonymous union
// definition, the members of the anonymous union are
// considered to have been defined in the scope in which the
// anonymous union is declared.
unsigned OldChainingSize = Chaining.size();
if (IndirectFieldDecl *IF = dyn_cast<IndirectFieldDecl>(VD))
Chaining.append(IF->chain_begin(), IF->chain_end());
else
Chaining.push_back(VD);

assert(Chaining.size() >= 2);
NamedDecl **NamedChain =
new (SemaRef.Context)NamedDecl*[Chaining.size()];
for (unsigned i = 0; i < Chaining.size(); i++)
NamedChain[i] = Chaining[i];
// Inject the IndirectFieldDecl even if invalid, because later
// diagnostics may depend on it being present, see findDefaultInitializer.

// C++ [class.union]p2:
// For the purpose of name lookup, after the anonymous union
// definition, the members of the anonymous union are
// considered to have been defined in the scope in which the
// anonymous union is declared.
unsigned OldChainingSize = Chaining.size();
if (IndirectFieldDecl *IF = dyn_cast<IndirectFieldDecl>(VD))
Chaining.append(IF->chain_begin(), IF->chain_end());
else
Chaining.push_back(VD);

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

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

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

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

Chaining.resize(OldChainingSize);
}
// That includes picking up the appropriate access specifier.
if (AS != AS_none)
IndirectField->setAccess(AS);

Chaining.resize(OldChainingSize);
}
}

Expand Down
5 changes: 4 additions & 1 deletion clang/lib/Sema/SemaDeclCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7012,9 +7012,12 @@ void Sema::CheckCompletedCXXClass(Scope *S, CXXRecordDecl *Record) {
for (DeclContext::lookup_iterator I = R.begin(), E = R.end(); I != E;
++I) {
NamedDecl *D = (*I)->getUnderlyingDecl();
// Invalid IndirectFieldDecls have already been diagnosed with
// err_anonymous_record_member_redecl in
// SemaDecl.cpp:CheckAnonMemberRedeclaration.
if (((isa<FieldDecl>(D) || isa<UnresolvedUsingValueDecl>(D)) &&
Record->hasUserDeclaredConstructor()) ||
isa<IndirectFieldDecl>(D)) {
(isa<IndirectFieldDecl>(D) && !D->isInvalidDecl())) {
Diag((*I)->getLocation(), diag::err_member_name_of_class)
<< D->getDeclName();
break;
Expand Down
25 changes: 25 additions & 0 deletions clang/test/CXX/class/class.union/class.union.anon/p4.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,28 @@ union U {
int y = 1; // expected-error {{initializing multiple members of union}}
};
};

namespace GH149985 {
union X {
enum {
csize = 42,
cs = sizeof(int) // expected-note {{previous declaration is here}}
};
struct {
int data; // expected-note {{previous declaration is here}}
union X *cs[csize] = {}; // expected-error {{member of anonymous struct redeclares}} expected-note {{previous initialization is here}}
};
struct {
int data; // expected-error {{member of anonymous struct redeclares}}
union X *ds[2] = {}; // expected-error {{initializing multiple members of union}}
};
};

union U {
int x; // expected-note {{previous declaration is here}}
union {
int x = {}; // expected-error {{member of anonymous union redeclares}} expected-note {{previous initialization is here}}
};
int y = {}; // expected-error {{initializing multiple members of union}}
};
}