[clang] af96ed6 - [clang] Inject IndirectFieldDecl even if name conflicts. (#153140)
via cfe-commits
cfe-commits at lists.llvm.org
Fri Aug 15 09:43:32 PDT 2025
Author: keinflue
Date: 2025-08-15T09:43:29-07:00
New Revision: af96ed6bf6e6a1ba0cbb36cb3925dd44f41c301e
URL: https://github.com/llvm/llvm-project/commit/af96ed6bf6e6a1ba0cbb36cb3925dd44f41c301e
DIFF: https://github.com/llvm/llvm-project/commit/af96ed6bf6e6a1ba0cbb36cb3925dd44f41c301e.diff
LOG: [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
Added:
Modified:
clang/docs/ReleaseNotes.rst
clang/lib/Sema/SemaDecl.cpp
clang/lib/Sema/SemaDeclCXX.cpp
clang/test/CXX/class/class.union/class.union.anon/p4.cpp
Removed:
################################################################################
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 42571a833ded5..604b4c3f714b7 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -77,6 +77,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
--------------------------------------------------
@@ -217,6 +220,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)
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 6581d4c604eb2..5001e080f946b 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -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);
}
}
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 0477d37cac4c5..dd66a5f15a970 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -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;
diff --git a/clang/test/CXX/class/class.union/class.union.anon/p4.cpp b/clang/test/CXX/class/class.union/class.union.anon/p4.cpp
index a12ec38503fa8..f124ac1052b7e 100644
--- a/clang/test/CXX/class/class.union/class.union.anon/p4.cpp
+++ b/clang/test/CXX/class/class.union/class.union.anon/p4.cpp
@@ -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}}
+ };
+}
More information about the cfe-commits
mailing list