r314838 - Suppress -Wmissing-braces warning when aggregate-initializing a struct with a single field that is itself an aggregate.
Richard Smith via cfe-commits
cfe-commits at lists.llvm.org
Tue Oct 3 13:36:00 PDT 2017
Author: rsmith
Date: Tue Oct 3 13:36:00 2017
New Revision: 314838
URL: http://llvm.org/viewvc/llvm-project?rev=314838&view=rev
Log:
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.
Modified:
cfe/trunk/lib/Sema/SemaInit.cpp
cfe/trunk/test/Sema/zero-initializer.c
cfe/trunk/test/SemaCXX/aggregate-initialization.cpp
Modified: cfe/trunk/lib/Sema/SemaInit.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaInit.cpp?rev=314838&r1=314837&r2=314838&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaInit.cpp (original)
+++ cfe/trunk/lib/Sema/SemaInit.cpp Tue Oct 3 13:36:00 2017
@@ -826,6 +826,34 @@ int InitListChecker::numStructUnionEleme
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::CheckImplicitInitL
// 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()
Modified: cfe/trunk/test/Sema/zero-initializer.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/zero-initializer.c?rev=314838&r1=314837&r2=314838&view=diff
==============================================================================
--- cfe/trunk/test/Sema/zero-initializer.c (original)
+++ cfe/trunk/test/Sema/zero-initializer.c Tue Oct 3 13:36:00 2017
@@ -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;
}
Modified: cfe/trunk/test/SemaCXX/aggregate-initialization.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/aggregate-initialization.cpp?rev=314838&r1=314837&r2=314838&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/aggregate-initialization.cpp (original)
+++ cfe/trunk/test/SemaCXX/aggregate-initialization.cpp Tue Oct 3 13:36:00 2017
@@ -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 at -5 {{protected constructor}}
// expected-note at -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
+}
More information about the cfe-commits
mailing list