forked from OSchip/llvm-project
Suppress -Wmissing-braces warning when aggregate-initializing a struct with a single field that is itself an aggregate.
In C++, such initialization of std::array<T, N> types is guaranteed to work by the standard, is completely idiomatic, and the "suggested" alternative from Clang was technically invalid. llvm-svn: 314838
This commit is contained in:
parent
389b7cedc3
commit
283e2076f6
|
@ -826,6 +826,34 @@ int InitListChecker::numStructUnionElements(QualType DeclType) {
|
|||
return InitializableMembers - structDecl->hasFlexibleArrayMember();
|
||||
}
|
||||
|
||||
/// Determine whether Entity is an entity for which it is idiomatic to elide
|
||||
/// the braces in aggregate initialization.
|
||||
static bool isIdiomaticBraceElisionEntity(const InitializedEntity &Entity) {
|
||||
// Recursive initialization of the one and only field within an aggregate
|
||||
// class is considered idiomatic. This case arises in particular for
|
||||
// initialization of std::array, where the C++ standard suggests the idiom of
|
||||
//
|
||||
// std::array<T, N> arr = {1, 2, 3};
|
||||
//
|
||||
// (where std::array is an aggregate struct containing a single array field.
|
||||
|
||||
// FIXME: Should aggregate initialization of a struct with a single
|
||||
// base class and no members also suppress the warning?
|
||||
if (Entity.getKind() != InitializedEntity::EK_Member || !Entity.getParent())
|
||||
return false;
|
||||
|
||||
auto *ParentRD =
|
||||
Entity.getParent()->getType()->castAs<RecordType>()->getDecl();
|
||||
if (CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(ParentRD))
|
||||
if (CXXRD->getNumBases())
|
||||
return false;
|
||||
|
||||
auto FieldIt = ParentRD->field_begin();
|
||||
assert(FieldIt != ParentRD->field_end() &&
|
||||
"no fields but have initializer for member?");
|
||||
return ++FieldIt == ParentRD->field_end();
|
||||
}
|
||||
|
||||
/// Check whether the range of the initializer \p ParentIList from element
|
||||
/// \p Index onwards can be used to initialize an object of type \p T. Update
|
||||
/// \p Index to indicate how many elements of the list were consumed.
|
||||
|
@ -887,7 +915,8 @@ void InitListChecker::CheckImplicitInitList(const InitializedEntity &Entity,
|
|||
|
||||
// Complain about missing braces.
|
||||
if ((T->isArrayType() || T->isRecordType()) &&
|
||||
!ParentIList->isIdiomaticZeroInitializer(SemaRef.getLangOpts())) {
|
||||
!ParentIList->isIdiomaticZeroInitializer(SemaRef.getLangOpts()) &&
|
||||
!isIdiomaticBraceElisionEntity(Entity)) {
|
||||
SemaRef.Diag(StructuredSubobjectInitList->getLocStart(),
|
||||
diag::warn_missing_braces)
|
||||
<< StructuredSubobjectInitList->getSourceRange()
|
||||
|
|
|
@ -6,6 +6,7 @@ struct bar { struct foo a; struct foo b; };
|
|||
struct A { int a; };
|
||||
struct B { struct A a; };
|
||||
struct C { struct B b; };
|
||||
struct D { struct C c; int n; };
|
||||
|
||||
int main(void)
|
||||
{
|
||||
|
@ -20,7 +21,8 @@ int main(void)
|
|||
struct bar n = { { 0 }, { 9, 9 } }; // no-warning
|
||||
struct bar o = { { 9 }, { 9, 9 } }; // expected-warning {{missing field 'y' initializer}}
|
||||
struct C p = { 0 }; // no-warning
|
||||
struct C q = { 9 }; // expected-warning {{suggest braces around initialization of subobject}} expected-warning {{suggest braces around initialization of subobject}}
|
||||
struct C q = { 9 }; // warning suppressed for struct with single element
|
||||
struct D r = { 9 }; // expected-warning {{suggest braces around initialization of subobject}} expected-warning {{missing field 'n' initializer}}
|
||||
f = (struct foo ) { 0 }; // no-warning
|
||||
g = (struct foo ) { 9 }; // expected-warning {{missing field 'y' initializer}}
|
||||
h = (struct foo ) { 9, 9 }; // no-warning
|
||||
|
@ -32,7 +34,8 @@ int main(void)
|
|||
n = (struct bar) { { 0 }, { 9, 9 } }; // no-warning
|
||||
o = (struct bar) { { 9 }, { 9, 9 } }; // expected-warning {{missing field 'y' initializer}}
|
||||
p = (struct C) { 0 }; // no-warning
|
||||
q = (struct C) { 9 }; // expected-warning {{suggest braces around initialization of subobject}} expected-warning {{suggest braces around initialization of subobject}}
|
||||
q = (struct C) { 9 }; // warning suppressed for struct with single element
|
||||
r = (struct D) { 9 }; // expected-warning {{suggest braces around initialization of subobject}} expected-warning {{missing field 'n' initializer}}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
|
||||
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++14 %s
|
||||
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++1z %s
|
||||
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++17 %s
|
||||
|
||||
// Verify that using an initializer list for a non-aggregate looks for
|
||||
// constructors..
|
||||
|
@ -150,3 +150,33 @@ namespace ProtectedBaseCtor {
|
|||
// expected-error@-5 {{protected constructor}}
|
||||
// expected-note@-30 {{here}}
|
||||
}
|
||||
|
||||
namespace IdiomaticStdArrayInitDoesNotWarn {
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic warning "-Wmissing-braces"
|
||||
template<typename T, int N> struct StdArray {
|
||||
T contents[N];
|
||||
};
|
||||
StdArray<int, 3> x = {1, 2, 3};
|
||||
|
||||
template<typename T, int N> struct ArrayAndSomethingElse {
|
||||
T contents[N];
|
||||
int something_else;
|
||||
};
|
||||
ArrayAndSomethingElse<int, 3> y = {1, 2, 3}; // expected-warning {{suggest braces}}
|
||||
|
||||
#if __cplusplus >= 201703L
|
||||
template<typename T, int N> struct ArrayAndBaseClass : StdArray<int, 3> {
|
||||
T contents[N];
|
||||
};
|
||||
ArrayAndBaseClass<int, 3> z = {1, 2, 3}; // expected-warning {{suggest braces}}
|
||||
|
||||
// It's not clear whether we should be warning in this case. If this
|
||||
// pattern becomes idiomatic, it would be reasonable to suppress the
|
||||
// warning here too.
|
||||
template<typename T, int N> struct JustABaseClass : StdArray<T, N> {};
|
||||
JustABaseClass<int, 3> w = {1, 2, 3}; // expected-warning {{suggest braces}}
|
||||
#endif
|
||||
|
||||
#pragma clang diagnostic pop
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue