Skip to content

Commit

Permalink
[clang] Report missing designated initializers in C++
Browse files Browse the repository at this point in the history
Prior to this change clang didn't emit missing-field-initializers
warning for designated initializers. The comments say that it is done to
match gcc behavior. However, gcc behaves so only for C. For C++ warnings
are emitted.

Fixes llvm#56628

Reviewed By: aaron.ballman

Differential Revision: https://reviews.llvm.org/D157879
  • Loading branch information
Fznamznon authored and razmser committed Oct 2, 2023
1 parent 00c6fcc commit 818d41a
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 19 deletions.
3 changes: 3 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,9 @@ Bug Fixes in This Version
- Fix a hang on valid C code passing a function type as an argument to
``typeof`` to form a function declaration.
(`#64713 <https://github.com/llvm/llvm-project/issues/64713>_`)
- Clang now reports missing-field-initializers warning for missing designated
initializers in C++.
(`#56628 <https://github.com/llvm/llvm-project/issues/56628>`_)

Bug Fixes to Compiler Builtins
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down
46 changes: 29 additions & 17 deletions clang/lib/Sema/SemaInit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2252,6 +2252,8 @@ void InitListChecker::CheckStructUnionTypes(
!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();
Expand All @@ -2267,28 +2269,32 @@ void InitListChecker::CheckStructUnionTypes(

// Handle this designated initializer. Field will be updated to
// the next field that we'll be initializing.
if (CheckDesignatedInitializer(Entity, IList, DIE, 0,
DeclType, &Field, nullptr, Index,
StructuredList, StructuredIndex,
true, TopLevelObject))
bool DesignatedInitFailed = CheckDesignatedInitializer(
Entity, IList, DIE, 0, DeclType, &Field, nullptr, Index,
StructuredList, StructuredIndex, true, TopLevelObject);
if (DesignatedInitFailed)
hadError = true;
else if (!VerifyOnly) {
// Find the field named by the designated initializer.
RecordDecl::field_iterator F = RD->field_begin();
while (std::next(F) != Field)
++F;
QualType ET = SemaRef.Context.getBaseElementType(F->getType());
if (checkDestructorReference(ET, InitLoc, SemaRef)) {
hadError = true;
return;

// Find the field named by the designated initializer.
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)) {
hadError = true;
return;
}
}
}

InitializedSomething = true;

// Disable check for missing fields when designators are used.
// This matches gcc behaviour.
CheckForMissingFields = false;
if (!SemaRef.getLangOpts().CPlusPlus)
CheckForMissingFields = false;
continue;
}

Expand Down Expand Up @@ -2367,6 +2373,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.
Expand All @@ -2378,15 +2385,20 @@ void InitListChecker::CheckStructUnionTypes(

// Emit warnings for missing struct field initializers.
if (!VerifyOnly && InitializedSomething && CheckForMissingFields &&
Field != FieldEnd && !Field->getType()->isIncompleteArrayType() &&
!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 = Field, end = RD->field_end();
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()) {
SemaRef.Diag(IList->getSourceRange().getEnd(),
diag::warn_missing_field_initializers) << *it;
diag::warn_missing_field_initializers)
<< *it;
break;
}
}
Expand Down
14 changes: 12 additions & 2 deletions clang/test/SemaCXX/cxx2a-initializer-aggregates.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +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


namespace class_with_ctor {
Expand Down Expand Up @@ -49,15 +50,17 @@ A a3 = {
A a4 = {
.x = 1, // override-note {{previous}}
.x = 1 // override-error {{overrides prior initialization}}
};
}; // wmissing-warning {{missing field 'y' initializer}}
A a5 = {
.y = 1, // override-note {{previous}}
.y = 1 // override-error {{overrides prior initialization}}
};
}; // wmissing-warning {{missing field 'x' initializer}}
B b2 = {.a = 1}; // pedantic-error {{brace elision for designated initializer is a C99 extension}}
// wmissing-warning@-1 {{missing field 'y' initializer}}
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@-1 {{missing field 'y' initializer}}
struct C { int :0, x, :0, y, :0; };
C c = {
.x = 1, // override-note {{previous}}
Expand All @@ -67,6 +70,13 @@ C c = {
.x = 1, // reorder-error {{declaration order}} override-error {{overrides prior initialization}} override-note {{previous}}
.x = 1, // override-error {{overrides prior initialization}}
};

struct Foo { int a, b; };

struct Foo foo0 = { 1 }; // wmissing-warning {{missing field 'b' initializer}}
struct Foo foo1 = { .a = 1 }; // wmissing-warning {{missing field 'b' initializer}}
struct Foo foo2 = { .b = 1 }; // wmissing-warning {{missing field 'a' initializer}}

}

namespace base_class {
Expand Down

0 comments on commit 818d41a

Please sign in to comment.