https://github.com/akashagrwl created 
https://github.com/llvm/llvm-project/pull/210964

TryListInitialization's by-value array-copy fast path for structured bindings 
([dcl.struct.bind]p1) asserted that a decomposition declaration's declared 
array type matches its initializer's array type. That invariant always holds 
when the declared type came from auto deduction, but can fail for an 
explicitly-typed decomposition declaration: such a declaration is ill-formed 
(diagnosed via err_decomp_decl_type) but not marked invalid, so it can still 
reach this fast path with a DestType that doesn't match the initializer's array 
type, aborting on the assert.

Turn the assumed invariant into an actual entry condition for the fast path 
instead of asserting it after already committing to it. When the condition is 
false, execution falls through to the general list-initialization handling 
below, which reports an ordinary initialization diagnostic instead of crashing.

Fixes #210960

>From 06b5455a0e0048850e388947f68dd7cc4808b154 Mon Sep 17 00:00:00 2001
From: Akash Agrawal <[email protected]>
Date: Tue, 21 Jul 2026 05:23:50 -0700
Subject: [PATCH] [Clang][Sema] Don't assert on mismatched array type in
 decomposition-decl fast path

TryListInitialization's by-value array-copy fast path for structured
bindings ([dcl.struct.bind]p1) asserted that a decomposition
declaration's declared array type matches its initializer's array
type. That invariant always holds when the declared type came from
auto deduction, but can fail for an explicitly-typed decomposition
declaration: such a declaration is ill-formed (diagnosed via
err_decomp_decl_type) but not marked invalid, so it can still reach
this fast path with a DestType that doesn't match the initializer's
array type, aborting on the assert.

Turn the assumed invariant into an actual entry condition for the
fast path instead of asserting it after already committing to it.
When the condition is false, execution falls through to the general
list-initialization handling below, which reports an ordinary
initialization diagnostic instead of crashing.

Fixes #210960
---
 clang/lib/Sema/SemaInit.cpp                | 13 +++++++-----
 clang/test/SemaCXX/cxx1z-decomposition.cpp | 23 ++++++++++++++++++++++
 2 files changed, 31 insertions(+), 5 deletions(-)

diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp
index 09d9f1eabd058..70a2c94f26577 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/lib/Sema/SemaInit.cpp
@@ -5112,13 +5112,16 @@ static void TryListInitialization(Sema &S,
       // of the assignment-expression as specified by the form of the
       // initializer. ...
       //
-      // This is a special case not following list-initialization.
+      // This is a special case not following list-initialization, valid
+      // only when DestType was deduced from the initializer (the 'auto'
+      // case). A decomposition declared with an explicit, non-'auto' type
+      // is ill-formed (diagnosed elsewhere) and may still reach here with a
+      // DestType that doesn't match the initializer's array type, so check
+      // that instead of asserting it.
       if (isa<ConstantArrayType>(DestAT) &&
           Entity.getKind() == InitializedEntity::EK_Variable &&
-          isa<DecompositionDecl>(Entity.getDecl())) {
-        assert(
-            S.Context.hasSameUnqualifiedType(SubInit[0]->getType(), DestType) 
&&
-            "Deduced to other type?");
+          isa<DecompositionDecl>(Entity.getDecl()) &&
+          S.Context.hasSameUnqualifiedType(SubInit[0]->getType(), DestType)) {
         assert(Kind.getKind() == clang::InitializationKind::IK_DirectList &&
                "List-initialize structured bindings but not "
                "direct-list-initialization?");
diff --git a/clang/test/SemaCXX/cxx1z-decomposition.cpp 
b/clang/test/SemaCXX/cxx1z-decomposition.cpp
index 6425f1ee7796e..4b826acd6f46f 100644
--- a/clang/test/SemaCXX/cxx1z-decomposition.cpp
+++ b/clang/test/SemaCXX/cxx1z-decomposition.cpp
@@ -229,4 +229,27 @@ namespace by_value_array_copy {
     auto [d] = T{};
   }
 
+  // Don't crash when a decomposition is declared with an explicit
+  // (non-'auto') array type whose size doesn't match the initializer's
+  // array type: the declared type is ill-formed and was never deduced,
+  // so it need not match.
+  typedef int array_type[3];
+  void explicit_array_type() {
+    int arr[4]{1, 2, 3, 4};
+    array_type [a, b, c]{arr}; // expected-error {{structured binding 
declaration cannot be declared with type 'array_type' (aka 'int[3]'); declared 
type must be 'auto' or reference to 'auto'}} expected-error {{cannot initialize 
an array element of type 'int' with an lvalue of type 'int[4]'}}
+  }
+
+  // Same as above, but the explicit (non-'auto') array type has the *same*
+  // number of elements as the initializer. The same-type condition then
+  // holds, so the by-value array-copy fast path is *entered* (rather than
+  // fallen through as in the mismatched-size case above) even though the
+  // type was never deduced from 'auto'. This must still only diagnose that
+  // the declared type must be 'auto', never crash -- it also guards the
+  // second assert in that fast path (IK_DirectList).
+  typedef int array_type_4[4];
+  void explicit_array_type_same_size() {
+    int arr[4]{1, 2, 3, 4};
+    array_type_4 [a, b, c, d]{arr}; // expected-error {{structured binding 
declaration cannot be declared with type 'array_type_4' (aka 'int[4]'); 
declared type must be 'auto' or reference to 'auto'}}
+  }
+
 } // namespace by_value_array_copy

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

Reply via email to