diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -154,6 +154,8 @@ "'new' cannot allocate object of variably modified type %0">; // C99 Designated Initializers +def ext_c20_designated_init : Extension< + "C99 %0 designated initializers are a C++20 extention">, InGroup; def ext_designated_init : Extension< "designated initializers are a C99 feature">, InGroup; def err_array_designator_negative : Error< diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -1999,6 +1999,7 @@ bool CheckForMissingFields = !IList->isIdiomaticZeroInitializer(SemaRef.getLangOpts()); bool HasDesignatedInit = false; + bool HasNonDesignatedInit = false; while (Index < IList->getNumInits()) { Expr *Init = IList->getInit(Index); @@ -2013,6 +2014,10 @@ HasDesignatedInit = true; + unsigned LastIdx = + Field != FieldEnd ? Field->getFieldIndex() + : std::distance(RD->field_begin(), RD->field_end()); + // Handle this designated initializer. Field will be updated to // the next field that we'll be initializing. if (CheckDesignatedInitializer(Entity, IList, DIE, 0, @@ -2032,6 +2037,20 @@ } } + unsigned NextIdx = + Field != FieldEnd ? Field->getFieldIndex() + : std::distance(RD->field_begin(), RD->field_end()); + if (!VerifyOnly && SemaRef.getLangOpts().CPlusPlus2a) { + if (LastIdx >= NextIdx) { + SemaRef.Diag(Init->getBeginLoc(), diag::ext_c20_designated_init) + << "out of order" << Init->getSourceRange(); + } + if (HasNonDesignatedInit) { + SemaRef.Diag(Init->getBeginLoc(), diag::ext_c20_designated_init) + << "mixed" << Init->getSourceRange(); + } + } + InitializedSomething = true; // Disable check for missing fields when designators are used. @@ -2045,6 +2064,13 @@ break; } + HasNonDesignatedInit = true; + + if (!VerifyOnly && HasDesignatedInit && SemaRef.getLangOpts().CPlusPlus2a) { + SemaRef.Diag(Init->getBeginLoc(), diag::ext_c20_designated_init) + << "mixed" << Init->getSourceRange(); + } + // We've already initialized a member of a union. We're done. if (InitializedSomething && DeclType->isUnionType()) break; @@ -2980,6 +3006,7 @@ bool Invalid = false; SmallVector Designators; SmallVector InitExpressions; + bool HasArrayDesignator = false; // Build designators and check array designator expressions. for (unsigned Idx = 0; Idx < Desig.getNumDesignators(); ++Idx) { @@ -3003,6 +3030,7 @@ D.getRBracketLoc())); InitExpressions.push_back(Index); } + HasArrayDesignator = true; break; } @@ -3046,6 +3074,7 @@ InitExpressions.push_back(EndIndex); } } + HasArrayDesignator = true; break; } } @@ -3063,9 +3092,19 @@ InitExpressions, Loc, GNUSyntax, Init.getAs()); - if (!getLangOpts().C99) + if (!getLangOpts().C99 && !getLangOpts().CPlusPlus2a) { Diag(DIE->getBeginLoc(), diag::ext_designated_init) << DIE->getSourceRange(); + } else if (getLangOpts().CPlusPlus2a) { + if (Desig.getNumDesignators() > 1) { + Diag(DIE->getBeginLoc(), diag::ext_c20_designated_init) + << "nested" << DIE->getSourceRange(); + } + if (HasArrayDesignator) { + Diag(DIE->getBeginLoc(), diag::ext_c20_designated_init) + << "array" << DIE->getSourceRange(); + } + } return DIE; } diff --git a/clang/test/SemaCXX/cxx2a-initializer-aggregates.cpp b/clang/test/SemaCXX/cxx2a-initializer-aggregates.cpp --- a/clang/test/SemaCXX/cxx2a-initializer-aggregates.cpp +++ b/clang/test/SemaCXX/cxx2a-initializer-aggregates.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -std=c++2a %s -verify +// RUN: %clang_cc1 -std=c++2a %s -verify -pedantic namespace class_with_ctor { struct A { // expected-note 6{{candidate}} @@ -21,3 +21,14 @@ C c1 = {{}, {}}; // ok, call default ctor twice C c2 = {{1, 2}, {3, 4}}; // expected-error 2{{no matching constructor}} } + +namespace designator { +struct A { int x, y; }; +struct B { A a; }; + +A a1 = {.y = 1, .x = 2}; // expected-warning {{C99 out of order designated initializers are a C++20 extention}} +int arr[3] = {[1] = 5}; // expected-warning {{C99 array designated initializers are a C++20 extention}} +B b = {.a.x = 0}; // expected-warning {{C99 nested designated initializers are a C++20 extention}} +A a2 = {.x = 1, 2}; // expected-warning {{C99 mixed designated initializers are a C++20 extention}} +A a3 = {1, .y = 2}; // expected-warning {{C99 mixed designated initializers are a C++20 extention}} +}