https://github.com/Tsche updated https://github.com/llvm/llvm-project/pull/191880
>From 67a82941e949c778c6bb0408352b17f6876bf846 Mon Sep 17 00:00:00 2001 From: Matthias Wippich <[email protected]> Date: Tue, 5 May 2026 05:13:16 +0200 Subject: [PATCH 1/4] [clang] Implement CWG3135 - constexpr structured bindings with prvalues from tuples --- clang/docs/ReleaseNotes.rst | 3 + clang/lib/Analysis/FlowSensitive/Transfer.cpp | 2 +- clang/lib/Sema/SemaDeclCXX.cpp | 29 +++++---- clang/test/Analysis/anonymous-decls.cpp | 14 ++--- clang/test/Analysis/live-bindings-test.cpp | 11 ---- clang/test/CXX/dcl.decl/dcl.decomp/p3.cpp | 5 +- clang/test/CXX/drs/cwg31xx.cpp | 61 ++++++++++++++++--- ...egen-for-constexpr-structured-bindings.cpp | 2 +- clang/test/CodeGenCXX/cxx1z-decomposition.cpp | 13 ++-- .../test/DebugInfo/CXX/structured-binding.cpp | 2 +- clang/test/SemaCXX/cxx2c-decomposition.cpp | 4 +- clang/www/cxx_dr_status.html | 2 +- 12 files changed, 91 insertions(+), 57 deletions(-) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index eb1d926926d9e..ee4843c3f0665 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -164,6 +164,9 @@ Resolutions to C++ Defect Reports - Clang now allows omitting ``typename`` before a template name in a conversion operator, implementing `CWG2413 <https://wg21.link/cwg2413>`_. +- Clang now uses non-reference types for structured bindings whose initializer + returns a prvalue. This resolves `CWG3135 <https://wg21.link/cwg3135>`_. + C Language Changes ------------------ diff --git a/clang/lib/Analysis/FlowSensitive/Transfer.cpp b/clang/lib/Analysis/FlowSensitive/Transfer.cpp index 57ee93f5e156e..d40843ff4ec43 100644 --- a/clang/lib/Analysis/FlowSensitive/Transfer.cpp +++ b/clang/lib/Analysis/FlowSensitive/Transfer.cpp @@ -255,7 +255,7 @@ class TransferVisitor : public ConstStmtVisitor<TransferVisitor> { // If this is the holding variable for a `BindingDecl`, we may already // have a storage location set up -- so check. (See also explanation below // where we process the `BindingDecl`.) - if (D.getType()->isReferenceType() && Env.getStorageLocation(D) != nullptr) + if (D.isImplicit() && Env.getStorageLocation(D) != nullptr) return; assert(Env.getStorageLocation(D) == nullptr); diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 1e339fee29ab8..e7c1984c2f17b 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -1380,25 +1380,28 @@ static bool checkTupleLikeDecomposition(Sema &S, return true; Expr *Init = E.get(); - // Given the type T designated by std::tuple_element<i - 1, E>::type, + // Given the type T designated by std::tuple_element<i - 1, E>::type QualType T = getTupleLikeElementType(S, Loc, I, DecompType); if (T.isNull()) return true; - // each vi is a variable of type "reference to T" initialized with the - // initializer, where the reference is an lvalue reference if the - // initializer is an lvalue and an rvalue reference otherwise - QualType RefType = - S.BuildReferenceType(T, E.get()->isLValue(), Loc, B->getDeclName()); - if (RefType.isNull()) + // C++26 [dcl.struct.bind]p7: + // and the type Ui, defined as Ti if the initializer is a prvalue, + // as "lvalue reference to Ti" if the initializer is an lvalue, + // or as "rvalue reference to Ti" otherwise + // "defined as Ti if the initializer is a prvalue" was introduced by CWG3135 + QualType U = E.get()->isPRValue() + ? T + : S.BuildReferenceType(T, E.get()->isLValue(), Loc, + B->getDeclName()); + if (U.isNull()) return true; // Don't give this VarDecl a TypeSourceInfo, since this is a synthesized // entity and this type was never written in source code. - auto *RefVD = - VarDecl::Create(S.Context, Src->getDeclContext(), Loc, Loc, - B->getDeclName().getAsIdentifierInfo(), RefType, - /*TInfo=*/nullptr, Src->getStorageClass()); + auto *RefVD = VarDecl::Create(S.Context, Src->getDeclContext(), Loc, Loc, + B->getDeclName().getAsIdentifierInfo(), U, + /*TInfo=*/nullptr, Src->getStorageClass()); RefVD->setLexicalDeclContext(Src->getLexicalDeclContext()); RefVD->setTSCSpec(Src->getTSCSpec()); RefVD->setImplicit(); @@ -1407,7 +1410,9 @@ static bool checkTupleLikeDecomposition(Sema &S, RefVD->getLexicalDeclContext()->addHiddenDecl(RefVD); InitializedEntity Entity = InitializedEntity::InitializeBinding(RefVD); - InitializationKind Kind = InitializationKind::CreateCopy(Loc, Loc); + InitializationKind Kind = + E.get()->isPRValue() ? InitializationKind::CreateDirect(Loc, Loc, Loc) + : InitializationKind::CreateCopy(Loc, Loc); InitializationSequence Seq(S, Entity, Kind, Init); E = Seq.Perform(S, Entity, Kind, Init); if (E.isInvalid()) diff --git a/clang/test/Analysis/anonymous-decls.cpp b/clang/test/Analysis/anonymous-decls.cpp index 76e5155b61b67..705273328e6cc 100644 --- a/clang/test/Analysis/anonymous-decls.cpp +++ b/clang/test/Analysis/anonymous-decls.cpp @@ -77,13 +77,11 @@ int main() { // CHECK-NEXT: 7: [B3.6] (ImplicitCastExpr, FunctionToPointerDecay, tuple_element<0L, pair<int, int> >::type (*)(pair<int, int> &)) // CHECK-NEXT: 8: decomposition-a-b // CHECK-NEXT: 9: [B3.7]([B3.8]) -// CHECK-NEXT: 10: [B3.9] -// CHECK-NEXT: 11: std::tuple_element<0UL, std::pair<int, int>>::type &&a = get<0UL>(decomposition-a-b); -// CHECK-NEXT: 12: get<1UL> -// CHECK-NEXT: 13: [B3.12] (ImplicitCastExpr, FunctionToPointerDecay, tuple_element<1L, pair<int, int> >::type (*)(pair<int, int> &)) -// CHECK-NEXT: 14: decomposition-a-b -// CHECK-NEXT: 15: [B3.13]([B3.14]) -// CHECK-NEXT: 16: [B3.15] -// CHECK-NEXT: 17: std::tuple_element<1UL, std::pair<int, int>>::type &&b = get<1UL>(decomposition-a-b); +// CHECK-NEXT: 10: std::tuple_element<0UL, std::pair<int, int>>::type a = get<0UL>(decomposition-a-b); +// CHECK-NEXT: 11: get<1UL> +// CHECK-NEXT: 12: [B3.11] (ImplicitCastExpr, FunctionToPointerDecay, tuple_element<1L, pair<int, int> >::type (*)(pair<int, int> &)) +// CHECK-NEXT: 13: decomposition-a-b +// CHECK-NEXT: 14: [B3.12]([B3.13]) +// CHECK-NEXT: 15: std::tuple_element<1UL, std::pair<int, int>>::type b = get<1UL>(decomposition-a-b); // CHECK-NEXT: Preds (1): B1 // CHECK-NEXT: Succs (1): B2 diff --git a/clang/test/Analysis/live-bindings-test.cpp b/clang/test/Analysis/live-bindings-test.cpp index 7660e9c9904d7..eebd928145522 100644 --- a/clang/test/Analysis/live-bindings-test.cpp +++ b/clang/test/Analysis/live-bindings-test.cpp @@ -108,19 +108,8 @@ namespace std { }; } -void no_warning_on_tuple_types_copy(Mytuple t) { - auto [a, b] = t; // no-warning -} - Mytuple getMytuple(); -void deconstruct_tuple_types_warning() { - // The initializers reference the decomposed region, so the warning is not reported - // FIXME: ideally we want to ignore that the initializers reference the decomposed region, and report the warning, - // though the first step towards that is to handle DeadCode if the initializer is CXXConstructExpr. - auto [a, b] = getMytuple(); // no-warning -} - int deconstruct_tuple_types_no_warning() { auto [a, b] = getMytuple(); // no-warning return a + b; diff --git a/clang/test/CXX/dcl.decl/dcl.decomp/p3.cpp b/clang/test/CXX/dcl.decl/dcl.decomp/p3.cpp index b9d19c1eb4371..b1e639efc441f 100644 --- a/clang/test/CXX/dcl.decl/dcl.decomp/p3.cpp +++ b/clang/test/CXX/dcl.decl/dcl.decomp/p3.cpp @@ -222,9 +222,6 @@ template<> struct std::tuple_size<constant::Q> { static const int value = 3; }; template<int N> struct std::tuple_element<N, constant::Q> { typedef int type; }; namespace constant { Q q; - // This creates and lifetime-extends a temporary to hold the result of each get() call. - auto [a, b, c] = q; // expected-note {{temporary}} - static_assert(a == 0); // expected-error {{constant expression}} expected-note {{temporary}} constexpr bool f() { auto [a, b, c] = q; @@ -235,7 +232,7 @@ namespace constant { constexpr int g() { int *p = nullptr; { - auto [a, b, c] = q; // expected-note {{temporary created here}} + auto [a, b, c] = q; // expected-note {{declared here}} p = &c; } return *p; // expected-note {{read of object outside its lifetime}} diff --git a/clang/test/CXX/drs/cwg31xx.cpp b/clang/test/CXX/drs/cwg31xx.cpp index 3c88d5ff7c607..ee41c77f6f181 100644 --- a/clang/test/CXX/drs/cwg31xx.cpp +++ b/clang/test/CXX/drs/cwg31xx.cpp @@ -1,16 +1,61 @@ -// RUN: %clang_cc1 -std=c++98 -fexceptions -fcxx-exceptions -pedantic-errors %s -verify-directives -verify=expected -// RUN: %clang_cc1 -std=c++11 -fexceptions -fcxx-exceptions -pedantic-errors %s -verify-directives -verify=expected -// RUN: %clang_cc1 -std=c++14 -fexceptions -fcxx-exceptions -pedantic-errors %s -verify-directives -verify=expected -// RUN: %clang_cc1 -std=c++17 -fexceptions -fcxx-exceptions -pedantic-errors %s -verify-directives -verify=expected -// RUN: %clang_cc1 -std=c++20 -fexceptions -fcxx-exceptions -pedantic-errors %s -verify-directives -verify=expected -// RUN: %clang_cc1 -std=c++23 -fexceptions -fcxx-exceptions -pedantic-errors %s -verify-directives -verify=expected -// RUN: %clang_cc1 -std=c++2c -fexceptions -fcxx-exceptions -pedantic-errors %s -verify-directives -verify=expected +// RUN: %clang_cc1 -std=c++98 %s -fexceptions -fcxx-exceptions -pedantic-errors -verify-directives -verify=expected,cxx98-14 +// RUN: %clang_cc1 -std=c++11 %s -fexceptions -fcxx-exceptions -pedantic-errors -verify-directives -verify=expected,cxx98-14,cxx11-17,since-cxx11 +// RUN: %clang_cc1 -std=c++14 %s -fexceptions -fcxx-exceptions -pedantic-errors -verify-directives -verify=expected,cxx98-14,cxx14-17,cxx11-17,since-cxx11,since-cxx14 +// RUN: %clang_cc1 -std=c++17 %s -fexceptions -fcxx-exceptions -pedantic-errors -verify-directives -verify=expected,cxx14-17,cxx11-17,since-cxx11,since-cxx14,since-cxx17 +// RUN: %clang_cc1 -std=c++20 %s -fexceptions -fcxx-exceptions -pedantic-errors -verify-directives -verify=expected,since-cxx11,since-cxx14,since-cxx17,since-cxx20 +// RUN: %clang_cc1 -std=c++23 %s -fexceptions -fcxx-exceptions -pedantic-errors -verify-directives -verify=expected,since-cxx11,since-cxx14,since-cxx17,since-cxx20 +// RUN: %clang_cc1 -std=c++2c %s -fexceptions -fcxx-exceptions -pedantic-errors -verify-directives -verify=expected,since-cxx11,since-cxx14,since-cxx17,since-cxx20 +// RUN: %clang_cc1 -std=c++98 %s -fexceptions -fcxx-exceptions -pedantic-errors -fexperimental-new-constant-interpreter -verify-directives -verify=expected,cxx98-14 +// RUN: %clang_cc1 -std=c++11 %s -fexceptions -fcxx-exceptions -pedantic-errors -fexperimental-new-constant-interpreter -verify-directives -verify=expected,cxx98-14,cxx11-17,since-cxx11 +// RUN: %clang_cc1 -std=c++14 %s -fexceptions -fcxx-exceptions -pedantic-errors -fexperimental-new-constant-interpreter -verify-directives -verify=expected,cxx98-14,cxx14-17,cxx11-17,since-cxx11,since-cxx14 +// RUN: %clang_cc1 -std=c++17 %s -fexceptions -fcxx-exceptions -pedantic-errors -fexperimental-new-constant-interpreter -verify-directives -verify=expected,cxx14-17,cxx11-17,since-cxx11,since-cxx14,since-cxx17 +// RUN: %clang_cc1 -std=c++20 %s -fexceptions -fcxx-exceptions -pedantic-errors -fexperimental-new-constant-interpreter -verify-directives -verify=expected,since-cxx11,since-cxx14,since-cxx17,since-cxx20 +// RUN: %clang_cc1 -std=c++23 %s -fexceptions -fcxx-exceptions -pedantic-errors -fexperimental-new-constant-interpreter -verify-directives -verify=expected,since-cxx11,since-cxx14,since-cxx17,since-cxx20 +// RUN: %clang_cc1 -std=c++2c %s -fexceptions -fcxx-exceptions -pedantic-errors -fexperimental-new-constant-interpreter -verify-directives -verify=expected,since-cxx11,since-cxx14,since-cxx17,since-cxx20 -// expected-no-diagnostics +// cxx98-14-no-diagnostics namespace cwg3106 { // cwg3106: 2.7 #if __cplusplus >= 201103L const char str[9] = R"(\u{1234})"; #endif } // namespace cwg3106 + +namespace cwg3135 { // cwg3135: 23 +#if __cplusplus >= 201703L +struct Pinned { + Pinned(const Pinned&) = delete; // #cwg3135-pinned-ctor + Pinned& operator=(const Pinned&) = delete; +}; + +struct Source { + operator Pinned&&() const; + + template<int> + Source get() noexcept; +}; +} // namespace cwg3135 + +namespace std { + template<typename> struct tuple_size; + template<int, typename> struct tuple_element; + + template<> + struct tuple_size<cwg3135::Source> { + static constexpr int value = 1; + }; + + template<> + struct tuple_element<0, cwg3135::Source> { using type = cwg3135::Pinned; }; +} // namespace std + +namespace cwg3135 { +// CWG3135: `x` is of type Pinned rather than Pinned&&. +// This leads to the deleted copy ctor being called. +auto [x] = Source{}; +// since-cxx17-error-re@-1 {{call to deleted constructor of 'std::tuple_element<0U{{L*}}, Source>::type' (aka 'cwg3135::Pinned')}} +// since-cxx17-note@-2 {{in implicit initialization of binding declaration 'x'}} +// since-cxx17-note@#cwg3135-pinned-ctor {{'Pinned' has been explicitly marked deleted here}} +#endif +} // namespace cwg3135 diff --git a/clang/test/CodeGenCXX/bad-codegen-for-constexpr-structured-bindings.cpp b/clang/test/CodeGenCXX/bad-codegen-for-constexpr-structured-bindings.cpp index ce81f7d8d026e..87c2055627aa7 100644 --- a/clang/test/CodeGenCXX/bad-codegen-for-constexpr-structured-bindings.cpp +++ b/clang/test/CodeGenCXX/bad-codegen-for-constexpr-structured-bindings.cpp @@ -35,6 +35,6 @@ const u8 &f() { return I; } -// CHECK: @[[TMP:_ZGR.*]] = internal constant i8 0, align 1 +// CHECK: @[[TMP:_ZZ1fvE1I]] = internal constant i8 0, align 1 // CHECK-LABEL: define {{.*}} @_Z1fv( // CHECK: ret ptr @[[TMP]] diff --git a/clang/test/CodeGenCXX/cxx1z-decomposition.cpp b/clang/test/CodeGenCXX/cxx1z-decomposition.cpp index 228a6fd910248..a2f5a91aa9b2e 100644 --- a/clang/test/CodeGenCXX/cxx1z-decomposition.cpp +++ b/clang/test/CodeGenCXX/cxx1z-decomposition.cpp @@ -33,8 +33,7 @@ template<typename T> T &make(); // CHECK: @_ZDC2a12a2E ={{.*}} global {{.*}} zeroinitializer, align 4 auto [a1, a2] = make<A>(); // CHECK: @_ZDC2b12b2E ={{.*}} global {{.*}} zeroinitializer, align 1 -// CHECK: @b1 ={{.*}} global ptr null, align 8 -// CHECK: @_ZGR2b1_ = internal global {{.*}} zeroinitializer, align 1 +// CHECK: @b1 ={{.*}} global {{.*}} zeroinitializer, align 1 // CHECK: @b2 ={{.*}} global ptr null, align 8 // CHECK: @_ZGR2b2_ = internal global i32 0, align 4 auto [b1, b2] = make<B>(); @@ -50,9 +49,8 @@ auto [e1, e2] = make<E>(); // CHECK: @_Z4makeI1BERT_v() // CHECK: call i32 @_Z3getILi0EEDa1B() -// CHECK: call void @_ZN1XC1E1Y(ptr {{[^,]*}} @_ZGR2b1_, i32 -// CHECK: call i32 @__cxa_atexit({{.*}}@_ZN1XD1Ev{{.*}}@_ZGR2b1_ -// CHECK: store ptr @_ZGR2b1_, +// CHECK: call void @_ZN1XC1E1Y(ptr {{[^,]*}} @b1, i32 +// CHECK: call i32 @__cxa_atexit({{.*}}@_ZN1XD1Ev{{.*}}@b1 // // CHECK: call noundef double @_Z3getILi1EEDa1B() // CHECK: fptosi double %{{.*}} to i32 @@ -149,9 +147,8 @@ int test_static_tuple() { // CHECK: br i1 // CHECK: @__cxa_guard_acquire({{.*}} @_ZGVZ17test_static_tuplevE2x1) // CHECK: call {{.*}} @_Z3getILi0EEDa1B( - // CHECK: call {{.*}} @_ZN1XC1E1Y({{.*}} @_ZGRZ17test_static_tuplevE2x1_, - // CHECK: call {{.*}} @__cxa_atexit({{.*}} @_ZN1XD1Ev, {{.*}} @_ZGRZ17test_static_tuplevE2x1_ - // CHECK: store {{.*}} @_ZGRZ17test_static_tuplevE2x1_, {{.*}} @_ZZ17test_static_tuplevE2x1 + // CHECK: call {{.*}} @_ZN1XC1E1Y({{.*}} @_ZZ17test_static_tuplevE2x1, + // CHECK: call {{.*}} @__cxa_atexit({{.*}} @_ZN1XD1Ev, {{.*}} @_ZZ17test_static_tuplevE2x1 // CHECK: call void @__cxa_guard_release({{.*}} @_ZGVZ17test_static_tuplevE2x1) // Initialization of the secret 'x2' variable. diff --git a/clang/test/DebugInfo/CXX/structured-binding.cpp b/clang/test/DebugInfo/CXX/structured-binding.cpp index 51818e7e16f00..e124a53762be6 100644 --- a/clang/test/DebugInfo/CXX/structured-binding.cpp +++ b/clang/test/DebugInfo/CXX/structured-binding.cpp @@ -17,7 +17,7 @@ // CHECK: #dbg_declare(ptr %p, ![[VAR_13:[0-9]+]], !DIExpression() // CHECK: getelementptr inbounds nuw %struct.A, ptr {{.*}}, i32 0, i32 1, !dbg ![[Y1_DEBUG_LOC:[0-9]+]] // CHECK: getelementptr inbounds nuw %struct.A, ptr {{.*}}, i32 0, i32 1, !dbg ![[Y2_DEBUG_LOC:[0-9]+]] -// CHECK: load ptr, ptr %z2, {{.*}}!dbg ![[Z2_DEBUG_LOC:[0-9]+]] +// CHECK: load i32, ptr %z2, {{.*}}!dbg ![[Z2_DEBUG_LOC:[0-9]+]] // CHECK: getelementptr inbounds [2 x i32], ptr {{.*}}, i{{64|32}} 0, i{{64|32}} 1, !dbg ![[A2_DEBUG_LOC:[0-9]+]] // CHECK: getelementptr inbounds nuw { i32, i32 }, ptr {{.*}}, i32 0, i32 1, !dbg ![[C2_DEBUG_LOC:[0-9]+]] // CHECK: extractelement <2 x i32> {{.*}}, i32 1, !dbg ![[V2_DEBUG_LOC:[0-9]+]] diff --git a/clang/test/SemaCXX/cxx2c-decomposition.cpp b/clang/test/SemaCXX/cxx2c-decomposition.cpp index 99278c6575ef1..df2e3fa90263a 100644 --- a/clang/test/SemaCXX/cxx2c-decomposition.cpp +++ b/clang/test/SemaCXX/cxx2c-decomposition.cpp @@ -66,8 +66,8 @@ void test() { constexpr auto [a, b] = B{}; static_assert(a.n == 0); // expected-error@-1 {{static assertion expression is not an integral constant expression}} \ -// expected-note@-1 {{read of temporary is not allowed in a constant expression outside the expression that created the temporary}}\ -// expected-note@-2 {{temporary created here}} +// expected-note@-1 {{read of non-constexpr variable 'a' is not allowed in a constant expression}} \ +// expected-note@-2 {{declared here}} constinit auto [init1] = Y {42}; constinit auto [init2] = X {}; // expected-error {{variable does not have a constant initializer}} \ diff --git a/clang/www/cxx_dr_status.html b/clang/www/cxx_dr_status.html index c3571b59ba874..d0f871b7bc901 100755 --- a/clang/www/cxx_dr_status.html +++ b/clang/www/cxx_dr_status.html @@ -21762,7 +21762,7 @@ <h2 id="cxxdr">C++ defect report implementation status</h2> <td>[<a href="https://wg21.link/dcl.struct.bind">dcl.struct.bind</a>]</td> <td>accepted</td> <td>constexpr structured bindings with prvalues from tuples</td> - <td class="unknown" align="center">Unknown</td> + <td class="unreleased" align="center">Clang 23</td> </tr> <tr id="3136"> <td><a href="https://cplusplus.github.io/CWG/issues/3136.html">3136</a></td> >From ba2a5ca4c007dd9e71ba4b07786ac8a02ee3d289 Mon Sep 17 00:00:00 2001 From: Matthias Wippich <[email protected]> Date: Tue, 5 May 2026 05:16:21 +0200 Subject: [PATCH 2/4] rename RefVD to BindingVD --- clang/lib/Sema/SemaDeclCXX.cpp | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index e7c1984c2f17b..4608807c829bb 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -1399,17 +1399,18 @@ static bool checkTupleLikeDecomposition(Sema &S, // Don't give this VarDecl a TypeSourceInfo, since this is a synthesized // entity and this type was never written in source code. - auto *RefVD = VarDecl::Create(S.Context, Src->getDeclContext(), Loc, Loc, - B->getDeclName().getAsIdentifierInfo(), U, - /*TInfo=*/nullptr, Src->getStorageClass()); - RefVD->setLexicalDeclContext(Src->getLexicalDeclContext()); - RefVD->setTSCSpec(Src->getTSCSpec()); - RefVD->setImplicit(); + auto *BindingVD = + VarDecl::Create(S.Context, Src->getDeclContext(), Loc, Loc, + B->getDeclName().getAsIdentifierInfo(), U, + /*TInfo=*/nullptr, Src->getStorageClass()); + BindingVD->setLexicalDeclContext(Src->getLexicalDeclContext()); + BindingVD->setTSCSpec(Src->getTSCSpec()); + BindingVD->setImplicit(); if (Src->isInlineSpecified()) - RefVD->setInlineSpecified(); - RefVD->getLexicalDeclContext()->addHiddenDecl(RefVD); + BindingVD->setInlineSpecified(); + BindingVD->getLexicalDeclContext()->addHiddenDecl(BindingVD); - InitializedEntity Entity = InitializedEntity::InitializeBinding(RefVD); + InitializedEntity Entity = InitializedEntity::InitializeBinding(BindingVD); InitializationKind Kind = E.get()->isPRValue() ? InitializationKind::CreateDirect(Loc, Loc, Loc) : InitializationKind::CreateCopy(Loc, Loc); @@ -1420,12 +1421,11 @@ static bool checkTupleLikeDecomposition(Sema &S, E = S.ActOnFinishFullExpr(E.get(), Loc, /*DiscardedValue*/ false); if (E.isInvalid()) return true; - RefVD->setInit(E.get()); - S.CheckCompleteVariableDeclaration(RefVD); + BindingVD->setInit(E.get()); + S.CheckCompleteVariableDeclaration(BindingVD); - E = S.BuildDeclarationNameExpr(CXXScopeSpec(), - DeclarationNameInfo(B->getDeclName(), Loc), - RefVD); + E = S.BuildDeclarationNameExpr( + CXXScopeSpec(), DeclarationNameInfo(B->getDeclName(), Loc), BindingVD); if (E.isInvalid()) return true; >From 3f3eca576145cfa3367b3ee1c5fe3ac9f5c80188 Mon Sep 17 00:00:00 2001 From: Matthias Wippich <[email protected]> Date: Wed, 20 May 2026 00:08:12 +0200 Subject: [PATCH 3/4] revert initialization change --- clang/lib/Sema/SemaDeclCXX.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 4608807c829bb..21dc20799da00 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -1411,9 +1411,7 @@ static bool checkTupleLikeDecomposition(Sema &S, BindingVD->getLexicalDeclContext()->addHiddenDecl(BindingVD); InitializedEntity Entity = InitializedEntity::InitializeBinding(BindingVD); - InitializationKind Kind = - E.get()->isPRValue() ? InitializationKind::CreateDirect(Loc, Loc, Loc) - : InitializationKind::CreateCopy(Loc, Loc); + InitializationKind Kind = InitializationKind::CreateCopy(Loc, Loc); InitializationSequence Seq(S, Entity, Kind, Init); E = Seq.Perform(S, Entity, Kind, Init); if (E.isInvalid()) >From 4e737a25e7f3976e3b904011bd9f349ec2a51cfb Mon Sep 17 00:00:00 2001 From: Matthias Wippich <[email protected]> Date: Wed, 20 May 2026 01:33:46 +0200 Subject: [PATCH 4/4] fix broken diagnostic --- clang/include/clang/Basic/DiagnosticSemaKinds.td | 2 +- clang/test/CXX/drs/cwg31xx.cpp | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index e059260778631..576ad88e0f86d 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -2602,7 +2602,7 @@ def select_initialized_entity_kind : TextSubstitution< "returning object|initializing statement expression result|" "throwing object|copying member subobject|copying array element|" "allocating object|copying temporary|initializing base subobject|" - "initializing vector element|capturing value}0">; + "initializing vector element|capturing value|||||||||initializing binding}0">; def err_temp_copy_no_viable : Error< "no viable constructor %sub{select_initialized_entity_kind}0 of type %1">; diff --git a/clang/test/CXX/drs/cwg31xx.cpp b/clang/test/CXX/drs/cwg31xx.cpp index ee41c77f6f181..710a48236aac7 100644 --- a/clang/test/CXX/drs/cwg31xx.cpp +++ b/clang/test/CXX/drs/cwg31xx.cpp @@ -54,8 +54,8 @@ namespace cwg3135 { // CWG3135: `x` is of type Pinned rather than Pinned&&. // This leads to the deleted copy ctor being called. auto [x] = Source{}; -// since-cxx17-error-re@-1 {{call to deleted constructor of 'std::tuple_element<0U{{L*}}, Source>::type' (aka 'cwg3135::Pinned')}} -// since-cxx17-note@-2 {{in implicit initialization of binding declaration 'x'}} -// since-cxx17-note@#cwg3135-pinned-ctor {{'Pinned' has been explicitly marked deleted here}} +// since-cxx17-error@-1 {{initializing binding of type 'Pinned' invokes deleted constructor}} +// since-cxx17-note@-2 {{in implicit initialization of binding declaration 'x'}} +// since-cxx17-note@#cwg3135-pinned-ctor {{'Pinned' has been explicitly marked deleted here}} #endif } // namespace cwg3135 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
