Skip to content

Commit ac30780

Browse files
committed
[clang] Fix false positive -Wmissing-field-initializer for anonymous unions
Normally warning is not reported when a field has default initializer. Do so for anonymous unions with default initializers as well. No release note since it is a regression in clang 18. Fixes #70384
1 parent 6be0e97 commit ac30780

File tree

2 files changed

+122
-43
lines changed

2 files changed

+122
-43
lines changed

clang/lib/Sema/SemaInit.cpp

Lines changed: 57 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -349,17 +349,13 @@ class InitListChecker {
349349
bool SubobjectIsDesignatorContext, unsigned &Index,
350350
InitListExpr *StructuredList,
351351
unsigned &StructuredIndex);
352-
bool CheckDesignatedInitializer(const InitializedEntity &Entity,
353-
InitListExpr *IList, DesignatedInitExpr *DIE,
354-
unsigned DesigIdx,
355-
QualType &CurrentObjectType,
356-
RecordDecl::field_iterator *NextField,
357-
llvm::APSInt *NextElementIndex,
358-
unsigned &Index,
359-
InitListExpr *StructuredList,
360-
unsigned &StructuredIndex,
361-
bool FinishSubobjectInit,
362-
bool TopLevelObject);
352+
bool CheckDesignatedInitializer(
353+
const InitializedEntity &Entity, InitListExpr *IList,
354+
DesignatedInitExpr *DIE, unsigned DesigIdx, QualType &CurrentObjectType,
355+
RecordDecl::field_iterator *NextField, llvm::APSInt *NextElementIndex,
356+
unsigned &Index, InitListExpr *StructuredList, unsigned &StructuredIndex,
357+
bool FinishSubobjectInit, bool TopLevelObject,
358+
llvm::SmallPtrSetImpl<FieldDecl *> *InitializedFields = nullptr);
363359
InitListExpr *getStructuredSubobjectInit(InitListExpr *IList, unsigned Index,
364360
QualType CurrentObjectType,
365361
InitListExpr *StructuredList,
@@ -2248,15 +2244,15 @@ void InitListChecker::CheckStructUnionTypes(
22482244
// the next field that we'll be initializing.
22492245
bool DesignatedInitFailed = CheckDesignatedInitializer(
22502246
Entity, IList, DIE, 0, DeclType, &Field, nullptr, Index,
2251-
StructuredList, StructuredIndex, true, TopLevelObject);
2247+
StructuredList, StructuredIndex, true, TopLevelObject,
2248+
&InitializedFields);
22522249
if (DesignatedInitFailed)
22532250
hadError = true;
22542251

22552252
// Find the field named by the designated initializer.
22562253
DesignatedInitExpr::Designator *D = DIE->getDesignator(0);
22572254
if (!VerifyOnly && D->isFieldDesignator()) {
22582255
FieldDecl *F = D->getFieldDecl();
2259-
InitializedFields.insert(F);
22602256
if (!DesignatedInitFailed) {
22612257
QualType ET = SemaRef.Context.getBaseElementType(F->getType());
22622258
if (checkDestructorReference(ET, InitLoc, SemaRef)) {
@@ -2365,21 +2361,43 @@ void InitListChecker::CheckStructUnionTypes(
23652361
!RD->isUnion()) {
23662362
// It is possible we have one or more unnamed bitfields remaining.
23672363
// Find first (if any) named field and emit warning.
2368-
for (RecordDecl::field_iterator it = HasDesignatedInit ? RD->field_begin()
2369-
: Field,
2370-
end = RD->field_end();
2371-
it != end; ++it) {
2372-
if (HasDesignatedInit && InitializedFields.count(*it))
2373-
continue;
2364+
auto MissingFieldCheck = [&](const RecordDecl *Record,
2365+
RecordDecl::field_iterator StartField,
2366+
auto &&MissingFieldCheck) -> bool {
2367+
FieldDecl *FirstUninitialized = nullptr;
2368+
for (RecordDecl::field_iterator it = StartField,
2369+
end = Record->field_end();
2370+
it != end; ++it) {
2371+
bool AllSet = false;
2372+
if (it->isAnonymousStructOrUnion()) {
2373+
RecordDecl *RDAnon = it->getType()->getAsRecordDecl();
2374+
AllSet = MissingFieldCheck(RDAnon, RDAnon->field_begin(),
2375+
MissingFieldCheck);
2376+
}
2377+
2378+
if ((HasDesignatedInit && InitializedFields.count(*it)) ||
2379+
it->hasInClassInitializer() || AllSet) {
2380+
if (Record->isUnion())
2381+
return true;
2382+
continue;
2383+
}
23742384

2375-
if (!it->isUnnamedBitfield() && !it->hasInClassInitializer() &&
2376-
!it->getType()->isIncompleteArrayType()) {
2385+
if (!it->isUnnamedBitfield() &&
2386+
!it->getType()->isIncompleteArrayType() &&
2387+
!it->isAnonymousStructOrUnion() && !FirstUninitialized)
2388+
FirstUninitialized = *it;
2389+
}
2390+
2391+
if (FirstUninitialized) {
23772392
SemaRef.Diag(IList->getSourceRange().getEnd(),
23782393
diag::warn_missing_field_initializers)
2379-
<< *it;
2380-
break;
2394+
<< FirstUninitialized;
2395+
return false;
23812396
}
2382-
}
2397+
return true;
2398+
};
2399+
MissingFieldCheck(RD, HasDesignatedInit ? RD->field_begin() : Field,
2400+
MissingFieldCheck);
23832401
}
23842402

23852403
// Check that any remaining fields can be value-initialized if we're not
@@ -2537,19 +2555,13 @@ class FieldInitializerValidatorCCC final : public CorrectionCandidateCallback {
25372555
/// actually be initialized.
25382556
///
25392557
/// @returns true if there was an error, false otherwise.
2540-
bool
2541-
InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
2542-
InitListExpr *IList,
2543-
DesignatedInitExpr *DIE,
2544-
unsigned DesigIdx,
2545-
QualType &CurrentObjectType,
2546-
RecordDecl::field_iterator *NextField,
2547-
llvm::APSInt *NextElementIndex,
2548-
unsigned &Index,
2549-
InitListExpr *StructuredList,
2550-
unsigned &StructuredIndex,
2551-
bool FinishSubobjectInit,
2552-
bool TopLevelObject) {
2558+
bool InitListChecker::CheckDesignatedInitializer(
2559+
const InitializedEntity &Entity, InitListExpr *IList,
2560+
DesignatedInitExpr *DIE, unsigned DesigIdx, QualType &CurrentObjectType,
2561+
RecordDecl::field_iterator *NextField, llvm::APSInt *NextElementIndex,
2562+
unsigned &Index, InitListExpr *StructuredList, unsigned &StructuredIndex,
2563+
bool FinishSubobjectInit, bool TopLevelObject,
2564+
llvm::SmallPtrSetImpl<FieldDecl *> *InitializedFields) {
25532565
if (DesigIdx == DIE->size()) {
25542566
// C++20 designated initialization can result in direct-list-initialization
25552567
// of the designated subobject. This is the only way that we can end up
@@ -2853,8 +2865,11 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
28532865

28542866

28552867
// Update the designator with the field declaration.
2856-
if (!VerifyOnly)
2868+
if (!VerifyOnly) {
28572869
D->setFieldDecl(*Field);
2870+
if (InitializedFields)
2871+
InitializedFields->insert(*Field);
2872+
}
28582873

28592874
// Make sure that our non-designated initializer list has space
28602875
// for a subobject corresponding to this field.
@@ -2929,10 +2944,10 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
29292944

29302945
InitializedEntity MemberEntity =
29312946
InitializedEntity::InitializeMember(*Field, &Entity);
2932-
if (CheckDesignatedInitializer(MemberEntity, IList, DIE, DesigIdx + 1,
2933-
FieldType, nullptr, nullptr, Index,
2934-
StructuredList, newStructuredIndex,
2935-
FinishSubobjectInit, false))
2947+
if (CheckDesignatedInitializer(
2948+
MemberEntity, IList, DIE, DesigIdx + 1, FieldType, nullptr,
2949+
nullptr, Index, StructuredList, newStructuredIndex,
2950+
FinishSubobjectInit, false, InitializedFields))
29362951
return true;
29372952
}
29382953

clang/test/SemaCXX/cxx2a-initializer-aggregates.cpp

Lines changed: 65 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
// RUN: %clang_cc1 -std=c++20 %s -verify=cxx20,expected,reorder -Wno-c99-designator -Werror=reorder-init-list -Wno-initializer-overrides
55
// RUN: %clang_cc1 -std=c++20 %s -verify=cxx20,expected,override -Wno-c99-designator -Wno-reorder-init-list -Werror=initializer-overrides
66
// RUN: %clang_cc1 -std=c++20 %s -verify=cxx20,expected -Wno-c99-designator -Wno-reorder-init-list -Wno-initializer-overrides
7-
// RUN: %clang_cc1 -std=c++20 %s -verify=cxx20,expected,wmissing -Wmissing-field-initializers -Wno-c99-designator -Wno-reorder-init-list -Wno-initializer-overrides
7+
// RUN: %clang_cc1 -std=c++20 %s -verify=cxx20,expected,wmissing -Wmissing-field-initializers -Wno-c99-designator -Wno-reorder-init-list -Wno-initializer-overrides -D NON_PEDANTIC
88

99

1010
namespace class_with_ctor {
@@ -247,3 +247,67 @@ void foo() {
247247
//
248248
}
249249
}
250+
251+
namespace GH70384 {
252+
253+
struct A {
254+
int m;
255+
union { int a; float n = 0; };
256+
};
257+
258+
struct B {
259+
int m;
260+
int b;
261+
union { int a ; };
262+
};
263+
264+
union CU {
265+
int a = 1;
266+
double b;
267+
};
268+
269+
struct C {
270+
int a;
271+
union { int b; CU c;};
272+
};
273+
274+
struct CC {
275+
int a;
276+
CU c;
277+
};
278+
279+
void foo() {
280+
A a = A{.m = 0};
281+
A aa = {0};
282+
A aaa = {.a = 7}; // wmissing-warning {{missing field 'm' initializer}}
283+
B b = {.m = 1, .b = 3 }; //wmissing-warning {{missing field 'a' initializer}}
284+
B bb = {1}; // wmissing-warning {{missing field 'b' initializer}}
285+
// wmissing-warning@-1 {{missing field 'a' initializer}}
286+
C c = {.a = 1}; // wmissing-warning {{missing field 'b' initializer}}
287+
CC cc = {.a = 1}; //// wmissing-warning {{missing field 'c' initializer}}
288+
}
289+
290+
#if defined NON_PEDANTIC
291+
struct C1 {
292+
int m;
293+
union { float b; union {int n = 1; }; };
294+
};
295+
296+
struct C2 {
297+
int m;
298+
struct { float b; int n = 1; };
299+
};
300+
301+
struct C3 {
302+
int m;
303+
struct { float b = 1; union {int a;}; int n = 1; };
304+
};
305+
306+
C1 c = C1{.m = 1};
307+
C1 cc = C1{.b = 1}; // wmissing-warning {{missing field 'm' initializer}}
308+
C2 c1 = C2{.m = 1}; // wmissing-warning {{missing field 'b' initializer}}
309+
C2 c22 = C2{.m = 1, .b = 1};
310+
C3 c2 = C3{.b = 1}; // wmissing-warning {{missing field 'a' initializer}}
311+
// wmissing-warning@-1 {{missing field 'm' initializer}}
312+
#endif // NON_PEDANTIC
313+
}

0 commit comments

Comments
 (0)