https://github.com/akashagrwl updated https://github.com/llvm/llvm-project/pull/210964
>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 1/2] [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 >From aaa1bccf9f6e11c932e65e4e4256441e6128bcaf Mon Sep 17 00:00:00 2001 From: Akash Agrawal <[email protected]> Date: Mon, 27 Jul 2026 05:24:53 -0700 Subject: [PATCH 2/2] Mark decomposition decl invalid for explicit array type --- clang/docs/ReleaseNotes.md | 3 +++ clang/lib/Sema/SemaDeclCXX.cpp | 11 +++++++---- clang/test/SemaCXX/cxx1z-decomposition.cpp | 23 +++++----------------- 3 files changed, 15 insertions(+), 22 deletions(-) diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md index 5a07e77076d17..1defcc81fcc86 100644 --- a/clang/docs/ReleaseNotes.md +++ b/clang/docs/ReleaseNotes.md @@ -323,6 +323,9 @@ latest release, please see the [Clang Web Site](https://clang.llvm.org) or the - Fixed a crash when a using-declaration naming an unresolvable member of a dependent base was shadowed by an invalid using-declaration. (#GH209427) +- Fixed a crash when a structured binding was declared with an explicit + (non-``auto``) array type. (#GH200834) + #### Bug Fixes to AST Handling - Fixed a non-deterministic ordering of unused local typedefs that made diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 37bb69da90b6c..bd8645d55e38f 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -855,10 +855,13 @@ Sema::ActOnDecompositionDeclarator(Scope *S, Declarator &D, : diag::err_decomp_decl_type) << R; - // In most cases, there's no actual problem with an explicitly-specified - // type, but a function type won't work here, and ActOnVariableDeclarator - // shouldn't be called for such a type. - if (R->isFunctionType()) + // An explicitly-specified type is diagnosed above, but for most types we + // can still recover and diagnose the bindings. A function or array type + // won't work here: ActOnVariableDeclarator shouldn't be called for a + // function type, and an explicit array type would reach the array-copy + // initialization path with a type that need not match the initializer, + // hitting an assertion. Mark those invalid so no initialization is done. + if (R->isFunctionType() || R->isArrayType()) D.setInvalidType(); } diff --git a/clang/test/SemaCXX/cxx1z-decomposition.cpp b/clang/test/SemaCXX/cxx1z-decomposition.cpp index 4b826acd6f46f..fe6e76459f01d 100644 --- a/clang/test/SemaCXX/cxx1z-decomposition.cpp +++ b/clang/test/SemaCXX/cxx1z-decomposition.cpp @@ -229,27 +229,14 @@ 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. + // A structured binding declared with an explicit (non-'auto') array type is + // ill-formed; it must be diagnosed and marked invalid rather than reaching + // the by-value array-copy path (which used to crash). Only the "must be + // 'auto'" error is expected. 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'}} + 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'}} } } // namespace by_value_array_copy _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
