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; + auto 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,15 @@ } } + // Warn on out of order and mixed designators in C++20. + auto NextIdx = Field != FieldEnd + ? Field->getFieldIndex() + : std::distance(RD->field_begin(), RD->field_end()); + if (VerifyOnly && (LastIdx >= NextIdx || HasNonDesignatedInit) && + SemaRef.getLangOpts().CPlusPlus2a) + SemaRef.Diag(Init->getBeginLoc(), diag::ext_designated_init) + << Init->getSourceRange(); + InitializedSomething = true; // Disable check for missing fields when designators are used. @@ -2045,6 +2059,13 @@ break; } + HasNonDesignatedInit = true; + + // Warn on mixed designators in C++20 + if (VerifyOnly && HasDesignatedInit && SemaRef.getLangOpts().CPlusPlus2a) + SemaRef.Diag(Init->getBeginLoc(), diag::ext_designated_init) + << Init->getSourceRange(); + // We've already initialized a member of a union. We're done. if (InitializedSomething && DeclType->isUnionType()) break; @@ -2976,6 +2997,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) { @@ -2999,6 +3021,7 @@ D.getRBracketLoc())); InitExpressions.push_back(Index); } + HasArrayDesignator = true; break; } @@ -3042,6 +3065,7 @@ InitExpressions.push_back(EndIndex); } } + HasArrayDesignator = true; break; } } @@ -3060,8 +3084,11 @@ Init.getAs()); if (!getLangOpts().C99) - Diag(DIE->getBeginLoc(), diag::ext_designated_init) - << DIE->getSourceRange(); + // Warn on nested and array designators in C++20 + if (!getLangOpts().CPlusPlus2a || Desig.getNumDesignators() > 1 || + HasArrayDesignator) + Diag(DIE->getBeginLoc(), diag::ext_designated_init) + << 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,21 @@ 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; }; + +// out of order designators +A a1 = {.y = 1, .x = 2}; // expected-warning {{designated initializers are a C99 feature}} + +// array designator +int arr[3] = {[1] = 5}; // expected-warning {{designated initializers are a C99 feature}} + +// nested designator +B b = {.a.x = 0}; // expected-warning {{designated initializers are a C99 feature}} + +// mixed designator and non-designator +A a2 = {.x = 1, 2}; // expected-warning {{designated initializers are a C99 feature}} +A a3 = {1, .y = 2}; // expected-warning {{designated initializers are a C99 feature}} +}