[clang] [clang] Add -Wmissing-designated-field-initializers (PR #81364)

Vadim D. via cfe-commits cfe-commits at lists.llvm.org
Mon Mar 4 14:49:40 PST 2024


https://github.com/vvd170501 updated https://github.com/llvm/llvm-project/pull/81364

>From f73060f7f09a747c90fa559641abd8c72f4ee66f Mon Sep 17 00:00:00 2001
From: vvd170501 <36827317+vvd170501 at users.noreply.github.com>
Date: Sat, 10 Feb 2024 19:19:52 +0300
Subject: [PATCH 1/8] Add -Wmissing-designated-field-initializers, decide
 whether to skip m-f-i check only when needed

---
 clang/include/clang/Basic/DiagnosticGroups.td | 10 +++-
 .../clang/Basic/DiagnosticSemaKinds.td        |  4 ++
 clang/lib/Sema/SemaInit.cpp                   | 50 ++++++++++---------
 .../SemaCXX/cxx2a-initializer-aggregates.cpp  | 11 ++--
 4 files changed, 45 insertions(+), 30 deletions(-)

diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td
index e8b4139d7893ce..0791a0002319de 100644
--- a/clang/include/clang/Basic/DiagnosticGroups.td
+++ b/clang/include/clang/Basic/DiagnosticGroups.td
@@ -517,7 +517,15 @@ def MethodSignatures : DiagGroup<"method-signatures">;
 def MismatchedParameterTypes : DiagGroup<"mismatched-parameter-types">;
 def MismatchedReturnTypes : DiagGroup<"mismatched-return-types">;
 def MismatchedTags : DiagGroup<"mismatched-tags">;
-def MissingFieldInitializers : DiagGroup<"missing-field-initializers">;
+def MissingDesignatedFieldInitializers : DiagGroup<"missing-designated-field-initializers">{
+  code Documentation = [{
+Warn about designated initializers with some fields missing (only in C++).
+  }];
+}
+// Default -Wmissing-field-initializers matches gcc behavior,
+// but missing-designated-field-initializers can be turned off to match old clang behavior.
+def MissingFieldInitializers : DiagGroup<"missing-field-initializers",
+                                         [MissingDesignatedFieldInitializers]>;
 def ModuleLock : DiagGroup<"module-lock">;
 def ModuleBuild : DiagGroup<"module-build">;
 def ModuleImport : DiagGroup<"module-import">;
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 91105d4231f06a..8cf58299602ec7 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -6167,6 +6167,10 @@ def ext_initializer_string_for_char_array_too_long : ExtWarn<
 def warn_missing_field_initializers : Warning<
   "missing field %0 initializer">,
   InGroup<MissingFieldInitializers>, DefaultIgnore;
+// The same warning, but another group is needed to disable it separately.
+def warn_missing_designated_field_initializers : Warning<
+  "missing field %0 initializer">,
+  InGroup<MissingDesignatedFieldInitializers>, DefaultIgnore;
 def warn_braces_around_init : Warning<
   "braces around %select{scalar |}0initializer">,
   InGroup<DiagGroup<"braced-scalar-init">>;
diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp
index 0fd458837163e5..3227f16dd0c1ce 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/lib/Sema/SemaInit.cpp
@@ -2227,8 +2227,6 @@ void InitListChecker::CheckStructUnionTypes(
   size_t NumRecordDecls = llvm::count_if(RD->decls(), [&](const Decl *D) {
     return isa<FieldDecl>(D) || isa<RecordDecl>(D);
   });
-  bool CheckForMissingFields =
-    !IList->isIdiomaticZeroInitializer(SemaRef.getLangOpts());
   bool HasDesignatedInit = false;
 
   llvm::SmallPtrSet<FieldDecl *, 4> InitializedFields;
@@ -2269,11 +2267,6 @@ void InitListChecker::CheckStructUnionTypes(
       }
 
       InitializedSomething = true;
-
-      // Disable check for missing fields when designators are used.
-      // This matches gcc behaviour.
-      if (!SemaRef.getLangOpts().CPlusPlus)
-        CheckForMissingFields = false;
       continue;
     }
 
@@ -2285,7 +2278,7 @@ void InitListChecker::CheckStructUnionTypes(
     // These are okay for randomized structures. [C99 6.7.8p19]
     //
     // Also, if there is only one element in the structure, we allow something
-    // like this, because it's really not randomized in the tranditional sense.
+    // like this, because it's really not randomized in the traditional sense.
     //
     //   struct foo h = {bar};
     auto IsZeroInitializer = [&](const Expr *I) {
@@ -2363,23 +2356,32 @@ void InitListChecker::CheckStructUnionTypes(
   }
 
   // Emit warnings for missing struct field initializers.
-  if (!VerifyOnly && InitializedSomething && CheckForMissingFields &&
-      !RD->isUnion()) {
-    // It is possible we have one or more unnamed bitfields remaining.
-    // Find first (if any) named field and emit warning.
-    for (RecordDecl::field_iterator it = HasDesignatedInit ? RD->field_begin()
-                                                           : Field,
-                                    end = RD->field_end();
-         it != end; ++it) {
-      if (HasDesignatedInit && InitializedFields.count(*it))
-        continue;
+  if (!VerifyOnly && InitializedSomething && !RD->isUnion()) {
+    // Disable missing fields check for:
+    // - Zero initializers
+    // - Designated initializers (only in C). This matches gcc behaviour.
+    bool DisableCheck =
+        IList->isIdiomaticZeroInitializer(SemaRef.getLangOpts()) ||
+        (HasDesignatedInit && !SemaRef.getLangOpts().CPlusPlus);
+
+    if (!DisableCheck) {
+      // It is possible we have one or more unnamed bitfields remaining.
+      // Find first (if any) named field and emit warning.
+      for (RecordDecl::field_iterator it = HasDesignatedInit ? RD->field_begin()
+                                                             : Field,
+                                      end = RD->field_end();
+           it != end; ++it) {
+        if (HasDesignatedInit && InitializedFields.count(*it))
+          continue;
 
-      if (!it->isUnnamedBitfield() && !it->hasInClassInitializer() &&
-          !it->getType()->isIncompleteArrayType()) {
-        SemaRef.Diag(IList->getSourceRange().getEnd(),
-                     diag::warn_missing_field_initializers)
-            << *it;
-        break;
+        if (!it->isUnnamedBitfield() && !it->hasInClassInitializer() &&
+            !it->getType()->isIncompleteArrayType()) {
+          auto Diag = HasDesignatedInit
+                          ? diag::warn_missing_designated_field_initializers
+                          : diag::warn_missing_field_initializers;
+          SemaRef.Diag(IList->getSourceRange().getEnd(), Diag) << *it;
+          break;
+        }
       }
     }
   }
diff --git a/clang/test/SemaCXX/cxx2a-initializer-aggregates.cpp b/clang/test/SemaCXX/cxx2a-initializer-aggregates.cpp
index 510ace58c35a6a..1e9c5fa082d077 100644
--- a/clang/test/SemaCXX/cxx2a-initializer-aggregates.cpp
+++ b/clang/test/SemaCXX/cxx2a-initializer-aggregates.cpp
@@ -4,7 +4,8 @@
 // RUN: %clang_cc1 -std=c++20 %s -verify=cxx20,expected,reorder -Wno-c99-designator -Werror=reorder-init-list -Wno-initializer-overrides
 // RUN: %clang_cc1 -std=c++20 %s -verify=cxx20,expected,override -Wno-c99-designator -Wno-reorder-init-list -Werror=initializer-overrides
 // RUN: %clang_cc1 -std=c++20 %s -verify=cxx20,expected -Wno-c99-designator -Wno-reorder-init-list -Wno-initializer-overrides
-// RUN: %clang_cc1 -std=c++20 %s -verify=cxx20,expected,wmissing -Wmissing-field-initializers -Wno-c99-designator -Wno-reorder-init-list -Wno-initializer-overrides
+// 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
+// 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
 
 
 namespace class_with_ctor {
@@ -50,11 +51,11 @@ A a3 = {
 A a4 = {
   .x = 1, // override-note {{previous}}
   .x = 1 // override-error {{overrides prior initialization}}
-}; // wmissing-warning {{missing field 'y' initializer}}
+}; // wmissing-designated-warning {{missing field 'y' initializer}}
 A a5 = {
   .y = 1, // override-note {{previous}}
   .y = 1 // override-error {{overrides prior initialization}}
-}; // wmissing-warning {{missing field 'x' initializer}}
+}; // wmissing-designated-warning {{missing field 'x' initializer}}
 B b2 = {.a = 1}; // pedantic-error {{brace elision for designated initializer is a C99 extension}}
                  // wmissing-warning at -1 {{missing field 'y' initializer}}
 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 = {
 struct Foo { int a, b; };
 
 struct Foo foo0 = { 1 }; // wmissing-warning {{missing field 'b' initializer}}
-struct Foo foo1 = { .a = 1 }; // wmissing-warning {{missing field 'b' initializer}}
-struct Foo foo2 = { .b = 1 }; // wmissing-warning {{missing field 'a' initializer}}
+struct Foo foo1 = { .a = 1 }; // wmissing-designated-warning {{missing field 'b' initializer}}
+struct Foo foo2 = { .b = 1 }; // wmissing-designated-warning {{missing field 'a' initializer}}
 
 }
 

>From 1dc1b14e90faa2d9aaddffa1a250e0631f784f77 Mon Sep 17 00:00:00 2001
From: vvd170501 <36827317+vvd170501 at users.noreply.github.com>
Date: Tue, 13 Feb 2024 01:11:27 +0300
Subject: [PATCH 2/8] Reuse summary

---
 clang/include/clang/Basic/DiagnosticSemaKinds.td | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 8cf58299602ec7..f82cb8dc33914d 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -6169,7 +6169,7 @@ def warn_missing_field_initializers : Warning<
   InGroup<MissingFieldInitializers>, DefaultIgnore;
 // The same warning, but another group is needed to disable it separately.
 def warn_missing_designated_field_initializers : Warning<
-  "missing field %0 initializer">,
+  warn_missing_field_initializers.Summary>,
   InGroup<MissingDesignatedFieldInitializers>, DefaultIgnore;
 def warn_braces_around_init : Warning<
   "braces around %select{scalar |}0initializer">,

>From 83864610d6b6470a0f229c516821d8344d994562 Mon Sep 17 00:00:00 2001
From: vvd170501 <36827317+vvd170501 at users.noreply.github.com>
Date: Tue, 13 Feb 2024 01:11:44 +0300
Subject: [PATCH 3/8] Reduce indentation

---
 clang/lib/Sema/SemaInit.cpp | 45 +++++++++++++++++--------------------
 1 file changed, 20 insertions(+), 25 deletions(-)

diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp
index 3227f16dd0c1ce..6d5986fccd1133 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/lib/Sema/SemaInit.cpp
@@ -2356,32 +2356,27 @@ void InitListChecker::CheckStructUnionTypes(
   }
 
   // Emit warnings for missing struct field initializers.
-  if (!VerifyOnly && InitializedSomething && !RD->isUnion()) {
-    // Disable missing fields check for:
-    // - Zero initializers
-    // - Designated initializers (only in C). This matches gcc behaviour.
-    bool DisableCheck =
-        IList->isIdiomaticZeroInitializer(SemaRef.getLangOpts()) ||
-        (HasDesignatedInit && !SemaRef.getLangOpts().CPlusPlus);
-
-    if (!DisableCheck) {
-      // It is possible we have one or more unnamed bitfields remaining.
-      // Find first (if any) named field and emit warning.
-      for (RecordDecl::field_iterator it = HasDesignatedInit ? RD->field_begin()
-                                                             : Field,
-                                      end = RD->field_end();
-           it != end; ++it) {
-        if (HasDesignatedInit && InitializedFields.count(*it))
-          continue;
+  // This check is disabled for designated initializers in C.
+  // This matches gcc behaviour.
+  if (!VerifyOnly && InitializedSomething && !RD->isUnion() &&
+      !IList->isIdiomaticZeroInitializer(SemaRef.getLangOpts()) &&
+      !(HasDesignatedInit && !SemaRef.getLangOpts().CPlusPlus)) {
+    // It is possible we have one or more unnamed bitfields remaining.
+    // Find first (if any) named field and emit warning.
+    for (RecordDecl::field_iterator it = HasDesignatedInit ? RD->field_begin()
+                                                           : Field,
+                                    end = RD->field_end();
+         it != end; ++it) {
+      if (HasDesignatedInit && InitializedFields.count(*it))
+        continue;
 
-        if (!it->isUnnamedBitfield() && !it->hasInClassInitializer() &&
-            !it->getType()->isIncompleteArrayType()) {
-          auto Diag = HasDesignatedInit
-                          ? diag::warn_missing_designated_field_initializers
-                          : diag::warn_missing_field_initializers;
-          SemaRef.Diag(IList->getSourceRange().getEnd(), Diag) << *it;
-          break;
-        }
+      if (!it->isUnnamedBitfield() && !it->hasInClassInitializer() &&
+          !it->getType()->isIncompleteArrayType()) {
+        auto Diag = HasDesignatedInit
+                        ? diag::warn_missing_designated_field_initializers
+                        : diag::warn_missing_field_initializers;
+        SemaRef.Diag(IList->getSourceRange().getEnd(), Diag) << *it;
+        break;
       }
     }
   }

>From 61a4489d839f162f8b81c765cbc5993a76881d62 Mon Sep 17 00:00:00 2001
From: vvd170501 <36827317+vvd170501 at users.noreply.github.com>
Date: Tue, 13 Feb 2024 01:32:08 +0300
Subject: [PATCH 4/8] Update release notes

---
 clang/docs/ReleaseNotes.rst | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 6f6ce7c68a7a71..b6a83328f67338 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -148,6 +148,10 @@ Non-comprehensive list of changes in this release
 New Compiler Flags
 ------------------
 
+- ``-Wmissing-designated-field-initializers``, grouped under ``-Wmissing-designated-field-initializers``.
+  This diagnostic can be disabled to make ``-Wmissing-designated-field-initializers`` behave
+  like it did before Clang 18.x. Fixes (`#56628 <https://github.com/llvm/llvm-project/issues/68933>`_)
+
 Deprecated Compiler Flags
 -------------------------
 

>From d21b608e672425eb1bab6f1580934214f9d9f2df Mon Sep 17 00:00:00 2001
From: Vadim D <36827317+vvd170501 at users.noreply.github.com>
Date: Tue, 5 Mar 2024 00:02:49 +0300
Subject: [PATCH 5/8] Fix flag description in release notes

Co-authored-by: Aaron Ballman <aaron at aaronballman.com>
---
 clang/docs/ReleaseNotes.rst | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index b6a83328f67338..eb5901ed014590 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -148,7 +148,7 @@ Non-comprehensive list of changes in this release
 New Compiler Flags
 ------------------
 
-- ``-Wmissing-designated-field-initializers``, grouped under ``-Wmissing-designated-field-initializers``.
+- ``-Wmissing-designated-field-initializers``, grouped under ``-Wmissing-field-initializers``.
   This diagnostic can be disabled to make ``-Wmissing-designated-field-initializers`` behave
   like it did before Clang 18.x. Fixes (`#56628 <https://github.com/llvm/llvm-project/issues/68933>`_)
 

>From 495bc05709c8390fce43a9406406c487b4ea50f7 Mon Sep 17 00:00:00 2001
From: Vadim D <36827317+vvd170501 at users.noreply.github.com>
Date: Tue, 5 Mar 2024 00:04:27 +0300
Subject: [PATCH 6/8] Fix flag description in release notes (2)

Co-authored-by: Aaron Ballman <aaron at aaronballman.com>
---
 clang/docs/ReleaseNotes.rst | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index eb5901ed014590..62d523dd69de3e 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -149,7 +149,7 @@ New Compiler Flags
 ------------------
 
 - ``-Wmissing-designated-field-initializers``, grouped under ``-Wmissing-field-initializers``.
-  This diagnostic can be disabled to make ``-Wmissing-designated-field-initializers`` behave
+  This diagnostic can be disabled to make ``-Wmissing-field-initializers`` behave
   like it did before Clang 18.x. Fixes (`#56628 <https://github.com/llvm/llvm-project/issues/68933>`_)
 
 Deprecated Compiler Flags

>From fa70ace81c2311636ce369259aded2b8f40ad0d6 Mon Sep 17 00:00:00 2001
From: vvd170501 <36827317+vvd170501 at users.noreply.github.com>
Date: Tue, 5 Mar 2024 01:36:06 +0300
Subject: [PATCH 7/8] Add bool variable

---
 clang/lib/Sema/SemaInit.cpp | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp
index 6d5986fccd1133..e44752bb03c558 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/lib/Sema/SemaInit.cpp
@@ -2358,9 +2358,10 @@ void InitListChecker::CheckStructUnionTypes(
   // Emit warnings for missing struct field initializers.
   // This check is disabled for designated initializers in C.
   // This matches gcc behaviour.
+  bool IsCDesignatedInitializer = HasDesignatedInit && !SemaRef.getLangOpts().CPlusPlus;
   if (!VerifyOnly && InitializedSomething && !RD->isUnion() &&
       !IList->isIdiomaticZeroInitializer(SemaRef.getLangOpts()) &&
-      !(HasDesignatedInit && !SemaRef.getLangOpts().CPlusPlus)) {
+      !IsCDesignatedInitializer) {
     // It is possible we have one or more unnamed bitfields remaining.
     // Find first (if any) named field and emit warning.
     for (RecordDecl::field_iterator it = HasDesignatedInit ? RD->field_begin()

>From 56d8dc6df8919d492799054279939e2c16545a1e Mon Sep 17 00:00:00 2001
From: vvd170501 <36827317+vvd170501 at users.noreply.github.com>
Date: Tue, 5 Mar 2024 01:49:19 +0300
Subject: [PATCH 8/8] Fix formatting

---
 clang/lib/Sema/SemaInit.cpp | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp
index e44752bb03c558..bb8748f443a287 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/lib/Sema/SemaInit.cpp
@@ -2358,7 +2358,8 @@ void InitListChecker::CheckStructUnionTypes(
   // Emit warnings for missing struct field initializers.
   // This check is disabled for designated initializers in C.
   // This matches gcc behaviour.
-  bool IsCDesignatedInitializer = HasDesignatedInit && !SemaRef.getLangOpts().CPlusPlus;
+  bool IsCDesignatedInitializer =
+      HasDesignatedInit && !SemaRef.getLangOpts().CPlusPlus;
   if (!VerifyOnly && InitializedSomething && !RD->isUnion() &&
       !IList->isIdiomaticZeroInitializer(SemaRef.getLangOpts()) &&
       !IsCDesignatedInitializer) {



More information about the cfe-commits mailing list