Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Merged
merged 8 commits into from
Dec 13, 2023

Conversation

Fznamznon
Copy link
Contributor

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 #70384

…unions

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 llvm#70384
@llvmbot llvmbot added clang Clang issues not falling into any other category clang:frontend Language frontend issues, e.g. anything involving "Sema" labels Oct 31, 2023
@llvmbot
Copy link
Collaborator

llvmbot commented Oct 31, 2023

@llvm/pr-subscribers-clang

Author: Mariya Podchishchaeva (Fznamznon)

Changes

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 #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 --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@-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@-1 {{missing field 'm' initializer}}
+#endif // NON_PEDANTIC
+}

@zygoloid
Copy link
Collaborator

Thanks for looking into this!

I wonder if it would make sense to move the checking for this warning here, to the else case in line 725:

ExprResult MemberInit = PerformEmptyInit(Loc, MemberEntity);
if (MemberInit.isInvalid()) {
hadError = true;
return;
}
if (hadError || VerifyOnly) {
// Do nothing
} 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;
}

That should remove the need to build and check the InitializedFields set, because you'll never need to consider a field that is partially initialized: you'll only visit fully-uninitialized fields (we'll recurse into structs that are partially initialized). You'll still need to recurse into anonymous struct and union members when deciding whether to warn, so it doesn't remove all of the complexity here, but I think that change should simplify things a bit.

@@ -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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Imo it's clearer to unconditionally compile the same code for each test case, and instead introduce another -verify prefix for the diagnostics that aren't emitted by this invocation.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, done.

@Fznamznon
Copy link
Contributor Author

Fznamznon commented Nov 6, 2023

I wonder if it would make sense to move the checking for this warning here, to the else case in line 725

Thanks for the suggestion, I moved a warning. It turned out with a couple of questionable moments, but still looks simpler than the first version.

clang/lib/Sema/SemaInit.cpp Outdated Show resolved Hide resolved
@@ -727,6 +729,44 @@ void InitListChecker::FillInEmptyInitForField(unsigned Init, FieldDecl *Field,
if (hadError || VerifyOnly) {
// Do nothing
} else if (Init < NumInits) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it OK that we don't warn on the else case here? Do we still warn for:

struct A { int x, y; };
A a = {.x = 1}; // missing `.y` initializer

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, we still warn for this case.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, how does that work? If this if condition doesn't hold and we created an ImplicitValueInitExpr, we wouldn't produce the warning.

Ah, I see what's happening: the if condition on line 736 is always true, because since cb77930 we always resize the init list for a struct to be large enough for all fields, and our optimization to leave off trailing struct members was (accidentally, I think) removed. And we can see the optimization stops working between Clang 3.6 and Clang 3.7.

Given that we've been living without that optimization for 8 years and no-one seems to have noticed, I suppose that it's fine that we've lost it, but it looks like this function can be simplified a bit as a result. Half of the if condition on line 674 is always false, and this if condition is always true. Maybe consider changing the L674 condition to an assert(Init < NumInits) and simplify this too?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe consider changing the L674 condition to an assert(Init < NumInits) and simplify this too?

I'm not sure I understand the suggestion. The condition on L674 looks like:

if (Init >= NumInits || !ILE->getInit(Init)) {

Even if I only remove Init >= NumInits, build of check-clang starts asserting with

Assertion `Init < getNumInits() && "Initializer access out of range!"'

Removing !ILE->getInit(Init) also doesn't seem logical to me since FillInEmptyInitForField is called for all fields in a record.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm, right, we still call this with Init >= NumInits when in VerifyOnly mode (but only in that mode).

My concern here is that we're only warning in the Init < NumInits case, which is in principle wrong -- we should warn regardless of whether Init < NumInits. But in fact, the caller always resizes the InitListExpr so that Init >= NumInits whenever we're not in VerifyOnly mode, so I think this is probably not actually wrong, but it still looks wrong.

To make it not look wrong, I think we should remove all the dead code here: instead of checking whether Init < NumInits in non-VerifyOnly mode, we should assert that Init < NumInits, and delete the unreachable code that is trying to handle the impossible case: lines 684-685, 704-707, 772-778. Does that make sense?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems Init < NumInits is always true for non-VerifyOnly mode only for structs. So, removing lines 684-685, 704-707, 772-778 breaks a number of tests with unions. The assertion on line 676 confirms:

if (Init >= NumInits || !ILE->getInit(Init)) {
  if (const RecordType *RType = ILE->getType()->getAs<RecordType>())
    if (!RType->getDecl()->isUnion())
      assert((Init < NumInits || VerifyOnly) &&
             "This ILE should have been expanded");

I can still put warning emission out of Init < NumInits check though if that seems more correct.

clang/lib/Sema/SemaInit.cpp Outdated Show resolved Hide resolved
clang/lib/Sema/SemaInit.cpp Outdated Show resolved Hide resolved
Comment on lines 743 to 753
for (auto *F : RD->fields()) {
if (F->isAnonymousStructOrUnion())
Uninitialized = CheckAnonMember(F, CheckAnonMember);
else if (!F->isUnnamedBitfield() &&
!F->getType()->isIncompleteArrayType() && !Uninitialized &&
!F->hasInClassInitializer())
Uninitialized = F;

if (RD->isUnion() && (F->hasInClassInitializer() || !Uninitialized))
return nullptr;
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this will not warn on

struct A {
  int a;
  struct {
    int x;
    struct { int y = 0; };
  };
};
A a = A{.a = 0};

... because the Uninitialized value for x will get overwritten by the nullptr returned from the struct containing y. How about:

Suggested change
for (auto *F : RD->fields()) {
if (F->isAnonymousStructOrUnion())
Uninitialized = CheckAnonMember(F, CheckAnonMember);
else if (!F->isUnnamedBitfield() &&
!F->getType()->isIncompleteArrayType() && !Uninitialized &&
!F->hasInClassInitializer())
Uninitialized = F;
if (RD->isUnion() && (F->hasInClassInitializer() || !Uninitialized))
return nullptr;
}
for (auto *F : RD->fields()) {
FieldDecl *UninitializedFieldInF;
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;
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, done. Thanks for the catch!

Comment on lines 659 to 662
for (const Stmt *Init : *IL)
if (isa_and_nonnull<DesignatedInitExpr>(Init))
return true;
return false;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you use llvm::any_of ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, done.

@Fznamznon
Copy link
Contributor Author

Ping.

@Fznamznon
Copy link
Contributor Author

Ping.

1 similar comment
@Fznamznon
Copy link
Contributor Author

Ping.

Copy link
Collaborator

@AaronBallman AaronBallman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the changes here look reasonable. CC @zygoloid to make sure he agrees as there's still one potentially outstanding comment (if we don't hear back from Richard, I think we can address his concerns post-commit as it seems like a refactoring rather than a behavioral fix).

clang/lib/Sema/SemaInit.cpp Outdated Show resolved Hide resolved
clang/lib/Sema/SemaInit.cpp Outdated Show resolved Hide resolved
Copy link
Collaborator

@AaronBallman AaronBallman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, but please wait until sometime mid-next week to land in case Richard has concerns.

@Fznamznon Fznamznon merged commit a01307a into llvm:main Dec 13, 2023
4 checks passed
@mikaelholmen
Copy link
Collaborator

Hi @Fznamznon and others!

It looks like this patch not only avoids a false positive, but it also causes warnigns on stuff it didn't warn on before.
So if I add the following to clang/test/Sema/missing-field-initializers.c

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 };

union U1 {
  long int l;
  struct  { int a, b; } d1;
};

union U1 u01 = { 1 };
union U1 u02 = { .d1.a = 1 };

Without the patch it's silent, but with the patch I get

  File /repo/uabelho/main-github/clang/test/Sema/missing-field-initializers.c Line 11: missing field 'b' initializer
  File /repo/uabelho/main-github/clang/test/Sema/missing-field-initializers.c Line 19: missing field 'b' initializer

so it warns on

struct S1 s02 = { .d1.a = 1 };

and

union U1 u02 = { .d1.a = 1 };

I suppose this is not as expected?

We see thousands of warnings like this with our downstream compiler.

@Fznamznon
Copy link
Contributor Author

@mikaelholmen , thanks for the report. These warnings are kind of expected, there is no big difference between struct S1 s01 = { 1, {1} }; and struct S1 s02 = { .d1.a = 1 }; in both cases field b of d1 is not initialized. But they are not expected for C, since we aim to silence missing field initializer warning for designated initializers in C, just to match gcc behavior. It seems the patch broke this "silencing" for nested designators, I'll try to provide the fix shortly. If I'm not able, I'll revert.

@mikaelholmen
Copy link
Collaborator

I'll try to provide the fix shortly. If I'm not able, I'll revert.

Sounds good. Thank you!

@mikaelholmen
Copy link
Collaborator

mikaelholmen commented Dec 18, 2023

Hi again @Fznamznon
the following also started causing warnings after this patch (also with the fix)

struct S3 {
  long int l;
  struct  { int a, b; } d1[2];
};

struct S3 s32 = { .d1[0].a = 1 };

We get

foo.c:6:30: warning: missing field 'b' initializer [-Wmissing-field-initializers]
    6 | struct S3 s32 = { .d1[0].a = 1 };
      |                              ^
1 warning generated.

with this patch.

EDIT: we saw 2870 -Wmissing-field-initializers warnings with the original version of the patch for one kind of downstream build.
After the friday fix we're now down to 2757 warnings for that build, but really hard to say how many different kinds of cases we get warnings for. The one above is at least one but I suppose there are more hiding...

@Fznamznon
Copy link
Contributor Author

@mikaelholmen , I see. I'll revert both patches to unblock you and I'll think about the proper solution after the holidays.
Perhaps there should be wider discussion whether we should emulate GCC behavior regarding silencing of these warnings.
IMO, the warnings you're seeing are correct, there is no initializer for field b. It is emulating of possible gcc bug that this patch breaks.

@mikaelholmen
Copy link
Collaborator

mikaelholmen commented Dec 18, 2023

@Fznamznon : Thank you!
A wider discussion about how clang should behave sounds good.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:frontend Language frontend issues, e.g. anything involving "Sema" clang Clang issues not falling into any other category
Projects
None yet
7 participants