https://github.com/Z3rox-dev created 
https://github.com/llvm/llvm-project/pull/181803

Follow-up to #127924, which appears to be abandoned.

The diagnostic for a structured binding declaration without an initializer 
(e.g. auto [a, b];) now tells the user what to write

>From 9b370e5f26d64a498fefdb3503cdfb4f799dea66 Mon Sep 17 00:00:00 2001
From: Giovanni Baldon <[email protected]>
Date: Tue, 17 Feb 2026 12:24:11 +0100
Subject: [PATCH] [Clang][Sema] Clarify structured binding diagnostic when
 initializer is missing

The error now suggests what the user should write (= or braced init list)
instead of only stating the initializer is required.

This is a follow-up to #127924, which appears to be abandoned.
Incorporates the diagnostic wording suggested by @AaronBallman in that review.

Fixes #90107
---
 .../checkers/misc/misplaced-const-cxx17.cpp   |  2 +-
 clang/docs/ReleaseNotes.rst                   |  4 +++
 .../clang/Basic/DiagnosticSemaKinds.td        |  3 ++-
 clang/lib/Sema/SemaDecl.cpp                   |  6 ++---
 clang/test/PCH/cxx1z-decomposition.cpp        |  2 +-
 clang/test/Parser/cxx1z-decomposition.cpp     |  2 +-
 .../Parser/decomp-decl-init-diagnostic.cpp    | 26 +++++++++++++++++++
 7 files changed, 38 insertions(+), 7 deletions(-)
 create mode 100644 clang/test/Parser/decomp-decl-init-diagnostic.cpp

diff --git 
a/clang-tools-extra/test/clang-tidy/checkers/misc/misplaced-const-cxx17.cpp 
b/clang-tools-extra/test/clang-tidy/checkers/misc/misplaced-const-cxx17.cpp
index 56029325420e1..d22394ae874a4 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/misc/misplaced-const-cxx17.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/misc/misplaced-const-cxx17.cpp
@@ -3,7 +3,7 @@
 // This test previously would cause a failed assertion because the structured
 // binding declaration had no valid type associated with it. This ensures the
 // expected clang diagnostic is generated instead.
-// CHECK-MESSAGES: :[[@LINE+1]]:6: error: structured binding declaration '[x]' 
requires an initializer [clang-diagnostic-error]
+// CHECK-MESSAGES: :[[@LINE+1]]:6: error: structured binding declaration '[x]' 
requires an initializer; expected '=' or a braced initializer list 
[clang-diagnostic-error]
 auto [x];
 
 struct S { int a; };
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index c9bedb87c6a79..25b318aa69f8c 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -245,6 +245,10 @@ Improvements to Clang's diagnostics
 - The ``-Wloop-analysis`` warning has been extended to catch more cases of
   variable modification inside lambda expressions (#GH132038).
 
+- Improved the diagnostic for structured binding declarations missing an
+  initializer to tell the user what is expected (``=`` or a braced initializer
+  list). (#GH90107)
+
 Improvements to Clang's time-trace
 ----------------------------------
 
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 85a023435ba23..29340caea5980 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -606,7 +606,8 @@ def err_decomp_decl_template : Error<
 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">;
+  "structured binding declaration %0 requires an initializer; "
+  "expected '=' or a 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 "
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 4dfde4bf8cedf..892c5646892af 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -14378,9 +14378,9 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl) {
     QualType Type = Var->getType();
 
     // 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();
+    if (auto *DD = dyn_cast<DecompositionDecl>(RealDecl)) {
+      Diag(DD->getLocation(), diag::err_decomp_decl_requires_init) << DD;
+      DD->setInvalidDecl();
       return;
     }
 
diff --git a/clang/test/PCH/cxx1z-decomposition.cpp 
b/clang/test/PCH/cxx1z-decomposition.cpp
index 340d5eae0b8c3..086eed71d8ed5 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}}
+auto [noinit]; // expected-error{{structured binding declaration '[noinit]' 
requires an initializer; expected '=' or a braced initializer list}}
 
 #else
 
diff --git a/clang/test/Parser/cxx1z-decomposition.cpp 
b/clang/test/Parser/cxx1z-decomposition.cpp
index 21c9419e8f413..9fa78fa0d4c81 100644
--- a/clang/test/Parser/cxx1z-decomposition.cpp
+++ b/clang/test/Parser/cxx1z-decomposition.cpp
@@ -152,7 +152,7 @@ namespace Init {
   void f() {
     int arr[1];
     struct S { int n; };
-    auto &[bad1]; // expected-error {{structured binding declaration '[bad1]' 
requires an initializer}}
+    auto &[bad1]; // expected-error {{structured binding declaration '[bad1]' 
requires an initializer; expected '=' or a 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;
diff --git a/clang/test/Parser/decomp-decl-init-diagnostic.cpp 
b/clang/test/Parser/decomp-decl-init-diagnostic.cpp
new file mode 100644
index 0000000000000..b0322d717c4c3
--- /dev/null
+++ b/clang/test/Parser/decomp-decl-init-diagnostic.cpp
@@ -0,0 +1,26 @@
+// RUN: %clang_cc1 -std=c++17 -fsyntax-only -verify %s
+
+struct S { int a; double b; };
+S getS();
+
+void test() {
+  auto [x]; // expected-error {{requires an initializer; expected '=' or a 
braced initializer list}}
+  auto &[a, b]; // expected-error {{requires an initializer; expected '=' or a 
braced initializer list}}
+  const auto &[p, q]; // expected-error {{requires an initializer; expected 
'=' or a braced initializer list}}
+  auto &&[r, s]; // expected-error {{requires an initializer; expected '=' or 
a braced initializer list}}
+
+  auto [c, d] e = getS(); // expected-error {{requires an initializer; 
expected '=' or a braced initializer list}} \
+                           // expected-error {{expected ';' at end of 
declaration}}
+}
+
+template <typename T>
+void test_template(T) {
+  auto [x, y]; // expected-error {{requires an initializer; expected '=' or a 
braced initializer list}}
+}
+
+void test_valid() {
+  S s = {1, 2.0};
+  auto [a, b] = s;
+  auto &[c, d] = s;
+  auto &&[e, f] = getS();
+}

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to