@@ -465,7 +465,8 @@ class InitListChecker {
465
465
void FillInEmptyInitForField (unsigned Init, FieldDecl *Field,
466
466
const InitializedEntity &ParentEntity,
467
467
InitListExpr *ILE, bool &RequiresSecondPass,
468
- bool FillWithNoInit = false );
468
+ bool FillWithNoInit = false ,
469
+ bool WarnIfMissing = false );
469
470
void FillInEmptyInitializations (const InitializedEntity &Entity,
470
471
InitListExpr *ILE, bool &RequiresSecondPass,
471
472
InitListExpr *OuterILE, unsigned OuterIndex,
@@ -654,11 +655,16 @@ void InitListChecker::FillInEmptyInitForBase(
654
655
}
655
656
}
656
657
657
- void InitListChecker::FillInEmptyInitForField (unsigned Init, FieldDecl *Field,
658
- const InitializedEntity &ParentEntity,
659
- InitListExpr *ILE,
660
- bool &RequiresSecondPass,
661
- bool FillWithNoInit) {
658
+ static bool hasAnyDesignatedInits (const InitListExpr *IL) {
659
+ return llvm::any_of (*IL, [=](const Stmt *Init) {
660
+ return isa_and_nonnull<DesignatedInitExpr>(Init);
661
+ });
662
+ }
663
+
664
+ void InitListChecker::FillInEmptyInitForField (
665
+ unsigned Init, FieldDecl *Field, const InitializedEntity &ParentEntity,
666
+ InitListExpr *ILE, bool &RequiresSecondPass, bool FillWithNoInit,
667
+ bool WarnIfMissing) {
662
668
SourceLocation Loc = ILE->getEndLoc ();
663
669
unsigned NumInits = ILE->getNumInits ();
664
670
InitializedEntity MemberEntity
@@ -726,15 +732,52 @@ void InitListChecker::FillInEmptyInitForField(unsigned Init, FieldDecl *Field,
726
732
727
733
if (hadError || VerifyOnly) {
728
734
// Do nothing
729
- } else if (Init < NumInits) {
730
- ILE->setInit (Init, MemberInit.getAs <Expr>());
731
- } else if (!isa<ImplicitValueInitExpr>(MemberInit.get ())) {
732
- // Empty initialization requires a constructor call, so
733
- // extend the initializer list to include the constructor
734
- // call and make a note that we'll need to take another pass
735
- // through the initializer list.
736
- ILE->updateInit (SemaRef.Context , Init, MemberInit.getAs <Expr>());
737
- RequiresSecondPass = true ;
735
+ } else {
736
+ if (WarnIfMissing) {
737
+ auto CheckAnonMember = [&](const FieldDecl *FD,
738
+ auto &&CheckAnonMember) -> FieldDecl * {
739
+ FieldDecl *Uninitialized = nullptr ;
740
+ RecordDecl *RD = FD->getType ()->getAsRecordDecl ();
741
+ assert (RD && " Not anonymous member checked?" );
742
+ for (auto *F : RD->fields ()) {
743
+ FieldDecl *UninitializedFieldInF = nullptr ;
744
+ if (F->isAnonymousStructOrUnion ())
745
+ UninitializedFieldInF = CheckAnonMember (F, CheckAnonMember);
746
+ else if (!F->isUnnamedBitfield () &&
747
+ !F->getType ()->isIncompleteArrayType () &&
748
+ !F->hasInClassInitializer ())
749
+ UninitializedFieldInF = F;
750
+
751
+ if (RD->isUnion () && !UninitializedFieldInF)
752
+ return nullptr ;
753
+ if (!Uninitialized)
754
+ Uninitialized = UninitializedFieldInF;
755
+ }
756
+ return Uninitialized;
757
+ };
758
+
759
+ FieldDecl *FieldToDiagnose = nullptr ;
760
+ if (Field->isAnonymousStructOrUnion ())
761
+ FieldToDiagnose = CheckAnonMember (Field, CheckAnonMember);
762
+ else if (!Field->isUnnamedBitfield () &&
763
+ !Field->getType ()->isIncompleteArrayType ())
764
+ FieldToDiagnose = Field;
765
+
766
+ if (FieldToDiagnose)
767
+ SemaRef.Diag (Loc, diag::warn_missing_field_initializers)
768
+ << FieldToDiagnose;
769
+ }
770
+
771
+ if (Init < NumInits) {
772
+ ILE->setInit (Init, MemberInit.getAs <Expr>());
773
+ } else if (!isa<ImplicitValueInitExpr>(MemberInit.get ())) {
774
+ // Empty initialization requires a constructor call, so
775
+ // extend the initializer list to include the constructor
776
+ // call and make a note that we'll need to take another pass
777
+ // through the initializer list.
778
+ ILE->updateInit (SemaRef.Context , Init, MemberInit.getAs <Expr>());
779
+ RequiresSecondPass = true ;
780
+ }
738
781
}
739
782
} else if (InitListExpr *InnerILE
740
783
= dyn_cast<InitListExpr>(ILE->getInit (Init))) {
@@ -802,9 +845,25 @@ InitListChecker::FillInEmptyInitializations(const InitializedEntity &Entity,
802
845
}
803
846
}
804
847
} else {
848
+ InitListExpr *SForm =
849
+ ILE->isSyntacticForm () ? ILE : ILE->getSyntacticForm ();
805
850
// The fields beyond ILE->getNumInits() are default initialized, so in
806
851
// order to leave them uninitialized, the ILE is expanded and the extra
807
852
// fields are then filled with NoInitExpr.
853
+
854
+ // Some checks that are required for missing fields warning are bound to
855
+ // how many elements the initializer list originally was provided; perform
856
+ // them before the list is expanded.
857
+ bool WarnIfMissingField =
858
+ !SForm->isIdiomaticZeroInitializer (SemaRef.getLangOpts ()) &&
859
+ ILE->getNumInits ();
860
+
861
+ // Disable check for missing fields when designators are used in C to
862
+ // match gcc behaviour.
863
+ // FIXME: Should we emulate possible gcc warning bug?
864
+ WarnIfMissingField &=
865
+ SemaRef.getLangOpts ().CPlusPlus || !hasAnyDesignatedInits (SForm);
866
+
808
867
unsigned NumElems = numStructUnionElements (ILE->getType ());
809
868
if (!RDecl->isUnion () && RDecl->hasFlexibleArrayMember ())
810
869
++NumElems;
@@ -832,7 +891,7 @@ InitListChecker::FillInEmptyInitializations(const InitializedEntity &Entity,
832
891
return ;
833
892
834
893
FillInEmptyInitForField (Init, Field, Entity, ILE, RequiresSecondPass,
835
- FillWithNoInit);
894
+ FillWithNoInit, WarnIfMissingField );
836
895
if (hadError)
837
896
return ;
838
897
@@ -947,13 +1006,6 @@ InitListChecker::FillInEmptyInitializations(const InitializedEntity &Entity,
947
1006
}
948
1007
}
949
1008
950
- static bool hasAnyDesignatedInits (const InitListExpr *IL) {
951
- for (const Stmt *Init : *IL)
952
- if (isa_and_nonnull<DesignatedInitExpr>(Init))
953
- return true ;
954
- return false ;
955
- }
956
-
957
1009
InitListChecker::InitListChecker (
958
1010
Sema &S, const InitializedEntity &Entity, InitListExpr *IL, QualType &T,
959
1011
bool VerifyOnly, bool TreatUnavailableAsInvalid, bool InOverloadResolution,
@@ -2225,12 +2277,8 @@ void InitListChecker::CheckStructUnionTypes(
2225
2277
size_t NumRecordDecls = llvm::count_if (RD->decls (), [&](const Decl *D) {
2226
2278
return isa<FieldDecl>(D) || isa<RecordDecl>(D);
2227
2279
});
2228
- bool CheckForMissingFields =
2229
- !IList->isIdiomaticZeroInitializer (SemaRef.getLangOpts ());
2230
2280
bool HasDesignatedInit = false ;
2231
2281
2232
- llvm::SmallPtrSet<FieldDecl *, 4 > InitializedFields;
2233
-
2234
2282
while (Index < IList->getNumInits ()) {
2235
2283
Expr *Init = IList->getInit (Index);
2236
2284
SourceLocation InitLoc = Init->getBeginLoc ();
@@ -2254,24 +2302,17 @@ void InitListChecker::CheckStructUnionTypes(
2254
2302
2255
2303
// Find the field named by the designated initializer.
2256
2304
DesignatedInitExpr::Designator *D = DIE->getDesignator (0 );
2257
- if (!VerifyOnly && D->isFieldDesignator ()) {
2305
+ if (!VerifyOnly && D->isFieldDesignator () && !DesignatedInitFailed ) {
2258
2306
FieldDecl *F = D->getFieldDecl ();
2259
- InitializedFields.insert (F);
2260
- if (!DesignatedInitFailed) {
2261
- QualType ET = SemaRef.Context .getBaseElementType (F->getType ());
2262
- if (checkDestructorReference (ET, InitLoc, SemaRef)) {
2263
- hadError = true ;
2264
- return ;
2265
- }
2307
+ QualType ET = SemaRef.Context .getBaseElementType (F->getType ());
2308
+ if (checkDestructorReference (ET, InitLoc, SemaRef)) {
2309
+ hadError = true ;
2310
+ return ;
2266
2311
}
2267
2312
}
2268
2313
2269
2314
InitializedSomething = true ;
2270
2315
2271
- // Disable check for missing fields when designators are used.
2272
- // This matches gcc behaviour.
2273
- if (!SemaRef.getLangOpts ().CPlusPlus )
2274
- CheckForMissingFields = false ;
2275
2316
continue ;
2276
2317
}
2277
2318
@@ -2350,7 +2391,6 @@ void InitListChecker::CheckStructUnionTypes(
2350
2391
CheckSubElementType (MemberEntity, IList, Field->getType (), Index,
2351
2392
StructuredList, StructuredIndex);
2352
2393
InitializedSomething = true ;
2353
- InitializedFields.insert (*Field);
2354
2394
2355
2395
if (RD->isUnion () && StructuredList) {
2356
2396
// Initialize the first field within the union.
@@ -2360,28 +2400,6 @@ void InitListChecker::CheckStructUnionTypes(
2360
2400
++Field;
2361
2401
}
2362
2402
2363
- // Emit warnings for missing struct field initializers.
2364
- if (!VerifyOnly && InitializedSomething && CheckForMissingFields &&
2365
- !RD->isUnion ()) {
2366
- // It is possible we have one or more unnamed bitfields remaining.
2367
- // Find first (if any) named field and emit warning.
2368
- for (RecordDecl::field_iterator it = HasDesignatedInit ? RD->field_begin ()
2369
- : Field,
2370
- end = RD->field_end ();
2371
- it != end; ++it) {
2372
- if (HasDesignatedInit && InitializedFields.count (*it))
2373
- continue ;
2374
-
2375
- if (!it->isUnnamedBitfield () && !it->hasInClassInitializer () &&
2376
- !it->getType ()->isIncompleteArrayType ()) {
2377
- SemaRef.Diag (IList->getSourceRange ().getEnd (),
2378
- diag::warn_missing_field_initializers)
2379
- << *it;
2380
- break ;
2381
- }
2382
- }
2383
- }
2384
-
2385
2403
// Check that any remaining fields can be value-initialized if we're not
2386
2404
// building a structured list. (If we are, we'll check this later.)
2387
2405
if (!StructuredList && Field != FieldEnd && !RD->isUnion () &&
0 commit comments