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@-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 +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits