https://github.com/Murthy-Manideep updated https://github.com/llvm/llvm-project/pull/235427
>From 988f161231196f2a0779086d2cc8c2512a72f3bd Mon Sep 17 00:00:00 2001 From: Murthy-Manideep <[email protected]> Date: Sun, 25 Oct 2026 17:19:17 +0530 Subject: [PATCH 1/2] Fix extra error message (#222605) --- clang/lib/Sema/SemaDeclCXX.cpp | 14 ++++-- clang/test/Parser/cxx1z-decomposition.cpp | 4 +- clang/test/SemaCXX/GH222605.cpp | 53 +++++++++++++++++++++++ 3 files changed, 66 insertions(+), 5 deletions(-) create mode 100644 clang/test/SemaCXX/GH222605.cpp diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 0fe0daa71c1bcf..2b9059f24f0214 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -863,10 +863,11 @@ Sema::ActOnDecompositionDeclarator(Scope *S, Declarator &D, // The syntax only allows a single ref-qualifier prior to the decomposition // declarator. No other declarator chunks are permitted. Also check the type // specifier here. - if (DS.getTypeSpecType() != DeclSpec::TST_auto || + bool HasBadDeclarator = D.hasGroupingParens() || D.getNumTypeObjects() > 1 || (D.getNumTypeObjects() == 1 && - D.getTypeObject(0).Kind != DeclaratorChunk::Reference)) { + D.getTypeObject(0).Kind != DeclaratorChunk::Reference); + if (DS.getTypeSpecType() != DeclSpec::TST_auto || HasBadDeclarator) { Diag(Decomp.getLSquareLoc(), (D.hasGroupingParens() || (D.getNumTypeObjects() && @@ -878,7 +879,9 @@ Sema::ActOnDecompositionDeclarator(Scope *S, Declarator &D, // 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()) + // If the declaration is invalid, there is no need to continue with deduction + // or binding, as this can lead to extra error messages. + if (R->isFunctionType() || HasBadDeclarator) D.setInvalidType(); } @@ -988,6 +991,11 @@ Sema::ActOnDecompositionDeclarator(Scope *S, Declarator &D, CurContext->addHiddenDecl(New); } + if (New && New->isInvalidDecl()) { + for (auto *B : Bindings) + B->setInvalidDecl(); + } + if (OpenMP().isInOpenMPDeclareTargetContext()) OpenMP().checkDeclIsAllowedInOpenMPTarget(nullptr, New); diff --git a/clang/test/Parser/cxx1z-decomposition.cpp b/clang/test/Parser/cxx1z-decomposition.cpp index 45329b766bc281..dcccd63ae40ef3 100644 --- a/clang/test/Parser/cxx1z-decomposition.cpp +++ b/clang/test/Parser/cxx1z-decomposition.cpp @@ -121,8 +121,8 @@ namespace BadSpecifiers { // CHECK: :[[@LINE-1]]:13: error: structured binding declaration '[K]' requires an initializer; expected '=' or braced initializer list int [5] arr = {0}; // expected-error {{place the brackets after the name}} - auto *[f] = s; // expected-error {{cannot be declared with type 'auto *'}} expected-error {{incompatible initializer}} - auto S::*[g] = s; // expected-error {{cannot be declared with type 'auto S::*'}} expected-error {{incompatible initializer}} + auto *[f] = s; // expected-error {{cannot be declared with type 'auto *'}} + auto S::*[g] = s; // expected-error {{cannot be declared with type 'auto S::*'}} // ref-qualifiers are OK. auto &&[ok_1] = S(); diff --git a/clang/test/SemaCXX/GH222605.cpp b/clang/test/SemaCXX/GH222605.cpp new file mode 100644 index 00000000000000..dbe81addf49847 --- /dev/null +++ b/clang/test/SemaCXX/GH222605.cpp @@ -0,0 +1,53 @@ +// RUN: %clang_cc1 -std=c++17 -fsyntax-only -verify %s +// RUN: %clang_cc1 -std=c++20 -fsyntax-only -verify %s +// RUN: %clang_cc1 -std=c++23 -fsyntax-only -verify %s + +struct S { + int *p; + int *q; +}; + +struct Point { + double x; + double y; + double z; +}; + +void test_original(S s) { + auto* [x, y] = s; // expected-error {{structured binding declaration cannot be declared with type 'auto *'; declared type must be 'auto' or reference to 'auto'}} +} + +void test_other_struct(Point pt) { + auto* [x, y, z] = pt; // expected-error {{structured binding declaration cannot be declared with type 'auto *'; declared type must be 'auto' or reference to 'auto'}} +} + +void test_auto_variations(S s) { + auto*& [a, b] = s; // expected-error {{structured binding declaration cannot be declared with type 'auto *&'; declared type must be 'auto' or reference to 'auto'}} + const auto* [c, d] = s; // expected-error {{structured binding declaration cannot be declared with type 'const auto *'; declared type must be 'auto' or reference to 'auto'}} + const auto*& [e, f] = s; // expected-error {{structured binding declaration cannot be declared with type 'const auto *&'; declared type must be 'auto' or reference to 'auto'}} +} + +void test_valid(S s, Point pt) { + auto [a, b] = s; + auto& [c, d] = s; + const auto& [e, f] = s; + auto&& [g, h] = S{}; + + auto [x, y, z] = pt; + const auto& [cx, cy, cz] = pt; +} + +void test_other_errors(S s) { + auto* p = s; // expected-error {{variable 'p' with type 'auto *' has incompatible initializer of type 'S'}} + + auto [a] = s; // expected-error {{type 'S' binds to 2 elements, but only 1 name was provided}} + auto [b, c, d] = s; // expected-error {{type 'S' binds to 2 elements, but 3 names were provided}} + + int n = 0; + auto [x, y] = n; // expected-error {{cannot bind non-class, non-array type 'int'}} +} + +void test_pointer(S *s) { + auto* [a, b] = s; // expected-error {{structured binding declaration cannot be declared with type 'auto *'; declared type must be 'auto' or reference to 'auto'}} + auto** [c, d] = &s; // expected-error {{structured binding declaration cannot be declared with type 'auto **'; declared type must be 'auto' or reference to 'auto'}} +} >From 56e584e89cc821dffb9a1444732d247fe970a7e5 Mon Sep 17 00:00:00 2001 From: Murthy-Manideep <[email protected]> Date: Mon, 26 Oct 2026 22:17:38 +0530 Subject: [PATCH 2/2] Improve recovery for structured binding pointer declarators --- clang/docs/ReleaseNotes.md | 5 +++++ clang/include/clang/Sema/DeclSpec.h | 11 +++++++--- clang/lib/Sema/SemaDeclCXX.cpp | 28 ++++++++++++++++++++---- clang/test/SemaCXX/GH222605.cpp | 34 +++++++++++++++++++++-------- 4 files changed, 62 insertions(+), 16 deletions(-) diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md index 44f30666457f94..1aa987ec437b00 100644 --- a/clang/docs/ReleaseNotes.md +++ b/clang/docs/ReleaseNotes.md @@ -889,6 +889,11 @@ documentation](CIR/index.md) for more information regarding ClangIR's status and type. (#GH204756) #### Bug Fixes to C++ Support +- Clang now handles invalid pointer declarators in structured bindings + (such as ``auto* [x, y] = s;``) by removing the pointer part. This + avoids extra type deduction errors and improves error messages. + (#GH222605) + - Instantiate constexpr functions as needed before they are evaluated. (#GH73232) (#GH35052) (#GH100897) - Fixed lambdas with specifiers or attributes after the capture list being diff --git a/clang/include/clang/Sema/DeclSpec.h b/clang/include/clang/Sema/DeclSpec.h index 7b58bfcf53d98a..bc93eaaeeda158 100644 --- a/clang/include/clang/Sema/DeclSpec.h +++ b/clang/include/clang/Sema/DeclSpec.h @@ -2489,10 +2489,15 @@ class Declarator { return type_object_range(DeclTypeInfo.begin(), DeclTypeInfo.end()); } + /// Removes the type object at the specified index. + void DropTypeObject(unsigned index) { + assert(index < DeclTypeInfo.size() && "Invalid type chunk"); + DeclTypeInfo[index].destroy(); + DeclTypeInfo.erase(DeclTypeInfo.begin() + index); + } + void DropFirstTypeObject() { - assert(!DeclTypeInfo.empty() && "No type chunks to drop."); - DeclTypeInfo.front().destroy(); - DeclTypeInfo.erase(DeclTypeInfo.begin()); + DropTypeObject(0); } /// Return the innermost (closest to the declarator) chunk of this diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 2b9059f24f0214..0d67212c21c611 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -878,10 +878,30 @@ Sema::ActOnDecompositionDeclarator(Scope *S, Declarator &D, // 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 the declaration is invalid, there is no need to continue with deduction - // or binding, as this can lead to extra error messages. - if (R->isFunctionType() || HasBadDeclarator) + // shouldn't be called for such a type. + // Recover from invalid pointer declarators by removing pointer chunks + // so type deduction can proceed and the bindings remain usable. + bool DroppedPointer = false; + for (unsigned I = D.getNumTypeObjects(); I > 0; --I) { + const DeclaratorChunk &Chunk = D.getTypeObject(I - 1); + if (Chunk.Kind == DeclaratorChunk::Pointer || + Chunk.Kind == DeclaratorChunk::MemberPointer) { + D.DropTypeObject(I - 1); + DroppedPointer = true; + } + } + + if (DroppedPointer) { + TInfo = GetTypeForDeclarator(D); + R = TInfo->getType(); + } + + bool StillHasBadDeclarator = + D.hasGroupingParens() || D.getNumTypeObjects() > 1 || + (D.getNumTypeObjects() == 1 && + D.getTypeObject(0).Kind != DeclaratorChunk::Reference); + + if (R->isFunctionType() || StillHasBadDeclarator) D.setInvalidType(); } diff --git a/clang/test/SemaCXX/GH222605.cpp b/clang/test/SemaCXX/GH222605.cpp index dbe81addf49847..b6cd1651ff46d1 100644 --- a/clang/test/SemaCXX/GH222605.cpp +++ b/clang/test/SemaCXX/GH222605.cpp @@ -13,18 +13,32 @@ struct Point { double z; }; -void test_original(S s) { +void test_recovery(S s) { auto* [x, y] = s; // expected-error {{structured binding declaration cannot be declared with type 'auto *'; declared type must be 'auto' or reference to 'auto'}} + x = nullptr; + y = nullptr; + + auto*& [r1, r2] = s; // expected-error {{structured binding declaration cannot be declared with type 'auto *&'; declared type must be 'auto' or reference to 'auto'}} + r1 = nullptr; + r2 = nullptr; + + const auto* [c1, c2] = s; // expected-error {{structured binding declaration cannot be declared with type 'const auto *'; declared type must be 'auto' or reference to 'auto'}} + + const auto*& [cr1, cr2] = s; // expected-error {{structured binding declaration cannot be declared with type 'const auto *&'; declared type must be 'auto' or reference to 'auto'}} + + auto** [p1, p2] = s; // expected-error {{structured binding declaration cannot be declared with type 'auto **'; declared type must be 'auto' or reference to 'auto'}} + p1 = nullptr; + p2 = nullptr; } -void test_other_struct(Point pt) { +void test_aggregate(Point pt) { auto* [x, y, z] = pt; // expected-error {{structured binding declaration cannot be declared with type 'auto *'; declared type must be 'auto' or reference to 'auto'}} + double sum = x + y + z; } -void test_auto_variations(S s) { - auto*& [a, b] = s; // expected-error {{structured binding declaration cannot be declared with type 'auto *&'; declared type must be 'auto' or reference to 'auto'}} - const auto* [c, d] = s; // expected-error {{structured binding declaration cannot be declared with type 'const auto *'; declared type must be 'auto' or reference to 'auto'}} - const auto*& [e, f] = s; // expected-error {{structured binding declaration cannot be declared with type 'const auto *&'; declared type must be 'auto' or reference to 'auto'}} +void test_downstream_type_checking(Point pt) { + auto* [x, y, z] = pt; // expected-error {{structured binding declaration cannot be declared with type 'auto *'; declared type must be 'auto' or reference to 'auto'}} + decltype(x) bad = "string"; // expected-error {{cannot initialize a variable of type 'decltype(x)' (aka 'double') with an lvalue of type 'const char[7]'}} } void test_valid(S s, Point pt) { @@ -47,7 +61,9 @@ void test_other_errors(S s) { auto [x, y] = n; // expected-error {{cannot bind non-class, non-array type 'int'}} } -void test_pointer(S *s) { - auto* [a, b] = s; // expected-error {{structured binding declaration cannot be declared with type 'auto *'; declared type must be 'auto' or reference to 'auto'}} - auto** [c, d] = &s; // expected-error {{structured binding declaration cannot be declared with type 'auto **'; declared type must be 'auto' or reference to 'auto'}} +void test_pointer(S *sp) { + auto* [a, b] = sp; // expected-error {{structured binding declaration cannot be declared with type 'auto *'; declared type must be 'auto' or reference to 'auto'}} \ + // expected-error {{cannot bind non-class, non-array type 'S *'}} + auto** [c, d] = &sp; // expected-error {{structured binding declaration cannot be declared with type 'auto **'; declared type must be 'auto' or reference to 'auto'}} \ + // expected-error {{cannot bind non-class, non-array type 'S **'}} } _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
