Skip to content

Commit 9108897

Browse files
committed
[clang] Report missing designated initializers in C++
Prior to this change clang didn't emit missing-field-initializers warning for designated initializers. The comments say that it is done to match gcc behavior. However, gcc behaves so only for C. For C++ warnings are emitted. Fixes #56628 Reviewed By: aaron.ballman Differential Revision: https://reviews.llvm.org/D157879
1 parent a40c984 commit 9108897

File tree

3 files changed

+44
-19
lines changed

3 files changed

+44
-19
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,9 @@ Bug Fixes in This Version
154154
- Fix a hang on valid C code passing a function type as an argument to
155155
``typeof`` to form a function declaration.
156156
(`#64713 <https://github.com/llvm/llvm-project/issues/64713>_`)
157+
- Clang now reports missing-field-initializers warning for missing designated
158+
initializers in C++.
159+
(`#56628 <https://github.com/llvm/llvm-project/issues/56628>`_)
157160

158161
Bug Fixes to Compiler Builtins
159162
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

clang/lib/Sema/SemaInit.cpp

Lines changed: 29 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2252,6 +2252,8 @@ void InitListChecker::CheckStructUnionTypes(
22522252
!IList->isIdiomaticZeroInitializer(SemaRef.getLangOpts());
22532253
bool HasDesignatedInit = false;
22542254

2255+
llvm::SmallPtrSet<FieldDecl *, 4> InitializedFields;
2256+
22552257
while (Index < IList->getNumInits()) {
22562258
Expr *Init = IList->getInit(Index);
22572259
SourceLocation InitLoc = Init->getBeginLoc();
@@ -2267,28 +2269,32 @@ void InitListChecker::CheckStructUnionTypes(
22672269

22682270
// Handle this designated initializer. Field will be updated to
22692271
// the next field that we'll be initializing.
2270-
if (CheckDesignatedInitializer(Entity, IList, DIE, 0,
2271-
DeclType, &Field, nullptr, Index,
2272-
StructuredList, StructuredIndex,
2273-
true, TopLevelObject))
2272+
bool DesignatedInitFailed = CheckDesignatedInitializer(
2273+
Entity, IList, DIE, 0, DeclType, &Field, nullptr, Index,
2274+
StructuredList, StructuredIndex, true, TopLevelObject);
2275+
if (DesignatedInitFailed)
22742276
hadError = true;
2275-
else if (!VerifyOnly) {
2276-
// Find the field named by the designated initializer.
2277-
RecordDecl::field_iterator F = RD->field_begin();
2278-
while (std::next(F) != Field)
2279-
++F;
2280-
QualType ET = SemaRef.Context.getBaseElementType(F->getType());
2281-
if (checkDestructorReference(ET, InitLoc, SemaRef)) {
2282-
hadError = true;
2283-
return;
2277+
2278+
// Find the field named by the designated initializer.
2279+
DesignatedInitExpr::Designator *D = DIE->getDesignator(0);
2280+
if (!VerifyOnly && D->isFieldDesignator()) {
2281+
FieldDecl *F = D->getFieldDecl();
2282+
InitializedFields.insert(F);
2283+
if (!DesignatedInitFailed) {
2284+
QualType ET = SemaRef.Context.getBaseElementType(F->getType());
2285+
if (checkDestructorReference(ET, InitLoc, SemaRef)) {
2286+
hadError = true;
2287+
return;
2288+
}
22842289
}
22852290
}
22862291

22872292
InitializedSomething = true;
22882293

22892294
// Disable check for missing fields when designators are used.
22902295
// This matches gcc behaviour.
2291-
CheckForMissingFields = false;
2296+
if (!SemaRef.getLangOpts().CPlusPlus)
2297+
CheckForMissingFields = false;
22922298
continue;
22932299
}
22942300

@@ -2367,6 +2373,7 @@ void InitListChecker::CheckStructUnionTypes(
23672373
CheckSubElementType(MemberEntity, IList, Field->getType(), Index,
23682374
StructuredList, StructuredIndex);
23692375
InitializedSomething = true;
2376+
InitializedFields.insert(*Field);
23702377

23712378
if (RD->isUnion() && StructuredList) {
23722379
// Initialize the first field within the union.
@@ -2378,15 +2385,20 @@ void InitListChecker::CheckStructUnionTypes(
23782385

23792386
// Emit warnings for missing struct field initializers.
23802387
if (!VerifyOnly && InitializedSomething && CheckForMissingFields &&
2381-
Field != FieldEnd && !Field->getType()->isIncompleteArrayType() &&
23822388
!RD->isUnion()) {
23832389
// It is possible we have one or more unnamed bitfields remaining.
23842390
// Find first (if any) named field and emit warning.
2385-
for (RecordDecl::field_iterator it = Field, end = RD->field_end();
2391+
for (RecordDecl::field_iterator it = HasDesignatedInit ? RD->field_begin()
2392+
: Field,
2393+
end = RD->field_end();
23862394
it != end; ++it) {
2395+
if (HasDesignatedInit && InitializedFields.count(*it))
2396+
continue;
2397+
23872398
if (!it->isUnnamedBitfield() && !it->hasInClassInitializer()) {
23882399
SemaRef.Diag(IList->getSourceRange().getEnd(),
2389-
diag::warn_missing_field_initializers) << *it;
2400+
diag::warn_missing_field_initializers)
2401+
<< *it;
23902402
break;
23912403
}
23922404
}

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

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +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
78

89

910
namespace class_with_ctor {
@@ -49,15 +50,17 @@ A a3 = {
4950
A a4 = {
5051
.x = 1, // override-note {{previous}}
5152
.x = 1 // override-error {{overrides prior initialization}}
52-
};
53+
}; // wmissing-warning {{missing field 'y' initializer}}
5354
A a5 = {
5455
.y = 1, // override-note {{previous}}
5556
.y = 1 // override-error {{overrides prior initialization}}
56-
};
57+
}; // wmissing-warning {{missing field 'x' initializer}}
5758
B b2 = {.a = 1}; // pedantic-error {{brace elision for designated initializer is a C99 extension}}
59+
// wmissing-warning@-1 {{missing field 'y' initializer}}
5860
B b3 = {.a = 1, 2}; // pedantic-error {{mixture of designated and non-designated}} pedantic-note {{first non-designated}} pedantic-error {{brace elision}}
5961
B b4 = {.a = 1, 2, 3}; // pedantic-error {{mixture of designated and non-designated}} pedantic-note {{first non-designated}} pedantic-error {{brace elision}} expected-error {{excess elements}}
6062
B b5 = {.a = nullptr}; // expected-error {{cannot initialize}}
63+
// wmissing-warning@-1 {{missing field 'y' initializer}}
6164
struct C { int :0, x, :0, y, :0; };
6265
C c = {
6366
.x = 1, // override-note {{previous}}
@@ -67,6 +70,13 @@ C c = {
6770
.x = 1, // reorder-error {{declaration order}} override-error {{overrides prior initialization}} override-note {{previous}}
6871
.x = 1, // override-error {{overrides prior initialization}}
6972
};
73+
74+
struct Foo { int a, b; };
75+
76+
struct Foo foo0 = { 1 }; // wmissing-warning {{missing field 'b' initializer}}
77+
struct Foo foo1 = { .a = 1 }; // wmissing-warning {{missing field 'b' initializer}}
78+
struct Foo foo2 = { .b = 1 }; // wmissing-warning {{missing field 'a' initializer}}
79+
7080
}
7181

7282
namespace base_class {

0 commit comments

Comments
 (0)