]> granicus.if.org Git - clang/commitdiff
[c++20] Add support for designated direct-list-initialization syntax.
authorRichard Smith <richard-llvm@metafoo.co.uk>
Sat, 31 Aug 2019 01:00:37 +0000 (01:00 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Sat, 31 Aug 2019 01:00:37 +0000 (01:00 +0000)
This completes the implementation of P0329R4.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@370558 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/AST/Expr.h
include/clang/Sema/Sema.h
lib/Parse/ParseInit.cpp
lib/Sema/SemaInit.cpp
test/Parser/cxx2a-designated-init.cpp [new file with mode: 0644]
www/cxx_status.html

index 3dff4df0a11ec77f132898cd4cd8ba699b60cbbf..30fa84315ff5376ff58ef03a17e3315e07ae9ec8 100644 (file)
@@ -4831,6 +4831,10 @@ public:
   SourceLocation getEqualOrColonLoc() const { return EqualOrColonLoc; }
   void setEqualOrColonLoc(SourceLocation L) { EqualOrColonLoc = L; }
 
+  /// Whether this designated initializer should result in direct-initialization
+  /// of the designated subobject (eg, '{.foo{1, 2, 3}}').
+  bool isDirectInit() const { return EqualOrColonLoc.isInvalid(); }
+
   /// Determines whether this designated initializer used the
   /// deprecated GNU syntax for designated initializers.
   bool usesGNUSyntax() const { return GNUSyntax; }
index 0ca74e58e0da72e720c5fa6d1600fbb516fc9124..d7581a16739b8c1d468d272e29cb47870ad785c5 100644 (file)
@@ -4644,7 +4644,7 @@ public:
                            SourceLocation RBraceLoc);
 
   ExprResult ActOnDesignatedInitializer(Designation &Desig,
-                                        SourceLocation Loc,
+                                        SourceLocation EqualOrColonLoc,
                                         bool GNUSyntax,
                                         ExprResult Init);
 
