hankadusikova created this revision. hankadusikova added a reviewer: clang. hankadusikova requested review of this revision. Herald added a project: clang. Herald added a subscriber: cfe-commits.
Removes this warning: template<typename T, int N> struct StdArray { T contents[N]; }; template<typename T, int N> struct AggregateAndEmpty : StdArray<T,N> { }; AggregateAndEmpty<int, 3> p = {1, 2, 3}; // <-- warning here about omitted braces This warning starts to be prominent when you have multiple levels of inheritance for strong typing with aggregates: template<typename T, int N> struct StdArray { T contents[N]; }; template <typename T, int N> struct JustABaseClass : StdArray<T, N> {}; template <typename T, int N> struct OnionBaseClass : JustABaseClass<T, N> {}; OnionBaseClass<int,3> i = {1,2,3}; // instead {{{1,2,3}}} This is my first patch for clang, so I hopefully didn't overlook something, but all tests are green. Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D100057 Files: clang/lib/Sema/SemaInit.cpp clang/test/SemaCXX/aggregate-initialization.cpp Index: clang/test/SemaCXX/aggregate-initialization.cpp =================================================================== --- clang/test/SemaCXX/aggregate-initialization.cpp +++ clang/test/SemaCXX/aggregate-initialization.cpp @@ -172,11 +172,20 @@ }; 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. + // This pattern is used for tagged aggregates and must not warn template<typename T, int N> struct JustABaseClass : StdArray<T, N> {}; - JustABaseClass<int, 3> w = {1, 2, 3}; // expected-warning {{suggest braces}} + JustABaseClass<int, 3> w = {1, 2, 3}; + // but this should be also ok + JustABaseClass<int, 3> v = {{1, 2, 3}}; + + template <typename T, int N> struct OnionBaseClass : JustABaseClass<T, N> {}; + OnionBaseClass<int, 3> u = {1, 2, 3}; + OnionBaseClass<int, 3> t = {{{1, 2, 3}}}; + + struct EmptyBase {}; + + template <typename T, int N> struct AggregateAndEmpty : StdArray<T, N>, EmptyBase {}; + AggregateAndEmpty<int, 3> p = {1, 2, 3}; // expected-warning {{suggest braces}} #endif #pragma clang diagnostic pop Index: clang/lib/Sema/SemaInit.cpp =================================================================== --- clang/lib/Sema/SemaInit.cpp +++ clang/lib/Sema/SemaInit.cpp @@ -1007,21 +1007,37 @@ // // (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()) + if (!Entity.getParent()) return false; - auto *ParentRD = - Entity.getParent()->getType()->castAs<RecordType>()->getDecl(); - if (CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(ParentRD)) - if (CXXRD->getNumBases()) - return false; + // Allows elide brace initialization for aggreagates with empty base + if (Entity.getKind() == InitializedEntity::EK_Base) { + auto *ParentRD = + Entity.getParent()->getType()->castAs<RecordType>()->getDecl(); + if (CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(ParentRD)) { + if (CXXRD->getNumBases() == 1) { + return ParentRD->field_begin() == ParentRD->field_end(); + } + } + return false; + } - auto FieldIt = ParentRD->field_begin(); - assert(FieldIt != ParentRD->field_end() && - "no fields but have initializer for member?"); - return ++FieldIt == ParentRD->field_end(); + // Allows elide brace initilization for aggregates with one member + if (Entity.getKind() == InitializedEntity::EK_Member) { + 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(); + } + + return false; } /// Check whether the range of the initializer \p ParentIList from element
Index: clang/test/SemaCXX/aggregate-initialization.cpp =================================================================== --- clang/test/SemaCXX/aggregate-initialization.cpp +++ clang/test/SemaCXX/aggregate-initialization.cpp @@ -172,11 +172,20 @@ }; 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. + // This pattern is used for tagged aggregates and must not warn template<typename T, int N> struct JustABaseClass : StdArray<T, N> {}; - JustABaseClass<int, 3> w = {1, 2, 3}; // expected-warning {{suggest braces}} + JustABaseClass<int, 3> w = {1, 2, 3}; + // but this should be also ok + JustABaseClass<int, 3> v = {{1, 2, 3}}; + + template <typename T, int N> struct OnionBaseClass : JustABaseClass<T, N> {}; + OnionBaseClass<int, 3> u = {1, 2, 3}; + OnionBaseClass<int, 3> t = {{{1, 2, 3}}}; + + struct EmptyBase {}; + + template <typename T, int N> struct AggregateAndEmpty : StdArray<T, N>, EmptyBase {}; + AggregateAndEmpty<int, 3> p = {1, 2, 3}; // expected-warning {{suggest braces}} #endif #pragma clang diagnostic pop Index: clang/lib/Sema/SemaInit.cpp =================================================================== --- clang/lib/Sema/SemaInit.cpp +++ clang/lib/Sema/SemaInit.cpp @@ -1007,21 +1007,37 @@ // // (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()) + if (!Entity.getParent()) return false; - auto *ParentRD = - Entity.getParent()->getType()->castAs<RecordType>()->getDecl(); - if (CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(ParentRD)) - if (CXXRD->getNumBases()) - return false; + // Allows elide brace initialization for aggreagates with empty base + if (Entity.getKind() == InitializedEntity::EK_Base) { + auto *ParentRD = + Entity.getParent()->getType()->castAs<RecordType>()->getDecl(); + if (CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(ParentRD)) { + if (CXXRD->getNumBases() == 1) { + return ParentRD->field_begin() == ParentRD->field_end(); + } + } + return false; + } - auto FieldIt = ParentRD->field_begin(); - assert(FieldIt != ParentRD->field_end() && - "no fields but have initializer for member?"); - return ++FieldIt == ParentRD->field_end(); + // Allows elide brace initilization for aggregates with one member + if (Entity.getKind() == InitializedEntity::EK_Member) { + 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(); + } + + return false; } /// Check whether the range of the initializer \p ParentIList from element
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits