Skip to content

Commit 7df43cc

Browse files
authored
[clang] Add -Wmissing-designated-field-initializers (#81364)
#56628 changed the behavior of `-Wmissing-field-initializers`, which introduces many new warnings in C++ code that uses partial designated initializers. If such code is being built with `-Wextra -Werror`, this change will break the build. This PR adds a new flag that allows to disable these new warnings and keep the old ones, as was suggested by @AaronBallman in the original issue: #56628 (comment) Fixes #68933
1 parent afb05cd commit 7df43cc

File tree

5 files changed

+35
-19
lines changed

5 files changed

+35
-19
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,10 @@ Non-comprehensive list of changes in this release
150150
New Compiler Flags
151151
------------------
152152

153+
- ``-Wmissing-designated-field-initializers``, grouped under ``-Wmissing-field-initializers``.
154+
This diagnostic can be disabled to make ``-Wmissing-field-initializers`` behave
155+
like it did before Clang 18.x. Fixes (`#56628 <https://github.com/llvm/llvm-project/issues/68933>`_)
156+
153157
Deprecated Compiler Flags
154158
-------------------------
155159

clang/include/clang/Basic/DiagnosticGroups.td

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -517,7 +517,15 @@ def MethodSignatures : DiagGroup<"method-signatures">;
517517
def MismatchedParameterTypes : DiagGroup<"mismatched-parameter-types">;
518518
def MismatchedReturnTypes : DiagGroup<"mismatched-return-types">;
519519
def MismatchedTags : DiagGroup<"mismatched-tags">;
520-
def MissingFieldInitializers : DiagGroup<"missing-field-initializers">;
520+
def MissingDesignatedFieldInitializers : DiagGroup<"missing-designated-field-initializers">{
521+
code Documentation = [{
522+
Warn about designated initializers with some fields missing (only in C++).
523+
}];
524+
}
525+
// Default -Wmissing-field-initializers matches gcc behavior,
526+
// but missing-designated-field-initializers can be turned off to match old clang behavior.
527+
def MissingFieldInitializers : DiagGroup<"missing-field-initializers",
528+
[MissingDesignatedFieldInitializers]>;
521529
def ModuleLock : DiagGroup<"module-lock">;
522530
def ModuleBuild : DiagGroup<"module-build">;
523531
def ModuleImport : DiagGroup<"module-import">;

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6170,6 +6170,10 @@ def ext_initializer_string_for_char_array_too_long : ExtWarn<
61706170
def warn_missing_field_initializers : Warning<
61716171
"missing field %0 initializer">,
61726172
InGroup<MissingFieldInitializers>, DefaultIgnore;
6173+
// The same warning, but another group is needed to disable it separately.
6174+
def warn_missing_designated_field_initializers : Warning<
6175+
warn_missing_field_initializers.Summary>,
6176+
InGroup<MissingDesignatedFieldInitializers>, DefaultIgnore;
61736177
def warn_braces_around_init : Warning<
61746178
"braces around %select{scalar |}0initializer">,
61756179
InGroup<DiagGroup<"braced-scalar-init">>;

clang/lib/Sema/SemaInit.cpp

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2227,8 +2227,6 @@ void InitListChecker::CheckStructUnionTypes(
22272227
size_t NumRecordDecls = llvm::count_if(RD->decls(), [&](const Decl *D) {
22282228
return isa<FieldDecl>(D) || isa<RecordDecl>(D);
22292229
});
2230-
bool CheckForMissingFields =
2231-
!IList->isIdiomaticZeroInitializer(SemaRef.getLangOpts());
22322230
bool HasDesignatedInit = false;
22332231

22342232
llvm::SmallPtrSet<FieldDecl *, 4> InitializedFields;
@@ -2269,11 +2267,6 @@ void InitListChecker::CheckStructUnionTypes(
22692267
}
22702268

22712269
InitializedSomething = true;
2272-
2273-
// Disable check for missing fields when designators are used.
2274-
// This matches gcc behaviour.
2275-
if (!SemaRef.getLangOpts().CPlusPlus)
2276-
CheckForMissingFields = false;
22772270
continue;
22782271
}
22792272

@@ -2285,7 +2278,7 @@ void InitListChecker::CheckStructUnionTypes(
22852278
// These are okay for randomized structures. [C99 6.7.8p19]
22862279
//
22872280
// Also, if there is only one element in the structure, we allow something
2288-
// like this, because it's really not randomized in the tranditional sense.
2281+
// like this, because it's really not randomized in the traditional sense.
22892282
//
22902283
// struct foo h = {bar};
22912284
auto IsZeroInitializer = [&](const Expr *I) {
@@ -2363,8 +2356,13 @@ void InitListChecker::CheckStructUnionTypes(
23632356
}
23642357

23652358
// Emit warnings for missing struct field initializers.
2366-
if (!VerifyOnly && InitializedSomething && CheckForMissingFields &&
2367-
!RD->isUnion()) {
2359+
// This check is disabled for designated initializers in C.
2360+
// This matches gcc behaviour.
2361+
bool IsCDesignatedInitializer =
2362+
HasDesignatedInit && !SemaRef.getLangOpts().CPlusPlus;
2363+
if (!VerifyOnly && InitializedSomething && !RD->isUnion() &&
2364+
!IList->isIdiomaticZeroInitializer(SemaRef.getLangOpts()) &&
2365+
!IsCDesignatedInitializer) {
23682366
// It is possible we have one or more unnamed bitfields remaining.
23692367
// Find first (if any) named field and emit warning.
23702368
for (RecordDecl::field_iterator it = HasDesignatedInit ? RD->field_begin()
@@ -2376,9 +2374,10 @@ void InitListChecker::CheckStructUnionTypes(
23762374

23772375
if (!it->isUnnamedBitfield() && !it->hasInClassInitializer() &&
23782376
!it->getType()->isIncompleteArrayType()) {
2379-
SemaRef.Diag(IList->getSourceRange().getEnd(),
2380-
diag::warn_missing_field_initializers)
2381-
<< *it;
2377+
auto Diag = HasDesignatedInit
2378+
? diag::warn_missing_designated_field_initializers
2379+
: diag::warn_missing_field_initializers;
2380+
SemaRef.Diag(IList->getSourceRange().getEnd(), Diag) << *it;
23822381
break;
23832382
}
23842383
}

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

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
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-designated -Wmissing-field-initializers -Wno-c99-designator -Wno-reorder-init-list -Wno-initializer-overrides
8+
// RUN: %clang_cc1 -std=c++20 %s -verify=cxx20,expected,wmissing -Wmissing-field-initializers -Wno-missing-designated-field-initializers -Wno-c99-designator -Wno-reorder-init-list -Wno-initializer-overrides
89

910

1011
namespace class_with_ctor {
@@ -50,11 +51,11 @@ A a3 = {
5051
A a4 = {
5152
.x = 1, // override-note {{previous}}
5253
.x = 1 // override-error {{overrides prior initialization}}
53-
}; // wmissing-warning {{missing field 'y' initializer}}
54+
}; // wmissing-designated-warning {{missing field 'y' initializer}}
5455
A a5 = {
5556
.y = 1, // override-note {{previous}}
5657
.y = 1 // override-error {{overrides prior initialization}}
57-
}; // wmissing-warning {{missing field 'x' initializer}}
58+
}; // wmissing-designated-warning {{missing field 'x' initializer}}
5859
B b2 = {.a = 1}; // pedantic-error {{brace elision for designated initializer is a C99 extension}}
5960
// wmissing-warning@-1 {{missing field 'y' initializer}}
6061
B b3 = {.a = 1, 2}; // pedantic-error {{mixture of designated and non-designated}} pedantic-note {{first non-designated}} pedantic-error {{brace elision}}
@@ -74,8 +75,8 @@ C c = {
7475
struct Foo { int a, b; };
7576

7677
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}}
78+
struct Foo foo1 = { .a = 1 }; // wmissing-designated-warning {{missing field 'b' initializer}}
79+
struct Foo foo2 = { .b = 1 }; // wmissing-designated-warning {{missing field 'a' initializer}}
7980

8081
}
8182

0 commit comments

Comments
 (0)