index eaf31e81b95b080e73631078b7fbc404eff8f701..5ab055130dc2ae87ade294823c3c0d8c75a61604 100644 (file)
@@ -116,6 +116,8 @@ static void CheckArrayDesignatorSyntax(Parser &P, SourceLocation Loc,
 /// ParseInitializerWithPotentialDesignator - Parse the 'initializer' production
 /// checking to see if the token stream starts with a designator.
 ///
+/// C99:
+///
 ///       designation:
 ///         designator-list '='
 /// [GNU]   array-designator
@@ -133,6 +135,21 @@ static void CheckArrayDesignatorSyntax(Parser &P, SourceLocation Loc,
 ///         '[' constant-expression ']'
 /// [GNU]   '[' constant-expression '...' constant-expression ']'
 ///
+/// C++20:
+///
+///       designated-initializer-list:
+///         designated-initializer-clause
+///         designated-initializer-list ',' designated-initializer-clause
+///
+///       designated-initializer-clause:
+///         designator brace-or-equal-initializer
+///
+///       designator:
+///         '.' identifier
+///
+/// We allow the C99 syntax extensions in C++20, but do not allow the C++20
+/// extension (a braced-init-list after the designator with no '=') in C99.
+///
 /// NOTE: [OBC] allows '[ objc-receiver objc-message-args ]' as an
 /// initializer (because it is an expression).  We need to consider this case
 /// when parsing array designators.
@@ -365,6 +382,14 @@ ExprResult Parser::ParseInitializerWithPotentialDesignator() {
                                               ParseInitializer());
   }
 
+  // Handle a C++20 braced designated initialization, which results in
+  // direct-list-initialization of the aggregate element. We allow this as an
+  // extension from C++11 onwards (when direct-list-initialization was added).
+  if (Tok.is(tok::l_brace) && getLangOpts().CPlusPlus11) {
+    return Actions.ActOnDesignatedInitializer(Desig, SourceLocation(), false,
+                                              ParseBraceInitializer());
+  }
+
   // We read some number of designators and found something that isn't an = or
   // an initializer.  If we have exactly one array designator, this
   // is the GNU 'designation: array-designator' extension.  Otherwise, it is a
index 297121381e8f7f07e81862a0de2e916a906d9528..87cc3cd762c5dbd4ce051f35293a8f2f522657f9 100644 (file)
@@ -2367,6 +2367,29 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
                                             bool FinishSubobjectInit,
                                             bool TopLevelObject) {
   if (DesigIdx == DIE->size()) {
+    // C++20 designated initialization can result in direct-list-initialization
+    // of the designated subobject. This is the only way that we can end up
+    // performing direct initialization as part of aggregate initialization, so
+    // it needs special handling.
+    if (DIE->isDirectInit()) {
+      Expr *Init = DIE->getInit();
+      assert(isa<InitListExpr>(Init) &&
+             "designator result in direct non-list initialization?");
+      InitializationKind Kind = InitializationKind::CreateDirectList(
+          DIE->getBeginLoc(), Init->getBeginLoc(), Init->getEndLoc());
+      InitializationSequence Seq(SemaRef, Entity, Kind, Init,
+                                 /*TopLevelOfInitList*/ true);
+      if (StructuredList) {
+        ExprResult Result = VerifyOnly
+                                ? getDummyInit()
+                                : Seq.Perform(SemaRef, Entity, Kind, Init);
+        UpdateStructuredListElement(StructuredList, StructuredIndex,
+                                    Result.get());
+      }
+      ++Index;
+      return !Seq;
+    }
+
     // Check the actual initialization for the designated object type.
     bool prevHadError = hadError;
 
@@ -3101,7 +3124,7 @@ CheckArrayDesignatorExpr(Sema &S, Expr *Index, llvm::APSInt &Value) {
 }
 
 ExprResult Sema::ActOnDesignatedInitializer(Designation &Desig,
-                                            SourceLocation Loc,
+                                            SourceLocation EqualOrColonLoc,
                                             bool GNUSyntax,
                                             ExprResult Init) {
   typedef DesignatedInitExpr::Designator ASTDesignator;
@@ -3189,8 +3212,9 @@ ExprResult Sema::ActOnDesignatedInitializer(Designation &Desig,
   // Clear out the expressions within the designation.
   Desig.ClearExprs(*this);
 
-  return DesignatedInitExpr::Create(Context, Designators, InitExpressions, Loc,
-                                    GNUSyntax, Init.getAs<Expr>());
+  return DesignatedInitExpr::Create(Context, Designators, InitExpressions,
+                                    EqualOrColonLoc, GNUSyntax,
+                                    Init.getAs<Expr>());
 }
 
 //===----------------------------------------------------------------------===//
diff --git a/test/Parser/cxx2a-designated-init.cpp b/test/Parser/cxx2a-designated-init.cpp
new file mode 100644 (file)
index 0000000..9742141
--- /dev/null
@@ -0,0 +1,25 @@
+// RUN: %clang_cc1 -std=c++98 -verify=cxx98 %s
+// RUN: %clang_cc1 -std=c++11 -verify %s -Wno-c++2a-extensions
+// RUN: %clang_cc1 -std=c++2a -verify %s
+
+struct A {
+  explicit A(int, int); // expected-note {{here}}
+};
+
+struct B {
+  A a;
+};
+
+B b1 = {.a = {1, 2}}; // cxx98-error {{non-aggregate type 'A' cannot be initialized with an initializer list}}
+// expected-error@-1 {{chosen constructor is explicit in copy-initialization}}
+B b2 = {.a{1, 2}}; // cxx98-error {{expected '='}}
+
+struct C {
+  char x, y;
+};
+struct D {
+  C c;
+};
+
+D d1 = {.c = {1, 2000}}; // cxx98-warning {{changes value}} expected-error {{narrow}} expected-warning {{changes value}} expected-note {{}}
+D d2 = {.c{1, 2000}}; // cxx98-error {{expected '='}} expected-error {{narrow}} expected-warning {{changes value}} expected-note {{}}
index 23cc6ca2c19292f7dcd2b6dd121e76bd54b4ee7e..d3d610914dfb3b59a4701817799b593df5183fa5 100755 (executable)
@@ -871,7 +871,7 @@ as the draft C++2a standard evolves.
     <tr>
       <td>Designated initializers</td>
       <td><a href="http://wg21.link/p0329r4">P0329R4</a></td>
-      <td class="partial" align="center">Partial (extension)</td>
+      <td class="svn" align="center">SVN (Clang 10)</td>
     </tr>
     <tr>
       <td><i>template-parameter-list</i> for generic lambdas</td>