[clang] [clang] Fix false positive -Wmissing-field-initializer for anonymous unions (PR #70829)

via cfe-commits cfe-commits at lists.llvm.org
Tue Oct 31 10:01:40 PDT 2023


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang

Author: Mariya Podchishchaeva (Fznamznon)

<details>
<summary>Changes</summary>

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 https://github.com/llvm/llvm-project/issues/70384

---
Full diff: https://github.com/llvm/llvm-project/pull/70829.diff


2 Files Affected:

- (modified) clang/lib/Sema/SemaInit.cpp (+57-42) 
- (modified) clang/test/SemaCXX/cxx2a-initializer-aggregates.cpp (+65-1) 


``````````diff
diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp
index ec796def96ad3d8..881e67587e430e7 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/lib/Sema/SemaInit.cpp
@@ -349,17 +349,13 @@ class InitListChecker {
                       bool SubobjectIsDesignatorContext, unsigned &Index,
                       InitListExpr *StructuredList,
                       unsigned &StructuredIndex);
-  bool CheckDesignatedInitializer(const InitializedEntity &Entity,
-                                  InitListExpr *IList, DesignatedInitExpr *DIE,
-                                  unsigned DesigIdx,
-                                  QualType &CurrentObjectType,
-                                  RecordDecl::field_iterator *NextField,
-                                  llvm::APSInt *NextElementIndex,
-                                  unsigned &Index,
-                                  InitListExpr *StructuredList,
-                                  unsigned &StructuredIndex,
-                                  bool FinishSubobjectInit,
-                                  bool TopLevelObject);
+  bool CheckDesignatedInitializer(
+      const InitializedEntity &Entity, InitListExpr *IList,
+      DesignatedInitExpr *DIE, unsigned DesigIdx, QualType &CurrentObjectType,
+      RecordDecl::field_iterator *NextField, llvm::APSInt *NextElementIndex,
+      unsigned &Index, InitListExpr *StructuredList, unsigned &StructuredIndex,
+      bool FinishSubobjectInit, bool TopLevelObject,
+      llvm::SmallPtrSetImpl<FieldDecl *> *InitializedFields = nullptr);
   InitListExpr *getStructuredSubobjectInit(InitListExpr *IList, unsigned Index,
                                            QualType CurrentObjectType,
                                            InitListExpr *StructuredList,
@@ -2248,7 +2244,8 @@ void InitListChecker::CheckStructUnionTypes(
       // the next field that we'll be initializing.
       bool DesignatedInitFailed = CheckDesignatedInitializer(
           Entity, IList, DIE, 0, DeclType, &Field, nullptr, Index,
-          StructuredList, StructuredIndex, true, TopLevelObject);
+          StructuredList, StructuredIndex, true, TopLevelObject,
+          &InitializedFields);
       if (DesignatedInitFailed)
         hadError = true;
 
@@ -2256,7 +2253,6 @@ void InitListChecker::CheckStructUnionTypes(
       DesignatedInitExpr::Designator *D = DIE->getDesignator(0);
       if (!VerifyOnly && D->isFieldDesignator()) {
         FieldDecl *F = D->getFieldDecl();
-        InitializedFields.insert(F);
         if (!DesignatedInitFailed) {
           QualType ET = SemaRef.Context.getBaseElementType(F->getType());
           if (checkDestructorReference(ET, InitLoc, SemaRef)) {
@@ -2365,21 +2361,43 @@ void InitListChecker::CheckStructUnionTypes(
       !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;
+    auto MissingFieldCheck = [&](const RecordDecl *Record,
+                                 RecordDecl::field_iterator StartField,
+                                 auto &&MissingFieldCheck) -> bool {
+      FieldDecl *FirstUninitialized = nullptr;
+      for (RecordDecl::field_iterator it = StartField,
+                                      end = Record->field_end();
+           it != end; ++it) {
+        bool AllSet = false;
+        if (it->isAnonymousStructOrUnion()) {
+          RecordDecl *RDAnon = it->getType()->getAsRecordDecl();
+          AllSet = MissingFieldCheck(RDAnon, RDAnon->field_begin(),
+                                     MissingFieldCheck);
+        }
+
+        if ((HasDesignatedInit && InitializedFields.count(*it)) ||
+            it->hasInClassInitializer() || AllSet) {
+          if (Record->isUnion())
+            return true;
+          continue;
+        }
 
-      if (!it->isUnnamedBitfield() && !it->hasInClassInitializer() &&
-          !it->getType()->isIncompleteArrayType()) {
+        if (!it->isUnnamedBitfield() &&
+            !it->getType()->isIncompleteArrayType() &&
+            !it->isAnonymousStructOrUnion() && !FirstUninitialized)
+          FirstUninitialized = *it;
+      }
+
+      if (FirstUninitialized) {
         SemaRef.Diag(IList->getSourceRange().getEnd(),
                      diag::warn_missing_field_initializers)
-            << *it;
-        break;
+            << FirstUninitialized;
+        return false;
       }
-    }
+      return true;
+    };
+    MissingFieldCheck(RD, HasDesignatedInit ? RD->field_begin() : Field,
+                      MissingFieldCheck);
   }
 
   // Check that any remaining fields can be value-initialized if we're not
@@ -2537,19 +2555,13 @@ class FieldInitializerValidatorCCC final : public CorrectionCandidateCallback {
 /// actually be initialized.
 ///
 /// @returns true if there was an error, false otherwise.
-bool
-InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
-                                            InitListExpr *IList,
-                                            DesignatedInitExpr *DIE,
-                                            unsigned DesigIdx,
-                                            QualType &CurrentObjectType,
-                                          RecordDecl::field_iterator *NextField,
-                                            llvm::APSInt *NextElementIndex,
-                                            unsigned &Index,
-                                            InitListExpr *StructuredList,
-                                            unsigned &StructuredIndex,
-                                            bool FinishSubobjectInit,
-                                            bool TopLevelObject) {
+bool InitListChecker::CheckDesignatedInitializer(
+    const InitializedEntity &Entity, InitListExpr *IList,
+    DesignatedInitExpr *DIE, unsigned DesigIdx, QualType &CurrentObjectType,
+    RecordDecl::field_iterator *NextField, llvm::APSInt *NextElementIndex,
+    unsigned &Index, InitListExpr *StructuredList, unsigned &StructuredIndex,
+    bool FinishSubobjectInit, bool TopLevelObject,
+    llvm::SmallPtrSetImpl<FieldDecl *> *InitializedFields) {
   if (DesigIdx == DIE->size()) {
     // C++20 designated initialization can result in direct-list-initialization
     // of the designated subobject. This is the only way that we can end up
@@ -2853,8 +2865,11 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
 
 
     // Update the designator with the field declaration.
-    if (!VerifyOnly)
+    if (!VerifyOnly) {
       D->setFieldDecl(*Field);
+      if (InitializedFields)
+        InitializedFields->insert(*Field);
+    }
 
     // Make sure that our non-designated initializer list has space
     // for a subobject corresponding to this field.
@@ -2929,10 +2944,10 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
 
       InitializedEntity MemberEntity =
         InitializedEntity::InitializeMember(*Field, &Entity);
-      if (CheckDesignatedInitializer(MemberEntity, IList, DIE, DesigIdx + 1,
-                                     FieldType, nullptr, nullptr, Index,
-                                     StructuredList, newStructuredIndex,
-                                     FinishSubobjectInit, false))
+      if (CheckDesignatedInitializer(
+              MemberEntity, IList, DIE, DesigIdx + 1, FieldType, nullptr,
+              nullptr, Index, StructuredList, newStructuredIndex,
+              FinishSubobjectInit, false, InitializedFields))
         return true;
     }
 
diff --git a/clang/test/SemaCXX/cxx2a-initializer-aggregates.cpp b/clang/test/SemaCXX/cxx2a-initializer-aggregates.cpp
index 510ace58c35a6aa..87bc01a51d2f297 100644
--- a/clang/test/SemaCXX/cxx2a-initializer-aggregates.cpp
+++ b/clang/test/SemaCXX/cxx2a-initializer-aggregates.cpp
@@ -4,7 +4,7 @@
 // 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-field-initializers -Wno-c99-designator -Wno-reorder-init-list -Wno-initializer-overrides -D NON_PEDANTIC
 
 
 namespace class_with_ctor {
@@ -247,3 +247,67 @@ void foo() {
                            //
 }
 }
+
+namespace GH70384 {
+
+struct A {
+  int m;
+  union { int a; float n = 0; };
+};
+
+struct B {
+  int m;
+  int b;
+  union { int a ; };
+};
+
+union CU {
+  int a = 1;
+  double b;
+};
+
+struct C {
+  int a;
+  union { int b; CU c;};
+};
+
+struct CC {
+  int a;
+  CU c;
+};
+
+void foo() {
+  A a = A{.m = 0};
+  A aa = {0};
+  A aaa = {.a = 7}; // wmissing-warning {{missing field 'm' initializer}}
+  B b = {.m = 1, .b = 3 }; //wmissing-warning {{missing field 'a' initializer}}
+  B bb = {1}; // wmissing-warning {{missing field 'b' initializer}}
+              // wmissing-warning at -1 {{missing field 'a' initializer}}
+  C c = {.a = 1}; // wmissing-warning {{missing field 'b' initializer}}
+  CC cc = {.a = 1}; //// wmissing-warning {{missing field 'c' initializer}}
+}
+
+#if defined NON_PEDANTIC
+struct C1 {
+  int m;
+  union { float b; union {int n = 1; }; };
+};
+
+struct C2 {
+  int m;
+  struct { float b; int n = 1; };
+};
+
+struct C3 {
+  int m;
+  struct { float b = 1; union {int a;}; int n = 1; };
+};
+
+C1 c = C1{.m = 1};
+C1 cc = C1{.b = 1}; // wmissing-warning {{missing field 'm' initializer}}
+C2 c1 = C2{.m = 1}; // wmissing-warning {{missing field 'b' initializer}}
+C2 c22 = C2{.m = 1, .b = 1};
+C3 c2 = C3{.b = 1}; // wmissing-warning {{missing field 'a' initializer}}
+                    // wmissing-warning at -1 {{missing field 'm' initializer}}
+#endif // NON_PEDANTIC
+}

``````````

</details>


https://github.com/llvm/llvm-project/pull/70829


More information about the cfe-commits mailing list