https://github.com/Fznamznon created https://github.com/llvm/llvm-project/pull/70829
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 >From ac30780250875802d13450d17e6959f9e2ad3a70 Mon Sep 17 00:00:00 2001 From: "Podchishchaeva, Mariya" <mariya.podchishcha...@intel.com> Date: Tue, 31 Oct 2023 09:27:51 -0700 Subject: [PATCH] [clang] Fix false positive -Wmissing-field-initializer for anonymous 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 https://github.com/llvm/llvm-project/issues/70384 --- clang/lib/Sema/SemaInit.cpp | 99 +++++++++++-------- .../SemaCXX/cxx2a-initializer-aggregates.cpp | 66 ++++++++++++- 2 files changed, 122 insertions(+), 43 deletions(-) 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 +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits