summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/AST/Expr.h4
-rw-r--r--include/clang/Sema/Sema.h2
-rw-r--r--lib/Parse/ParseInit.cpp25
-rw-r--r--lib/Sema/SemaInit.cpp30
-rw-r--r--test/Parser/cxx2a-designated-init.cpp25
-rwxr-xr-xwww/cxx_status.html2
6 files changed, 83 insertions, 5 deletions
diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h
index 3dff4df0a1..30fa84315f 100644
--- a/include/clang/AST/Expr.h
+++ b/include/clang/AST/Expr.h
@@ -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; }
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index 0ca74e58e0..d7581a1673 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -4644,7 +4644,7 @@ public:
SourceLocation RBraceLoc);
ExprResult ActOnDesignatedInitializer(Designation &Desig,
- SourceLocation Loc,
+ SourceLocation EqualOrColonLoc,
bool GNUSyntax,
ExprResult Init);
diff --git a/lib/Parse/ParseInit.cpp b/lib/Parse/ParseInit.cpp
index eaf31e81b9..5ab055130d 100644
--- a/lib/Parse/ParseInit.cpp
+++ b/lib/Parse/ParseInit.cpp
@@ -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
diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp
index 297121381e..87cc3cd762 100644
--- a/lib/Sema/SemaInit.cpp
+++ b/lib/Sema/SemaInit.cpp
@@ -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
index 0000000000..974214137a
--- /dev/null
+++ b/test/Parser/cxx2a-designated-init.cpp
@@ -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 {{}}
diff --git a/www/cxx_status.html b/www/cxx_status.html
index 23cc6ca2c1..d3d610914d 100755
--- a/www/cxx_status.html
+++ b/www/cxx_status.html
@@ -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>