https://gcc.gnu.org/g:b7e4b5e862fcb12cfeaa3bee4e8c77098201d5f4
commit r16-3122-gb7e4b5e862fcb12cfeaa3bee4e8c77098201d5f4 Author: Jakub Jelinek <ja...@redhat.com> Date: Mon Aug 11 09:02:38 2025 +0200 c++: Fix up handling of name independent structured binding packs [PR117783] I've realized I haven't added testsuite coverage for name independent structured binding packs. And the auto [i, ..._, j] = T {}; auto [k, ..._, l] = T {}; case shows a problem with that. The elements of the structured binding pack have #i appended to their names, so for the _ case e.g. _#0, _#1 etc. (to print something useful in diagnostics, perhaps debug info later on). The above is valid though as long as one doesn't use _ (which is ambiguous), but we were emitting errors on redeclaration of _#0, _#1 etc. The following patch uses DECL_NAME (decl) = NULL_TREE; for the name independent decl case so that the false positive redeclaration errors aren't emitted. 2025-08-11 Jakub Jelinek <ja...@redhat.com> PR c++/117783 * decl.cc (set_sb_pack_name): For name independent decls just clear DECL_NAME instead of appending #i to it. * g++.dg/cpp26/name-independent-decl11.C: New test. Diff: --- gcc/cp/decl.cc | 24 ++-- .../g++.dg/cpp26/name-independent-decl11.C | 129 +++++++++++++++++++++ 2 files changed, 146 insertions(+), 7 deletions(-) diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc index 693cf65fd012..5aa8203649cd 100644 --- a/gcc/cp/decl.cc +++ b/gcc/cp/decl.cc @@ -9870,17 +9870,27 @@ cp_maybe_mangle_decomp (tree decl, cp_decomp *decomp) } } -/* Append #i to DECL_NAME (decl). */ +/* Append #i to DECL_NAME (decl) or for name independent decls + clear DECL_NAME (decl). */ static void set_sb_pack_name (tree decl, unsigned HOST_WIDE_INT i) { - tree name = DECL_NAME (decl); - size_t len = IDENTIFIER_LENGTH (name) + 22; - char *n = XALLOCAVEC (char, len); - snprintf (n, len, "%s#" HOST_WIDE_INT_PRINT_UNSIGNED, - IDENTIFIER_POINTER (name), i); - DECL_NAME (decl) = get_identifier (n); + if (name_independent_decl_p (decl)) + /* Only "_" names are treated as name independent, "_#0" etc. is not and + because we pushdecl the individual decl elements of structured binding + pack, we could get redeclaration errors if there are 2 or more name + independent structured binding packs in the same scope. */ + DECL_NAME (decl) = NULL_TREE; + else + { + tree name = DECL_NAME (decl); + size_t len = IDENTIFIER_LENGTH (name) + 22; + char *n = XALLOCAVEC (char, len); + snprintf (n, len, "%s#" HOST_WIDE_INT_PRINT_UNSIGNED, + IDENTIFIER_POINTER (name), i); + DECL_NAME (decl) = get_identifier (n); + } } /* Finish a decomposition declaration. DECL is the underlying declaration diff --git a/gcc/testsuite/g++.dg/cpp26/name-independent-decl11.C b/gcc/testsuite/g++.dg/cpp26/name-independent-decl11.C new file mode 100644 index 000000000000..643b1db25c37 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp26/name-independent-decl11.C @@ -0,0 +1,129 @@ +// P2169R4 - A nice placeholder with no name +// { dg-do compile { target c++11 } } +// { dg-options "" } + +template <typename T> +void +foo () +{ + { + auto [i, ..._, k] = T {}; // { dg-warning "structured bindings only available with" "" { target c++14_down } } + // { dg-warning "structured binding packs only available with" "" { target { c++17 && c++23_down } } .-1 } + ++_...[0]; // { dg-warning "pack indexing only available with" "" { target c++23_down } } + } + { + auto [_, ..._, k] = T {}; // { dg-warning "structured bindings only available with" "" { target c++14_down } } + // { dg-warning "name-independent declarations only available with" "" { target c++23_down } .-1 } + // { dg-warning "structured binding packs only available with" "" { target { c++17 && c++23_down } } .-2 } + ++_; // { dg-error "reference to '_' is ambiguous" } + } + { + auto [i, ..._, _] = T {}; // { dg-warning "structured bindings only available with" "" { target c++14_down } } + // { dg-warning "name-independent declarations only available with" "" { target c++23_down } .-1 } + // { dg-warning "structured binding packs only available with" "" { target { c++17 && c++23_down } } .-2 } + ++_; // { dg-error "reference to '_' is ambiguous" } + } + { + auto [i, ..._, j] = T {}; // { dg-warning "structured bindings only available with" "" { target c++14_down } } + // { dg-warning "structured binding packs only available with" "" { target { c++17 && c++23_down } } .-1 } + auto [k, ..._, l] = T {}; // { dg-warning "structured bindings only available with" "" { target c++14_down } } + // { dg-warning "name-independent declarations only available with" "" { target c++23_down } .-1 } + // { dg-warning "structured binding packs only available with" "" { target { c++17 && c++23_down } } .-2 } + ++_...[0]; // { dg-error "reference to '_' is ambiguous" } + } + { + static auto [i, ..._, j] = T {};// { dg-warning "structured bindings only available with" "" { target c++14_down } } + // { dg-warning "structured binding packs only available with" "" { target { c++17 && c++23_down } } .-1 } + // { dg-warning "structured binding declaration can be 'static' only in" "" { target c++17_down } .-2 } + ++_...[0]; // { dg-warning "pack indexing only available with" "" { target c++23_down } } + } + { + static auto [_, ..._, j] = T {};// { dg-error "redeclaration of 'auto _'" } + // { dg-warning "structured bindings only available with" "" { target c++14_down } .-1 } + // { dg-warning "structured binding packs only available with" "" { target { c++17 && c++23_down } } .-2 } + // { dg-warning "structured binding declaration can be 'static' only in" "" { target c++17_down } .-3 } + } + { + static auto [i, ..._, _] = T {};// { dg-error "conflicting declaration 'auto _'" } + // { dg-warning "structured bindings only available with" "" { target c++14_down } .-1 } + // { dg-warning "structured binding packs only available with" "" { target { c++17 && c++23_down } } .-2 } + // { dg-warning "structured binding declaration can be 'static' only in" "" { target c++17_down } .-3 } + } +} + +template <typename T> +void +bar () +{ + T s[4] = {}; + for (auto [..._, _, a] : s) // { dg-warning "name-independent declarations only available with" "" { target c++23_down } } + // { dg-warning "structured bindings only available with" "" { target c++14_down } .-1 } + // { dg-warning "structured binding packs only available with" "" { target { c++17 && c++23_down } } .-2 } + ++_; // { dg-error "reference to '_' is ambiguous" } + for (auto [a, ..._, b] : s) // { dg-warning "structured bindings only available with" "" { target c++14_down } } + // { dg-warning "structured binding packs only available with" "" { target { c++17 && c++23_down } } .-1 } + ++_...[0]; // { dg-warning "pack indexing only available with" "" { target c++23_down } } + for (auto [_, ..._, a] : s) // { dg-warning "name-independent declarations only available with" "" { target c++23_down } } + { // { dg-warning "structured bindings only available with" "" { target c++14_down } .-1 } + // { dg-warning "structured binding packs only available with" "" { target { c++17 && c++23_down } } .-2 } + ++_; // { dg-error "reference to '_' is ambiguous" } + } + for (auto [a, ..._, b] : s) // { dg-warning "structured bindings only available with" "" { target c++14_down } } + { // { dg-warning "structured binding packs only available with" "" { target { c++17 && c++23_down } } .-1 } + ++_...[0]; // { dg-warning "pack indexing only available with" "" { target c++23_down } } + int _ = ++b; // { dg-warning "name-independent declarations only available with" "" { target c++23_down } } + ++_; // { dg-error "reference to '_' is ambiguous" } + } +} + +template <typename T> +void +baz () +{ + T s[4] = {}; + for (auto [a, ..._, _] : s) // { dg-warning "name-independent declarations only available with" "" { target c++23_down } } + // { dg-warning "structured bindings only available with" "" { target c++14_down } .-1 } + // { dg-warning "structured binding packs only available with" "" { target { c++17 && c++23_down } } .-2 } + ++_; // { dg-error "reference to '_' is ambiguous" } + for (auto [a, b, ..._] : s) // { dg-warning "structured bindings only available with" "" { target c++14_down } } + // { dg-warning "structured binding packs only available with" "" { target { c++17 && c++23_down } } .-1 } + ++_...[0]; // { dg-warning "pack indexing only available with" "" { target c++23_down } } + for (auto [a, ..._, _] : s) // { dg-warning "name-independent declarations only available with" "" { target c++23_down } } + { // { dg-warning "structured bindings only available with" "" { target c++14_down } .-1 } + // { dg-warning "structured binding packs only available with" "" { target { c++17 && c++23_down } } .-2 } + ++_; // { dg-error "reference to '_' is ambiguous" } + ++a; + } + for (auto [a, b, ..._] : s) // { dg-warning "structured bindings only available with" "" { target c++14_down } } + { // { dg-warning "structured binding packs only available with" "" { target { c++17 && c++23_down } } .-1 } + ++_...[0]; // { dg-warning "pack indexing only available with" "" { target c++23_down } } + int _ = a + b; // { dg-warning "name-independent declarations only available with" "" { target c++23_down } } + ++_; // { dg-error "reference to '_' is ambiguous" } + } +} + +struct A { int a, b, c, d, e; }; + +namespace std { + template<typename T> struct tuple_size; + template<int, typename> struct tuple_element; +} + +struct B { + int a[5]; + template <int I> int &get () { return a[I]; } +}; + +template<> struct std::tuple_size<B> { static const int value = 5; }; +template<int I> struct std::tuple_element<I,B> { using type = int; }; + +void +qux () +{ + foo <A> (); + bar <A> (); + baz <A> (); + foo <B> (); + bar <B> (); + baz <B> (); +}