[clang] b15cbaf - PR49020: Diagnose brace elision in designated initializers in C++.

Richard Smith via cfe-commits cfe-commits at lists.llvm.org
Wed Feb 3 14:37:03 PST 2021


Author: Richard Smith
Date: 2021-02-03T14:36:49-08:00
New Revision: b15cbaf5a03d0b32dbc32c37766e32ccf66e6c87

URL: https://github.com/llvm/llvm-project/commit/b15cbaf5a03d0b32dbc32c37766e32ccf66e6c87
DIFF: https://github.com/llvm/llvm-project/commit/b15cbaf5a03d0b32dbc32c37766e32ccf66e6c87.diff

LOG: PR49020: Diagnose brace elision in designated initializers in C++.

This is a corner of the differences between C99 designators and C++20
designators that we'd previously overlooked. As with other such cases,
this continues to be permitted as an extension and allowed by default,
behind the -Wc99-designators warning flag, except in cases where it
leads to a conformance difference (such as in overload resolution and in
a SFINAE context).

Added: 
    

Modified: 
    clang/include/clang/Basic/DiagnosticSemaKinds.td
    clang/lib/Sema/SemaInit.cpp
    clang/test/SemaCXX/cxx2a-initializer-aggregates.cpp

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index d31cc76b04d1..61e8f7f28f1c 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -214,6 +214,9 @@ def ext_designated_init_reordered : ExtWarn<
   SFINAEFailure;
 def note_previous_field_init : Note<
   "previous initialization for field %0 is here">;
+def ext_designated_init_brace_elision : ExtWarn<
+  "brace elision for designated initializer is a C99 extension">,
+  InGroup<C99Designator>, SFINAEFailure;
 
 // Declarations.
 def ext_plain_complex : ExtWarn<

diff  --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp
index 4e3547c5121f..640755cec222 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/lib/Sema/SemaInit.cpp
@@ -315,7 +315,8 @@ class InitListChecker {
                            InitListExpr *IList, QualType ElemType,
                            unsigned &Index,
                            InitListExpr *StructuredList,
-                           unsigned &StructuredIndex);
+                           unsigned &StructuredIndex,
+                           bool DirectlyDesignated = false);
   void CheckComplexType(const InitializedEntity &Entity,
                         InitListExpr *IList, QualType DeclType,
                         unsigned &Index,
@@ -1326,7 +1327,8 @@ void InitListChecker::CheckSubElementType(const InitializedEntity &Entity,
                                           QualType ElemType,
                                           unsigned &Index,
                                           InitListExpr *StructuredList,
-                                          unsigned &StructuredIndex) {
+                                          unsigned &StructuredIndex,
+                                          bool DirectlyDesignated) {
   Expr *expr = IList->getInit(Index);
 
   if (ElemType->isReferenceType())
@@ -1462,6 +1464,20 @@ void InitListChecker::CheckSubElementType(const InitializedEntity &Entity,
     CheckImplicitInitList(Entity, IList, ElemType, Index, StructuredList,
                           StructuredIndex);
     ++StructuredIndex;
+
+    // In C++20, brace elision is not permitted for a designated initializer.
+    if (DirectlyDesignated && SemaRef.getLangOpts().CPlusPlus && !hadError) {
+      if (InOverloadResolution)
+        hadError = true;
+      if (!VerifyOnly) {
+        SemaRef.Diag(expr->getBeginLoc(),
+                     diag::ext_designated_init_brace_elision)
+            << expr->getSourceRange()
+            << FixItHint::CreateInsertion(expr->getBeginLoc(), "{")
+            << FixItHint::CreateInsertion(
+                   SemaRef.getLocForEndOfToken(expr->getEndLoc()), "}");
+      }
+    }
   } else {
     if (!VerifyOnly) {
       // We cannot initialize this element, so let PerformCopyInitialization
@@ -2413,8 +2429,8 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
     unsigned OldIndex = Index;
     IList->setInit(OldIndex, DIE->getInit());
 
-    CheckSubElementType(Entity, IList, CurrentObjectType, Index,
-                        StructuredList, StructuredIndex);
+    CheckSubElementType(Entity, IList, CurrentObjectType, Index, StructuredList,
+                        StructuredIndex, /*DirectlyDesignated=*/true);
 
     // Restore the designated initializer expression in the syntactic
     // form of the initializer list.

diff  --git a/clang/test/SemaCXX/cxx2a-initializer-aggregates.cpp b/clang/test/SemaCXX/cxx2a-initializer-aggregates.cpp
index 653fcf439c15..c6339116af8b 100644
--- a/clang/test/SemaCXX/cxx2a-initializer-aggregates.cpp
+++ b/clang/test/SemaCXX/cxx2a-initializer-aggregates.cpp
@@ -54,6 +54,10 @@ A a5 = {
   .y = 1, // override-note {{previous}}
   .y = 1 // override-error {{overrides prior initialization}}
 };
+B b2 = {.a = 1}; // pedantic-error {{brace elision for designated initializer is a C99 extension}}
+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}}
 struct C { int :0, x, :0, y, :0; };
 C c = {
   .x = 1, // override-note {{previous}}
@@ -112,6 +116,15 @@ namespace overload_resolution {
   void k() {
     j({.x = 1, .y = 2}); // expected-error {{ambiguous}}
   }
+
+  struct E { A a; };
+  struct F { int a; };
+  void l(E e); // expected-note {{candidate}}
+  int &l(F f); // expected-note {{candidate}}
+  void m() {
+    int &r = l({.a = 0}); // ok, l(E) is not viable
+    int &s = l({.a = {0}}); // expected-error {{ambiguous}}
+  }
 }
 
 namespace deduction {
@@ -128,4 +141,18 @@ namespace deduction {
   void i() {
     h<A, C>(); // ok, selects C overload by SFINAE
   }
+
+  struct D { int n; };
+  struct E { D n; };
+  template<typename T, typename U> void j1(decltype(T{.n = 0}));
+  template<typename T, typename U> void j1(decltype(U{.n = 0})) = delete;
+  template<typename T, typename U> void j2(decltype(T{.n = {0}})); // expected-note {{candidate}}
+  template<typename T, typename U> void j2(decltype(U{.n = {0}})); // expected-note {{candidate}}
+  template<typename T, typename U> void j3(decltype(T{.n = {{0}}})) = delete;
+  template<typename T, typename U> void j3(decltype(U{.n = {{0}}}));
+  void k() {
+    j1<D, E>({}); // ok, selects D overload by SFINAE (too few braces for E)
+    j2<D, E>({}); // expected-error {{ambiguous}}
+    j3<D, E>({}); // ok, selects E overload by SFINAE (too many braces for D)
+  }
 }


        


More information about the cfe-commits mailing list