https://github.com/kbrav updated https://github.com/llvm/llvm-project/pull/127924
>From 7f7b9b3f2e7324bd290decb7151c9432875b1dd6 Mon Sep 17 00:00:00 2001 From: kbrav <[email protected]> Date: Wed, 19 Feb 2025 19:05:05 -0500 Subject: [PATCH 1/9] [clang] more useful error message for decomposition declaration missing initializer (#90107) --- clang/include/clang/Basic/DiagnosticSemaKinds.td | 2 +- clang/lib/Sema/SemaDecl.cpp | 12 +++++++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index feef50812eca9..ad36ae898b147 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -555,7 +555,7 @@ def err_decomp_decl_template : Error< def err_decomp_decl_not_alone : Error< "decomposition declaration must be the only declaration in its group">; def err_decomp_decl_requires_init : Error< - "decomposition declaration %0 requires an initializer">; + "decomposition declaration %0 requires an initializer, but got %1 instead">; def err_decomp_decl_wrong_number_bindings : Error< "type %0 decomposes into %3 %plural{1:element|:elements}2, but " "%select{%plural{0:no|:only %1}1|%1}4 " diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 362df485a025c..c62041c8c5e93 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -14058,7 +14058,17 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl) { // C++1z [dcl.dcl]p1 grammar implies that an initializer is mandatory. if (isa<DecompositionDecl>(RealDecl)) { - Diag(Var->getLocation(), diag::err_decomp_decl_requires_init) << Var; + Preprocessor &PP = getPreprocessor(); + SourceManager &SM = Context.getSourceManager(); + LangOptions LO = Context.getLangOpts(); + + // Lexer previously checked for '=' and didn't find it + // Highlight the token found in its place in the error message + Token Tok; + Lexer::getRawToken(PP.getLastCachedTokenLocation(), Tok, SM, LO); + + Diag(Tok.getLocation(), diag::err_decomp_decl_requires_init) + << Var << Lexer::getSpelling(Tok, SM, LO); Var->setInvalidDecl(); return; } >From cd657462ec40663896fa60fdabf565625188958f Mon Sep 17 00:00:00 2001 From: kbrav <[email protected]> Date: Wed, 19 Feb 2025 19:51:19 -0500 Subject: [PATCH 2/9] run clang-format --- clang/lib/Sema/SemaDecl.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index c62041c8c5e93..724da72b8115e 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -14058,9 +14058,9 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl) { // C++1z [dcl.dcl]p1 grammar implies that an initializer is mandatory. if (isa<DecompositionDecl>(RealDecl)) { - Preprocessor &PP = getPreprocessor(); + Preprocessor &PP = getPreprocessor(); SourceManager &SM = Context.getSourceManager(); - LangOptions LO = Context.getLangOpts(); + LangOptions LO = Context.getLangOpts(); // Lexer previously checked for '=' and didn't find it // Highlight the token found in its place in the error message @@ -14068,7 +14068,7 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl) { Lexer::getRawToken(PP.getLastCachedTokenLocation(), Tok, SM, LO); Diag(Tok.getLocation(), diag::err_decomp_decl_requires_init) - << Var << Lexer::getSpelling(Tok, SM, LO); + << Var << Lexer::getSpelling(Tok, SM, LO); Var->setInvalidDecl(); return; } >From feac0003628dd18a54a8c1f101bd21be4e714534 Mon Sep 17 00:00:00 2001 From: kbrav <[email protected]> Date: Tue, 25 Feb 2025 02:01:22 -0500 Subject: [PATCH 3/9] highlight token after decomposition decl in parser --- clang/docs/ReleaseNotes.rst | 1 + clang/include/clang/Basic/DiagnosticParseKinds.td | 1 + clang/include/clang/Basic/DiagnosticSemaKinds.td | 2 +- clang/lib/Parse/ParseDecl.cpp | 2 ++ clang/lib/Sema/SemaDecl.cpp | 12 +----------- clang/test/PCH/cxx1z-decomposition.cpp | 2 +- clang/test/Parser/cxx1z-decomposition.cpp | 9 +++++---- clang/test/SemaCXX/cxx1z-decomposition.cpp | 2 +- 8 files changed, 13 insertions(+), 18 deletions(-) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 657340c170503..109abdef4ad01 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -193,6 +193,7 @@ Improvements to Clang's diagnostics under the subgroup ``-Wunsafe-buffer-usage-in-libc-call``. - Diagnostics on chained comparisons (``a < b < c``) are now an error by default. This can be disabled with ``-Wno-error=parentheses``. +- Added a clearer diagnostic for uninitialized decomposition declarations. Improvements to Clang's time-trace ---------------------------------- diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td index c513dab810d1f..f80670949e58a 100644 --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -497,6 +497,7 @@ def err_expected_coloncolon_after_super : Error< def ext_decomp_decl_empty : ExtWarn< "ISO C++17 does not allow a decomposition group to be empty">, InGroup<DiagGroup<"empty-decomposition">>; +def err_expected_init : Error<"expected initializer before '%0'">; def err_function_parameter_limit_exceeded : Error< "too many function parameters; subsequent parameters will be ignored">; diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 980960095d68a..51301d95e55b9 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -555,7 +555,7 @@ def err_decomp_decl_template : Error< def err_decomp_decl_not_alone : Error< "decomposition declaration must be the only declaration in its group">; def err_decomp_decl_requires_init : Error< - "decomposition declaration %0 requires an initializer, but got %1 instead">; + "decomposition declaration %0 requires an initializer">; def err_decomp_decl_wrong_number_bindings : Error< "type %0 decomposes into %3 %plural{1:element|:elements}2, but " "%select{%plural{0:no|:only %1}1|%1}4 " diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index 7ae136af47391..1cb871493aaeb 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -2932,6 +2932,8 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes( break; } case InitKind::Uninitialized: { + if (D.isDecompositionDeclarator()) + Diag(Tok, diag::err_expected_init) << PP.getSpelling(Tok); Actions.ActOnUninitializedDecl(ThisDecl); break; } diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 54bd22a4f5254..285bd27a35a76 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -14065,17 +14065,7 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl) { // C++1z [dcl.dcl]p1 grammar implies that an initializer is mandatory. if (isa<DecompositionDecl>(RealDecl)) { - Preprocessor &PP = getPreprocessor(); - SourceManager &SM = Context.getSourceManager(); - LangOptions LO = Context.getLangOpts(); - - // Lexer previously checked for '=' and didn't find it - // Highlight the token found in its place in the error message - Token Tok; - Lexer::getRawToken(PP.getLastCachedTokenLocation(), Tok, SM, LO); - - Diag(Tok.getLocation(), diag::err_decomp_decl_requires_init) - << Var << Lexer::getSpelling(Tok, SM, LO); + Diag(Var->getLocation(), diag::err_decomp_decl_requires_init) << Var; Var->setInvalidDecl(); return; } diff --git a/clang/test/PCH/cxx1z-decomposition.cpp b/clang/test/PCH/cxx1z-decomposition.cpp index 914ce80c550d1..e6d56bfefd3d0 100644 --- a/clang/test/PCH/cxx1z-decomposition.cpp +++ b/clang/test/PCH/cxx1z-decomposition.cpp @@ -22,7 +22,7 @@ constexpr int foo(Q &&q) { return a * 10 + b; } -auto [noinit]; // expected-error{{decomposition declaration '[noinit]' requires an initializer}} +auto [noinit]; // expected-error{{decomposition declaration '[noinit]' requires an initializer}} expected-error{{expected initializer before ';'}} #else diff --git a/clang/test/Parser/cxx1z-decomposition.cpp b/clang/test/Parser/cxx1z-decomposition.cpp index acf3f99069185..94d3f15f2e498 100644 --- a/clang/test/Parser/cxx1z-decomposition.cpp +++ b/clang/test/Parser/cxx1z-decomposition.cpp @@ -103,10 +103,10 @@ namespace BadSpecifiers { // FIXME: This error is not very good. auto [d]() = s; // expected-error {{expected ';'}} expected-error {{expected expression}} - auto [e][1] = s; // expected-error {{expected ';'}} expected-error {{requires an initializer}} + auto [e][1] = s; // expected-error {{expected ';'}} expected-error {{requires an initializer}} expected-error {{expected initializer before '['}} // FIXME: This should fire the 'misplaced array declarator' diagnostic. - int [K] arr = {0}; // expected-error {{expected ';'}} expected-error {{cannot be declared with type 'int'}} expected-error {{decomposition declaration '[K]' requires an initializer}} + int [K] arr = {0}; // expected-error {{expected ';'}} expected-error {{cannot be declared with type 'int'}} expected-error {{decomposition declaration '[K]' requires an initializer}} expected-error {{expected initializer before 'arr'}} int [5] arr = {0}; // expected-error {{place the brackets after the name}} auto *[f] = s; // expected-error {{cannot be declared with type 'auto *'}} expected-error {{incompatible initializer}} @@ -120,7 +120,7 @@ namespace BadSpecifiers { [[]] auto [ok_3] = s; alignas(S) auto [ok_4] = s; - auto [bad_attr_2] [[]] = s; // expected-error {{expected ';'}} expected-error {{}} + auto [bad_attr_2] [[]] = s; // expected-error {{expected ';'}} expected-error {{}} expected-error {{decomposition declaration '[bad_attr_2]' requires an initializer}} } } @@ -144,7 +144,7 @@ namespace Init { void f() { int arr[1]; struct S { int n; }; - auto &[bad1]; // expected-error {{decomposition declaration '[bad1]' requires an initializer}} + auto &[bad1]; // expected-error {{decomposition declaration '[bad1]' requires an initializer}} expected-error {{expected initializer before ';'}} const auto &[bad2](S{}, S{}); // expected-error {{initializer for variable '[bad2]' with type 'const auto &' contains multiple expressions}} const auto &[bad3](); // expected-error {{expected expression}} auto &[good1] = arr; @@ -152,6 +152,7 @@ namespace Init { const auto &[good3](S{}); S [goodish3] = { 4 }; // expected-error {{cannot be declared with type 'S'}} S [goodish4] { 4 }; // expected-error {{cannot be declared with type 'S'}} + auto [A, B] C = {1, 2}; // expected-error{{expected initializer before 'C'}} expected-error{{decomposition declaration '[A, B]' requires an initializer}} expected-error{{expected ';' at end of declaration}} } } diff --git a/clang/test/SemaCXX/cxx1z-decomposition.cpp b/clang/test/SemaCXX/cxx1z-decomposition.cpp index 95c64bc3b8bff..f68d87446d33a 100644 --- a/clang/test/SemaCXX/cxx1z-decomposition.cpp +++ b/clang/test/SemaCXX/cxx1z-decomposition.cpp @@ -121,7 +121,7 @@ void for_range() { } int error_recovery() { - auto [foobar]; // expected-error {{requires an initializer}} + auto [foobar]; // expected-error {{requires an initializer}} expected-error {{expected initializer before ';'}} return foobar_; // expected-error {{undeclared identifier 'foobar_'}} } >From 8bf9b8304a6e8f4e4a6e96bec9ccf48ebb11a6bd Mon Sep 17 00:00:00 2001 From: kbrav <[email protected]> Date: Fri, 28 Feb 2025 19:54:07 -0500 Subject: [PATCH 4/9] test uninitialized decomposition decl error with templates --- clang/test/Parser/cxx1z-decomposition.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/clang/test/Parser/cxx1z-decomposition.cpp b/clang/test/Parser/cxx1z-decomposition.cpp index 94d3f15f2e498..9b7a320ad7dd1 100644 --- a/clang/test/Parser/cxx1z-decomposition.cpp +++ b/clang/test/Parser/cxx1z-decomposition.cpp @@ -140,8 +140,10 @@ namespace Template { template<typename T> auto [a, b, c] = n; // expected-error {{decomposition declaration template not supported}} } +#define MYC C + namespace Init { - void f() { + template<typename T> T f(T t) { int arr[1]; struct S { int n; }; auto &[bad1]; // expected-error {{decomposition declaration '[bad1]' requires an initializer}} expected-error {{expected initializer before ';'}} @@ -153,6 +155,8 @@ namespace Init { S [goodish3] = { 4 }; // expected-error {{cannot be declared with type 'S'}} S [goodish4] { 4 }; // expected-error {{cannot be declared with type 'S'}} auto [A, B] C = {1, 2}; // expected-error{{expected initializer before 'C'}} expected-error{{decomposition declaration '[A, B]' requires an initializer}} expected-error{{expected ';' at end of declaration}} + T t1 = t; // check that uninitialized decomposition declaration error works with templates and macros + auto [t0, t2] MYC = {t, t1}; // expected-error{{expected initializer before 'C'}} expected-error{{decomposition declaration '[t0, t2]' requires an initializer}} expected-error{{expected ';' at end of declaration}} } } >From a940d4934c6232f7cc078837da00a37b32fbc9eb Mon Sep 17 00:00:00 2001 From: kbrav <[email protected]> Date: Mon, 3 Mar 2025 06:42:10 -0500 Subject: [PATCH 5/9] make uninitialized decomposition declaration errors less redundant --- clang/include/clang/Basic/DiagnosticParseKinds.td | 2 +- clang/include/clang/Basic/DiagnosticSemaKinds.td | 2 -- clang/lib/Parse/ParseDecl.cpp | 2 +- clang/lib/Sema/SemaDecl.cpp | 1 - clang/test/PCH/cxx1z-decomposition.cpp | 2 +- clang/test/Parser/cxx1z-decomposition.cpp | 12 ++++++------ clang/test/SemaCXX/cxx1z-decomposition.cpp | 2 +- 7 files changed, 10 insertions(+), 13 deletions(-) diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td index f80670949e58a..bd2c6ad77340f 100644 --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -497,7 +497,7 @@ def err_expected_coloncolon_after_super : Error< def ext_decomp_decl_empty : ExtWarn< "ISO C++17 does not allow a decomposition group to be empty">, InGroup<DiagGroup<"empty-decomposition">>; -def err_expected_init : Error<"expected initializer before '%0'">; +def err_decomp_decl_expected_init : Error<"decomposition declaration expected initializer before '%0'">; def err_function_parameter_limit_exceeded : Error< "too many function parameters; subsequent parameters will be ignored">; diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 51301d95e55b9..7bfcdded70d6d 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -554,8 +554,6 @@ def err_decomp_decl_template : Error< "decomposition declaration template not supported">; def err_decomp_decl_not_alone : Error< "decomposition declaration must be the only declaration in its group">; -def err_decomp_decl_requires_init : Error< - "decomposition declaration %0 requires an initializer">; def err_decomp_decl_wrong_number_bindings : Error< "type %0 decomposes into %3 %plural{1:element|:elements}2, but " "%select{%plural{0:no|:only %1}1|%1}4 " diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index 1cb871493aaeb..487580d6f2dcc 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -2933,7 +2933,7 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes( } case InitKind::Uninitialized: { if (D.isDecompositionDeclarator()) - Diag(Tok, diag::err_expected_init) << PP.getSpelling(Tok); + Diag(Tok, diag::err_decomp_decl_expected_init) << PP.getSpelling(Tok); Actions.ActOnUninitializedDecl(ThisDecl); break; } diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 285bd27a35a76..5860e80d45a8a 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -14065,7 +14065,6 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl) { // C++1z [dcl.dcl]p1 grammar implies that an initializer is mandatory. if (isa<DecompositionDecl>(RealDecl)) { - Diag(Var->getLocation(), diag::err_decomp_decl_requires_init) << Var; Var->setInvalidDecl(); return; } diff --git a/clang/test/PCH/cxx1z-decomposition.cpp b/clang/test/PCH/cxx1z-decomposition.cpp index e6d56bfefd3d0..13e77f0b16e73 100644 --- a/clang/test/PCH/cxx1z-decomposition.cpp +++ b/clang/test/PCH/cxx1z-decomposition.cpp @@ -22,7 +22,7 @@ constexpr int foo(Q &&q) { return a * 10 + b; } -auto [noinit]; // expected-error{{decomposition declaration '[noinit]' requires an initializer}} expected-error{{expected initializer before ';'}} +auto [noinit]; // expected-error{{decomposition declaration expected initializer before ';'}} #else diff --git a/clang/test/Parser/cxx1z-decomposition.cpp b/clang/test/Parser/cxx1z-decomposition.cpp index 9b7a320ad7dd1..a4dfb4370c661 100644 --- a/clang/test/Parser/cxx1z-decomposition.cpp +++ b/clang/test/Parser/cxx1z-decomposition.cpp @@ -103,10 +103,10 @@ namespace BadSpecifiers { // FIXME: This error is not very good. auto [d]() = s; // expected-error {{expected ';'}} expected-error {{expected expression}} - auto [e][1] = s; // expected-error {{expected ';'}} expected-error {{requires an initializer}} expected-error {{expected initializer before '['}} + auto [e][1] = s; // expected-error {{expected ';'}} expected-error {{expected initializer before '['}} // FIXME: This should fire the 'misplaced array declarator' diagnostic. - int [K] arr = {0}; // expected-error {{expected ';'}} expected-error {{cannot be declared with type 'int'}} expected-error {{decomposition declaration '[K]' requires an initializer}} expected-error {{expected initializer before 'arr'}} + int [K] arr = {0}; // expected-error {{expected ';'}} expected-error {{cannot be declared with type 'int'}} expected-error {{expected initializer before 'arr'}} int [5] arr = {0}; // expected-error {{place the brackets after the name}} auto *[f] = s; // expected-error {{cannot be declared with type 'auto *'}} expected-error {{incompatible initializer}} @@ -120,7 +120,7 @@ namespace BadSpecifiers { [[]] auto [ok_3] = s; alignas(S) auto [ok_4] = s; - auto [bad_attr_2] [[]] = s; // expected-error {{expected ';'}} expected-error {{}} expected-error {{decomposition declaration '[bad_attr_2]' requires an initializer}} + auto [bad_attr_2] [[]] = s; // expected-error {{expected ';'}} expected-error {{}} } } @@ -146,7 +146,7 @@ namespace Init { template<typename T> T f(T t) { int arr[1]; struct S { int n; }; - auto &[bad1]; // expected-error {{decomposition declaration '[bad1]' requires an initializer}} expected-error {{expected initializer before ';'}} + auto &[bad1]; // expected-error {{decomposition declaration expected initializer before ';'}} const auto &[bad2](S{}, S{}); // expected-error {{initializer for variable '[bad2]' with type 'const auto &' contains multiple expressions}} const auto &[bad3](); // expected-error {{expected expression}} auto &[good1] = arr; @@ -154,9 +154,9 @@ namespace Init { const auto &[good3](S{}); S [goodish3] = { 4 }; // expected-error {{cannot be declared with type 'S'}} S [goodish4] { 4 }; // expected-error {{cannot be declared with type 'S'}} - auto [A, B] C = {1, 2}; // expected-error{{expected initializer before 'C'}} expected-error{{decomposition declaration '[A, B]' requires an initializer}} expected-error{{expected ';' at end of declaration}} + auto [A, B] C = {1, 2}; // expected-error{{decomposition declaration expected initializer before 'C'}} expected-error{{expected ';' at end of declaration}} T t1 = t; // check that uninitialized decomposition declaration error works with templates and macros - auto [t0, t2] MYC = {t, t1}; // expected-error{{expected initializer before 'C'}} expected-error{{decomposition declaration '[t0, t2]' requires an initializer}} expected-error{{expected ';' at end of declaration}} + auto [t0, t2] MYC = {t, t1}; // expected-error{{decomposition declaration expected initializer before 'C'}} expected-error{{expected ';' at end of declaration}} } } diff --git a/clang/test/SemaCXX/cxx1z-decomposition.cpp b/clang/test/SemaCXX/cxx1z-decomposition.cpp index f68d87446d33a..c678e9cac38f3 100644 --- a/clang/test/SemaCXX/cxx1z-decomposition.cpp +++ b/clang/test/SemaCXX/cxx1z-decomposition.cpp @@ -121,7 +121,7 @@ void for_range() { } int error_recovery() { - auto [foobar]; // expected-error {{requires an initializer}} expected-error {{expected initializer before ';'}} + auto [foobar]; // expected-error {{decomposition declaration expected initializer before ';'}} return foobar_; // expected-error {{undeclared identifier 'foobar_'}} } >From 05b5b634cea48ffbbaf37378a694f6bfc2f1c23f Mon Sep 17 00:00:00 2001 From: kbrav <[email protected]> Date: Mon, 3 Mar 2025 13:36:43 -0500 Subject: [PATCH 6/9] highlight the declaration --- clang/include/clang/Basic/DiagnosticParseKinds.td | 2 +- clang/lib/Parse/ParseDecl.cpp | 5 +++-- clang/test/PCH/cxx1z-decomposition.cpp | 2 +- clang/test/Parser/cxx1z-decomposition.cpp | 6 +++--- clang/test/SemaCXX/cxx1z-decomposition.cpp | 2 +- 5 files changed, 9 insertions(+), 8 deletions(-) diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td index bd2c6ad77340f..71abda07ef3f3 100644 --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -497,7 +497,7 @@ def err_expected_coloncolon_after_super : Error< def ext_decomp_decl_empty : ExtWarn< "ISO C++17 does not allow a decomposition group to be empty">, InGroup<DiagGroup<"empty-decomposition">>; -def err_decomp_decl_expected_init : Error<"decomposition declaration expected initializer before '%0'">; +def err_decomp_decl_expected_init : Error<"decomposition declaration %0 expected initializer before '%1'">; def err_function_parameter_limit_exceeded : Error< "too many function parameters; subsequent parameters will be ignored">; diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index 487580d6f2dcc..9566668a1860c 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -2932,9 +2932,10 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes( break; } case InitKind::Uninitialized: { - if (D.isDecompositionDeclarator()) - Diag(Tok, diag::err_decomp_decl_expected_init) << PP.getSpelling(Tok); Actions.ActOnUninitializedDecl(ThisDecl); + if (D.isDecompositionDeclarator()) + Diag(Tok, diag::err_decomp_decl_expected_init) + << dyn_cast<VarDecl>(ThisDecl) << PP.getSpelling(Tok); break; } } diff --git a/clang/test/PCH/cxx1z-decomposition.cpp b/clang/test/PCH/cxx1z-decomposition.cpp index 13e77f0b16e73..be8999bc10480 100644 --- a/clang/test/PCH/cxx1z-decomposition.cpp +++ b/clang/test/PCH/cxx1z-decomposition.cpp @@ -22,7 +22,7 @@ constexpr int foo(Q &&q) { return a * 10 + b; } -auto [noinit]; // expected-error{{decomposition declaration expected initializer before ';'}} +auto [noinit]; // expected-error{{decomposition declaration '[noinit]' expected initializer before ';'}} #else diff --git a/clang/test/Parser/cxx1z-decomposition.cpp b/clang/test/Parser/cxx1z-decomposition.cpp index a4dfb4370c661..e507d0885fa85 100644 --- a/clang/test/Parser/cxx1z-decomposition.cpp +++ b/clang/test/Parser/cxx1z-decomposition.cpp @@ -146,7 +146,7 @@ namespace Init { template<typename T> T f(T t) { int arr[1]; struct S { int n; }; - auto &[bad1]; // expected-error {{decomposition declaration expected initializer before ';'}} + auto &[bad1]; // expected-error {{decomposition declaration '[bad1]' expected initializer before ';'}} const auto &[bad2](S{}, S{}); // expected-error {{initializer for variable '[bad2]' with type 'const auto &' contains multiple expressions}} const auto &[bad3](); // expected-error {{expected expression}} auto &[good1] = arr; @@ -154,9 +154,9 @@ namespace Init { const auto &[good3](S{}); S [goodish3] = { 4 }; // expected-error {{cannot be declared with type 'S'}} S [goodish4] { 4 }; // expected-error {{cannot be declared with type 'S'}} - auto [A, B] C = {1, 2}; // expected-error{{decomposition declaration expected initializer before 'C'}} expected-error{{expected ';' at end of declaration}} + auto [A, B] C = {1, 2}; // expected-error{{decomposition declaration '[A, B]' expected initializer before 'C'}} expected-error{{expected ';' at end of declaration}} T t1 = t; // check that uninitialized decomposition declaration error works with templates and macros - auto [t0, t2] MYC = {t, t1}; // expected-error{{decomposition declaration expected initializer before 'C'}} expected-error{{expected ';' at end of declaration}} + auto [t0, t2] MYC = {t, t1}; // expected-error{{decomposition declaration '[t0, t2]' expected initializer before 'C'}} expected-error{{expected ';' at end of declaration}} } } diff --git a/clang/test/SemaCXX/cxx1z-decomposition.cpp b/clang/test/SemaCXX/cxx1z-decomposition.cpp index c678e9cac38f3..ccef39f320f7f 100644 --- a/clang/test/SemaCXX/cxx1z-decomposition.cpp +++ b/clang/test/SemaCXX/cxx1z-decomposition.cpp @@ -121,7 +121,7 @@ void for_range() { } int error_recovery() { - auto [foobar]; // expected-error {{decomposition declaration expected initializer before ';'}} + auto [foobar]; // expected-error {{decomposition declaration '[foobar]' expected initializer before ';'}} return foobar_; // expected-error {{undeclared identifier 'foobar_'}} } >From 96e8723fbf341aa83b2b32df31acb0c3d0e9f86e Mon Sep 17 00:00:00 2001 From: kbrav <[email protected]> Date: Mon, 3 Mar 2025 13:37:28 -0500 Subject: [PATCH 7/9] format --- clang/lib/Parse/ParseDecl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index 9566668a1860c..65fa3620f952b 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -2935,7 +2935,7 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes( Actions.ActOnUninitializedDecl(ThisDecl); if (D.isDecompositionDeclarator()) Diag(Tok, diag::err_decomp_decl_expected_init) - << dyn_cast<VarDecl>(ThisDecl) << PP.getSpelling(Tok); + << dyn_cast<VarDecl>(ThisDecl) << PP.getSpelling(Tok); break; } } >From 344cec303d71bcd8ebc6791e4df23e383ff43f58 Mon Sep 17 00:00:00 2001 From: kbrav <[email protected]> Date: Tue, 4 Mar 2025 13:35:22 -0500 Subject: [PATCH 8/9] clearer wording --- clang/include/clang/Basic/DiagnosticParseKinds.td | 2 +- clang/test/PCH/cxx1z-decomposition.cpp | 2 +- clang/test/Parser/cxx1z-decomposition.cpp | 10 +++++----- clang/test/SemaCXX/cxx1z-decomposition.cpp | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td index 71abda07ef3f3..bc41d8d771404 100644 --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -497,7 +497,7 @@ def err_expected_coloncolon_after_super : Error< def ext_decomp_decl_empty : ExtWarn< "ISO C++17 does not allow a decomposition group to be empty">, InGroup<DiagGroup<"empty-decomposition">>; -def err_decomp_decl_expected_init : Error<"decomposition declaration %0 expected initializer before '%1'">; +def err_decomp_decl_expected_init : Error<"decomposition declaration %0 requires an initializer; got '%1'">; def err_function_parameter_limit_exceeded : Error< "too many function parameters; subsequent parameters will be ignored">; diff --git a/clang/test/PCH/cxx1z-decomposition.cpp b/clang/test/PCH/cxx1z-decomposition.cpp index be8999bc10480..5bd02963bdafa 100644 --- a/clang/test/PCH/cxx1z-decomposition.cpp +++ b/clang/test/PCH/cxx1z-decomposition.cpp @@ -22,7 +22,7 @@ constexpr int foo(Q &&q) { return a * 10 + b; } -auto [noinit]; // expected-error{{decomposition declaration '[noinit]' expected initializer before ';'}} +auto [noinit]; // expected-error{{decomposition declaration '[noinit]' requires an initializer; got ';'}} #else diff --git a/clang/test/Parser/cxx1z-decomposition.cpp b/clang/test/Parser/cxx1z-decomposition.cpp index e507d0885fa85..88f9be292dcf2 100644 --- a/clang/test/Parser/cxx1z-decomposition.cpp +++ b/clang/test/Parser/cxx1z-decomposition.cpp @@ -103,10 +103,10 @@ namespace BadSpecifiers { // FIXME: This error is not very good. auto [d]() = s; // expected-error {{expected ';'}} expected-error {{expected expression}} - auto [e][1] = s; // expected-error {{expected ';'}} expected-error {{expected initializer before '['}} + auto [e][1] = s; // expected-error {{expected ';'}} expected-error {{decomposition declaration '[e]' requires an initializer; got '['}} // FIXME: This should fire the 'misplaced array declarator' diagnostic. - int [K] arr = {0}; // expected-error {{expected ';'}} expected-error {{cannot be declared with type 'int'}} expected-error {{expected initializer before 'arr'}} + int [K] arr = {0}; // expected-error {{expected ';'}} expected-error {{cannot be declared with type 'int'}} expected-error {{decomposition declaration '[K]' requires an initializer; got 'arr'}} int [5] arr = {0}; // expected-error {{place the brackets after the name}} auto *[f] = s; // expected-error {{cannot be declared with type 'auto *'}} expected-error {{incompatible initializer}} @@ -146,7 +146,7 @@ namespace Init { template<typename T> T f(T t) { int arr[1]; struct S { int n; }; - auto &[bad1]; // expected-error {{decomposition declaration '[bad1]' expected initializer before ';'}} + auto &[bad1]; // expected-error {{decomposition declaration '[bad1]' requires an initializer; got ';'}} const auto &[bad2](S{}, S{}); // expected-error {{initializer for variable '[bad2]' with type 'const auto &' contains multiple expressions}} const auto &[bad3](); // expected-error {{expected expression}} auto &[good1] = arr; @@ -154,9 +154,9 @@ namespace Init { const auto &[good3](S{}); S [goodish3] = { 4 }; // expected-error {{cannot be declared with type 'S'}} S [goodish4] { 4 }; // expected-error {{cannot be declared with type 'S'}} - auto [A, B] C = {1, 2}; // expected-error{{decomposition declaration '[A, B]' expected initializer before 'C'}} expected-error{{expected ';' at end of declaration}} + auto [A, B] C = {1, 2}; // expected-error{{decomposition declaration '[A, B]' requires an initializer; got 'C'}} expected-error{{expected ';' at end of declaration}} T t1 = t; // check that uninitialized decomposition declaration error works with templates and macros - auto [t0, t2] MYC = {t, t1}; // expected-error{{decomposition declaration '[t0, t2]' expected initializer before 'C'}} expected-error{{expected ';' at end of declaration}} + auto [t0, t2] MYC = {t, t1}; // expected-error{{decomposition declaration '[t0, t2]' requires an initializer; got 'C'}} expected-error{{expected ';' at end of declaration}} } } diff --git a/clang/test/SemaCXX/cxx1z-decomposition.cpp b/clang/test/SemaCXX/cxx1z-decomposition.cpp index ccef39f320f7f..5020a84278e11 100644 --- a/clang/test/SemaCXX/cxx1z-decomposition.cpp +++ b/clang/test/SemaCXX/cxx1z-decomposition.cpp @@ -121,7 +121,7 @@ void for_range() { } int error_recovery() { - auto [foobar]; // expected-error {{decomposition declaration '[foobar]' expected initializer before ';'}} + auto [foobar]; // expected-error {{decomposition declaration '[foobar]' requires an initializer; got ';'}} return foobar_; // expected-error {{undeclared identifier 'foobar_'}} } >From 1673b01414cf8ddf2a07b3235ceddb38e14e3366 Mon Sep 17 00:00:00 2001 From: kbrav <[email protected]> Date: Sat, 27 Jun 2026 17:10:10 -0400 Subject: [PATCH 9/9] track right square bracket during semantic analysis for decomposition declaration point the carat to the token the right square on error for uninitialized decomposition declaration --- clang/include/clang/AST/DeclCXX.h | 12 +++++++++--- clang/include/clang/Basic/DiagnosticParseKinds.td | 1 - clang/include/clang/Basic/DiagnosticSemaKinds.td | 3 +++ clang/lib/AST/ASTImporter.cpp | 3 ++- clang/lib/AST/DeclCXX.cpp | 7 +++++-- clang/lib/Parse/ParseDecl.cpp | 3 --- clang/lib/Sema/SemaDecl.cpp | 9 +++++++-- clang/lib/Sema/SemaTemplateInstantiateDecl.cpp | 4 ++-- clang/test/PCH/cxx1z-decomposition.cpp | 2 +- clang/test/Parser/cxx1z-decomposition.cpp | 10 +++++----- 10 files changed, 34 insertions(+), 20 deletions(-) diff --git a/clang/include/clang/AST/DeclCXX.h b/clang/include/clang/AST/DeclCXX.h index 28d171253dc03..8c4017a80e485 100644 --- a/clang/include/clang/AST/DeclCXX.h +++ b/clang/include/clang/AST/DeclCXX.h @@ -4265,15 +4265,17 @@ class BindingDecl : public ValueDecl { class DecompositionDecl final : public VarDecl, private llvm::TrailingObjects<DecompositionDecl, BindingDecl *> { + /// The closing bracket (before the initializer is expected). + SourceLocation RSquareLoc; /// The number of BindingDecl*s following this object. unsigned NumBindings; DecompositionDecl(ASTContext &C, DeclContext *DC, SourceLocation StartLoc, - SourceLocation LSquareLoc, QualType T, - TypeSourceInfo *TInfo, StorageClass SC, + SourceLocation LSquareLoc, SourceLocation RSquareLoc, + QualType T, TypeSourceInfo *TInfo, StorageClass SC, ArrayRef<BindingDecl *> Bindings) : VarDecl(Decomposition, C, DC, StartLoc, LSquareLoc, nullptr, T, TInfo, - SC), + SC), RSquareLoc(RSquareLoc), NumBindings(Bindings.size()) { llvm::uninitialized_copy(Bindings, getTrailingObjects()); for (auto *B : Bindings) { @@ -4295,6 +4297,7 @@ class DecompositionDecl final static DecompositionDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation StartLoc, SourceLocation LSquareLoc, + SourceLocation RSquareLoc, QualType T, TypeSourceInfo *TInfo, StorageClass S, ArrayRef<BindingDecl *> Bindings); @@ -4326,6 +4329,9 @@ class DecompositionDecl final std::move(Bindings)); } + /// The closing bracket (before the initializer is expected). + SourceLocation getRSquareLoc() const { return RSquareLoc; } + void printName(raw_ostream &OS, const PrintingPolicy &Policy) const override; static bool classof(const Decl *D) { return classofKind(D->getKind()); } diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td index 91897d6261a5c..4c2db88958e5f 100644 --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -512,7 +512,6 @@ def err_expected_coloncolon_after_super : Error< def ext_decomp_decl_empty : ExtWarn< "ISO C++17 does not allow a structured binding group to be empty">, InGroup<DiagGroup<"empty-decomposition">>; -def err_decomp_decl_expected_init : Error<"structured binding declaration %0 requires an initializer; got '%1'">; def err_function_parameter_limit_exceeded : Error< "too many function parameters; subsequent parameters will be ignored">; diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 44fc74c7ff73f..4896b1437f67c 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -617,7 +617,10 @@ def err_decomp_decl_template : Error< "structured binding declaration cannot be a template">; def err_decomp_decl_not_alone : Error< "structured binding declaration must be the only declaration in its group">; +def err_decomp_decl_requires_init : Error< + "structured binding declaration %0 requires an initializer; expected '=' or braced initializer list">; def err_decomp_decl_wrong_number_bindings : Error< + "type %0 binds to %3 %plural{1:element|:elements}2, but " "%select{%plural{0:no|:only %1}1|%1}4 " "%plural{1:name was|:names were}1 provided">; diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index 567d2d07298a3..ebca88ae51d23 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -4838,7 +4838,8 @@ ExpectedDecl ASTNodeImporter::VisitVarDecl(VarDecl *D) { DecompositionDecl *ToDecomp; if (GetImportedOrCreateDecl( ToDecomp, FromDecomp, Importer.getToContext(), DC, ToInnerLocStart, - Loc, ToType, ToTypeSourceInfo, D->getStorageClass(), Bindings)) + Loc, FromDecomp->getRSquareLoc(), ToType, ToTypeSourceInfo, + D->getStorageClass(), Bindings)) return ToDecomp; ToVar = ToDecomp; } else { diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp index ce4ba971a4631..86b3182a28a87 100644 --- a/clang/lib/AST/DeclCXX.cpp +++ b/clang/lib/AST/DeclCXX.cpp @@ -3730,12 +3730,14 @@ void DecompositionDecl::anchor() {} DecompositionDecl *DecompositionDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation StartLoc, SourceLocation LSquareLoc, + SourceLocation RSquareLoc, QualType T, TypeSourceInfo *TInfo, StorageClass SC, ArrayRef<BindingDecl *> Bindings) { size_t Extra = additionalSizeToAlloc<BindingDecl *>(Bindings.size()); return new (C, DC, Extra) - DecompositionDecl(C, DC, StartLoc, LSquareLoc, T, TInfo, SC, Bindings); + DecompositionDecl(C, DC, StartLoc, LSquareLoc, RSquareLoc, T, TInfo, SC, + Bindings); } DecompositionDecl *DecompositionDecl::CreateDeserialized(ASTContext &C, @@ -3744,7 +3746,8 @@ DecompositionDecl *DecompositionDecl::CreateDeserialized(ASTContext &C, size_t Extra = additionalSizeToAlloc<BindingDecl *>(NumBindings); auto *Result = new (C, ID, Extra) DecompositionDecl(C, nullptr, SourceLocation(), SourceLocation(), - QualType(), nullptr, StorageClass(), {}); + SourceLocation(), QualType(), nullptr, StorageClass(), + {}); // Set up and clean out the bindings array. Result->NumBindings = NumBindings; auto *Trail = Result->getTrailingObjects(); diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index 62e8d58d492be..3f41e7c5c6f0d 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -2740,9 +2740,6 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes( case InitKind::Uninitialized: { InitializerScopeRAII InitScope(*this, D, ThisDecl); Actions.ActOnUninitializedDecl(ThisDecl); - if (D.isDecompositionDeclarator()) - Diag(Tok, diag::err_decomp_decl_expected_init) - << dyn_cast<VarDecl>(ThisDecl) << PP.getSpelling(Tok); break; } } diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 48ba8a9137152..996d68a97fc0e 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -8036,8 +8036,8 @@ NamedDecl *Sema::ActOnVariableDeclarator( AddToScope = false; } else if (D.isDecompositionDeclarator()) { NewVD = DecompositionDecl::Create(Context, DC, D.getBeginLoc(), - D.getIdentifierLoc(), R, TInfo, SC, - Bindings); + D.getIdentifierLoc(), D.getEndLoc(), + R, TInfo, SC, Bindings); } else NewVD = VarDecl::Create(Context, DC, D.getBeginLoc(), D.getIdentifierLoc(), II, R, TInfo, SC); @@ -14480,6 +14480,11 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl) { } // C++1z [dcl.dcl]p1 grammar implies that an initializer is mandatory. if (isa<DecompositionDecl>(RealDecl)) { + // point carat to the token immediately after the closing bracket + auto NextLoc = dyn_cast<DecompositionDecl>(RealDecl)->getRSquareLoc(); + NextLoc = Lexer::findNextToken(NextLoc, PP.getSourceManager(), + PP.getLangOpts())->getLocation(); + Diag(NextLoc, diag::err_decomp_decl_requires_init) << Var; Var->setInvalidDecl(); return; } diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 324d6bf3857c7..87a133b61c385 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -1777,8 +1777,8 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D, VarDecl *Var; if (Bindings) Var = DecompositionDecl::Create(SemaRef.Context, DC, D->getInnerLocStart(), - D->getLocation(), TSI->getType(), TSI, - D->getStorageClass(), *Bindings); + D->getLocation(), D->getEndLoc(), TSI->getType(), + TSI, D->getStorageClass(), *Bindings); else Var = VarDecl::Create(SemaRef.Context, DC, D->getInnerLocStart(), D->getLocation(), D->getIdentifier(), TSI->getType(), diff --git a/clang/test/PCH/cxx1z-decomposition.cpp b/clang/test/PCH/cxx1z-decomposition.cpp index 980fc4700b710..635ba7c26e09b 100644 --- a/clang/test/PCH/cxx1z-decomposition.cpp +++ b/clang/test/PCH/cxx1z-decomposition.cpp @@ -22,7 +22,7 @@ constexpr int foo(Q &&q) { return a * 10 + b; } -auto [noinit]; // expected-error{{structured binding declaration '[noinit]' requires an initializer; got ';'}} +auto [noinit]; // expected-error{{structured binding declaration '[noinit]' requires an initializer; expected '=' or braced initializer list}} #else diff --git a/clang/test/Parser/cxx1z-decomposition.cpp b/clang/test/Parser/cxx1z-decomposition.cpp index 2244743773d25..76f1b97085814 100644 --- a/clang/test/Parser/cxx1z-decomposition.cpp +++ b/clang/test/Parser/cxx1z-decomposition.cpp @@ -111,10 +111,10 @@ namespace BadSpecifiers { // FIXME: This error is not very good. auto [d]() = s; // expected-error {{expected ';'}} expected-error {{expected expression}} - auto [e][1] = s; // expected-error {{expected ';'}} expected-error {{structured binding declaration '[e]' requires an initializer; got '['}} + auto [e][1] = s; // expected-error {{expected ';'}} expected-error {{structured binding declaration '[e]' requires an initializer; expected '=' or braced initializer list}} // FIXME: This should fire the 'misplaced array declarator' diagnostic. - int [K] arr = {0}; // expected-error {{expected ';'}} expected-error {{cannot be declared with type 'int'}} expected-error {{structured binding declaration '[K]' requires an initializer; got 'arr'}} + int [K] arr = {0}; // expected-error {{expected ';'}} expected-error {{cannot be declared with type 'int'}} expected-error {{structured binding declaration '[K]' requires an initializer; expected '=' or braced initializer list}} int [5] arr = {0}; // expected-error {{place the brackets after the name}} auto *[f] = s; // expected-error {{cannot be declared with type 'auto *'}} expected-error {{incompatible initializer}} @@ -154,7 +154,7 @@ namespace Init { template<typename T> T f(T t) { int arr[1]; struct S { int n; }; - auto &[bad1]; // expected-error {{structured binding declaration '[bad1]' requires an initializer; got ';'}} + auto &[bad1]; // expected-error {{structured binding declaration '[bad1]' requires an initializer; expected '=' or braced initializer list}} const auto &[bad2](S{}, S{}); // expected-error {{initializer for variable '[bad2]' with type 'const auto &' contains multiple expressions}} const auto &[bad3](); // expected-error {{expected expression}} auto &[good1] = arr; @@ -162,9 +162,9 @@ namespace Init { const auto &[good3](S{}); S [goodish3] = { 4 }; // expected-error {{cannot be declared with type 'S'}} S [goodish4] { 4 }; // expected-error {{cannot be declared with type 'S'}} - auto [A, B] C = {1, 2}; // expected-error{{structured binding declaration '[A, B]' requires an initializer; got 'C'}} expected-error{{expected ';' at end of declaration}} + auto [A, B] C = {1, 2}; // expected-error{{structured binding declaration '[A, B]' requires an initializer; expected '=' or braced initializer list}} expected-error{{expected ';' at end of declaration}} T t1 = t; // check that uninitialized structured binding declaration error works with templates and macros - auto [t0, t2] MYC = {t, t1}; // expected-error{{structured binding declaration '[t0, t2]' requires an initializer; got 'C'}} expected-error{{expected ';' at end of declaration}} + auto [t0, t2] MYC = {t, t1}; // expected-error{{structured binding declaration '[t0, t2]' requires an initializer; expected '=' or braced initializer list}} expected-error{{expected ';' at end of declaration}} } } _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
