[clang] [Clang][Sema] Fix an ICE where structured binding packs within a lambda should be diagnosed immediately (PR #214716)
via cfe-commits
cfe-commits at lists.llvm.org
Sat Aug 8 06:24:14 PDT 2026
https://github.com/babadany2999 updated https://github.com/llvm/llvm-project/pull/214716
>From bf195ce6ef030b6f63931d1ce1d7e2cc12f44276 Mon Sep 17 00:00:00 2001
From: Baba Dan Constantin <babadany2999 at gmail.com>
Date: Sat, 8 Aug 2026 16:23:15 +0300
Subject: [PATCH] [Clang][Sema] Fix an ICE where structured binding packs
within a lambda should be diagnosed immediately. (#214160)
Signed-off-by: Baba Dan Constantin <babadany2999 at gmail.com>
---
clang/docs/ReleaseNotes.md | 3 +
clang/lib/Sema/SemaDeclCXX.cpp | 6 ++
clang/test/SemaCXX/GH214160.cpp | 129 ++++++++++++++++++++++++++++++++
3 files changed, 138 insertions(+)
create mode 100644 clang/test/SemaCXX/GH214160.cpp
diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index a00b725143d49..42de9d57d5e80 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -366,6 +366,9 @@ features cannot lower the translation-unit ABI level;
- Fixed USR generation for declarations whose signature mentions a class-type
non-type template parameter. (#GH212351)
- Clang now defines the GCC-compatible predefined macro `__SIG_ATOMIC_TYPE__`. (#GH213895)
+- Fixed an ICE where structured binding packs within a lambda were
+ considered for delayed diagnostics, when they should be diagnosed
+ immediately. (#GH214160)
#### Bug Fixes to Compiler Builtins
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 47b01b913b428..66c77a63fced6 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -914,6 +914,12 @@ Sema::ActOnDecompositionDeclarator(Scope *S, Declarator &D,
auto *BD = BindingDecl::Create(Context, DC, B.NameLoc, B.Name, QT);
+ if (BD->isParameterPack()) {
+ if (auto *CSI = getEnclosingLambdaOrBlock()) {
+ CSI->LocalPacks.push_back(BD);
+ }
+ }
+
ProcessDeclAttributeList(S, BD, *B.Attrs);
// Find the shadowed declaration before filtering for scope.
diff --git a/clang/test/SemaCXX/GH214160.cpp b/clang/test/SemaCXX/GH214160.cpp
new file mode 100644
index 0000000000000..2d732780afabc
--- /dev/null
+++ b/clang/test/SemaCXX/GH214160.cpp
@@ -0,0 +1,129 @@
+// RUN: %clang_cc1 -std=c++2c -fsyntax-only -verify %s
+
+namespace GH214160 {
+struct A {
+int x, y;
+};
+
+// Test case: non-constexpr right binary expansion
+template <typename = void>
+void f() {
+ ([&]{ auto [...tmp] = A{}; tmp; }() + ... + 0);
+ // expected-error at -1 {{expression contains unexpanded parameter pack 'tmp'}}
+ // expected-error at -2 {{pack expansion does not contain any unexpanded parameter packs}}
+}
+
+template void f<void>();
+
+// Test case: non-constexpr left binary expansion
+template <typename = void>
+void g() {
+ (0 + ... + [&]{ auto [...tmp] = A{}; tmp; }());
+ // expected-error at -1 {{expression contains unexpanded parameter pack 'tmp'}}
+ // expected-error at -2 {{pack expansion does not contain any unexpanded parameter packs}}
+}
+
+template void g<void>();
+
+// Test case: constexpr right binary expansion
+template <typename = void>
+constexpr void h() {
+ ([&]{ auto [...tmp] = A{}; tmp; }() + ... + 0);
+ // expected-error at -1 {{expression contains unexpanded parameter pack 'tmp'}}
+ // expected-error at -2 {{pack expansion does not contain any unexpanded parameter packs}}
+}
+
+template void h<void>();
+
+// Test case: constexpr left unary binary expansion
+template <typename = void>
+constexpr void i() {
+ (0 + ... + [&]{ auto [...tmp] = A{}; tmp; }());
+ // expected-error at -1 {{expression contains unexpanded parameter pack 'tmp'}}
+ // expected-error at -2 {{pack expansion does not contain any unexpanded parameter packs}}
+}
+
+template void i<void>();
+
+// The following should produce no unexpanded pack errors as they are valid expressions
+
+// Test case: non-constexpr left unary expansion within the scame scope
+template <typename = void>
+void j() {
+ auto [...p] = A{};
+ (..., [&]{ (void)p; }());
+}
+
+template void j<void>();
+
+// Test case: non-constexpr right unary expansion within the same scope
+template <typename = void>
+void l() {
+ auto [...p] = A{};
+ ([&]{ (void)p; }(), ...);
+}
+
+template void l<void>();
+
+// Test case: constexpr left unary expansion within the same scope
+template <typename = void>
+constexpr void m() {
+ auto [...p] = A{};
+ (..., [&]{ (void)p; }());
+}
+
+template void m<void>();
+
+// Test case: constexpr right unary expansion within the same scope
+template <typename = void>
+constexpr void n() {
+ auto [...p] = A{};
+ ([&]{ (void)p; }(), ...);
+}
+
+template void n<void>();
+
+// Test case: non-constexpr left unary expansion within the same scope enclosed within a lambda
+template <typename = void>
+void o() {
+ [] {
+ auto [...p] = A{};
+ (..., [&] { (void)p; }());
+ }();
+}
+
+template void o<void>();
+
+// Test case: non-constexpr right unary expansion within the same scope enclosed within a lambda
+template <typename = void>
+void p() {
+ [] {
+ auto [...p] = A{};
+ ([&] { (void)p; }(), ...);
+ }();
+}
+
+template void p<void>();
+
+// Test case: constexpr left unary expansion within the same scope enclosed within a lambda
+template <typename = void>
+constexpr void q() {
+ [] {
+ auto [...p] = A{};
+ (..., [&] { (void)p; }());
+ }();
+}
+
+template void q<void>();
+
+// Test case: constexpr right unary expansion within the same scope enclosed within a lambda
+template <typename = void>
+constexpr void r() {
+ [] {
+ auto [...p] = A{};
+ ([&] { (void)p; }(), ...);
+ }();
+}
+
+template void r<void>();
+}
More information about the cfe-commits
mailing list