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

Reply via email to