[clang] 5cda366 - Revert "[clang] Fix false positive -Wmissing-field-initializer for anonymous unions (#70829)"

via cfe-commits cfe-commits at lists.llvm.org
Mon Dec 18 07:09:26 PST 2023


Author: Podchishchaeva, Mariya
Date: 2023-12-18T07:08:27-08:00
New Revision: 5cda366221236a43fdd89bca59e153b4384eaba8

URL: https://github.com/llvm/llvm-project/commit/5cda366221236a43fdd89bca59e153b4384eaba8
DIFF: https://github.com/llvm/llvm-project/commit/5cda366221236a43fdd89bca59e153b4384eaba8.diff

LOG: Revert "[clang] Fix false positive -Wmissing-field-initializer for anonymous unions (#70829)"

This reverts commit a01307a6ee788fc6ac2e09e58f0f52e5666def86 and its
follow-up fix 32d5221ec4810dd723ccebaabbda1df5d3b4cfcf.

It caused unexpected warnings emitted for nested designators in C.

Added: 
    

Modified: 
    clang/lib/Sema/SemaInit.cpp
    clang/test/Sema/missing-field-initializers.c
    clang/test/SemaCXX/cxx2a-initializer-aggregates.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp
index 035eaae58965a4..d6459fd9d7875d 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/lib/Sema/SemaInit.cpp
@@ -465,8 +465,7 @@ class InitListChecker {
   void FillInEmptyInitForField(unsigned Init, FieldDecl *Field,
                                const InitializedEntity &ParentEntity,
                                InitListExpr *ILE, bool &RequiresSecondPass,
-                               bool FillWithNoInit = false,
-                               bool WarnIfMissing = false);
+                               bool FillWithNoInit = false);
   void FillInEmptyInitializations(const InitializedEntity &Entity,
                                   InitListExpr *ILE, bool &RequiresSecondPass,
                                   InitListExpr *OuterILE, unsigned OuterIndex,
@@ -655,16 +654,11 @@ void InitListChecker::FillInEmptyInitForBase(
   }
 }
 
-static bool hasAnyDesignatedInits(const InitListExpr *IL) {
-  return llvm::any_of(*IL, [=](const Stmt *Init) {
-    return isa_and_nonnull<DesignatedInitExpr>(Init);
-  });
-}
-
-void InitListChecker::FillInEmptyInitForField(
-    unsigned Init, FieldDecl *Field, const InitializedEntity &ParentEntity,
-    InitListExpr *ILE, bool &RequiresSecondPass, bool FillWithNoInit,
-    bool WarnIfMissing) {
+void InitListChecker::FillInEmptyInitForField(unsigned Init, FieldDecl *Field,
+                                        const InitializedEntity &ParentEntity,
+                                              InitListExpr *ILE,
+                                              bool &RequiresSecondPass,
+                                              bool FillWithNoInit) {
   SourceLocation Loc = ILE->getEndLoc();
   unsigned NumInits = ILE->getNumInits();
   InitializedEntity MemberEntity
@@ -732,52 +726,15 @@ void InitListChecker::FillInEmptyInitForField(
 
     if (hadError || VerifyOnly) {
       // Do nothing
-    } else {
-      if (WarnIfMissing) {
-        auto CheckAnonMember = [&](const FieldDecl *FD,
-                                   auto &&CheckAnonMember) -> FieldDecl * {
-          FieldDecl *Uninitialized = nullptr;
-          RecordDecl *RD = FD->getType()->getAsRecordDecl();
-          assert(RD && "Not anonymous member checked?");
-          for (auto *F : RD->fields()) {
-            FieldDecl *UninitializedFieldInF = nullptr;
-            if (F->isAnonymousStructOrUnion())
-              UninitializedFieldInF = CheckAnonMember(F, CheckAnonMember);
-            else if (!F->isUnnamedBitfield() &&
-                     !F->getType()->isIncompleteArrayType() &&
-                     !F->hasInClassInitializer())
-              UninitializedFieldInF = F;
-
-            if (RD->isUnion() && !UninitializedFieldInF)
-              return nullptr;
-            if (!Uninitialized)
-              Uninitialized = UninitializedFieldInF;
-          }
-          return Uninitialized;
-        };
-
-        FieldDecl *FieldToDiagnose = nullptr;
-        if (Field->isAnonymousStructOrUnion())
-          FieldToDiagnose = CheckAnonMember(Field, CheckAnonMember);
-        else if (!Field->isUnnamedBitfield() &&
-                 !Field->getType()->isIncompleteArrayType())
-          FieldToDiagnose = Field;
-
-        if (FieldToDiagnose)
-          SemaRef.Diag(Loc, diag::warn_missing_field_initializers)
-              << FieldToDiagnose;
-      }
-
-      if (Init < NumInits) {
-        ILE->setInit(Init, MemberInit.getAs<Expr>());
-      } else if (!isa<ImplicitValueInitExpr>(MemberInit.get())) {
-        // Empty initialization requires a constructor call, so
-        // extend the initializer list to include the constructor
-        // call and make a note that we'll need to take another pass
-        // through the initializer list.
-        ILE->updateInit(SemaRef.Context, Init, MemberInit.getAs<Expr>());
-        RequiresSecondPass = true;
-      }
+    } else if (Init < NumInits) {
+      ILE->setInit(Init, MemberInit.getAs<Expr>());
+    } else if (!isa<ImplicitValueInitExpr>(MemberInit.get())) {
+      // Empty initialization requires a constructor call, so
+      // extend the initializer list to include the constructor
+      // call and make a note that we'll need to take another pass
+      // through the initializer list.
+      ILE->updateInit(SemaRef.Context, Init, MemberInit.getAs<Expr>());
+      RequiresSecondPass = true;
     }
   } else if (InitListExpr *InnerILE
                = dyn_cast<InitListExpr>(ILE->getInit(Init))) {
@@ -845,36 +802,9 @@ InitListChecker::FillInEmptyInitializations(const InitializedEntity &Entity,
         }
       }
     } else {
-      InitListExpr *SForm =
-          ILE->isSyntacticForm() ? ILE : ILE->getSyntacticForm();
       // The fields beyond ILE->getNumInits() are default initialized, so in
       // order to leave them uninitialized, the ILE is expanded and the extra
       // fields are then filled with NoInitExpr.
-
-      // Some checks that are required for missing fields warning are bound to
-      // how many elements the initializer list originally was provided; perform
-      // them before the list is expanded.
-      bool WarnIfMissingField =
-          !SForm->isIdiomaticZeroInitializer(SemaRef.getLangOpts()) &&
-          ILE->getNumInits();
-
-      // Disable check for missing fields when designators are used in C to
-      // match gcc behaviour.
-      // FIXME: Should we emulate possible gcc warning bug?
-      WarnIfMissingField &=
-          SemaRef.getLangOpts().CPlusPlus || !hasAnyDesignatedInits(SForm);
-
-      if (OuterILE) {
-        // When nested designators are present, there might be two nested init
-        // lists created and only outer will contain designated initializer
-        // expression, so check outer list as well.
-        InitListExpr *OuterSForm = OuterILE->isSyntacticForm()
-                                       ? OuterILE
-                                       : OuterILE->getSyntacticForm();
-        WarnIfMissingField &= SemaRef.getLangOpts().CPlusPlus ||
-                              !hasAnyDesignatedInits(OuterSForm);
-      }
-
       unsigned NumElems = numStructUnionElements(ILE->getType());
       if (!RDecl->isUnion() && RDecl->hasFlexibleArrayMember())
         ++NumElems;
@@ -902,7 +832,7 @@ InitListChecker::FillInEmptyInitializations(const InitializedEntity &Entity,
           return;
 
         FillInEmptyInitForField(Init, Field, Entity, ILE, RequiresSecondPass,
-                                FillWithNoInit, WarnIfMissingField);
+                                FillWithNoInit);
         if (hadError)
           return;
 
@@ -1017,6 +947,13 @@ InitListChecker::FillInEmptyInitializations(const InitializedEntity &Entity,
   }
 }
 
+static bool hasAnyDesignatedInits(const InitListExpr *IL) {
+  for (const Stmt *Init : *IL)
+    if (isa_and_nonnull<DesignatedInitExpr>(Init))
+      return true;
+  return false;
+}
+
 InitListChecker::InitListChecker(
     Sema &S, const InitializedEntity &Entity, InitListExpr *IL, QualType &T,
     bool VerifyOnly, bool TreatUnavailableAsInvalid, bool InOverloadResolution,
@@ -2288,8 +2225,12 @@ 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;
+
   while (Index < IList->getNumInits()) {
     Expr *Init = IList->getInit(Index);
     SourceLocation InitLoc = Init->getBeginLoc();
@@ -2313,17 +2254,24 @@ void InitListChecker::CheckStructUnionTypes(
 
       // Find the field named by the designated initializer.
       DesignatedInitExpr::Designator *D = DIE->getDesignator(0);
-      if (!VerifyOnly && D->isFieldDesignator() && !DesignatedInitFailed) {
+      if (!VerifyOnly && D->isFieldDesignator()) {
         FieldDecl *F = D->getFieldDecl();
-        QualType ET = SemaRef.Context.getBaseElementType(F->getType());
-        if (checkDestructorReference(ET, InitLoc, SemaRef)) {
-          hadError = true;
-          return;
+        InitializedFields.insert(F);
+        if (!DesignatedInitFailed) {
+          QualType ET = SemaRef.Context.getBaseElementType(F->getType());
+          if (checkDestructorReference(ET, InitLoc, SemaRef)) {
+            hadError = true;
+            return;
+          }
         }
       }
 
       InitializedSomething = true;
 
+      // Disable check for missing fields when designators are used.
+      // This matches gcc behaviour.
+      if (!SemaRef.getLangOpts().CPlusPlus)
+        CheckForMissingFields = false;
       continue;
     }
 
@@ -2402,6 +2350,7 @@ void InitListChecker::CheckStructUnionTypes(
     CheckSubElementType(MemberEntity, IList, Field->getType(), Index,
                         StructuredList, StructuredIndex);
     InitializedSomething = true;
+    InitializedFields.insert(*Field);
 
     if (RD->isUnion() && StructuredList) {
       // Initialize the first field within the union.
@@ -2411,6 +2360,28 @@ void InitListChecker::CheckStructUnionTypes(
     ++Field;
   }
 
+  // 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 (!it->isUnnamedBitfield() && !it->hasInClassInitializer() &&
+          !it->getType()->isIncompleteArrayType()) {
+        SemaRef.Diag(IList->getSourceRange().getEnd(),
+                     diag::warn_missing_field_initializers)
+            << *it;
+        break;
+      }
+    }
+  }
+
   // Check that any remaining fields can be value-initialized if we're not
   // building a structured list. (If we are, we'll check this later.)
   if (!StructuredList && Field != FieldEnd && !RD->isUnion() &&

diff  --git a/clang/test/Sema/missing-field-initializers.c b/clang/test/Sema/missing-field-initializers.c
index 8dc8288ad92e6c..1e65b2d62e1ab8 100644
--- a/clang/test/Sema/missing-field-initializers.c
+++ b/clang/test/Sema/missing-field-initializers.c
@@ -18,7 +18,7 @@ struct Foo bar1[] = {
   1, 2,
   1, 2,
   1
-}; // expected-warning at -1 {{missing field 'b' initializer}}
+}; // expected-warning {{missing field 'b' initializer}}
 
 struct Foo bar2[] = { {}, {}, {} };
 
@@ -61,26 +61,3 @@ struct S {
 // f1, now we no longer issue that warning (note, this code is still unsafe
 // because of the buffer overrun).
 struct S s = {1, {1, 2}};
-
-struct S1 {
-  long int l;
-  struct  { int a, b; } d1;
-};
-
-struct S1 s01 = { 1, {1} }; // expected-warning {{missing field 'b' initializer}}
-struct S1 s02 = { .d1.a = 1 }; // designator avoids MFI warning
-
-union U1 {
-  long int l;
-  struct  { int a, b; } d1;
-};
-
-union U1 u01 = { 1 };
-union U1 u02 = { .d1.a = 1 }; // designator avoids MFI warning
-
-struct S2 {
-  long int l;
-  struct { int a, b; struct {int c; } d2; } d1;
-};
-
-struct S2 s22 = { .d1.d2.c = 1 }; // designator avoids MFI warning

diff  --git a/clang/test/SemaCXX/cxx2a-initializer-aggregates.cpp b/clang/test/SemaCXX/cxx2a-initializer-aggregates.cpp
index 0d977e07ed034e..510ace58c35a6a 100644
--- a/clang/test/SemaCXX/cxx2a-initializer-aggregates.cpp
+++ b/clang/test/SemaCXX/cxx2a-initializer-aggregates.cpp
@@ -1,6 +1,6 @@
 // RUN: %clang_cc1 -std=c++20 %s -verify=cxx20,expected,pedantic,override,reorder -pedantic-errors
 // RUN: %clang_cc1 -std=c++17 %s -verify=expected,pedantic,override,reorder -Wno-c++20-designator -pedantic-errors
-// RUN: %clang_cc1 -std=c++20 %s -verify=cxx20,expected,pedantic -Werror=c99-designator -Wno-reorder-init-list -Wno-initializer-overrides -Werror=nested-anon-types -Werror=gnu-anonymous-struct
+// RUN: %clang_cc1 -std=c++20 %s -verify=cxx20,expected,pedantic -Werror=c99-designator -Wno-reorder-init-list -Wno-initializer-overrides
 // 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
@@ -39,7 +39,6 @@ A a1 = {
 };
 int arr[3] = {[1] = 5}; // pedantic-error {{array designators are a C99 extension}}
 B b = {.a.x = 0}; // pedantic-error {{nested designators are a C99 extension}}
-                  // wmissing-warning at -1 {{missing field 'y' initializer}}
 A a2 = {
   .x = 1, // pedantic-error {{mixture of designated and non-designated initializers in the same initializer list is a C99 extension}}
   2 // pedantic-note {{first non-designated initializer is here}}
@@ -61,6 +60,7 @@ B b2 = {.a = 1}; // pedantic-error {{brace elision for designated initializer is
 B b3 = {.a = 1, 2}; // pedantic-error {{mixture of designated and non-designated}} pedantic-note {{first non-designated}} pedantic-error {{brace elision}}
 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}}
 B b5 = {.a = nullptr}; // expected-error {{cannot initialize}}
+                       // wmissing-warning at -1 {{missing field 'y' initializer}}
 struct C { int :0, x, :0, y, :0; };
 C c = {
   .x = 1, // override-note {{previous}}
@@ -247,87 +247,3 @@ 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}}
-}
-
-struct C1 {
-  int m;
-  union { float b; union {int n = 1; }; };
-  // pedantic-error at -1 {{anonymous types declared in an anonymous union are an extension}}
-};
-
-struct C2 {
-  int m;
-  struct { float b; int n = 1; }; // pedantic-error {{anonymous structs are a GNU extension}}
-};
-
-struct C3 {
-  int m;
-  struct { float b = 1; union {int a;}; int n = 1; };
-  // pedantic-error at -1 {{anonymous structs are a GNU extension}}
-  // pedantic-error at -2 {{anonymous types declared in an anonymous struct are an extension}}
-};
-
-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}}
-
-struct C4 {
-  union {
-    struct { int n; }; // pedantic-error {{anonymous structs are a GNU extension}}
-    // pedantic-error at -1 {{anonymous types declared in an anonymous union are an extension}}
-    int m = 0; };
-  int z;
-};
-C4 a = {.z = 1};
-
-struct C5 {
-  int a;
-  struct { // pedantic-error {{anonymous structs are a GNU extension}}
-    int x;
-    struct { int y = 0; };  // pedantic-error {{anonymous types declared in an anonymous struct are an extension}}
-                            // pedantic-error at -1 {{anonymous structs are a GNU extension}}
-  };
-};
-C5 c5 = C5{.a = 0}; //wmissing-warning {{missing field 'x' initializer}}
-}


        


More information about the cfe-commits mailing list