c++, v4: Implement C++26 P2169R4 - Placeholder variables with no name [PR110349]

Message ID ZWd8kDzHru8DKB9p@tucnak
State New
Headers
Series c++, v4: Implement C++26 P2169R4 - Placeholder variables with no name [PR110349] |

Checks

Context Check Description
linaro-tcwg-bot/tcwg_gcc_build--master-arm fail Patch failed to apply
linaro-tcwg-bot/tcwg_gcc_build--master-aarch64 fail Patch failed to apply

Commit Message

Jakub Jelinek Nov. 29, 2023, 6:01 p.m. UTC
  On Tue, Nov 28, 2023 at 11:27:55AM -0500, Jason Merrill wrote:
> On 11/24/23 03:34, Jakub Jelinek wrote:
> > On Mon, Sep 18, 2023 at 07:12:40PM +0200, Jakub Jelinek via Gcc-patches wrote:
> > > On Tue, Aug 22, 2023 at 09:39:11AM +0200, Jakub Jelinek via Gcc-patches wrote:
> > > > The following patch implements the C++26 P2169R4 paper.
> > > > As written in the PR, the patch expects that:
> > > > 1) https://eel.is/c++draft/expr.prim.lambda.capture#2
> > > >     "Ignoring appearances in initializers of init-captures, an identifier
> > > >      or this shall not appear more than once in a lambda-capture."
> > > >     is adjusted such that name-independent lambda captures with initializers
> > > >     can violate this rule (but lambda captures which aren't name-independent
> > > >     can't appear after name-independent ones)
> > > > 2) https://eel.is/c++draft/class.mem#general-5
> > > >     "A member shall not be declared twice in the member-specification,
> > > >      except that"
> > > >     having an exception that name-independent non-static data member
> > > >     declarations can appear multiple times (but again, if there is
> > > >     a member which isn't name-independent, it can't appear after
> > > >     name-independent ones)
> > > > 3) it assumes that any name-independent declarations which weren't
> > > >     previously valid result in the _ lookups being ambiguous, not just
> > > >     if there are 2 _ declarations in the same scope, in particular the
> > > >     https://eel.is/c++draft/basic.scope#block-2 mentioned cases
> > > > 4) it assumes that _ in static function/block scope structured bindings
> > > >     is never name-independent like in namespace scope structured bindings;
> > > >     it matches clang behavior and is consistent with e.g. static type _;
> > > >     not being name-independent both at namespace scope and at function/block
> > > >     scope

> > 2023-11-23  Jakub Jelinek  <jakub@redhat.com>
> > 
> > 	PR c++/110349
> > gcc/c-family/
> > 	* c-cppbuiltin.cc (c_cpp_builtins): Predefine
> > 	__cpp_placeholder_variables=202306L for C++26.
> > gcc/cp/
> > 	* cp-tree.h: Implement C++26 P2169R4 - Placeholder variables with no
> > 	name.
> > 	(OVL_PLACEHOLDER_P): Define.
> 
> Throughout this patch let's follow the standard and avoid using the word
> "placeholder" to refer to name-independent decls.  There are a lot of other
> things that could be meant by "placeholder", notably "auto".

Ok, changed it almost everywhere, except for the predefined macro which
the C++ standard defines that way and the name of the P2169R4 paper in
ChangeLog and test comments because the paper is called like that.
> > +	  else
> > +	    {
> 
> Please add a comment here with your rationale from the commit message.

Done.

> > +	  binding->value = nreverse (binding->value);
> > +	  /* Skip over TREE_LISTs added for check_local_shadow detected
> 
> This should mention pushdecl, since that's where they're actually added
> (which, as mentioned below, I don't understand why).

Done.

> > -	  check_local_shadow (decl);
> > +	  tree local_shadow = check_local_shadow (decl);
> > +	  if (placeholder_p && local_shadow)
> > +	    {
> > +	      if (cxx_dialect < cxx26 && !placeholder_diagnosed_p)
> > +		pedwarn (DECL_SOURCE_LOCATION (decl), OPT_Wc__26_extensions,
> > +			 "placeholder variables only available with "
> > +			 "%<-std=c++2c%> or %<-std=gnu++2c%>");
> > +	      placeholder_diagnosed_p = true;
> > +	      if (old == NULL_TREE)
> > +		{
> > +		  old = build_tree_list (error_mark_node, local_shadow);
> > +		  TREE_TYPE (old) = error_mark_node;
> > +		}
> > +	    }
> 
> This needs a rationale comment; I don't understand what the purpose is.

Added it, but in short it is the assumption 3) above (which dunno if
it is something that has been discussed or I should file as DR or you
would), I believe it would be very weird if say for
void foo (int x) { int x = 5; }
the standard says it must be rejected even when the 2 x decls don't
live in the same scope (ditto all other cases check_local_shadow deals
with), while
void foo (int _) { int _ = 5; return _; }
would be accepted and
void bar () { int _ = 4; int _ = 5; return _; }
not.

> > @@ -7579,7 +7800,30 @@ lookup_name (tree name, LOOK_where where
> >   		&& (bool (want & LOOK_want::HIDDEN_LAMBDA)
> >   		    || !is_lambda_ignored_entity (iter->value))
> >   		&& qualify_lookup (iter->value, want))
> > -	      binding = iter->value;
> > +	      {
> > +		binding = iter->value;
> > +		if (binding
> > +		    && TREE_CODE (binding) == TREE_LIST
> > +		    && name_independent_decl_p (TREE_VALUE (binding)))
> > +		  {
> > +		    for (tree b = binding; b; b = TREE_CHAIN (b))
> > +		      if (TREE_CHAIN (b) == NULL
> > +			  && TREE_CODE (TREE_VALUE (b)) == OVERLOAD)
> > +			{
> > +			  /* If the scope has an overload with _ function
> > +			     declarations followed by at least one
> > +			     name-independent declaration, we shouldn't return
> > +			     iter->value but a new TREE_LIST containing the
> > +			     name-independent declaration(s) and functions
> > +			     from the OVERLOAD.  */
> 
> Why is the iter->value TREE_LIST unsuitable?

I thought the diagnostics routines to report the ambiguities would not be
happy seeing OVERLOADs among the TREE_LIST, but seems removal of the above
hunk just causes
 /usr/src/gcc/gcc/testsuite/g++.dg/cpp26/name-independent-decl2.C:44:7: error: reference to '_' is ambiguous
-/usr/src/gcc/gcc/testsuite/g++.dg/cpp26/name-independent-decl2.C:42:18: note: candidates are: 'float _(float)'
+/usr/src/gcc/gcc/testsuite/g++.dg/cpp26/name-independent-decl2.C:43:9: note: candidates are: 'int _'
+/usr/src/gcc/gcc/testsuite/g++.dg/cpp26/name-independent-decl2.C:42:18: note:                 'float _(float)'
 /usr/src/gcc/gcc/testsuite/g++.dg/cpp26/name-independent-decl2.C:41:17: note:                 'long int _(long int)'
 /usr/src/gcc/gcc/testsuite/g++.dg/cpp26/name-independent-decl2.C:40:16: note:                 'int _(int)'
-/usr/src/gcc/gcc/testsuite/g++.dg/cpp26/name-independent-decl2.C:43:9: note:                 'int _'
kind of changes (- with the hunk, + without), so I've dropped that hunk.

> > +    {
> > +      static int _ = 3;		// { dg-warning "declaration of '_' shadows a previous local" }
> 
> Perhaps we don't want to warn if either of the declarations is
> name-independent?

Done.

> > +  {
> > +    static auto [i, _, _] = a;	// { dg-error "redeclaration of 'auto _'" }
> 
> Would it be easy to add a note explaining that static static bindings aren't
> name-independent?

Tried to do that in duplicate_decls, but dunno if I've converted all the
most important reasons why something might not be name-independent despite
_ name (e.g. template parameter is not in the list) and whether the wording
is right in all cases.  And I've restricted the extra messages to C++26 and
later, because in older standards the fact that we treat something as
name-independent declaration is just an extension, pedantically nothing is
name-independent.

> > +namespace A
> > +{
> > +  int _ = 1;
> > +  int _ = 1;			// { dg-error "redefinition of 'int A::_'" }
> 
> Similarly, a note explaining that namespace-scope variables aren't
> name-independent.

And this.

> > +void
> > +corge (int _, int _)		// { dg-error "redefinition of 'int _'" }
> 
> ...likewise parameters.

And this too...

This patch passes
GXX_TESTSUITE_STDS=98,11,14,17,20,23,26 make check-g++ RUNTESTFLAGS="dg.exp=cpp26/*.C"
but haven't tested it beyond that (of course will run it through full
bootstrap/regtest).

2023-11-29  Jakub Jelinek  <jakub@redhat.com>

	PR c++/110349
gcc/c-family/
	* c-cppbuiltin.cc (c_cpp_builtins): Predefine
	__cpp_placeholder_variables=202306L for C++26.
gcc/cp/
	* cp-tree.h: Implement C++26 P2169R4 - Placeholder variables with no
	name.
	(OVL_NAME_INDEPENDENT_DECL_P): Define.
	(add_capture): Add unsigned * argument.
	(name_independent_decl_p): New inline function.
	* name-lookup.cc (class name_lookup): Make ambiguous and
	add_value members public.
	(name_independent_linear_search): New function.
	(get_class_binding_direct): Handle member_vec_binary_search
	returning OVL_NAME_INDEPENDENT_DECL_P OVERLOAD.  Use
	name_independent_linear_search rather than fields_linear_search
	for linear lookup of _ name if !want_type.
	(member_name_cmp): Sort name-independent declarations first.
	(member_vec_dedup): Handle name-independent declarations.
	(pop_local_binding): Handle binding->value being a TREE_LIST for
	ambiguous name-independent declarations.
	(supplement_binding): Handle name-independent declarations.
	(update_binding): Likewise.
	(check_local_shadow): Return tree rather than void, normally
	NULL_TREE but old for name-independent declarations which used
	to conflict with outer scope declaration.  Don't emit -Wshadow*
	warnings for name-independent declarations.
	(pushdecl): Handle name-independent declarations.
	* search.cc (lookup_field_r): Handle nval being a TREE_LIST.
	* lambda.cc (build_capture_proxy): Adjust for ___.<number>
	names of members.
	(add_capture): Add NAME_INDEPENDENT_CNT argument.  Use ___.<number>
	name rather than ___ for second and following capture with
	_ name.
	(add_default_capture): Adjust add_capture caller.
	* decl.cc (poplevel): Don't warn about name-independent declarations.
	(duplicate_decls): If in C++26 a _ named declaration conflicts with
	earlier declarations, emit explaining note why the new declaration
	is not name-independent.
	(reshape_init_class): If field is a TREE_LIST, emit an ambiguity
	error with list of candidates rather than error about non-existing
	non-static data member.
	* parser.cc (cp_parser_lambda_introducer): Adjust add_capture callers.
	Allow name-independent capture redeclarations.
	(cp_parser_decomposition_declaration): Set decl_specs.storage_class
	to sc_static for static structured bindings.
	* pt.cc (tsubst_lambda_expr): Adjust add_capture caller.
gcc/testsuite/
	* g++.dg/cpp26/name-independent-decl1.C: New test.
	* g++.dg/cpp26/name-independent-decl2.C: New test.
	* g++.dg/cpp26/name-independent-decl3.C: New test.
	* g++.dg/cpp26/name-independent-decl4.C: New test.
	* g++.dg/cpp26/name-independent-decl5.C: New test.
	* g++.dg/cpp26/name-independent-decl6.C: New test.
	* g++.dg/cpp26/feat-cxx26.C: Add __cpp_placeholder_variables test.



	Jakub
  

Comments

Jason Merrill Nov. 29, 2023, 6:48 p.m. UTC | #1
On 11/29/23 13:01, Jakub Jelinek wrote:
> On Tue, Nov 28, 2023 at 11:27:55AM -0500, Jason Merrill wrote:
>> On 11/24/23 03:34, Jakub Jelinek wrote:
>>> On Mon, Sep 18, 2023 at 07:12:40PM +0200, Jakub Jelinek via Gcc-patches wrote:
>>>> On Tue, Aug 22, 2023 at 09:39:11AM +0200, Jakub Jelinek via Gcc-patches wrote:
>>>>> The following patch implements the C++26 P2169R4 paper.
>>>>> As written in the PR, the patch expects that:
>>>>> 1) https://eel.is/c++draft/expr.prim.lambda.capture#2
>>>>>      "Ignoring appearances in initializers of init-captures, an identifier
>>>>>       or this shall not appear more than once in a lambda-capture."
>>>>>      is adjusted such that name-independent lambda captures with initializers
>>>>>      can violate this rule (but lambda captures which aren't name-independent
>>>>>      can't appear after name-independent ones)
>>>>> 2) https://eel.is/c++draft/class.mem#general-5
>>>>>      "A member shall not be declared twice in the member-specification,
>>>>>       except that"
>>>>>      having an exception that name-independent non-static data member
>>>>>      declarations can appear multiple times (but again, if there is
>>>>>      a member which isn't name-independent, it can't appear after
>>>>>      name-independent ones)
>>>>> 3) it assumes that any name-independent declarations which weren't
>>>>>      previously valid result in the _ lookups being ambiguous, not just
>>>>>      if there are 2 _ declarations in the same scope, in particular the
>>>>>      https://eel.is/c++draft/basic.scope#block-2 mentioned cases
>>>>> 4) it assumes that _ in static function/block scope structured bindings
>>>>>      is never name-independent like in namespace scope structured bindings;
>>>>>      it matches clang behavior and is consistent with e.g. static type _;
>>>>>      not being name-independent both at namespace scope and at function/block
>>>>>      scope
> 
>>> 2023-11-23  Jakub Jelinek  <jakub@redhat.com>
>>>
>>> 	PR c++/110349
>>> gcc/c-family/
>>> 	* c-cppbuiltin.cc (c_cpp_builtins): Predefine
>>> 	__cpp_placeholder_variables=202306L for C++26.
>>> gcc/cp/
>>> 	* cp-tree.h: Implement C++26 P2169R4 - Placeholder variables with no
>>> 	name.
>>> 	(OVL_PLACEHOLDER_P): Define.
>>
>> Throughout this patch let's follow the standard and avoid using the word
>> "placeholder" to refer to name-independent decls.  There are a lot of other
>> things that could be meant by "placeholder", notably "auto".
> 
> Ok, changed it almost everywhere, except for the predefined macro which
> the C++ standard defines that way and the name of the P2169R4 paper in
> ChangeLog and test comments because the paper is called like that.
>>> +	  else
>>> +	    {
>>
>> Please add a comment here with your rationale from the commit message.
> 
> Done.
> 
>>> +	  binding->value = nreverse (binding->value);
>>> +	  /* Skip over TREE_LISTs added for check_local_shadow detected
>>
>> This should mention pushdecl, since that's where they're actually added
>> (which, as mentioned below, I don't understand why).
> 
> Done.
> 
>>> -	  check_local_shadow (decl);
>>> +	  tree local_shadow = check_local_shadow (decl);
>>> +	  if (placeholder_p && local_shadow)
>>> +	    {
>>> +	      if (cxx_dialect < cxx26 && !placeholder_diagnosed_p)
>>> +		pedwarn (DECL_SOURCE_LOCATION (decl), OPT_Wc__26_extensions,
>>> +			 "placeholder variables only available with "
>>> +			 "%<-std=c++2c%> or %<-std=gnu++2c%>");
>>> +	      placeholder_diagnosed_p = true;
>>> +	      if (old == NULL_TREE)
>>> +		{
>>> +		  old = build_tree_list (error_mark_node, local_shadow);
>>> +		  TREE_TYPE (old) = error_mark_node;
>>> +		}
>>> +	    }
>>
>> This needs a rationale comment; I don't understand what the purpose is.
> 
> Added it, but in short it is the assumption 3) above (which dunno if
> it is something that has been discussed or I should file as DR or you
> would), I believe it would be very weird if say for
> void foo (int x) { int x = 5; }
> the standard says it must be rejected even when the 2 x decls don't
> live in the same scope (ditto all other cases check_local_shadow deals
> with), while
> void foo (int _) { int _ = 5; return _; }
> would be accepted and
> void bar () { int _ = 4; int _ = 5; return _; }
> not.
> 
>>> @@ -7579,7 +7800,30 @@ lookup_name (tree name, LOOK_where where
>>>    		&& (bool (want & LOOK_want::HIDDEN_LAMBDA)
>>>    		    || !is_lambda_ignored_entity (iter->value))
>>>    		&& qualify_lookup (iter->value, want))
>>> -	      binding = iter->value;
>>> +	      {
>>> +		binding = iter->value;
>>> +		if (binding
>>> +		    && TREE_CODE (binding) == TREE_LIST
>>> +		    && name_independent_decl_p (TREE_VALUE (binding)))
>>> +		  {
>>> +		    for (tree b = binding; b; b = TREE_CHAIN (b))
>>> +		      if (TREE_CHAIN (b) == NULL
>>> +			  && TREE_CODE (TREE_VALUE (b)) == OVERLOAD)
>>> +			{
>>> +			  /* If the scope has an overload with _ function
>>> +			     declarations followed by at least one
>>> +			     name-independent declaration, we shouldn't return
>>> +			     iter->value but a new TREE_LIST containing the
>>> +			     name-independent declaration(s) and functions
>>> +			     from the OVERLOAD.  */
>>
>> Why is the iter->value TREE_LIST unsuitable?
> 
> I thought the diagnostics routines to report the ambiguities would not be
> happy seeing OVERLOADs among the TREE_LIST, but seems removal of the above
> hunk just causes
>   /usr/src/gcc/gcc/testsuite/g++.dg/cpp26/name-independent-decl2.C:44:7: error: reference to '_' is ambiguous
> -/usr/src/gcc/gcc/testsuite/g++.dg/cpp26/name-independent-decl2.C:42:18: note: candidates are: 'float _(float)'
> +/usr/src/gcc/gcc/testsuite/g++.dg/cpp26/name-independent-decl2.C:43:9: note: candidates are: 'int _'
> +/usr/src/gcc/gcc/testsuite/g++.dg/cpp26/name-independent-decl2.C:42:18: note:                 'float _(float)'
>   /usr/src/gcc/gcc/testsuite/g++.dg/cpp26/name-independent-decl2.C:41:17: note:                 'long int _(long int)'
>   /usr/src/gcc/gcc/testsuite/g++.dg/cpp26/name-independent-decl2.C:40:16: note:                 'int _(int)'
> -/usr/src/gcc/gcc/testsuite/g++.dg/cpp26/name-independent-decl2.C:43:9: note:                 'int _'
> kind of changes (- with the hunk, + without), so I've dropped that hunk.
> 
>>> +    {
>>> +      static int _ = 3;		// { dg-warning "declaration of '_' shadows a previous local" }
>>
>> Perhaps we don't want to warn if either of the declarations is
>> name-independent?
> 
> Done.
> 
>>> +  {
>>> +    static auto [i, _, _] = a;	// { dg-error "redeclaration of 'auto _'" }
>>
>> Would it be easy to add a note explaining that static static bindings aren't
>> name-independent?
> 
> Tried to do that in duplicate_decls, but dunno if I've converted all the
> most important reasons why something might not be name-independent despite
> _ name (e.g. template parameter is not in the list) and whether the wording
> is right in all cases.  And I've restricted the extra messages to C++26 and
> later, because in older standards the fact that we treat something as
> name-independent declaration is just an extension, pedantically nothing is
> name-independent.
> 
>>> +namespace A
>>> +{
>>> +  int _ = 1;
>>> +  int _ = 1;			// { dg-error "redefinition of 'int A::_'" }
>>
>> Similarly, a note explaining that namespace-scope variables aren't
>> name-independent.
> 
> And this.
> 
>>> +void
>>> +corge (int _, int _)		// { dg-error "redefinition of 'int _'" }
>>
>> ...likewise parameters.
> 
> And this too...
> 
> This patch passes
> GXX_TESTSUITE_STDS=98,11,14,17,20,23,26 make check-g++ RUNTESTFLAGS="dg.exp=cpp26/*.C"
> but haven't tested it beyond that (of course will run it through full
> bootstrap/regtest).

OK if it passes, thanks.

> 2023-11-29  Jakub Jelinek  <jakub@redhat.com>
> 
> 	PR c++/110349
> gcc/c-family/
> 	* c-cppbuiltin.cc (c_cpp_builtins): Predefine
> 	__cpp_placeholder_variables=202306L for C++26.
> gcc/cp/
> 	* cp-tree.h: Implement C++26 P2169R4 - Placeholder variables with no
> 	name.
> 	(OVL_NAME_INDEPENDENT_DECL_P): Define.
> 	(add_capture): Add unsigned * argument.
> 	(name_independent_decl_p): New inline function.
> 	* name-lookup.cc (class name_lookup): Make ambiguous and
> 	add_value members public.
> 	(name_independent_linear_search): New function.
> 	(get_class_binding_direct): Handle member_vec_binary_search
> 	returning OVL_NAME_INDEPENDENT_DECL_P OVERLOAD.  Use
> 	name_independent_linear_search rather than fields_linear_search
> 	for linear lookup of _ name if !want_type.
> 	(member_name_cmp): Sort name-independent declarations first.
> 	(member_vec_dedup): Handle name-independent declarations.
> 	(pop_local_binding): Handle binding->value being a TREE_LIST for
> 	ambiguous name-independent declarations.
> 	(supplement_binding): Handle name-independent declarations.
> 	(update_binding): Likewise.
> 	(check_local_shadow): Return tree rather than void, normally
> 	NULL_TREE but old for name-independent declarations which used
> 	to conflict with outer scope declaration.  Don't emit -Wshadow*
> 	warnings for name-independent declarations.
> 	(pushdecl): Handle name-independent declarations.
> 	* search.cc (lookup_field_r): Handle nval being a TREE_LIST.
> 	* lambda.cc (build_capture_proxy): Adjust for ___.<number>
> 	names of members.
> 	(add_capture): Add NAME_INDEPENDENT_CNT argument.  Use ___.<number>
> 	name rather than ___ for second and following capture with
> 	_ name.
> 	(add_default_capture): Adjust add_capture caller.
> 	* decl.cc (poplevel): Don't warn about name-independent declarations.
> 	(duplicate_decls): If in C++26 a _ named declaration conflicts with
> 	earlier declarations, emit explaining note why the new declaration
> 	is not name-independent.
> 	(reshape_init_class): If field is a TREE_LIST, emit an ambiguity
> 	error with list of candidates rather than error about non-existing
> 	non-static data member.
> 	* parser.cc (cp_parser_lambda_introducer): Adjust add_capture callers.
> 	Allow name-independent capture redeclarations.
> 	(cp_parser_decomposition_declaration): Set decl_specs.storage_class
> 	to sc_static for static structured bindings.
> 	* pt.cc (tsubst_lambda_expr): Adjust add_capture caller.
> gcc/testsuite/
> 	* g++.dg/cpp26/name-independent-decl1.C: New test.
> 	* g++.dg/cpp26/name-independent-decl2.C: New test.
> 	* g++.dg/cpp26/name-independent-decl3.C: New test.
> 	* g++.dg/cpp26/name-independent-decl4.C: New test.
> 	* g++.dg/cpp26/name-independent-decl5.C: New test.
> 	* g++.dg/cpp26/name-independent-decl6.C: New test.
> 	* g++.dg/cpp26/feat-cxx26.C: Add __cpp_placeholder_variables test.
> 
> --- gcc/c-family/c-cppbuiltin.cc.jj	2023-11-24 08:43:01.177963318 +0100
> +++ gcc/c-family/c-cppbuiltin.cc	2023-11-29 15:51:49.331881183 +0100
> @@ -1088,6 +1088,7 @@ c_cpp_builtins (cpp_reader *pfile)
>   	  /* Set feature test macros for C++26.  */
>   	  cpp_define (pfile, "__cpp_constexpr=202306L");
>   	  cpp_define (pfile, "__cpp_static_assert=202306L");
> +	  cpp_define (pfile, "__cpp_placeholder_variables=202306L");
>   	}
>         if (flag_concepts)
>           {
> --- gcc/cp/cp-tree.h.jj	2023-11-29 08:36:33.194393034 +0100
> +++ gcc/cp/cp-tree.h	2023-11-29 15:51:49.332881169 +0100
> @@ -523,6 +523,7 @@ extern GTY(()) tree cp_global_trees[CPTI
>         RANGE_FOR_IVDEP (in RANGE_FOR_STMT)
>         CALL_EXPR_OPERATOR_SYNTAX (in CALL_EXPR, AGGR_INIT_EXPR)
>         CONSTRUCTOR_IS_DESIGNATED_INIT (in CONSTRUCTOR)
> +      OVL_NAME_INDEPENDENT_DECL_P (in OVERLOAD)
>   
>      Usage of TYPE_LANG_FLAG_?:
>      0: TYPE_DEPENDENT_P
> @@ -815,6 +816,9 @@ typedef struct ptrmem_cst * ptrmem_cst_t
>   #define OVL_LOOKUP_P(NODE)	TREE_LANG_FLAG_4 (OVERLOAD_CHECK (NODE))
>   /* If set, this OVL_USING_P overload is exported.  */
>   #define OVL_EXPORT_P(NODE)	TREE_LANG_FLAG_5 (OVERLOAD_CHECK (NODE))
> +/* If set, this overload includes name-independent declarations.  */
> +#define OVL_NAME_INDEPENDENT_DECL_P(NODE) \
> +  TREE_LANG_FLAG_6 (OVERLOAD_CHECK (NODE))
>   
>   /* The first decl of an overload.  */
>   #define OVL_FIRST(NODE)	ovl_first (NODE)
> @@ -7864,7 +7868,7 @@ extern tree lambda_capture_field_type		(
>   extern tree lambda_proxy_type			(tree);
>   extern tree lambda_function			(tree);
>   extern void apply_deduced_return_type           (tree, tree);
> -extern tree add_capture                         (tree, tree, tree, bool, bool);
> +extern tree add_capture                         (tree, tree, tree, bool, bool, unsigned *);
>   extern tree add_default_capture                 (tree, tree, tree);
>   extern void insert_capture_proxy		(tree);
>   extern void insert_pending_capture_proxies	(void);
> @@ -8930,6 +8934,18 @@ extended_float_type_p (tree type)
>     return false;
>   }
>   
> +/* True if DECL is name-independent declaration.  */
> +
> +inline bool
> +name_independent_decl_p (tree decl)
> +{
> +  return ((VAR_P (decl) || TREE_CODE (decl) == FIELD_DECL)
> +	  && DECL_NAME (decl)
> +	  && id_equal (DECL_NAME (decl), "_")
> +	  && !TREE_STATIC (decl)
> +	  && !DECL_EXTERNAL (decl));
> +}
> +
>   #if CHECKING_P
>   namespace selftest {
>     extern void run_cp_tests (void);
> --- gcc/cp/name-lookup.cc.jj	2023-11-25 10:28:27.747191994 +0100
> +++ gcc/cp/name-lookup.cc	2023-11-29 17:26:12.143505568 +0100
> @@ -511,10 +511,11 @@ private:
>     void preserve_state ();
>     void restore_state ();
>   
> -private:
> +public:
>     static tree ambiguous (tree thing, tree current);
> -  void add_overload (tree fns);
>     void add_value (tree new_val);
> +private:
> +  void add_overload (tree fns);
>     void add_type (tree new_type);
>     bool process_binding (tree val_bind, tree type_bind);
>     unsigned process_module_binding (tree val_bind, tree type_bind, unsigned);
> @@ -1806,6 +1807,71 @@ fields_linear_search (tree klass, tree n
>     return NULL_TREE;
>   }
>   
> +/* Like fields_linear_search, but specific for "_" name.  There can be multiple
> +   name-independent non-static data members and in that case a TREE_LIST with the
> +   ambiguous decls should be returned.  */
> +
> +static tree
> +name_independent_linear_search (tree val, tree klass, tree name)
> +{
> +  for (tree fields = TYPE_FIELDS (klass); fields; fields = DECL_CHAIN (fields))
> +    {
> +      tree decl = fields;
> +
> +      if (TREE_CODE (decl) == FIELD_DECL
> +	  && ANON_AGGR_TYPE_P (TREE_TYPE (decl)))
> +	{
> +	  if (tree temp = search_anon_aggr (TREE_TYPE (decl), name, false))
> +	    {
> +	      decl = temp;
> +	      goto add;
> +	    }
> +	}
> +
> +      if (DECL_NAME (decl) != name)
> +	continue;
> +
> +      if (TREE_CODE (decl) == USING_DECL)
> +	{
> +	  decl = strip_using_decl (decl);
> +	  if (is_overloaded_fn (decl))
> +	    continue;
> +	}
> +
> +      if (DECL_DECLARES_FUNCTION_P (decl))
> +	/* Functions are found separately.  */
> +	continue;
> +
> +    add:
> +      if (val == NULL_TREE)
> +	val = decl;
> +      else
> +	{
> +	  if (TREE_CODE (val) != TREE_LIST)
> +	    {
> +	      if (TREE_CODE (val) == OVERLOAD
> +		  && OVL_DEDUP_P (val)
> +		  && TREE_CODE (decl) == USING_DECL)
> +		{
> +		  val = ovl_make (decl, val);
> +		  continue;
> +		}
> +	      val = tree_cons (NULL_TREE, val, NULL_TREE);
> +	      TREE_TYPE (val) = error_mark_node;
> +	    }
> +	  if (TREE_CODE (decl) == TREE_LIST)
> +	    val = chainon (decl, val);
> +	  else
> +	    {
> +	      val = tree_cons (NULL_TREE, decl, val);
> +	      TREE_TYPE (val) = error_mark_node;
> +	    }
> +	}
> +    }
> +
> +  return val;
> +}
> +
>   /* Look for NAME member inside of anonymous aggregate ANON.  Although
>      such things should only contain FIELD_DECLs, we check that too
>      late, and would give very confusing errors if we weren't
> @@ -1843,6 +1909,50 @@ get_class_binding_direct (tree klass, tr
>         val = member_vec_binary_search (member_vec, lookup);
>         if (!val)
>   	;
> +      else if (TREE_CODE (val) == OVERLOAD
> +	       && OVL_NAME_INDEPENDENT_DECL_P (val))
> +	{
> +	  if (want_type)
> +	    {
> +	      while (TREE_CODE (val) == OVERLOAD
> +		     && OVL_NAME_INDEPENDENT_DECL_P (val))
> +		val = OVL_CHAIN (val);
> +	      if (STAT_HACK_P (val))
> +		val = STAT_TYPE (val);
> +	      else if (!DECL_DECLARES_TYPE_P (val))
> +		val = NULL_TREE;
> +	    }
> +	  else
> +	    {
> +	      /* OVERLOAD with a special OVL_NAME_INDEPENDENT_DECL_P
> +		 flag is used under the hood to represent lookup
> +		 results which include name-independent declarations,
> +		 and get_class_binding_direct is turning that into
> +		 TREE_LIST representation (which the callers expect for
> +		 ambiguous lookups) instead.
> +		 There are 2 reasons for that:
> +		 1) in order to keep the member_vec binary search fast, I
> +		 think it is better to keep OVL_NAME usable on all elements
> +		 because having to special case TREE_LIST would slow
> +		 everything down;
> +		 2) the callers need to be able to chain the results anyway
> +		 and so need an unshared TREE_LIST they can tweak/destroy.  */
> +	      tree ovl = val;
> +	      val = NULL_TREE;
> +	      while (TREE_CODE (ovl) == OVERLOAD
> +		     && OVL_NAME_INDEPENDENT_DECL_P (ovl))
> +		{
> +		  val = tree_cons (NULL_TREE, OVL_FUNCTION (ovl), val);
> +		  TREE_TYPE (val) = error_mark_node;
> +		  ovl = OVL_CHAIN (ovl);
> +		}
> +	      if (STAT_HACK_P (ovl))
> +		val = tree_cons (NULL_TREE, STAT_DECL (ovl), val);
> +	      else
> +		val = tree_cons (NULL_TREE, ovl, val);
> +	      TREE_TYPE (val) = error_mark_node;
> +	    }
> +	}
>         else if (STAT_HACK_P (val))
>   	val = want_type ? STAT_TYPE (val) : STAT_DECL (val);
>         else if (want_type && !DECL_DECLARES_TYPE_P (val))
> @@ -1853,7 +1963,9 @@ get_class_binding_direct (tree klass, tr
>         if (member_vec && !want_type)
>   	val = member_vec_linear_search (member_vec, lookup);
>   
> -      if (!val || (TREE_CODE (val) == OVERLOAD && OVL_DEDUP_P (val)))
> +      if (id_equal (lookup, "_") && !want_type)
> +	val = name_independent_linear_search (val, klass, lookup);
> +      else if (!val || (TREE_CODE (val) == OVERLOAD && OVL_DEDUP_P (val)))
>   	/* Dependent using declarations are a 'field', make sure we
>   	   return that even if we saw an overload already.  */
>   	if (tree field_val = fields_linear_search (klass, lookup, want_type))
> @@ -2049,6 +2161,25 @@ member_name_cmp (const void *a_p, const
>     if (TREE_CODE (b) == OVERLOAD)
>       b = OVL_FUNCTION (b);
>   
> +  if (id_equal (name_a, "_"))
> +    {
> +      /* Sort name-independent members first.  */
> +      if (name_independent_decl_p (a))
> +	{
> +	  if (name_independent_decl_p (b))
> +	    {
> +	      if (DECL_UID (a) != DECL_UID (b))
> +		return DECL_UID (a) < DECL_UID (b) ? -1 : +1;
> +	      gcc_assert (a == b);
> +	      return 0;
> +	    }
> +	  else
> +	    return -1;
> +	}
> +      else if (name_independent_decl_p (b))
> +	return +1;
> +    }
> +
>     /* We're in STAT_HACK or USING_DECL territory (or possibly error-land). */
>     if (TREE_CODE (a) != TREE_CODE (b))
>       {
> @@ -2183,14 +2314,15 @@ member_vec_append_enum_values (vec<tree,
>   /* MEMBER_VEC has just had new DECLs added to it, but is sorted.
>      DeDup adjacent DECLS of the same name.  We already dealt with
>      conflict resolution when adding the fields or methods themselves.
> -   There are three cases (which could all be combined):
> +   There are four cases (which could all be combined):
>      1) a TYPE_DECL and non TYPE_DECL.  Deploy STAT_HACK as appropriate.
>      2) a USING_DECL and an overload.  If the USING_DECL is dependent,
>      it wins.  Otherwise the OVERLOAD does.
> -   3) two USING_DECLS. ...
> +   3) two USING_DECLS.
> +   4) name-independent members plus others. ...
>   
>      member_name_cmp will have ordered duplicates as
> -   <fns><using><type>  */
> +   <name_independent><fns><using><type>  */
>   
>   static void
>   member_vec_dedup (vec<tree, va_gc> *member_vec)
> @@ -2208,6 +2340,7 @@ member_vec_dedup (vec<tree, va_gc> *memb
>         tree to_type = NULL_TREE;
>         tree to_using = NULL_TREE;
>         tree marker = NULL_TREE;
> +      unsigned name_independent = ix;
>   
>         for (jx = ix; jx < len; jx++)
>   	{
> @@ -2251,7 +2384,9 @@ member_vec_dedup (vec<tree, va_gc> *memb
>   	      continue;
>   	    }
>   
> -	  if (!current)
> +	  if (name_independent_decl_p (next))
> +	    name_independent = jx + 1;
> +	  else if (!current)
>   	    current = next;
>   	}
>   
> @@ -2271,6 +2406,17 @@ member_vec_dedup (vec<tree, va_gc> *memb
>   	    current = stat_hack (current, to_type);
>   	}
>   
> +      for (unsigned kx = name_independent; kx > ix; --kx)
> +	if (!current)
> +	  current = (*member_vec)[kx - 1];
> +	else if (current == to_type)
> +	  current = stat_hack ((*member_vec)[kx - 1], to_type);
> +	else
> +	  {
> +	    current = ovl_make ((*member_vec)[kx - 1], current);
> +	    OVL_NAME_INDEPENDENT_DECL_P (current) = 1;
> +	  }
> +
>         if (current)
>   	{
>   	  if (marker)
> @@ -2479,10 +2625,27 @@ pop_local_binding (tree id, tree decl)
>        away.  */
>     if (binding->value == decl)
>       binding->value = NULL_TREE;
> +  else if (binding->type == decl)
> +    binding->type = NULL_TREE;
>     else
>       {
> -      gcc_checking_assert (binding->type == decl);
> -      binding->type = NULL_TREE;
> +      /* Name-independent variable was found after at least one declaration
> +	 with the same name.  */
> +      gcc_assert (TREE_CODE (binding->value) == TREE_LIST);
> +      if (TREE_VALUE (binding->value) != decl)
> +	{
> +	  binding->value = nreverse (binding->value);
> +	  /* Skip over TREE_LISTs added in pushdecl for check_local_shadow
> +	     detected declarations, formerly at the tail, now at the start
> +	     of the list.  */
> +	  while (TREE_PURPOSE (binding->value) == error_mark_node)
> +	    binding->value = TREE_CHAIN (binding->value);
> +	}
> +      gcc_assert (TREE_VALUE (binding->value) == decl);
> +      binding->value = TREE_CHAIN (binding->value);
> +      while (binding->value
> +	     && TREE_PURPOSE (binding->value) == error_mark_node)
> +	binding->value = TREE_CHAIN (binding->value);
>       }
>   
>     if (!binding->value && !binding->type)
> @@ -2579,6 +2742,10 @@ supplement_binding (cxx_binding *binding
>   
>     tree bval = binding->value;
>     bool ok = true;
> +  if (bval
> +      && TREE_CODE (bval) == TREE_LIST
> +      && name_independent_decl_p (TREE_VALUE (bval)))
> +    bval = TREE_VALUE (bval);
>     tree target_bval = strip_using_decl (bval);
>     tree target_decl = strip_using_decl (decl);
>   
> @@ -2682,6 +2849,14 @@ supplement_binding (cxx_binding *binding
>   	   && CONST_DECL_USING_P (decl))
>       /* Let the clone hide the using-decl that introduced it.  */
>       binding->value = decl;
> +  else if (name_independent_decl_p (decl))
> +    {
> +      if (cxx_dialect < cxx26)
> +	pedwarn (DECL_SOURCE_LOCATION (decl), OPT_Wc__26_extensions,
> +		 "name-independent declarations only available with "
> +		 "%<-std=c++2c%> or %<-std=gnu++2c%>");
> +      binding->value = name_lookup::ambiguous (decl, binding->value);
> +    }
>     else
>       {
>         if (!error_operand_p (bval))
> @@ -2786,6 +2961,7 @@ update_binding (cp_binding_level *level,
>     tree old_type = NULL_TREE;
>     bool hide_type = false;
>     bool hide_value = false;
> +  bool name_independent_p = false;
>   
>     if (!slot)
>       {
> @@ -2793,6 +2969,7 @@ update_binding (cp_binding_level *level,
>         hide_type = HIDDEN_TYPE_BINDING_P (binding);
>         if (!old_type)
>   	hide_value = hide_type, hide_type = false;
> +      name_independent_p = name_independent_decl_p (decl);
>       }
>     else if (STAT_HACK_P (*slot))
>       {
> @@ -2888,7 +3065,9 @@ update_binding (cp_binding_level *level,
>       }
>     else if (old)
>       {
> -      if (TREE_CODE (old) != TREE_CODE (decl))
> +      if (name_independent_p)
> +	to_val = name_lookup::ambiguous (decl, old);
> +      else if (TREE_CODE (old) != TREE_CODE (decl))
>   	/* Different kinds of decls conflict.  */
>   	goto conflict;
>         else if (TREE_CODE (old) == TYPE_DECL)
> @@ -3088,13 +3267,13 @@ inform_shadowed (tree shadowed)
>   /* DECL is being declared at a local scope.  Emit suitable shadow
>      warnings.  */
>   
> -static void
> +static tree
>   check_local_shadow (tree decl)
>   {
>     /* Don't complain about the parms we push and then pop
>        while tentatively parsing a function declarator.  */
>     if (TREE_CODE (decl) == PARM_DECL && !DECL_CONTEXT (decl))
> -    return;
> +    return NULL_TREE;
>   
>     tree old = NULL_TREE;
>     cp_binding_level *old_scope = NULL;
> @@ -3129,7 +3308,7 @@ check_local_shadow (tree decl)
>   	    error_at (DECL_SOURCE_LOCATION (old),
>   		      "lambda parameter %qD "
>   		      "previously declared as a capture", old);
> -	  return;
> +	  return NULL_TREE;
>   	}
>         /* Don't complain if it's from an enclosing function.  */
>         else if (DECL_CONTEXT (old) == current_function_decl
> @@ -3153,6 +3332,9 @@ check_local_shadow (tree decl)
>   	     in the outermost block of the function definition.  */
>   	  if (b->kind == sk_function_parms)
>   	    {
> +	      if (name_independent_decl_p (decl))
> +		return old;
> +
>   	      auto_diagnostic_group d;
>   	      bool emit = true;
>   	      if (DECL_EXTERNAL (decl))
> @@ -3165,7 +3347,7 @@ check_local_shadow (tree decl)
>   	      if (emit)
>   		inform (DECL_SOURCE_LOCATION (old),
>   			"%q#D previously declared here", old);
> -	      return;
> +	      return NULL_TREE;
>   	    }
>   	}
>   
> @@ -3177,7 +3359,7 @@ check_local_shadow (tree decl)
>   	       scope != old_scope; scope = scope->level_chain)
>   	    if (scope->kind == sk_class
>   		&& !LAMBDA_TYPE_P (scope->this_entity))
> -	      return;
> +	      return NULL_TREE;
>   	}
>         /* Error if redeclaring a local declared in a
>   	 init-statement or in the condition of an if or
> @@ -3189,6 +3371,9 @@ check_local_shadow (tree decl)
>   	       && old_scope == current_binding_level->level_chain
>   	       && (old_scope->kind == sk_cond || old_scope->kind == sk_for))
>   	{
> +	  if (name_independent_decl_p (decl))
> +	    return old;
> +
>   	  auto_diagnostic_group d;
>   	  bool emit = true;
>   	  if (DECL_EXTERNAL (decl))
> @@ -3200,7 +3385,7 @@ check_local_shadow (tree decl)
>   	  if (emit)
>   	    inform (DECL_SOURCE_LOCATION (old),
>   		    "%q#D previously declared here", old);
> -	  return;
> +	  return NULL_TREE;
>   	}
>         /* C++11:
>   	 3.3.3/3:  The name declared in an exception-declaration (...)
> @@ -3212,6 +3397,9 @@ check_local_shadow (tree decl)
>   	       && old_scope == current_binding_level->level_chain
>   	       && old_scope->kind == sk_catch)
>   	{
> +	  if (name_independent_decl_p (decl))
> +	    return old;
> +
>   	  auto_diagnostic_group d;
>   	  bool emit;
>   	  if (DECL_EXTERNAL (decl))
> @@ -3223,9 +3411,13 @@ check_local_shadow (tree decl)
>   	  if (emit)
>   	    inform (DECL_SOURCE_LOCATION (old),
>   		    "%q#D previously declared here", old);
> -	  return;
> +	  return NULL_TREE;
>   	}
>   
> +      /* Don't emit -Wshadow* warnings for name-independent decls.  */
> +      if (name_independent_decl_p (decl) || name_independent_decl_p (old))
> +	return NULL_TREE;
> +
>         /* If '-Wshadow=compatible-local' is specified without other
>   	 -Wshadow= flags, we will warn only when the type of the
>   	 shadowing variable (DECL) can be converted to that of the
> @@ -3278,15 +3470,19 @@ check_local_shadow (tree decl)
>         auto_diagnostic_group d;
>         if (warning_at (DECL_SOURCE_LOCATION (decl), warning_code, msg, decl))
>   	inform_shadowed (old);
> -      return;
> +      return NULL_TREE;
>       }
>   
>     if (!warn_shadow)
> -    return;
> +    return NULL_TREE;
> +
> +  /* Don't emit -Wshadow for name-independent decls.  */
> +  if (name_independent_decl_p (decl))
> +    return NULL_TREE;
>   
>     /* Don't warn for artificial things that are not implicit typedefs.  */
>     if (DECL_ARTIFICIAL (decl) && !DECL_IMPLICIT_TYPEDEF_P (decl))
> -    return;
> +    return NULL_TREE;
>   
>     if (nonlambda_method_basetype ())
>       if (tree member = lookup_member (current_nonlambda_class_type (),
> @@ -3314,7 +3510,7 @@ check_local_shadow (tree decl)
>   		suppress_warning (decl, OPT_Wshadow);
>   	      }
>   	  }
> -	return;
> +	return NULL_TREE;
>         }
>   
>     /* Now look for a namespace shadow.  */
> @@ -3337,10 +3533,10 @@ check_local_shadow (tree decl)
>   	  inform_shadowed (old);
>   	  suppress_warning (decl, OPT_Wshadow);
>   	}
> -      return;
> +      return NULL_TREE;
>       }
>   
> -  return;
> +  return NULL_TREE;
>   }
>   
>   /* DECL is being pushed inside function CTX.  Set its context, if
> @@ -3659,6 +3855,8 @@ pushdecl (tree decl, bool hiding)
>         tree *slot = NULL; /* Binding slot in namespace.  */
>         tree *mslot = NULL; /* Current module slot in namespace.  */
>         tree old = NULL_TREE;
> +      bool name_independent_p = false;
> +      bool name_independent_diagnosed_p = false;
>   
>         if (level->kind == sk_namespace)
>   	{
> @@ -3682,56 +3880,82 @@ pushdecl (tree decl, bool hiding)
>   	  binding = find_local_binding (level, name);
>   	  if (binding)
>   	    old = binding->value;
> +	  name_independent_p = name_independent_decl_p (decl);
>   	}
>   
>         if (old == error_mark_node)
>   	old = NULL_TREE;
>   
> -      for (ovl_iterator iter (old); iter; ++iter)
> -	if (iter.using_p ())
> -	  ; /* Ignore using decls here.  */
> -	else if (iter.hidden_p ()
> -		 && TREE_CODE (*iter) == FUNCTION_DECL
> -		 && DECL_LANG_SPECIFIC (*iter)
> -		 && DECL_MODULE_IMPORT_P (*iter))
> -	  ; /* An undeclared builtin imported from elsewhere.  */
> -	else if (tree match
> -		 = duplicate_decls (decl, *iter, hiding, iter.hidden_p ()))
> -	  {
> -	    if (match == error_mark_node)
> -	      ;
> -	    else if (TREE_CODE (match) == TYPE_DECL)
> -	      gcc_checking_assert (REAL_IDENTIFIER_TYPE_VALUE (name)
> -				   == (level->kind == sk_namespace
> -				       ? NULL_TREE : TREE_TYPE (match)));
> -	    else if (iter.hidden_p () && !hiding)
> +      tree oldi, oldn;
> +      for (oldi = old; oldi; oldi = oldn)
> +	{
> +	  if (TREE_CODE (oldi) == TREE_LIST)
> +	    {
> +	      gcc_checking_assert (level->kind != sk_namespace
> +				   && name_independent_decl_p
> +							(TREE_VALUE (old)));
> +	      oldn = TREE_CHAIN (oldi);
> +	      oldi = TREE_VALUE (oldi);
> +	    }
> +	  else
> +	    oldn = NULL_TREE;
> +	  for (ovl_iterator iter (oldi); iter; ++iter)
> +	    if (iter.using_p ())
> +	      ; /* Ignore using decls here.  */
> +	    else if (iter.hidden_p ()
> +		     && TREE_CODE (*iter) == FUNCTION_DECL
> +		     && DECL_LANG_SPECIFIC (*iter)
> +		     && DECL_MODULE_IMPORT_P (*iter))
> +	      ; /* An undeclared builtin imported from elsewhere.  */
> +	    else if (name_independent_p)
>   	      {
> -		/* Unhiding a previously hidden decl.  */
> -		tree head = iter.reveal_node (old);
> -		if (head != old)
> +		/* Ignore name-independent declarations.  */
> +		if (cxx_dialect < cxx26 && !name_independent_diagnosed_p)
> +		  pedwarn (DECL_SOURCE_LOCATION (decl), OPT_Wc__26_extensions,
> +			   "name-independent declarations only available with "
> +			   "%<-std=c++2c%> or %<-std=gnu++2c%>");
> +		name_independent_diagnosed_p = true;
> +	      }
> +	    else if (tree match
> +		     = duplicate_decls (decl, *iter, hiding, iter.hidden_p ()))
> +	      {
> +		if (match == error_mark_node)
> +		  ;
> +		else if (TREE_CODE (match) == TYPE_DECL)
> +		  gcc_checking_assert (REAL_IDENTIFIER_TYPE_VALUE (name)
> +				       == (level->kind == sk_namespace
> +					   ? NULL_TREE : TREE_TYPE (match)));
> +		else if (iter.hidden_p () && !hiding)
>   		  {
> -		    gcc_checking_assert (ns);
> -		    if (STAT_HACK_P (*slot))
> -		      STAT_DECL (*slot) = head;
> +		    /* Unhiding a previously hidden decl.  */
> +		    tree head = iter.reveal_node (oldi);
> +		    if (head != oldi)
> +		      {
> +			gcc_checking_assert (ns);
> +			if (STAT_HACK_P (*slot))
> +			  STAT_DECL (*slot) = head;
> +			else
> +			  *slot = head;
> +		      }
> +		    if (DECL_EXTERN_C_P (match))
> +		      /* We need to check and register the decl now.  */
> +		      check_extern_c_conflict (match);
> +		  }
> +		else if (slot
> +			 && !hiding
> +			 && STAT_HACK_P (*slot)
> +			 && STAT_DECL_HIDDEN_P (*slot))
> +		  {
> +		    /* Unhide the non-function.  */
> +		    gcc_checking_assert (oldi == match);
> +		    if (!STAT_TYPE (*slot))
> +		      *slot = match;
>   		    else
> -		      *slot = head;
> +		      STAT_DECL (*slot) = match;
>   		  }
> -		if (DECL_EXTERN_C_P (match))
> -		  /* We need to check and register the decl now.  */
> -		  check_extern_c_conflict (match);
> -	      }
> -	    else if (slot && !hiding
> -		     && STAT_HACK_P (*slot) && STAT_DECL_HIDDEN_P (*slot))
> -	      {
> -		/* Unhide the non-function.  */
> -		gcc_checking_assert (old == match);
> -		if (!STAT_TYPE (*slot))
> -		  *slot = match;
> -		else
> -		  STAT_DECL (*slot) = match;
> +		return match;
>   	      }
> -	    return match;
> -	  }
> +	}
>   
>         /* Check for redeclaring an import.  */
>         if (slot && *slot && TREE_CODE (*slot) == BINDING_VECTOR)
> @@ -3780,7 +4004,28 @@ pushdecl (tree decl, bool hiding)
>   
>         if (level->kind != sk_namespace)
>   	{
> -	  check_local_shadow (decl);
> +	  tree local_shadow = check_local_shadow (decl);
> +	  if (name_independent_p && local_shadow)
> +	    {
> +	      if (cxx_dialect < cxx26 && !name_independent_diagnosed_p)
> +		pedwarn (DECL_SOURCE_LOCATION (decl), OPT_Wc__26_extensions,
> +			 "name-independent declarations only available with "
> +			 "%<-std=c++2c%> or %<-std=gnu++2c%>");
> +	      name_independent_diagnosed_p = true;
> +	      /* When a name-independent declaration is pushed into a scope
> +		 which itself does not contain a _ named declaration yet (so
> +		 _ name lookups wouldn't be normally ambiguous), but it
> +		 shadows a _ declaration in some outer scope in cases
> +		 described in [basic.scope.block]/2 where if the names of
> +		 the shadowed and shadowing declarations were different it
> +		 would be ill-formed program, arrange for _ name lookups
> +		 in this scope to be ambiguous.  */
> +	      if (old == NULL_TREE)
> +		{
> +		  old = build_tree_list (error_mark_node, local_shadow);
> +		  TREE_TYPE (old) = error_mark_node;
> +		}
> +	    }
>   
>   	  if (TREE_CODE (decl) == NAMESPACE_DECL)
>   	    /* A local namespace alias.  */
> --- gcc/cp/search.cc.jj	2023-11-24 08:43:01.665956431 +0100
> +++ gcc/cp/search.cc	2023-11-29 15:51:49.363880733 +0100
> @@ -1091,13 +1091,24 @@ lookup_field_r (tree binfo, void *data)
>   	    }
>   
>   	  /* Add the new value.  */
> -	  lfi->ambiguous = tree_cons (NULL_TREE, nval, lfi->ambiguous);
> -	  TREE_TYPE (lfi->ambiguous) = error_mark_node;
> +	  if (TREE_CODE (nval) == TREE_LIST)
> +	    lfi->ambiguous = chainon (nval, lfi->ambiguous);
> +	  else
> +	    {
> +	      lfi->ambiguous = tree_cons (NULL_TREE, nval, lfi->ambiguous);
> +	      TREE_TYPE (lfi->ambiguous) = error_mark_node;
> +	    }
>   	}
>       }
>     else
>       {
> -      lfi->rval = nval;
> +      if (TREE_CODE (nval) == TREE_LIST)
> +	{
> +	  lfi->ambiguous = chainon (nval, lfi->ambiguous);
> +	  lfi->rval = TREE_VALUE (nval);
> +	}
> +      else
> +	lfi->rval = nval;
>         lfi->rval_binfo = binfo;
>       }
>   
> --- gcc/cp/lambda.cc.jj	2023-11-24 08:43:01.369960609 +0100
> +++ gcc/cp/lambda.cc	2023-11-29 15:51:49.363880733 +0100
> @@ -412,7 +412,11 @@ build_capture_proxy (tree member, tree i
>       object = TREE_OPERAND (object, 0);
>   
>     /* Remove the __ inserted by add_capture.  */
> -  name = get_identifier (IDENTIFIER_POINTER (DECL_NAME (member)) + 2);
> +  if (IDENTIFIER_POINTER (DECL_NAME (member))[2] == '_'
> +      && IDENTIFIER_POINTER (DECL_NAME (member))[3] == '.')
> +    name = get_identifier ("_");
> +  else
> +    name = get_identifier (IDENTIFIER_POINTER (DECL_NAME (member)) + 2);
>   
>     type = lambda_proxy_type (object);
>   
> @@ -516,7 +520,7 @@ vla_capture_type (tree array_type)
>   
>   tree
>   add_capture (tree lambda, tree id, tree orig_init, bool by_reference_p,
> -	     bool explicit_init_p)
> +	     bool explicit_init_p, unsigned *name_independent_cnt)
>   {
>     char *buf;
>     tree type, member, name;
> @@ -610,11 +614,28 @@ add_capture (tree lambda, tree id, tree
>        won't find the field with name lookup.  We can't just leave the name
>        unset because template instantiation uses the name to find
>        instantiated fields.  */
> -  buf = (char *) alloca (IDENTIFIER_LENGTH (id) + 3);
> -  buf[1] = buf[0] = '_';
> -  memcpy (buf + 2, IDENTIFIER_POINTER (id),
> -	  IDENTIFIER_LENGTH (id) + 1);
> -  name = get_identifier (buf);
> +  if (id_equal (id, "_") && name_independent_cnt)
> +    {
> +      if (*name_independent_cnt == 0)
> +	name = get_identifier ("___");
> +      else
> +	{
> +	  /* For 2nd and later name-independent capture use
> +	     unique names.  */
> +	  char buf2[5 + (HOST_BITS_PER_INT + 2) / 3];
> +	  sprintf (buf2, "___.%u", *name_independent_cnt);
> +	  name = get_identifier (buf2);
> +	}
> +      name_independent_cnt[0]++;
> +    }
> +  else
> +    {
> +      buf = XALLOCAVEC (char, IDENTIFIER_LENGTH (id) + 3);
> +      buf[1] = buf[0] = '_';
> +      memcpy (buf + 2, IDENTIFIER_POINTER (id),
> +	      IDENTIFIER_LENGTH (id) + 1);
> +      name = get_identifier (buf);
> +    }
>   
>     if (variadic)
>       {
> @@ -718,7 +739,7 @@ add_default_capture (tree lambda_stack,
>   			    (this_capture_p
>   			     || (LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (lambda)
>   				 == CPLD_REFERENCE)),
> -			    /*explicit_init_p=*/false);
> +			    /*explicit_init_p=*/false, NULL);
>         initializer = convert_from_reference (var);
>   
>         /* Warn about deprecated implicit capture of this via [=].  */
> --- gcc/cp/decl.cc.jj	2023-11-29 08:36:33.204392893 +0100
> +++ gcc/cp/decl.cc	2023-11-29 17:56:31.299848688 +0100
> @@ -680,6 +680,8 @@ poplevel (int keep, int reverse, int fun
>   	       subobjects.  */
>   	    && (DECL_DECOMPOSITION_P (decl) ? !DECL_DECOMP_BASE (decl)
>   		: (DECL_NAME (decl) && !DECL_ARTIFICIAL (decl)))
> +	    /* Don't warn about name-independent declarations.  */
> +	    && !name_independent_decl_p (decl)
>   	    && type != error_mark_node
>   	    && (!CLASS_TYPE_P (type)
>   		|| !TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type)
> @@ -2063,6 +2065,44 @@ duplicate_decls (tree newdecl, tree oldd
>   		    (DECL_INITIAL (olddecl) && namespace_bindings_p ())
>   		    ? G_("%q#D previously defined here")
>   		    : G_("%q#D previously declared here"), olddecl);
> +	  if (cxx_dialect >= cxx26
> +	      && DECL_NAME (newdecl)
> +	      && id_equal (DECL_NAME (newdecl), "_")
> +	      && !name_independent_decl_p (newdecl))
> +	    {
> +	      if (TREE_CODE (newdecl) == PARM_DECL)
> +		inform (newdecl_loc,
> +			"parameter declaration is not name-independent");
> +	      else if (DECL_DECOMPOSITION_P (newdecl))
> +		{
> +		  if (at_namespace_scope_p ())
> +		    inform (newdecl_loc,
> +			    "structured binding at namespace scope is not "
> +			    "name-independent");
> +		  else if (TREE_STATIC (newdecl))
> +		    inform (newdecl_loc,
> +			    "static structured binding is not "
> +			    "name-independent");
> +		  else if (DECL_EXTERNAL (newdecl))
> +		    inform (newdecl_loc,
> +			    "extern structured binding is not "
> +			    "name-independent");
> +		}
> +	      else if (at_class_scope_p ()
> +		       && VAR_P (newdecl)
> +		       && TREE_STATIC (newdecl))
> +		inform (newdecl_loc,
> +			"static data member is not name-independent");
> +	      else if (VAR_P (newdecl) && at_namespace_scope_p ())
> +		inform (newdecl_loc,
> +			"variable at namespace scope is not name-independent");
> +	      else if (VAR_P (newdecl) && TREE_STATIC (newdecl))
> +		inform (newdecl_loc,
> +			"static variable is not name-independent");
> +	      else if (VAR_P (newdecl) && DECL_EXTERNAL (newdecl))
> +		inform (newdecl_loc,
> +			"extern variable is not name-independent");
> +	    }
>   	  return error_mark_node;
>   	}
>         else if (TREE_CODE (olddecl) == FUNCTION_DECL
> @@ -6869,8 +6909,17 @@ reshape_init_class (tree type, reshape_i
>   	  if (!field || TREE_CODE (field) != FIELD_DECL)
>   	    {
>   	      if (complain & tf_error)
> -		error ("%qT has no non-static data member named %qD", type,
> -		       d->cur->index);
> +		{
> +		  if (field && TREE_CODE (field) == TREE_LIST)
> +		    {
> +		      error ("request for member %qD is ambiguous",
> +			     d->cur->index);
> +		      print_candidates (field);
> +		    }
> +		  else
> +		    error ("%qT has no non-static data member named %qD", type,
> +			   d->cur->index);
> +		}
>   	      return error_mark_node;
>   	    }
>   
> --- gcc/cp/parser.cc.jj	2023-11-25 10:28:27.761191798 +0100
> +++ gcc/cp/parser.cc	2023-11-29 15:51:49.382880464 +0100
> @@ -11381,6 +11381,7 @@ cp_parser_lambda_introducer (cp_parser*
>   
>     hash_set<tree, true> ids;
>     tree first_capture_id = NULL_TREE;
> +  unsigned name_independent_cnt = 0;
>     while (cp_lexer_next_token_is_not (parser->lexer, CPP_CLOSE_SQUARE))
>       {
>         cp_token* capture_token;
> @@ -11425,7 +11426,7 @@ cp_parser_lambda_introducer (cp_parser*
>   	  else
>   	    add_capture (lambda_expr, /*id=*/this_identifier,
>   			 /*initializer=*/finish_this_expr (),
> -			 /*by_reference_p=*/true, explicit_init_p);
> +			 /*by_reference_p=*/true, explicit_init_p, NULL);
>   	  continue;
>   	}
>   
> @@ -11447,7 +11448,7 @@ cp_parser_lambda_introducer (cp_parser*
>   	  else
>   	    add_capture (lambda_expr, /*id=*/this_identifier,
>   			 /*initializer=*/finish_this_expr (),
> -			 /*by_reference_p=*/false, explicit_init_p);
> +			 /*by_reference_p=*/false, explicit_init_p, NULL);
>   	  continue;
>   	}
>   
> @@ -11634,13 +11635,15 @@ cp_parser_lambda_introducer (cp_parser*
>   	  ids.add (first_capture_id);
>   	  ids.add (capture_id);
>   	}
> +      if (found && explicit_init_p && id_equal (capture_id, "_"))
> +	found = false;
>         if (found)
>   	pedwarn (input_location, 0,
>   		 "already captured %qD in lambda expression", capture_id);
>         else
>   	add_capture (lambda_expr, capture_id, capture_init_expr,
>   		     /*by_reference_p=*/capture_kind == BY_REFERENCE,
> -		     explicit_init_p);
> +		     explicit_init_p, &name_independent_cnt);
>   
>         /* If there is any qualification still in effect, clear it
>   	 now; we will be starting fresh with the next capture.  */
> @@ -15874,6 +15877,8 @@ cp_parser_decomposition_declaration (cp_
>     cp_decl_specifier_seq decl_specs;
>     clear_decl_specs (&decl_specs);
>     decl_specs.type = make_auto ();
> +  if (decl_specifiers->storage_class == sc_static)
> +    decl_specs.storage_class = sc_static;
>     tree prev = decl;
>     FOR_EACH_VEC_ELT (v, i, e)
>       {
> --- gcc/cp/pt.cc.jj	2023-11-24 08:43:01.611957193 +0100
> +++ gcc/cp/pt.cc	2023-11-29 15:51:49.400880210 +0100
> @@ -19354,7 +19354,7 @@ tsubst_lambda_expr (tree t, tree args, t
>   	      && LAMBDA_EXPR_PENDING_PROXIES (t) == NULL);
>   
>     vec<tree,va_gc>* field_packs = NULL;
> -
> +  unsigned name_independent_cnt = 0;
>     for (tree cap = LAMBDA_EXPR_CAPTURE_LIST (t); cap;
>          cap = TREE_CHAIN (cap))
>       {
> @@ -19384,7 +19384,8 @@ tsubst_lambda_expr (tree t, tree args, t
>   	  bool by_ref = (TYPE_REF_P (ftype)
>   			 || (TREE_CODE (ftype) == DECLTYPE_TYPE
>   			     && DECLTYPE_FOR_REF_CAPTURE (ftype)));
> -	  add_capture (r, name, init, by_ref, !DECL_NORMAL_CAPTURE_P (ofield));
> +	  add_capture (r, name, init, by_ref, !DECL_NORMAL_CAPTURE_P (ofield),
> +		       &name_independent_cnt);
>   	  continue;
>   	}
>   
> --- gcc/testsuite/g++.dg/cpp26/name-independent-decl1.C.jj	2023-11-29 15:51:49.401880196 +0100
> +++ gcc/testsuite/g++.dg/cpp26/name-independent-decl1.C	2023-11-29 17:27:00.894799971 +0100
> @@ -0,0 +1,194 @@
> +// P2169R4 - A nice placeholder with no name
> +// { dg-do compile { target c++11 } }
> +// { dg-options "-Wunused-variable -Wunused-but-set-variable -Wunused-parameter -Wshadow" }
> +
> +int a[3];
> +
> +void
> +foo ()
> +{
> +  {
> +    int _ = 1;
> +    ++_;
> +  }
> +  {
> +    int _ = 3;
> +    ++_;
> +    int _ = 4;			// { dg-warning "name-independent declarations only available with" "" { target c++23_down } }
> +  }
> +  {
> +    int _ = 5;
> +    --_;
> +    int _ = 6;			// { dg-warning "name-independent declarations only available with" "" { target c++23_down } }
> +    int _ = 7;			// { dg-warning "name-independent declarations only available with" "" { target c++23_down } }
> +  }
> +  {
> +    auto [i, j, _] = a;		// { dg-warning "structured bindings only available with" "" { target c++14_down } }
> +    ++i;
> +    ++_;
> +  }
> +  {
> +    auto [_, _, k] = a;		// { dg-warning "name-independent declarations only available with" "" { target c++23_down } }
> +    ++k;			// { dg-warning "structured bindings only available with" "" { target c++14_down } .-1 }
> +  }
> +  {
> +    auto [i, j, _] = a;		// { dg-warning "structured bindings only available with" "" { target c++14_down } }
> +    auto [_, k, l] = a;		// { dg-warning "name-independent declarations only available with" "" { target c++23_down } }
> +    ++i;			// { dg-warning "structured bindings only available with" "" { target c++14_down } .-1 }
> +    ++l;
> +  }
> +  {
> +    int _;
> +    _ = 1;
> +  }
> +  {
> +    int _ = 1;
> +  }
> +  {
> +    int _;
> +  }
> +  {
> +    static int _;		// { dg-warning "unused variable" }
> +    int _ = 1;			// { dg-warning "name-independent declarations only available with" "" { target c++23_down } }
> +  }
> +  {
> +    extern int _ (int);
> +    extern long _ (long);
> +    extern float _ (float);
> +    int _ = 1;			// { dg-warning "name-independent declarations only available with" "" { target c++23_down } }
> +  }
> +  {
> +    extern double _ (double);
> +    extern short _ (short);
> +    int _ = 1;			// { dg-warning "name-independent declarations only available with" "" { target c++23_down } }
> +    int _ = 2;			// { dg-warning "name-independent declarations only available with" "" { target c++23_down } }
> +  }
> +  {
> +    int _ = 1;
> +    {
> +      int _ = 2;
> +      ++_;
> +    }
> +    {
> +      static int _ = 3;
> +      ++_;
> +    }
> +    {
> +      auto [i, j, _] = a;	// { dg-warning "structured bindings only available with" "" { target c++14_down } }
> +      ++_;
> +    }
> +  }
> +}
> +
> +int
> +bar (int _ = 0)			// { dg-warning "unused parameter '_'" }
> +{
> +  int _ = 1;			// { dg-warning "name-independent declarations only available with" "" { target c++23_down } }
> +  return 0;
> +}
> +
> +void
> +baz ()
> +{
> +  if (int _ = bar ())
> +    int _ = 2;			// { dg-warning "name-independent declarations only available with" "" { target c++23_down } }
> +  else
> +    int _ = 3;			// { dg-warning "name-independent declarations only available with" "" { target c++23_down } }
> +  while (int _ = bar ())
> +    int _ = 4;			// { dg-warning "name-independent declarations only available with" "" { target c++23_down } }
> +  for (int _ = bar (); _; ++_)
> +    int _ = 5;			// { dg-warning "name-independent declarations only available with" "" { target c++23_down } }
> +  if (int _ = bar ())
> +    {
> +      int _ = 6;		// { dg-warning "name-independent declarations only available with" "" { target c++23_down } }
> +    }
> +  else
> +    {
> +      int _ = 7;		// { dg-warning "name-independent declarations only available with" "" { target c++23_down } }
> +    }
> +  while (int _ = bar ())
> +    {
> +      int _ = 8;		// { dg-warning "name-independent declarations only available with" "" { target c++23_down } }
> +    }
> +  for (int _ = bar (); _; ++_)
> +    {
> +      int _ = 9;		// { dg-warning "name-independent declarations only available with" "" { target c++23_down } }
> +    }
> +}
> +
> +void
> +qux (short _ = 0)		// { dg-warning "unused parameter '_'" }
> +{
> +  {
> +    long _ = 1;
> +  }
> +}
> +
> +void
> +corge ()
> +{
> +  auto b = [_ = 1] () { (void) _; };	// { dg-warning "lambda capture initializers only available with" "" { target c++11_down } }
> +				// { dg-warning "variable 'b' set but not used" "" { target *-*-* } .-1 }
> +  auto c = [_ = 2, _ = 3] () {};// { dg-warning "name-independent declarations only available with" "" { target c++23_down } }
> +				// { dg-warning "lambda capture initializers only available with" "" { target c++11_down } .-1 }
> +				// { dg-warning "variable 'c' set but not used" "" { target *-*-* } .-2 }
> +  {
> +    int _ = 4;
> +    auto d = [_, _ = 5] () {};	// { dg-warning "name-independent declarations only available with" "" { target c++23_down } }
> +  }				// { dg-warning "lambda capture initializers only available with" "" { target c++11_down } .-1 }
> +				// { dg-warning "variable 'd' set but not used" "" { target *-*-* } .-2 }
> +  {
> +    int _ = 5;
> +    auto e = [_ = 6] () {};	// { dg-warning "lambda capture initializers only available with" "" { target c++11_down } }
> +  }				// { dg-warning "variable 'e' set but not used" "" { target *-*-* } .-1 }
> +}
> +
> +namespace A {
> +  int _ = 11;
> +}
> +
> +void
> +garply (int x,			// { dg-warning "unused parameter 'x'" }
> +	int _,			// { dg-warning "unused parameter '_'" }
> +	int)
> +{
> +}
> +
> +void
> +fred ()
> +{
> +  try {
> +  } catch (int _) {
> +    int _ = 5;			// { dg-warning "name-independent declarations only available with" "" { target c++23_down } }
> +  }
> +}
> +
> +void
> +waldo (int _)			// { dg-warning "unused parameter '_'" }
> +try
> +{
> +}
> +catch (int _)			// { dg-warning "name-independent declarations only available with" "" { target c++23_down } }
> +{
> +  int _ = 7;
> +}
> +
> +void
> +grault (int _)			// { dg-warning "unused parameter '_'" }
> +try
> +{
> +}
> +catch (int)
> +{
> +  int _ = 8;			// { dg-warning "name-independent declarations only available with" "" { target c++23_down } }
> +}
> +
> +void
> +plugh (int _)			// { dg-warning "unused parameter '_'" }
> +try
> +{
> +  int _ = 1;			// { dg-warning "name-independent declarations only available with" "" { target c++23_down } }
> +}
> +catch (int)
> +{
> +}
> --- gcc/testsuite/g++.dg/cpp26/name-independent-decl2.C.jj	2023-11-29 15:51:49.401880196 +0100
> +++ gcc/testsuite/g++.dg/cpp26/name-independent-decl2.C	2023-11-29 18:03:02.352295830 +0100
> @@ -0,0 +1,171 @@
> +// P2169R4 - A nice placeholder with no name
> +// { dg-do compile { target c++11 } }
> +// { dg-options "" }
> +
> +int a[3];
> +
> +void
> +foo ()
> +{
> +  {
> +    extern int _ (int);
> +    int _ = 2;			// { dg-warning "name-independent declarations only available with" "" { target c++23_down } }
> +    extern long _ (long);	// { dg-error "redeclared as different kind of entity" }
> +  }
> +  {
> +    int _ = 3;
> +    extern int _ (int);		// { dg-error "redeclared as different kind of entity" }
> +  }
> +  {
> +    int _ = 4;
> +    static int _ = 5;		// { dg-error "redeclaration of 'int _'" }
> +  }				// { dg-message "static variable is not name-independent" "" { target c++26 } .-1 }
> +  {
> +    int _ = 6;
> +    int _ = 7;			// { dg-warning "name-independent declarations only available with" "" { target c++23_down } }
> +    ++_;			// { dg-error "reference to '_' is ambiguous" }
> +  }
> +  {
> +    int _ = 8;
> +    int _ = 9;			// { dg-warning "name-independent declarations only available with" "" { target c++23_down } }
> +    int _ = 10;			// { dg-warning "name-independent declarations only available with" "" { target c++23_down } }
> +    ++_;			// { dg-error "reference to '_' is ambiguous" }
> +  }
> +  {
> +    static int _ = 11;
> +    static int _ = 12;		// { dg-error "redeclaration of 'int _'" }
> +    int _ = 13;			// { dg-warning "name-independent declarations only available with" "" { target c++23_down } }
> +  }				// { dg-message "static variable is not name-independent" "" { target c++26 } .-2 }
> +  {
> +    extern int _ (int);
> +    extern long _ (long);
> +    extern float _ (float);
> +    int _ = 1;			// { dg-warning "name-independent declarations only available with" "" { target c++23_down } }
> +    ++_;			// { dg-error "reference to '_' is ambiguous" }
> +  }
> +  {
> +    extern double _ (double);
> +    extern short _ (short);
> +    int _ = 1;			// { dg-warning "name-independent declarations only available with" "" { target c++23_down } }
> +    ++_;			// { dg-error "reference to '_' is ambiguous" }
> +    int _ = 2;			// { dg-warning "name-independent declarations only available with" "" { target c++23_down } }
> +    ++_;			// { dg-error "reference to '_' is ambiguous" }
> +  }
> +  {
> +    auto [i, _, _] = a;		// { 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-error "reference to '_' is ambiguous" }
> +  }
> +  {
> +    auto [i, j, _] = a;		// { dg-warning "structured bindings only available with" "" { target c++14_down } }
> +    auto [k, _, l] = a;		// { 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-error "reference to '_' is ambiguous" }
> +  }
> +  {
> +    static auto [i, _, _] = a;	// { dg-error "redeclaration of 'auto _'" }
> +				// { dg-warning "structured bindings only available with" "" { target c++14_down } .-1 }
> +				// { dg-warning "structured binding declaration can be 'static' only in" "" { target c++17_down } .-2 }
> +  }				// { dg-message "static structured binding is not name-independent" "" { target c++26 } .-3 }
> +}
> +
> +int
> +bar (int _ = 0)
> +{
> +  int _ = 1;			// { dg-warning "name-independent declarations only available with" "" { target c++23_down } }
> +  ++_;				// { dg-error "reference to '_' is ambiguous" }
> +  return 0;
> +}
> +
> +void
> +baz ()
> +{
> +  if (int _ = bar ())
> +    {
> +      int _ = 6;		// { dg-warning "name-independent declarations only available with" "" { target c++23_down } }
> +      ++_;			// { dg-error "reference to '_' is ambiguous" }
> +    }
> +  else
> +    {
> +      int _ = 7;		// { dg-warning "name-independent declarations only available with" "" { target c++23_down } }
> +      ++_;			// { dg-error "reference to '_' is ambiguous" }
> +    }
> +  while (int _ = bar ())
> +    {
> +      int _ = 8;		// { dg-warning "name-independent declarations only available with" "" { target c++23_down } }
> +      ++_;			// { dg-error "reference to '_' is ambiguous" }
> +    }
> +  for (int _ = bar (); _; ++_)
> +    {
> +      int _ = 9;		// { dg-warning "name-independent declarations only available with" "" { target c++23_down } }
> +      ++_;			// { dg-error "reference to '_' is ambiguous" }
> +    }
> +}
> +
> +namespace A
> +{
> +  int _ = 1;
> +  int _ = 1;			// { dg-error "redefinition of 'int A::_'" }
> +}				// { dg-message "variable at namespace scope is not name-independent" "" { target c++26 } .-1 }
> +
> +namespace B
> +{
> +  auto [_, _, _] = a;		// { dg-error "redefinition of 'auto B::_'" }
> +				// { dg-warning "structured bindings only available with" "" { target c++14_down } .-1 }
> +}				// { dg-message "structured binding at namespace scope is not name-independent" "" { target c++26 } .-2 }
> +
> +void
> +qux ()
> +{
> +  auto c = [_ = 2, _ = 3] () {	// { dg-warning "name-independent declarations only available with" "" { target c++23_down } }
> +				// { dg-warning "lambda capture initializers only available with" "" { target c++11_down } .-1 }
> +    (void) _;			// { dg-error "reference to '_' is ambiguous" }
> +  };
> +  {
> +    int _ = 4;
> +    auto d = [_, _ = 5] () {	// { dg-warning "name-independent declarations only available with" "" { target c++23_down } }
> +				// { dg-warning "lambda capture initializers only available with" "" { target c++11_down } .-1 }
> +      (void) _;			// { dg-error "reference to '_' is ambiguous" }
> +    };
> +  }
> +  auto e = [_ = 1] (int _) {};	// { dg-warning "lambda capture initializers only available with" "" { target c++11_down } }
> +}				// { dg-error "lambda parameter '_' previously declared as a capture" "" { target *-*-* } .-1 }
> +
> +void
> +corge (int _, int _)		// { dg-error "redefinition of 'int _'" }
> +{				// { dg-message "parameter declaration is not name-independent" "" { target c++26 } .-1 }
> +}
> +
> +namespace C
> +{
> +  typedef int _;
> +  typedef int _;
> +}
> +
> +namespace D
> +{
> +  namespace {
> +    int _;
> +    int _;			// { dg-error "redefinition of 'int D::.anonymous.::_'" }
> +  }				// { dg-message "variable at namespace scope is not name-independent" "" { target c++26 } .-1 }
> +}
> +
> +namespace E
> +{
> +  int _ (int);
> +  int _ (int);
> +  int _ (int) { return 0; }
> +  int _ (int) { return 0; }	// { dg-error "redefinition of 'int E::_\\\(int\\\)'" }
> +  long _ (long) { return 1; }
> +}
> +
> +template <int _, int _>		// { dg-error "redefinition of 'int _'" }
> +void
> +garply ()
> +{
> +}
> +
> +#if __cpp_concepts >= 202002L
> +template <typename T>
> +concept F = requires (T _, T _) { T{}; };	// { dg-error "redefinition of 'T _'" "" { target c++20 } }
> +#endif						// { dg-message "parameter declaration is not name-independent" "" { target c++26 } .-1 }
> --- gcc/testsuite/g++.dg/cpp26/name-independent-decl3.C.jj	2023-11-29 15:51:49.401880196 +0100
> +++ gcc/testsuite/g++.dg/cpp26/name-independent-decl3.C	2023-11-29 17:53:12.131669848 +0100
> @@ -0,0 +1,12 @@
> +// P2169R4 - A nice placeholder with no name
> +// { dg-do compile { target c++11 } }
> +// { dg-options "" }
> +
> +void
> +foo ()
> +{
> +  extern int _;
> +  extern int _;
> +  ++_;
> +  int _;		// { dg-warning "name-independent declarations only available with" "" { target c++23_down } }
> +}
> --- gcc/testsuite/g++.dg/cpp26/name-independent-decl4.C.jj	2023-11-29 15:51:49.401880196 +0100
> +++ gcc/testsuite/g++.dg/cpp26/name-independent-decl4.C	2023-11-29 17:53:17.361595773 +0100
> @@ -0,0 +1,12 @@
> +// P2169R4 - A nice placeholder with no name
> +// { dg-do compile { target c++11 } }
> +// { dg-options "" }
> +
> +void
> +foo ()
> +{
> +  extern int _;
> +  extern int _;
> +  int _;		// { dg-warning "name-independent declarations only available with" "" { target c++23_down } }
> +  ++_;			// { dg-error "reference to '_' is ambiguous" }
> +}
> --- gcc/testsuite/g++.dg/cpp26/name-independent-decl5.C.jj	2023-11-29 15:51:49.401880196 +0100
> +++ gcc/testsuite/g++.dg/cpp26/name-independent-decl5.C	2023-11-29 17:27:10.896655212 +0100
> @@ -0,0 +1,92 @@
> +// P2169R4 - A nice placeholder with no name
> +// { dg-do compile { target c++11 } }
> +// { dg-options "" }
> +
> +struct S {
> +  int _;
> +  int _;		// { dg-warning "name-independent declarations only available with" "" { target c++23_down } }
> +};
> +S s = { 1, 2 };
> +
> +struct T {
> +  int _ = 3;
> +  int _ = 4;		// { dg-warning "name-independent declarations only available with" "" { target c++23_down } }
> +};
> +T t1;
> +#if __cplusplus >= 201402L
> +T t2 = { 5, 6 };
> +#endif
> +
> +struct U {
> +  int _ (int) { return 1; }
> +  long _ (long) { return 2; }
> +  int _;		// { dg-warning "name-independent declarations only available with" "" { target c++23_down } }
> +};
> +U u = { 7 };
> +
> +struct V {
> +  static int _;
> +  int _;		// { dg-warning "name-independent declarations only available with" "" { target c++23_down } }
> +};
> +V v = { 8 };
> +
> +struct W : public S, T { int _; };
> +struct X : public S, T {
> +  int _;
> +  int _;		// { dg-warning "name-independent declarations only available with" "" { target c++23_down } }
> +};
> +
> +struct Y {
> +  int _;
> +  int &foo () { return _; }
> +};
> +
> +struct Z : public Y {
> +  int _;
> +  int bar ();
> +};
> +
> +int
> +Z::bar ()
> +{
> +  return _ + Y::_;
> +}
> +
> +struct A {
> +  int _;
> +  void foo () {
> +    int _;
> +    _ = 42;
> +    _ += ({ int _ = 0; _; });
> +  }
> +};
> +
> +struct B {
> +  union { int _; };
> +  void foo () { ++_; };
> +};
> +
> +struct C {
> +  int _;
> +  union { int x; };
> +  void foo () { ++_; };
> +};
> +
> +struct D {
> +  struct { int _; };
> +  void foo () { ++_; };
> +};
> +
> +struct E {
> +  struct _ {};
> +  int _;
> +  void foo () { ++_; int _; _ = 5; }
> +};
> +typedef struct E::_ E_;
> +
> +struct F {
> +  struct _ {};
> +  int _;
> +  int _;		// { dg-warning "name-independent declarations only available with" "" { target c++23_down } }
> +};
> +typedef struct F::_ F_;
> --- gcc/testsuite/g++.dg/cpp26/name-independent-decl6.C.jj	2023-11-29 15:51:49.401880196 +0100
> +++ gcc/testsuite/g++.dg/cpp26/name-independent-decl6.C	2023-11-29 17:58:42.506990066 +0100
> @@ -0,0 +1,135 @@
> +// P2169R4 - A nice placeholder with no name
> +// { dg-do compile { target c++11 } }
> +// { dg-options "" }
> +
> +struct S {
> +  int _;
> +  int _;		// { dg-warning "name-independent declarations only available with" "" { target c++23_down } }
> +  int foo ();
> +  S () : _ (1) {}	// { dg-error "request for member '_' is ambiguous" }
> +  void bar () { ++_; }	// { dg-error "reference to '_' is ambiguous" }
> +};
> +
> +int
> +S::foo ()
> +{
> +  int x = _;		// { dg-error "reference to '_' is ambiguous" }
> +  x += S::_;		// { dg-error "reference to '_' is ambiguous" }
> +  return x;
> +}
> +
> +struct T {
> +  int _;
> +  int _;		// { dg-warning "name-independent declarations only available with" "" { target c++23_down } }
> +};
> +T t = { ._ = 1 };	// { dg-error "request for member '_' is ambiguous" }
> +
> +auto o = __builtin_offsetof (T, _);	// { dg-error "request for member '_' is ambiguous" }
> +int T::* p = &T::_;	// { dg-error "reference to '_' is ambiguous" }
> +
> +struct U {
> +  U () : _ (42) {}	// { dg-error "request for member '_' is ambiguous" }
> +  int _;
> +  int _;		// { dg-warning "name-independent declarations only available with" "" { target c++23_down } }
> +};
> +
> +struct V {
> +  V ();
> +  int _;
> +  int _;		// { dg-warning "name-independent declarations only available with" "" { target c++23_down } }
> +};
> +
> +V::V () : _(42)		// { dg-error "request for member '_' is ambiguous" }
> +{
> +}
> +
> +struct A {
> +  int _;
> +  union { int _; };	// { dg-warning "name-independent declarations only available with" "" { target c++23_down } }
> +  A() : _(42) {}	// { dg-error "request for member '_' is ambiguous" }
> +};
> +
> +struct B {
> +  union { int _, _; };	// { dg-warning "name-independent declarations only available with" "" { target c++23_down } }
> +  union { int _, _; };	// { dg-warning "name-independent declarations only available with" "" { target c++23_down } }
> +  B() : _(42) {}	// { dg-error "request for member '_' is ambiguous" }
> +};
> +
> +void
> +bar ()
> +{
> +  union { int _;
> +	  int _; };	// { dg-warning "name-independent declarations only available with" "" { target c++23_down } }
> +  _ = 42;		// { dg-error "reference to '_' is ambiguous" }
> +}
> +
> +namespace C
> +{
> +  static union { int _ = 1; };
> +  static union { int _ = 2; };	// { dg-error "redeclaration of 'int _'" }
> +}
> +
> +void
> +baz ()
> +{
> +  static union { int _ = 3; };
> +  static union { int _ = 4; };	// { dg-error "redeclaration of 'int _'" }
> +}				// { dg-message "static variable is not name-independent" "" { target c++26 } .-1 }
> +
> +struct D {
> +  int _;
> +  int _;		// { dg-warning "name-independent declarations only available with" "" { target c++23_down } }
> +};
> +
> +struct E : public D {};
> +
> +void
> +qux ()
> +{
> +  D {}._;		// { dg-error "request for member '_' is ambiguous" }
> +  E {}._;		// { dg-error "request for member '_' is ambiguous" }
> +}
> +
> +struct F {
> +  struct _ {};
> +  int _;
> +  int _;		// { dg-warning "name-independent declarations only available with" "" { target c++23_down } }
> +  void foo () { ++_; }	// { dg-error "reference to '_' is ambiguous" }
> +  void bar ();
> +};
> +typedef struct F::_ F_;
> +
> +void
> +F::bar ()
> +{
> +  ++_;			// { dg-error "reference to '_' is ambiguous" }
> +}
> +
> +struct G {
> +  int _ (int) { return 1; }
> +  int _;		// { dg-warning "name-independent declarations only available with" "" { target c++23_down } }
> +  void foo () { ++_; }	// { dg-error "reference to '_' is ambiguous" }
> +  void bar ();
> +};
> +
> +void
> +G::bar ()
> +{
> +  ++_;			// { dg-error "reference to '_' is ambiguous" }
> +  this->_ (0);		// { dg-error "request for member '_' is ambiguous" }
> +}
> +
> +struct H {
> +  int _ (int) { return 1; }
> +  long _ (float) { return 2; }
> +  int _;		// { dg-warning "name-independent declarations only available with" "" { target c++23_down } }
> +  void foo () { ++_; }	// { dg-error "reference to '_' is ambiguous" }
> +  void bar ();
> +};
> +
> +void
> +H::bar ()
> +{
> +  ++_;			// { dg-error "reference to '_' is ambiguous" }
> +  this->_ (0);		// { dg-error "request for member '_' is ambiguous" }
> +}
> --- gcc/testsuite/g++.dg/cpp26/feat-cxx26.C.jj	2023-11-24 08:43:01.997951745 +0100
> +++ gcc/testsuite/g++.dg/cpp26/feat-cxx26.C	2023-11-29 15:51:49.415879997 +0100
> @@ -584,7 +584,7 @@
>   #  error "__cpp_auto_cast != 202110"
>   #endif
>   
> -//  C++23 attributes:
> +// C++23 attributes:
>   
>   #ifdef __has_cpp_attribute
>   #  if ! __has_cpp_attribute(assume)
> @@ -595,3 +595,11 @@
>   #else
>   #  error "__has_cpp_attribute"
>   #endif
> +
> +// C++26 features:
> +
> +#ifndef __cpp_placeholder_variables
> +#  error "__cpp_placeholder_variables"
> +#elif __cpp_placeholder_variables != 202306
> +#  error "__cpp_placeholder_variables != 202306"
> +#endif
> 
> 
> 	Jakub
>
  

Patch

--- gcc/c-family/c-cppbuiltin.cc.jj	2023-11-24 08:43:01.177963318 +0100
+++ gcc/c-family/c-cppbuiltin.cc	2023-11-29 15:51:49.331881183 +0100
@@ -1088,6 +1088,7 @@  c_cpp_builtins (cpp_reader *pfile)
 	  /* Set feature test macros for C++26.  */
 	  cpp_define (pfile, "__cpp_constexpr=202306L");
 	  cpp_define (pfile, "__cpp_static_assert=202306L");
+	  cpp_define (pfile, "__cpp_placeholder_variables=202306L");
 	}
       if (flag_concepts)
         {
--- gcc/cp/cp-tree.h.jj	2023-11-29 08:36:33.194393034 +0100
+++ gcc/cp/cp-tree.h	2023-11-29 15:51:49.332881169 +0100
@@ -523,6 +523,7 @@  extern GTY(()) tree cp_global_trees[CPTI
       RANGE_FOR_IVDEP (in RANGE_FOR_STMT)
       CALL_EXPR_OPERATOR_SYNTAX (in CALL_EXPR, AGGR_INIT_EXPR)
       CONSTRUCTOR_IS_DESIGNATED_INIT (in CONSTRUCTOR)
+      OVL_NAME_INDEPENDENT_DECL_P (in OVERLOAD)
 
    Usage of TYPE_LANG_FLAG_?:
    0: TYPE_DEPENDENT_P
@@ -815,6 +816,9 @@  typedef struct ptrmem_cst * ptrmem_cst_t
 #define OVL_LOOKUP_P(NODE)	TREE_LANG_FLAG_4 (OVERLOAD_CHECK (NODE))
 /* If set, this OVL_USING_P overload is exported.  */
 #define OVL_EXPORT_P(NODE)	TREE_LANG_FLAG_5 (OVERLOAD_CHECK (NODE))
+/* If set, this overload includes name-independent declarations.  */
+#define OVL_NAME_INDEPENDENT_DECL_P(NODE) \
+  TREE_LANG_FLAG_6 (OVERLOAD_CHECK (NODE))
 
 /* The first decl of an overload.  */
 #define OVL_FIRST(NODE)	ovl_first (NODE)
@@ -7864,7 +7868,7 @@  extern tree lambda_capture_field_type		(
 extern tree lambda_proxy_type			(tree);
 extern tree lambda_function			(tree);
 extern void apply_deduced_return_type           (tree, tree);
-extern tree add_capture                         (tree, tree, tree, bool, bool);
+extern tree add_capture                         (tree, tree, tree, bool, bool, unsigned *);
 extern tree add_default_capture                 (tree, tree, tree);
 extern void insert_capture_proxy		(tree);
 extern void insert_pending_capture_proxies	(void);
@@ -8930,6 +8934,18 @@  extended_float_type_p (tree type)
   return false;
 }
 
+/* True if DECL is name-independent declaration.  */
+
+inline bool
+name_independent_decl_p (tree decl)
+{
+  return ((VAR_P (decl) || TREE_CODE (decl) == FIELD_DECL)
+	  && DECL_NAME (decl)
+	  && id_equal (DECL_NAME (decl), "_")
+	  && !TREE_STATIC (decl)
+	  && !DECL_EXTERNAL (decl));
+}
+
 #if CHECKING_P
 namespace selftest {
   extern void run_cp_tests (void);
--- gcc/cp/name-lookup.cc.jj	2023-11-25 10:28:27.747191994 +0100
+++ gcc/cp/name-lookup.cc	2023-11-29 17:26:12.143505568 +0100
@@ -511,10 +511,11 @@  private:
   void preserve_state ();
   void restore_state ();
 
-private:
+public:
   static tree ambiguous (tree thing, tree current);
-  void add_overload (tree fns);
   void add_value (tree new_val);
+private:
+  void add_overload (tree fns);
   void add_type (tree new_type);
   bool process_binding (tree val_bind, tree type_bind);
   unsigned process_module_binding (tree val_bind, tree type_bind, unsigned);
@@ -1806,6 +1807,71 @@  fields_linear_search (tree klass, tree n
   return NULL_TREE;
 }
 
+/* Like fields_linear_search, but specific for "_" name.  There can be multiple
+   name-independent non-static data members and in that case a TREE_LIST with the
+   ambiguous decls should be returned.  */
+
+static tree
+name_independent_linear_search (tree val, tree klass, tree name)
+{
+  for (tree fields = TYPE_FIELDS (klass); fields; fields = DECL_CHAIN (fields))
+    {
+      tree decl = fields;
+
+      if (TREE_CODE (decl) == FIELD_DECL
+	  && ANON_AGGR_TYPE_P (TREE_TYPE (decl)))
+	{
+	  if (tree temp = search_anon_aggr (TREE_TYPE (decl), name, false))
+	    {
+	      decl = temp;
+	      goto add;
+	    }
+	}
+
+      if (DECL_NAME (decl) != name)
+	continue;
+
+      if (TREE_CODE (decl) == USING_DECL)
+	{
+	  decl = strip_using_decl (decl);
+	  if (is_overloaded_fn (decl))
+	    continue;
+	}
+
+      if (DECL_DECLARES_FUNCTION_P (decl))
+	/* Functions are found separately.  */
+	continue;
+
+    add:
+      if (val == NULL_TREE)
+	val = decl;
+      else
+	{
+	  if (TREE_CODE (val) != TREE_LIST)
+	    {
+	      if (TREE_CODE (val) == OVERLOAD
+		  && OVL_DEDUP_P (val)
+		  && TREE_CODE (decl) == USING_DECL)
+		{
+		  val = ovl_make (decl, val);
+		  continue;
+		}
+	      val = tree_cons (NULL_TREE, val, NULL_TREE);
+	      TREE_TYPE (val) = error_mark_node;
+	    }
+	  if (TREE_CODE (decl) == TREE_LIST)
+	    val = chainon (decl, val);
+	  else
+	    {
+	      val = tree_cons (NULL_TREE, decl, val);
+	      TREE_TYPE (val) = error_mark_node;
+	    }
+	}
+    }
+
+  return val;
+}
+
 /* Look for NAME member inside of anonymous aggregate ANON.  Although
    such things should only contain FIELD_DECLs, we check that too
    late, and would give very confusing errors if we weren't
@@ -1843,6 +1909,50 @@  get_class_binding_direct (tree klass, tr
       val = member_vec_binary_search (member_vec, lookup);
       if (!val)
 	;
+      else if (TREE_CODE (val) == OVERLOAD
+	       && OVL_NAME_INDEPENDENT_DECL_P (val))
+	{
+	  if (want_type)
+	    {
+	      while (TREE_CODE (val) == OVERLOAD
+		     && OVL_NAME_INDEPENDENT_DECL_P (val))
+		val = OVL_CHAIN (val);
+	      if (STAT_HACK_P (val))
+		val = STAT_TYPE (val);
+	      else if (!DECL_DECLARES_TYPE_P (val))
+		val = NULL_TREE;
+	    }
+	  else
+	    {
+	      /* OVERLOAD with a special OVL_NAME_INDEPENDENT_DECL_P
+		 flag is used under the hood to represent lookup
+		 results which include name-independent declarations,
+		 and get_class_binding_direct is turning that into
+		 TREE_LIST representation (which the callers expect for
+		 ambiguous lookups) instead.
+		 There are 2 reasons for that:
+		 1) in order to keep the member_vec binary search fast, I
+		 think it is better to keep OVL_NAME usable on all elements
+		 because having to special case TREE_LIST would slow
+		 everything down;
+		 2) the callers need to be able to chain the results anyway
+		 and so need an unshared TREE_LIST they can tweak/destroy.  */
+	      tree ovl = val;
+	      val = NULL_TREE;
+	      while (TREE_CODE (ovl) == OVERLOAD
+		     && OVL_NAME_INDEPENDENT_DECL_P (ovl))
+		{
+		  val = tree_cons (NULL_TREE, OVL_FUNCTION (ovl), val);
+		  TREE_TYPE (val) = error_mark_node;
+		  ovl = OVL_CHAIN (ovl);
+		}
+	      if (STAT_HACK_P (ovl))
+		val = tree_cons (NULL_TREE, STAT_DECL (ovl), val);
+	      else
+		val = tree_cons (NULL_TREE, ovl, val);
+	      TREE_TYPE (val) = error_mark_node;
+	    }
+	}
       else if (STAT_HACK_P (val))
 	val = want_type ? STAT_TYPE (val) : STAT_DECL (val);
       else if (want_type && !DECL_DECLARES_TYPE_P (val))
@@ -1853,7 +1963,9 @@  get_class_binding_direct (tree klass, tr
       if (member_vec && !want_type)
 	val = member_vec_linear_search (member_vec, lookup);
 
-      if (!val || (TREE_CODE (val) == OVERLOAD && OVL_DEDUP_P (val)))
+      if (id_equal (lookup, "_") && !want_type)
+	val = name_independent_linear_search (val, klass, lookup);
+      else if (!val || (TREE_CODE (val) == OVERLOAD && OVL_DEDUP_P (val)))
 	/* Dependent using declarations are a 'field', make sure we
 	   return that even if we saw an overload already.  */
 	if (tree field_val = fields_linear_search (klass, lookup, want_type))
@@ -2049,6 +2161,25 @@  member_name_cmp (const void *a_p, const
   if (TREE_CODE (b) == OVERLOAD)
     b = OVL_FUNCTION (b);
 
+  if (id_equal (name_a, "_"))
+    {
+      /* Sort name-independent members first.  */
+      if (name_independent_decl_p (a))
+	{
+	  if (name_independent_decl_p (b))
+	    {
+	      if (DECL_UID (a) != DECL_UID (b))
+		return DECL_UID (a) < DECL_UID (b) ? -1 : +1;
+	      gcc_assert (a == b);
+	      return 0;
+	    }
+	  else
+	    return -1;
+	}
+      else if (name_independent_decl_p (b))
+	return +1;
+    }
+
   /* We're in STAT_HACK or USING_DECL territory (or possibly error-land). */
   if (TREE_CODE (a) != TREE_CODE (b))
     {
@@ -2183,14 +2314,15 @@  member_vec_append_enum_values (vec<tree,
 /* MEMBER_VEC has just had new DECLs added to it, but is sorted.
    DeDup adjacent DECLS of the same name.  We already dealt with
    conflict resolution when adding the fields or methods themselves.
-   There are three cases (which could all be combined):
+   There are four cases (which could all be combined):
    1) a TYPE_DECL and non TYPE_DECL.  Deploy STAT_HACK as appropriate.
    2) a USING_DECL and an overload.  If the USING_DECL is dependent,
    it wins.  Otherwise the OVERLOAD does.
-   3) two USING_DECLS. ...
+   3) two USING_DECLS.
+   4) name-independent members plus others. ...
 
    member_name_cmp will have ordered duplicates as
-   <fns><using><type>  */
+   <name_independent><fns><using><type>  */
 
 static void
 member_vec_dedup (vec<tree, va_gc> *member_vec)
@@ -2208,6 +2340,7 @@  member_vec_dedup (vec<tree, va_gc> *memb
       tree to_type = NULL_TREE;
       tree to_using = NULL_TREE;
       tree marker = NULL_TREE;
+      unsigned name_independent = ix;
 
       for (jx = ix; jx < len; jx++)
 	{
@@ -2251,7 +2384,9 @@  member_vec_dedup (vec<tree, va_gc> *memb
 	      continue;
 	    }
 
-	  if (!current)
+	  if (name_independent_decl_p (next))
+	    name_independent = jx + 1;
+	  else if (!current)
 	    current = next;
 	}
 
@@ -2271,6 +2406,17 @@  member_vec_dedup (vec<tree, va_gc> *memb
 	    current = stat_hack (current, to_type);
 	}
 
+      for (unsigned kx = name_independent; kx > ix; --kx)
+	if (!current)
+	  current = (*member_vec)[kx - 1];
+	else if (current == to_type)
+	  current = stat_hack ((*member_vec)[kx - 1], to_type);
+	else
+	  {
+	    current = ovl_make ((*member_vec)[kx - 1], current);
+	    OVL_NAME_INDEPENDENT_DECL_P (current) = 1;
+	  }
+
       if (current)
 	{
 	  if (marker)
@@ -2479,10 +2625,27 @@  pop_local_binding (tree id, tree decl)
      away.  */
   if (binding->value == decl)
     binding->value = NULL_TREE;
+  else if (binding->type == decl)
+    binding->type = NULL_TREE;
   else
     {
-      gcc_checking_assert (binding->type == decl);
-      binding->type = NULL_TREE;
+      /* Name-independent variable was found after at least one declaration
+	 with the same name.  */
+      gcc_assert (TREE_CODE (binding->value) == TREE_LIST);
+      if (TREE_VALUE (binding->value) != decl)
+	{
+	  binding->value = nreverse (binding->value);
+	  /* Skip over TREE_LISTs added in pushdecl for check_local_shadow
+	     detected declarations, formerly at the tail, now at the start
+	     of the list.  */
+	  while (TREE_PURPOSE (binding->value) == error_mark_node)
+	    binding->value = TREE_CHAIN (binding->value);
+	}
+      gcc_assert (TREE_VALUE (binding->value) == decl);
+      binding->value = TREE_CHAIN (binding->value);
+      while (binding->value
+	     && TREE_PURPOSE (binding->value) == error_mark_node)
+	binding->value = TREE_CHAIN (binding->value);
     }
 
   if (!binding->value && !binding->type)
@@ -2579,6 +2742,10 @@  supplement_binding (cxx_binding *binding
 
   tree bval = binding->value;
   bool ok = true;
+  if (bval
+      && TREE_CODE (bval) == TREE_LIST
+      && name_independent_decl_p (TREE_VALUE (bval)))
+    bval = TREE_VALUE (bval);
   tree target_bval = strip_using_decl (bval);
   tree target_decl = strip_using_decl (decl);
 
@@ -2682,6 +2849,14 @@  supplement_binding (cxx_binding *binding
 	   && CONST_DECL_USING_P (decl))
     /* Let the clone hide the using-decl that introduced it.  */
     binding->value = decl;
+  else if (name_independent_decl_p (decl))
+    {
+      if (cxx_dialect < cxx26)
+	pedwarn (DECL_SOURCE_LOCATION (decl), OPT_Wc__26_extensions,
+		 "name-independent declarations only available with "
+		 "%<-std=c++2c%> or %<-std=gnu++2c%>");
+      binding->value = name_lookup::ambiguous (decl, binding->value);
+    }
   else
     {
       if (!error_operand_p (bval))
@@ -2786,6 +2961,7 @@  update_binding (cp_binding_level *level,
   tree old_type = NULL_TREE;
   bool hide_type = false;
   bool hide_value = false;
+  bool name_independent_p = false;
 
   if (!slot)
     {
@@ -2793,6 +2969,7 @@  update_binding (cp_binding_level *level,
       hide_type = HIDDEN_TYPE_BINDING_P (binding);
       if (!old_type)
 	hide_value = hide_type, hide_type = false;
+      name_independent_p = name_independent_decl_p (decl);
     }
   else if (STAT_HACK_P (*slot))
     {
@@ -2888,7 +3065,9 @@  update_binding (cp_binding_level *level,
     }
   else if (old)
     {
-      if (TREE_CODE (old) != TREE_CODE (decl))
+      if (name_independent_p)
+	to_val = name_lookup::ambiguous (decl, old);
+      else if (TREE_CODE (old) != TREE_CODE (decl))
 	/* Different kinds of decls conflict.  */
 	goto conflict;
       else if (TREE_CODE (old) == TYPE_DECL)
@@ -3088,13 +3267,13 @@  inform_shadowed (tree shadowed)
 /* DECL is being declared at a local scope.  Emit suitable shadow
    warnings.  */
 
-static void
+static tree
 check_local_shadow (tree decl)
 {
   /* Don't complain about the parms we push and then pop
      while tentatively parsing a function declarator.  */
   if (TREE_CODE (decl) == PARM_DECL && !DECL_CONTEXT (decl))
-    return;
+    return NULL_TREE;
 
   tree old = NULL_TREE;
   cp_binding_level *old_scope = NULL;
@@ -3129,7 +3308,7 @@  check_local_shadow (tree decl)
 	    error_at (DECL_SOURCE_LOCATION (old),
 		      "lambda parameter %qD "
 		      "previously declared as a capture", old);
-	  return;
+	  return NULL_TREE;
 	}
       /* Don't complain if it's from an enclosing function.  */
       else if (DECL_CONTEXT (old) == current_function_decl
@@ -3153,6 +3332,9 @@  check_local_shadow (tree decl)
 	     in the outermost block of the function definition.  */
 	  if (b->kind == sk_function_parms)
 	    {
+	      if (name_independent_decl_p (decl))
+		return old;
+
 	      auto_diagnostic_group d;
 	      bool emit = true;
 	      if (DECL_EXTERNAL (decl))
@@ -3165,7 +3347,7 @@  check_local_shadow (tree decl)
 	      if (emit)
 		inform (DECL_SOURCE_LOCATION (old),
 			"%q#D previously declared here", old);
-	      return;
+	      return NULL_TREE;
 	    }
 	}
 
@@ -3177,7 +3359,7 @@  check_local_shadow (tree decl)
 	       scope != old_scope; scope = scope->level_chain)
 	    if (scope->kind == sk_class
 		&& !LAMBDA_TYPE_P (scope->this_entity))
-	      return;
+	      return NULL_TREE;
 	}
       /* Error if redeclaring a local declared in a
 	 init-statement or in the condition of an if or
@@ -3189,6 +3371,9 @@  check_local_shadow (tree decl)
 	       && old_scope == current_binding_level->level_chain
 	       && (old_scope->kind == sk_cond || old_scope->kind == sk_for))
 	{
+	  if (name_independent_decl_p (decl))
+	    return old;
+
 	  auto_diagnostic_group d;
 	  bool emit = true;
 	  if (DECL_EXTERNAL (decl))
@@ -3200,7 +3385,7 @@  check_local_shadow (tree decl)
 	  if (emit)
 	    inform (DECL_SOURCE_LOCATION (old),
 		    "%q#D previously declared here", old);
-	  return;
+	  return NULL_TREE;
 	}
       /* C++11:
 	 3.3.3/3:  The name declared in an exception-declaration (...)
@@ -3212,6 +3397,9 @@  check_local_shadow (tree decl)
 	       && old_scope == current_binding_level->level_chain
 	       && old_scope->kind == sk_catch)
 	{
+	  if (name_independent_decl_p (decl))
+	    return old;
+
 	  auto_diagnostic_group d;
 	  bool emit;
 	  if (DECL_EXTERNAL (decl))
@@ -3223,9 +3411,13 @@  check_local_shadow (tree decl)
 	  if (emit)
 	    inform (DECL_SOURCE_LOCATION (old),
 		    "%q#D previously declared here", old);
-	  return;
+	  return NULL_TREE;
 	}
 
+      /* Don't emit -Wshadow* warnings for name-independent decls.  */
+      if (name_independent_decl_p (decl) || name_independent_decl_p (old))
+	return NULL_TREE;
+
       /* If '-Wshadow=compatible-local' is specified without other
 	 -Wshadow= flags, we will warn only when the type of the
 	 shadowing variable (DECL) can be converted to that of the
@@ -3278,15 +3470,19 @@  check_local_shadow (tree decl)
       auto_diagnostic_group d;
       if (warning_at (DECL_SOURCE_LOCATION (decl), warning_code, msg, decl))
 	inform_shadowed (old);
-      return;
+      return NULL_TREE;
     }
 
   if (!warn_shadow)
-    return;
+    return NULL_TREE;
+
+  /* Don't emit -Wshadow for name-independent decls.  */
+  if (name_independent_decl_p (decl))
+    return NULL_TREE;
 
   /* Don't warn for artificial things that are not implicit typedefs.  */
   if (DECL_ARTIFICIAL (decl) && !DECL_IMPLICIT_TYPEDEF_P (decl))
-    return;
+    return NULL_TREE;
 
   if (nonlambda_method_basetype ())
     if (tree member = lookup_member (current_nonlambda_class_type (),
@@ -3314,7 +3510,7 @@  check_local_shadow (tree decl)
 		suppress_warning (decl, OPT_Wshadow);
 	      }
 	  }
-	return;
+	return NULL_TREE;
       }
 
   /* Now look for a namespace shadow.  */
@@ -3337,10 +3533,10 @@  check_local_shadow (tree decl)
 	  inform_shadowed (old);
 	  suppress_warning (decl, OPT_Wshadow);
 	}
-      return;
+      return NULL_TREE;
     }
 
-  return;
+  return NULL_TREE;
 }
 
 /* DECL is being pushed inside function CTX.  Set its context, if
@@ -3659,6 +3855,8 @@  pushdecl (tree decl, bool hiding)
       tree *slot = NULL; /* Binding slot in namespace.  */
       tree *mslot = NULL; /* Current module slot in namespace.  */
       tree old = NULL_TREE;
+      bool name_independent_p = false;
+      bool name_independent_diagnosed_p = false;
 
       if (level->kind == sk_namespace)
 	{
@@ -3682,56 +3880,82 @@  pushdecl (tree decl, bool hiding)
 	  binding = find_local_binding (level, name);
 	  if (binding)
 	    old = binding->value;
+	  name_independent_p = name_independent_decl_p (decl);
 	}
 
       if (old == error_mark_node)
 	old = NULL_TREE;
 
-      for (ovl_iterator iter (old); iter; ++iter)
-	if (iter.using_p ())
-	  ; /* Ignore using decls here.  */
-	else if (iter.hidden_p ()
-		 && TREE_CODE (*iter) == FUNCTION_DECL
-		 && DECL_LANG_SPECIFIC (*iter)
-		 && DECL_MODULE_IMPORT_P (*iter))
-	  ; /* An undeclared builtin imported from elsewhere.  */
-	else if (tree match
-		 = duplicate_decls (decl, *iter, hiding, iter.hidden_p ()))
-	  {
-	    if (match == error_mark_node)
-	      ;
-	    else if (TREE_CODE (match) == TYPE_DECL)
-	      gcc_checking_assert (REAL_IDENTIFIER_TYPE_VALUE (name)
-				   == (level->kind == sk_namespace
-				       ? NULL_TREE : TREE_TYPE (match)));
-	    else if (iter.hidden_p () && !hiding)
+      tree oldi, oldn;
+      for (oldi = old; oldi; oldi = oldn)
+	{
+	  if (TREE_CODE (oldi) == TREE_LIST)
+	    {
+	      gcc_checking_assert (level->kind != sk_namespace
+				   && name_independent_decl_p
+							(TREE_VALUE (old)));
+	      oldn = TREE_CHAIN (oldi);
+	      oldi = TREE_VALUE (oldi);
+	    }
+	  else
+	    oldn = NULL_TREE;
+	  for (ovl_iterator iter (oldi); iter; ++iter)
+	    if (iter.using_p ())
+	      ; /* Ignore using decls here.  */
+	    else if (iter.hidden_p ()
+		     && TREE_CODE (*iter) == FUNCTION_DECL
+		     && DECL_LANG_SPECIFIC (*iter)
+		     && DECL_MODULE_IMPORT_P (*iter))
+	      ; /* An undeclared builtin imported from elsewhere.  */
+	    else if (name_independent_p)
 	      {
-		/* Unhiding a previously hidden decl.  */
-		tree head = iter.reveal_node (old);
-		if (head != old)
+		/* Ignore name-independent declarations.  */
+		if (cxx_dialect < cxx26 && !name_independent_diagnosed_p)
+		  pedwarn (DECL_SOURCE_LOCATION (decl), OPT_Wc__26_extensions,
+			   "name-independent declarations only available with "
+			   "%<-std=c++2c%> or %<-std=gnu++2c%>");
+		name_independent_diagnosed_p = true;
+	      }
+	    else if (tree match
+		     = duplicate_decls (decl, *iter, hiding, iter.hidden_p ()))
+	      {
+		if (match == error_mark_node)
+		  ;
+		else if (TREE_CODE (match) == TYPE_DECL)
+		  gcc_checking_assert (REAL_IDENTIFIER_TYPE_VALUE (name)
+				       == (level->kind == sk_namespace
+					   ? NULL_TREE : TREE_TYPE (match)));
+		else if (iter.hidden_p () && !hiding)
 		  {
-		    gcc_checking_assert (ns);
-		    if (STAT_HACK_P (*slot))
-		      STAT_DECL (*slot) = head;
+		    /* Unhiding a previously hidden decl.  */
+		    tree head = iter.reveal_node (oldi);
+		    if (head != oldi)
+		      {
+			gcc_checking_assert (ns);
+			if (STAT_HACK_P (*slot))
+			  STAT_DECL (*slot) = head;
+			else
+			  *slot = head;
+		      }
+		    if (DECL_EXTERN_C_P (match))
+		      /* We need to check and register the decl now.  */
+		      check_extern_c_conflict (match);
+		  }
+		else if (slot
+			 && !hiding
+			 && STAT_HACK_P (*slot)
+			 && STAT_DECL_HIDDEN_P (*slot))
+		  {
+		    /* Unhide the non-function.  */
+		    gcc_checking_assert (oldi == match);
+		    if (!STAT_TYPE (*slot))
+		      *slot = match;
 		    else
-		      *slot = head;
+		      STAT_DECL (*slot) = match;
 		  }
-		if (DECL_EXTERN_C_P (match))
-		  /* We need to check and register the decl now.  */
-		  check_extern_c_conflict (match);
-	      }
-	    else if (slot && !hiding
-		     && STAT_HACK_P (*slot) && STAT_DECL_HIDDEN_P (*slot))
-	      {
-		/* Unhide the non-function.  */
-		gcc_checking_assert (old == match);
-		if (!STAT_TYPE (*slot))
-		  *slot = match;
-		else
-		  STAT_DECL (*slot) = match;
+		return match;
 	      }
-	    return match;
-	  }
+	}
 
       /* Check for redeclaring an import.  */
       if (slot && *slot && TREE_CODE (*slot) == BINDING_VECTOR)
@@ -3780,7 +4004,28 @@  pushdecl (tree decl, bool hiding)
 
       if (level->kind != sk_namespace)
 	{
-	  check_local_shadow (decl);
+	  tree local_shadow = check_local_shadow (decl);
+	  if (name_independent_p && local_shadow)
+	    {
+	      if (cxx_dialect < cxx26 && !name_independent_diagnosed_p)
+		pedwarn (DECL_SOURCE_LOCATION (decl), OPT_Wc__26_extensions,
+			 "name-independent declarations only available with "
+			 "%<-std=c++2c%> or %<-std=gnu++2c%>");
+	      name_independent_diagnosed_p = true;
+	      /* When a name-independent declaration is pushed into a scope
+		 which itself does not contain a _ named declaration yet (so
+		 _ name lookups wouldn't be normally ambiguous), but it
+		 shadows a _ declaration in some outer scope in cases
+		 described in [basic.scope.block]/2 where if the names of
+		 the shadowed and shadowing declarations were different it
+		 would be ill-formed program, arrange for _ name lookups
+		 in this scope to be ambiguous.  */
+	      if (old == NULL_TREE)
+		{
+		  old = build_tree_list (error_mark_node, local_shadow);
+		  TREE_TYPE (old) = error_mark_node;
+		}
+	    }
 
 	  if (TREE_CODE (decl) == NAMESPACE_DECL)
 	    /* A local namespace alias.  */
--- gcc/cp/search.cc.jj	2023-11-24 08:43:01.665956431 +0100
+++ gcc/cp/search.cc	2023-11-29 15:51:49.363880733 +0100
@@ -1091,13 +1091,24 @@  lookup_field_r (tree binfo, void *data)
 	    }
 
 	  /* Add the new value.  */
-	  lfi->ambiguous = tree_cons (NULL_TREE, nval, lfi->ambiguous);
-	  TREE_TYPE (lfi->ambiguous) = error_mark_node;
+	  if (TREE_CODE (nval) == TREE_LIST)
+	    lfi->ambiguous = chainon (nval, lfi->ambiguous);
+	  else
+	    {
+	      lfi->ambiguous = tree_cons (NULL_TREE, nval, lfi->ambiguous);
+	      TREE_TYPE (lfi->ambiguous) = error_mark_node;
+	    }
 	}
     }
   else
     {
-      lfi->rval = nval;
+      if (TREE_CODE (nval) == TREE_LIST)
+	{
+	  lfi->ambiguous = chainon (nval, lfi->ambiguous);
+	  lfi->rval = TREE_VALUE (nval);
+	}
+      else
+	lfi->rval = nval;
       lfi->rval_binfo = binfo;
     }
 
--- gcc/cp/lambda.cc.jj	2023-11-24 08:43:01.369960609 +0100
+++ gcc/cp/lambda.cc	2023-11-29 15:51:49.363880733 +0100
@@ -412,7 +412,11 @@  build_capture_proxy (tree member, tree i
     object = TREE_OPERAND (object, 0);
 
   /* Remove the __ inserted by add_capture.  */
-  name = get_identifier (IDENTIFIER_POINTER (DECL_NAME (member)) + 2);
+  if (IDENTIFIER_POINTER (DECL_NAME (member))[2] == '_'
+      && IDENTIFIER_POINTER (DECL_NAME (member))[3] == '.')
+    name = get_identifier ("_");
+  else
+    name = get_identifier (IDENTIFIER_POINTER (DECL_NAME (member)) + 2);
 
   type = lambda_proxy_type (object);
 
@@ -516,7 +520,7 @@  vla_capture_type (tree array_type)
 
 tree
 add_capture (tree lambda, tree id, tree orig_init, bool by_reference_p,
-	     bool explicit_init_p)
+	     bool explicit_init_p, unsigned *name_independent_cnt)
 {
   char *buf;
   tree type, member, name;
@@ -610,11 +614,28 @@  add_capture (tree lambda, tree id, tree
      won't find the field with name lookup.  We can't just leave the name
      unset because template instantiation uses the name to find
      instantiated fields.  */
-  buf = (char *) alloca (IDENTIFIER_LENGTH (id) + 3);
-  buf[1] = buf[0] = '_';
-  memcpy (buf + 2, IDENTIFIER_POINTER (id),
-	  IDENTIFIER_LENGTH (id) + 1);
-  name = get_identifier (buf);
+  if (id_equal (id, "_") && name_independent_cnt)
+    {
+      if (*name_independent_cnt == 0)
+	name = get_identifier ("___");
+      else
+	{
+	  /* For 2nd and later name-independent capture use
+	     unique names.  */
+	  char buf2[5 + (HOST_BITS_PER_INT + 2) / 3];
+	  sprintf (buf2, "___.%u", *name_independent_cnt);
+	  name = get_identifier (buf2);
+	}
+      name_independent_cnt[0]++;
+    }
+  else
+    {
+      buf = XALLOCAVEC (char, IDENTIFIER_LENGTH (id) + 3);
+      buf[1] = buf[0] = '_';
+      memcpy (buf + 2, IDENTIFIER_POINTER (id),
+	      IDENTIFIER_LENGTH (id) + 1);
+      name = get_identifier (buf);
+    }
 
   if (variadic)
     {
@@ -718,7 +739,7 @@  add_default_capture (tree lambda_stack,
 			    (this_capture_p
 			     || (LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (lambda)
 				 == CPLD_REFERENCE)),
-			    /*explicit_init_p=*/false);
+			    /*explicit_init_p=*/false, NULL);
       initializer = convert_from_reference (var);
 
       /* Warn about deprecated implicit capture of this via [=].  */
--- gcc/cp/decl.cc.jj	2023-11-29 08:36:33.204392893 +0100
+++ gcc/cp/decl.cc	2023-11-29 17:56:31.299848688 +0100
@@ -680,6 +680,8 @@  poplevel (int keep, int reverse, int fun
 	       subobjects.  */
 	    && (DECL_DECOMPOSITION_P (decl) ? !DECL_DECOMP_BASE (decl)
 		: (DECL_NAME (decl) && !DECL_ARTIFICIAL (decl)))
+	    /* Don't warn about name-independent declarations.  */
+	    && !name_independent_decl_p (decl)
 	    && type != error_mark_node
 	    && (!CLASS_TYPE_P (type)
 		|| !TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type)
@@ -2063,6 +2065,44 @@  duplicate_decls (tree newdecl, tree oldd
 		    (DECL_INITIAL (olddecl) && namespace_bindings_p ())
 		    ? G_("%q#D previously defined here")
 		    : G_("%q#D previously declared here"), olddecl);
+	  if (cxx_dialect >= cxx26
+	      && DECL_NAME (newdecl)
+	      && id_equal (DECL_NAME (newdecl), "_")
+	      && !name_independent_decl_p (newdecl))
+	    {
+	      if (TREE_CODE (newdecl) == PARM_DECL)
+		inform (newdecl_loc,
+			"parameter declaration is not name-independent");
+	      else if (DECL_DECOMPOSITION_P (newdecl))
+		{
+		  if (at_namespace_scope_p ())
+		    inform (newdecl_loc,
+			    "structured binding at namespace scope is not "
+			    "name-independent");
+		  else if (TREE_STATIC (newdecl))
+		    inform (newdecl_loc,
+			    "static structured binding is not "
+			    "name-independent");
+		  else if (DECL_EXTERNAL (newdecl))
+		    inform (newdecl_loc,
+			    "extern structured binding is not "
+			    "name-independent");
+		}
+	      else if (at_class_scope_p ()
+		       && VAR_P (newdecl)
+		       && TREE_STATIC (newdecl))
+		inform (newdecl_loc,
+			"static data member is not name-independent");
+	      else if (VAR_P (newdecl) && at_namespace_scope_p ())
+		inform (newdecl_loc,
+			"variable at namespace scope is not name-independent");
+	      else if (VAR_P (newdecl) && TREE_STATIC (newdecl))
+		inform (newdecl_loc,
+			"static variable is not name-independent");
+	      else if (VAR_P (newdecl) && DECL_EXTERNAL (newdecl))
+		inform (newdecl_loc,
+			"extern variable is not name-independent");
+	    }
 	  return error_mark_node;
 	}
       else if (TREE_CODE (olddecl) == FUNCTION_DECL
@@ -6869,8 +6909,17 @@  reshape_init_class (tree type, reshape_i
 	  if (!field || TREE_CODE (field) != FIELD_DECL)
 	    {
 	      if (complain & tf_error)
-		error ("%qT has no non-static data member named %qD", type,
-		       d->cur->index);
+		{
+		  if (field && TREE_CODE (field) == TREE_LIST)
+		    {
+		      error ("request for member %qD is ambiguous",
+			     d->cur->index);
+		      print_candidates (field);
+		    }
+		  else
+		    error ("%qT has no non-static data member named %qD", type,
+			   d->cur->index);
+		}
 	      return error_mark_node;
 	    }
 
--- gcc/cp/parser.cc.jj	2023-11-25 10:28:27.761191798 +0100
+++ gcc/cp/parser.cc	2023-11-29 15:51:49.382880464 +0100
@@ -11381,6 +11381,7 @@  cp_parser_lambda_introducer (cp_parser*
 
   hash_set<tree, true> ids;
   tree first_capture_id = NULL_TREE;
+  unsigned name_independent_cnt = 0;
   while (cp_lexer_next_token_is_not (parser->lexer, CPP_CLOSE_SQUARE))
     {
       cp_token* capture_token;
@@ -11425,7 +11426,7 @@  cp_parser_lambda_introducer (cp_parser*
 	  else
 	    add_capture (lambda_expr, /*id=*/this_identifier,
 			 /*initializer=*/finish_this_expr (),
-			 /*by_reference_p=*/true, explicit_init_p);
+			 /*by_reference_p=*/true, explicit_init_p, NULL);
 	  continue;
 	}
 
@@ -11447,7 +11448,7 @@  cp_parser_lambda_introducer (cp_parser*
 	  else
 	    add_capture (lambda_expr, /*id=*/this_identifier,
 			 /*initializer=*/finish_this_expr (),
-			 /*by_reference_p=*/false, explicit_init_p);
+			 /*by_reference_p=*/false, explicit_init_p, NULL);
 	  continue;
 	}
 
@@ -11634,13 +11635,15 @@  cp_parser_lambda_introducer (cp_parser*
 	  ids.add (first_capture_id);
 	  ids.add (capture_id);
 	}
+      if (found && explicit_init_p && id_equal (capture_id, "_"))
+	found = false;
       if (found)
 	pedwarn (input_location, 0,
 		 "already captured %qD in lambda expression", capture_id);
       else
 	add_capture (lambda_expr, capture_id, capture_init_expr,
 		     /*by_reference_p=*/capture_kind == BY_REFERENCE,
-		     explicit_init_p);
+		     explicit_init_p, &name_independent_cnt);
 
       /* If there is any qualification still in effect, clear it
 	 now; we will be starting fresh with the next capture.  */
@@ -15874,6 +15877,8 @@  cp_parser_decomposition_declaration (cp_
   cp_decl_specifier_seq decl_specs;
   clear_decl_specs (&decl_specs);
   decl_specs.type = make_auto ();
+  if (decl_specifiers->storage_class == sc_static)
+    decl_specs.storage_class = sc_static;
   tree prev = decl;
   FOR_EACH_VEC_ELT (v, i, e)
     {
--- gcc/cp/pt.cc.jj	2023-11-24 08:43:01.611957193 +0100
+++ gcc/cp/pt.cc	2023-11-29 15:51:49.400880210 +0100
@@ -19354,7 +19354,7 @@  tsubst_lambda_expr (tree t, tree args, t
 	      && LAMBDA_EXPR_PENDING_PROXIES (t) == NULL);
 
   vec<tree,va_gc>* field_packs = NULL;
-
+  unsigned name_independent_cnt = 0;
   for (tree cap = LAMBDA_EXPR_CAPTURE_LIST (t); cap;
        cap = TREE_CHAIN (cap))
     {
@@ -19384,7 +19384,8 @@  tsubst_lambda_expr (tree t, tree args, t
 	  bool by_ref = (TYPE_REF_P (ftype)
 			 || (TREE_CODE (ftype) == DECLTYPE_TYPE
 			     && DECLTYPE_FOR_REF_CAPTURE (ftype)));
-	  add_capture (r, name, init, by_ref, !DECL_NORMAL_CAPTURE_P (ofield));
+	  add_capture (r, name, init, by_ref, !DECL_NORMAL_CAPTURE_P (ofield),
+		       &name_independent_cnt);
 	  continue;
 	}
 
--- gcc/testsuite/g++.dg/cpp26/name-independent-decl1.C.jj	2023-11-29 15:51:49.401880196 +0100
+++ gcc/testsuite/g++.dg/cpp26/name-independent-decl1.C	2023-11-29 17:27:00.894799971 +0100
@@ -0,0 +1,194 @@ 
+// P2169R4 - A nice placeholder with no name
+// { dg-do compile { target c++11 } }
+// { dg-options "-Wunused-variable -Wunused-but-set-variable -Wunused-parameter -Wshadow" }
+
+int a[3];
+
+void
+foo ()
+{
+  {
+    int _ = 1;
+    ++_;
+  }
+  {
+    int _ = 3;
+    ++_;
+    int _ = 4;			// { dg-warning "name-independent declarations only available with" "" { target c++23_down } }
+  }
+  {
+    int _ = 5;
+    --_;
+    int _ = 6;			// { dg-warning "name-independent declarations only available with" "" { target c++23_down } }
+    int _ = 7;			// { dg-warning "name-independent declarations only available with" "" { target c++23_down } }
+  }
+  {
+    auto [i, j, _] = a;		// { dg-warning "structured bindings only available with" "" { target c++14_down } }
+    ++i;
+    ++_;
+  }
+  {
+    auto [_, _, k] = a;		// { dg-warning "name-independent declarations only available with" "" { target c++23_down } }
+    ++k;			// { dg-warning "structured bindings only available with" "" { target c++14_down } .-1 }
+  }
+  {
+    auto [i, j, _] = a;		// { dg-warning "structured bindings only available with" "" { target c++14_down } }
+    auto [_, k, l] = a;		// { dg-warning "name-independent declarations only available with" "" { target c++23_down } }
+    ++i;			// { dg-warning "structured bindings only available with" "" { target c++14_down } .-1 }
+    ++l;
+  }
+  {
+    int _;
+    _ = 1;
+  }
+  {
+    int _ = 1;
+  }
+  {
+    int _;
+  }
+  {
+    static int _;		// { dg-warning "unused variable" }
+    int _ = 1;			// { dg-warning "name-independent declarations only available with" "" { target c++23_down } }
+  }
+  {
+    extern int _ (int);
+    extern long _ (long);
+    extern float _ (float);
+    int _ = 1;			// { dg-warning "name-independent declarations only available with" "" { target c++23_down } }
+  }
+  {
+    extern double _ (double);
+    extern short _ (short);
+    int _ = 1;			// { dg-warning "name-independent declarations only available with" "" { target c++23_down } }
+    int _ = 2;			// { dg-warning "name-independent declarations only available with" "" { target c++23_down } }
+  }
+  {
+    int _ = 1;
+    {
+      int _ = 2;
+      ++_;
+    }
+    {
+      static int _ = 3;
+      ++_;
+    }
+    {
+      auto [i, j, _] = a;	// { dg-warning "structured bindings only available with" "" { target c++14_down } }
+      ++_;
+    }
+  }
+}
+
+int
+bar (int _ = 0)			// { dg-warning "unused parameter '_'" }
+{
+  int _ = 1;			// { dg-warning "name-independent declarations only available with" "" { target c++23_down } }
+  return 0;
+}
+
+void
+baz ()
+{
+  if (int _ = bar ())
+    int _ = 2;			// { dg-warning "name-independent declarations only available with" "" { target c++23_down } }
+  else
+    int _ = 3;			// { dg-warning "name-independent declarations only available with" "" { target c++23_down } }
+  while (int _ = bar ())
+    int _ = 4;			// { dg-warning "name-independent declarations only available with" "" { target c++23_down } }
+  for (int _ = bar (); _; ++_)
+    int _ = 5;			// { dg-warning "name-independent declarations only available with" "" { target c++23_down } }
+  if (int _ = bar ())
+    {
+      int _ = 6;		// { dg-warning "name-independent declarations only available with" "" { target c++23_down } }
+    }
+  else
+    {
+      int _ = 7;		// { dg-warning "name-independent declarations only available with" "" { target c++23_down } }
+    }
+  while (int _ = bar ())
+    {
+      int _ = 8;		// { dg-warning "name-independent declarations only available with" "" { target c++23_down } }
+    }
+  for (int _ = bar (); _; ++_)
+    {
+      int _ = 9;		// { dg-warning "name-independent declarations only available with" "" { target c++23_down } }
+    }
+}
+
+void
+qux (short _ = 0)		// { dg-warning "unused parameter '_'" }
+{
+  {
+    long _ = 1;
+  }
+}
+
+void
+corge ()
+{
+  auto b = [_ = 1] () { (void) _; };	// { dg-warning "lambda capture initializers only available with" "" { target c++11_down } }
+				// { dg-warning "variable 'b' set but not used" "" { target *-*-* } .-1 }
+  auto c = [_ = 2, _ = 3] () {};// { dg-warning "name-independent declarations only available with" "" { target c++23_down } }
+				// { dg-warning "lambda capture initializers only available with" "" { target c++11_down } .-1 }
+				// { dg-warning "variable 'c' set but not used" "" { target *-*-* } .-2 }
+  {
+    int _ = 4;
+    auto d = [_, _ = 5] () {};	// { dg-warning "name-independent declarations only available with" "" { target c++23_down } }
+  }				// { dg-warning "lambda capture initializers only available with" "" { target c++11_down } .-1 }
+				// { dg-warning "variable 'd' set but not used" "" { target *-*-* } .-2 }
+  {
+    int _ = 5;
+    auto e = [_ = 6] () {};	// { dg-warning "lambda capture initializers only available with" "" { target c++11_down } }
+  }				// { dg-warning "variable 'e' set but not used" "" { target *-*-* } .-1 }
+}
+
+namespace A {
+  int _ = 11;
+}
+
+void
+garply (int x,			// { dg-warning "unused parameter 'x'" }
+	int _,			// { dg-warning "unused parameter '_'" }
+	int)
+{
+}
+
+void
+fred ()
+{
+  try {
+  } catch (int _) {
+    int _ = 5;			// { dg-warning "name-independent declarations only available with" "" { target c++23_down } }
+  }
+}
+
+void
+waldo (int _)			// { dg-warning "unused parameter '_'" }
+try
+{
+}
+catch (int _)			// { dg-warning "name-independent declarations only available with" "" { target c++23_down } }
+{
+  int _ = 7;
+}
+
+void
+grault (int _)			// { dg-warning "unused parameter '_'" }
+try
+{
+}
+catch (int)
+{
+  int _ = 8;			// { dg-warning "name-independent declarations only available with" "" { target c++23_down } }
+}
+
+void
+plugh (int _)			// { dg-warning "unused parameter '_'" }
+try
+{
+  int _ = 1;			// { dg-warning "name-independent declarations only available with" "" { target c++23_down } }
+}
+catch (int)
+{
+}
--- gcc/testsuite/g++.dg/cpp26/name-independent-decl2.C.jj	2023-11-29 15:51:49.401880196 +0100
+++ gcc/testsuite/g++.dg/cpp26/name-independent-decl2.C	2023-11-29 18:03:02.352295830 +0100
@@ -0,0 +1,171 @@ 
+// P2169R4 - A nice placeholder with no name
+// { dg-do compile { target c++11 } }
+// { dg-options "" }
+
+int a[3];
+
+void
+foo ()
+{
+  {
+    extern int _ (int);
+    int _ = 2;			// { dg-warning "name-independent declarations only available with" "" { target c++23_down } }
+    extern long _ (long);	// { dg-error "redeclared as different kind of entity" }
+  }
+  {
+    int _ = 3;
+    extern int _ (int);		// { dg-error "redeclared as different kind of entity" }
+  }
+  {
+    int _ = 4;
+    static int _ = 5;		// { dg-error "redeclaration of 'int _'" }
+  }				// { dg-message "static variable is not name-independent" "" { target c++26 } .-1 }
+  {
+    int _ = 6;
+    int _ = 7;			// { dg-warning "name-independent declarations only available with" "" { target c++23_down } }
+    ++_;			// { dg-error "reference to '_' is ambiguous" }
+  }
+  {
+    int _ = 8;
+    int _ = 9;			// { dg-warning "name-independent declarations only available with" "" { target c++23_down } }
+    int _ = 10;			// { dg-warning "name-independent declarations only available with" "" { target c++23_down } }
+    ++_;			// { dg-error "reference to '_' is ambiguous" }
+  }
+  {
+    static int _ = 11;
+    static int _ = 12;		// { dg-error "redeclaration of 'int _'" }
+    int _ = 13;			// { dg-warning "name-independent declarations only available with" "" { target c++23_down } }
+  }				// { dg-message "static variable is not name-independent" "" { target c++26 } .-2 }
+  {
+    extern int _ (int);
+    extern long _ (long);
+    extern float _ (float);
+    int _ = 1;			// { dg-warning "name-independent declarations only available with" "" { target c++23_down } }
+    ++_;			// { dg-error "reference to '_' is ambiguous" }
+  }
+  {
+    extern double _ (double);
+    extern short _ (short);
+    int _ = 1;			// { dg-warning "name-independent declarations only available with" "" { target c++23_down } }
+    ++_;			// { dg-error "reference to '_' is ambiguous" }
+    int _ = 2;			// { dg-warning "name-independent declarations only available with" "" { target c++23_down } }
+    ++_;			// { dg-error "reference to '_' is ambiguous" }
+  }
+  {
+    auto [i, _, _] = a;		// { 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-error "reference to '_' is ambiguous" }
+  }
+  {
+    auto [i, j, _] = a;		// { dg-warning "structured bindings only available with" "" { target c++14_down } }
+    auto [k, _, l] = a;		// { 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-error "reference to '_' is ambiguous" }
+  }
+  {
+    static auto [i, _, _] = a;	// { dg-error "redeclaration of 'auto _'" }
+				// { dg-warning "structured bindings only available with" "" { target c++14_down } .-1 }
+				// { dg-warning "structured binding declaration can be 'static' only in" "" { target c++17_down } .-2 }
+  }				// { dg-message "static structured binding is not name-independent" "" { target c++26 } .-3 }
+}
+
+int
+bar (int _ = 0)
+{
+  int _ = 1;			// { dg-warning "name-independent declarations only available with" "" { target c++23_down } }
+  ++_;				// { dg-error "reference to '_' is ambiguous" }
+  return 0;
+}
+
+void
+baz ()
+{
+  if (int _ = bar ())
+    {
+      int _ = 6;		// { dg-warning "name-independent declarations only available with" "" { target c++23_down } }
+      ++_;			// { dg-error "reference to '_' is ambiguous" }
+    }
+  else
+    {
+      int _ = 7;		// { dg-warning "name-independent declarations only available with" "" { target c++23_down } }
+      ++_;			// { dg-error "reference to '_' is ambiguous" }
+    }
+  while (int _ = bar ())
+    {
+      int _ = 8;		// { dg-warning "name-independent declarations only available with" "" { target c++23_down } }
+      ++_;			// { dg-error "reference to '_' is ambiguous" }
+    }
+  for (int _ = bar (); _; ++_)
+    {
+      int _ = 9;		// { dg-warning "name-independent declarations only available with" "" { target c++23_down } }
+      ++_;			// { dg-error "reference to '_' is ambiguous" }
+    }
+}
+
+namespace A
+{
+  int _ = 1;
+  int _ = 1;			// { dg-error "redefinition of 'int A::_'" }
+}				// { dg-message "variable at namespace scope is not name-independent" "" { target c++26 } .-1 }
+
+namespace B
+{
+  auto [_, _, _] = a;		// { dg-error "redefinition of 'auto B::_'" }
+				// { dg-warning "structured bindings only available with" "" { target c++14_down } .-1 }
+}				// { dg-message "structured binding at namespace scope is not name-independent" "" { target c++26 } .-2 }
+
+void
+qux ()
+{
+  auto c = [_ = 2, _ = 3] () {	// { dg-warning "name-independent declarations only available with" "" { target c++23_down } }
+				// { dg-warning "lambda capture initializers only available with" "" { target c++11_down } .-1 }
+    (void) _;			// { dg-error "reference to '_' is ambiguous" }
+  };
+  {
+    int _ = 4;
+    auto d = [_, _ = 5] () {	// { dg-warning "name-independent declarations only available with" "" { target c++23_down } }
+				// { dg-warning "lambda capture initializers only available with" "" { target c++11_down } .-1 }
+      (void) _;			// { dg-error "reference to '_' is ambiguous" }
+    };
+  }
+  auto e = [_ = 1] (int _) {};	// { dg-warning "lambda capture initializers only available with" "" { target c++11_down } }
+}				// { dg-error "lambda parameter '_' previously declared as a capture" "" { target *-*-* } .-1 }
+
+void
+corge (int _, int _)		// { dg-error "redefinition of 'int _'" }
+{				// { dg-message "parameter declaration is not name-independent" "" { target c++26 } .-1 }
+}
+
+namespace C
+{
+  typedef int _;
+  typedef int _;
+}
+
+namespace D
+{
+  namespace {
+    int _;
+    int _;			// { dg-error "redefinition of 'int D::.anonymous.::_'" }
+  }				// { dg-message "variable at namespace scope is not name-independent" "" { target c++26 } .-1 }
+}
+
+namespace E
+{
+  int _ (int);
+  int _ (int);
+  int _ (int) { return 0; }
+  int _ (int) { return 0; }	// { dg-error "redefinition of 'int E::_\\\(int\\\)'" }
+  long _ (long) { return 1; }
+}
+
+template <int _, int _>		// { dg-error "redefinition of 'int _'" }
+void
+garply ()
+{
+}
+
+#if __cpp_concepts >= 202002L
+template <typename T>
+concept F = requires (T _, T _) { T{}; };	// { dg-error "redefinition of 'T _'" "" { target c++20 } }
+#endif						// { dg-message "parameter declaration is not name-independent" "" { target c++26 } .-1 }
--- gcc/testsuite/g++.dg/cpp26/name-independent-decl3.C.jj	2023-11-29 15:51:49.401880196 +0100
+++ gcc/testsuite/g++.dg/cpp26/name-independent-decl3.C	2023-11-29 17:53:12.131669848 +0100
@@ -0,0 +1,12 @@ 
+// P2169R4 - A nice placeholder with no name
+// { dg-do compile { target c++11 } }
+// { dg-options "" }
+
+void
+foo ()
+{
+  extern int _;
+  extern int _;
+  ++_;
+  int _;		// { dg-warning "name-independent declarations only available with" "" { target c++23_down } }
+}
--- gcc/testsuite/g++.dg/cpp26/name-independent-decl4.C.jj	2023-11-29 15:51:49.401880196 +0100
+++ gcc/testsuite/g++.dg/cpp26/name-independent-decl4.C	2023-11-29 17:53:17.361595773 +0100
@@ -0,0 +1,12 @@ 
+// P2169R4 - A nice placeholder with no name
+// { dg-do compile { target c++11 } }
+// { dg-options "" }
+
+void
+foo ()
+{
+  extern int _;
+  extern int _;
+  int _;		// { dg-warning "name-independent declarations only available with" "" { target c++23_down } }
+  ++_;			// { dg-error "reference to '_' is ambiguous" }
+}
--- gcc/testsuite/g++.dg/cpp26/name-independent-decl5.C.jj	2023-11-29 15:51:49.401880196 +0100
+++ gcc/testsuite/g++.dg/cpp26/name-independent-decl5.C	2023-11-29 17:27:10.896655212 +0100
@@ -0,0 +1,92 @@ 
+// P2169R4 - A nice placeholder with no name
+// { dg-do compile { target c++11 } }
+// { dg-options "" }
+
+struct S {
+  int _;
+  int _;		// { dg-warning "name-independent declarations only available with" "" { target c++23_down } }
+};
+S s = { 1, 2 };
+
+struct T {
+  int _ = 3;
+  int _ = 4;		// { dg-warning "name-independent declarations only available with" "" { target c++23_down } }
+};
+T t1;
+#if __cplusplus >= 201402L
+T t2 = { 5, 6 };
+#endif
+
+struct U {
+  int _ (int) { return 1; }
+  long _ (long) { return 2; }
+  int _;		// { dg-warning "name-independent declarations only available with" "" { target c++23_down } }
+};
+U u = { 7 };
+
+struct V {
+  static int _;
+  int _;		// { dg-warning "name-independent declarations only available with" "" { target c++23_down } }
+};
+V v = { 8 };
+
+struct W : public S, T { int _; };
+struct X : public S, T {
+  int _;
+  int _;		// { dg-warning "name-independent declarations only available with" "" { target c++23_down } }
+};
+
+struct Y {
+  int _;
+  int &foo () { return _; }
+};
+
+struct Z : public Y {
+  int _;
+  int bar ();
+};
+
+int
+Z::bar ()
+{
+  return _ + Y::_;
+}
+
+struct A {
+  int _;
+  void foo () {
+    int _;
+    _ = 42;
+    _ += ({ int _ = 0; _; });
+  }
+};
+
+struct B {
+  union { int _; };
+  void foo () { ++_; };
+};
+
+struct C {
+  int _;
+  union { int x; };
+  void foo () { ++_; };
+};
+
+struct D {
+  struct { int _; };
+  void foo () { ++_; };
+};
+
+struct E {
+  struct _ {};
+  int _;
+  void foo () { ++_; int _; _ = 5; }
+};
+typedef struct E::_ E_;
+
+struct F {
+  struct _ {};
+  int _;
+  int _;		// { dg-warning "name-independent declarations only available with" "" { target c++23_down } }
+};
+typedef struct F::_ F_;
--- gcc/testsuite/g++.dg/cpp26/name-independent-decl6.C.jj	2023-11-29 15:51:49.401880196 +0100
+++ gcc/testsuite/g++.dg/cpp26/name-independent-decl6.C	2023-11-29 17:58:42.506990066 +0100
@@ -0,0 +1,135 @@ 
+// P2169R4 - A nice placeholder with no name
+// { dg-do compile { target c++11 } }
+// { dg-options "" }
+
+struct S {
+  int _;
+  int _;		// { dg-warning "name-independent declarations only available with" "" { target c++23_down } }
+  int foo ();
+  S () : _ (1) {}	// { dg-error "request for member '_' is ambiguous" }
+  void bar () { ++_; }	// { dg-error "reference to '_' is ambiguous" }
+};
+
+int
+S::foo ()
+{
+  int x = _;		// { dg-error "reference to '_' is ambiguous" }
+  x += S::_;		// { dg-error "reference to '_' is ambiguous" }
+  return x;
+}
+
+struct T {
+  int _;
+  int _;		// { dg-warning "name-independent declarations only available with" "" { target c++23_down } }
+};
+T t = { ._ = 1 };	// { dg-error "request for member '_' is ambiguous" }
+
+auto o = __builtin_offsetof (T, _);	// { dg-error "request for member '_' is ambiguous" }
+int T::* p = &T::_;	// { dg-error "reference to '_' is ambiguous" }
+
+struct U {
+  U () : _ (42) {}	// { dg-error "request for member '_' is ambiguous" }
+  int _;
+  int _;		// { dg-warning "name-independent declarations only available with" "" { target c++23_down } }
+};
+
+struct V {
+  V ();
+  int _;
+  int _;		// { dg-warning "name-independent declarations only available with" "" { target c++23_down } }
+};
+
+V::V () : _(42)		// { dg-error "request for member '_' is ambiguous" }
+{
+}
+
+struct A {
+  int _;
+  union { int _; };	// { dg-warning "name-independent declarations only available with" "" { target c++23_down } }
+  A() : _(42) {}	// { dg-error "request for member '_' is ambiguous" }
+};
+
+struct B {
+  union { int _, _; };	// { dg-warning "name-independent declarations only available with" "" { target c++23_down } }
+  union { int _, _; };	// { dg-warning "name-independent declarations only available with" "" { target c++23_down } }
+  B() : _(42) {}	// { dg-error "request for member '_' is ambiguous" }
+};
+
+void
+bar ()
+{
+  union { int _;
+	  int _; };	// { dg-warning "name-independent declarations only available with" "" { target c++23_down } }
+  _ = 42;		// { dg-error "reference to '_' is ambiguous" }
+}
+
+namespace C
+{
+  static union { int _ = 1; };
+  static union { int _ = 2; };	// { dg-error "redeclaration of 'int _'" }
+}
+
+void
+baz ()
+{
+  static union { int _ = 3; };
+  static union { int _ = 4; };	// { dg-error "redeclaration of 'int _'" }
+}				// { dg-message "static variable is not name-independent" "" { target c++26 } .-1 }
+
+struct D {
+  int _;
+  int _;		// { dg-warning "name-independent declarations only available with" "" { target c++23_down } }
+};
+
+struct E : public D {};
+
+void
+qux ()
+{
+  D {}._;		// { dg-error "request for member '_' is ambiguous" }
+  E {}._;		// { dg-error "request for member '_' is ambiguous" }
+}
+
+struct F {
+  struct _ {};
+  int _;
+  int _;		// { dg-warning "name-independent declarations only available with" "" { target c++23_down } }
+  void foo () { ++_; }	// { dg-error "reference to '_' is ambiguous" }
+  void bar ();
+};
+typedef struct F::_ F_;
+
+void
+F::bar ()
+{
+  ++_;			// { dg-error "reference to '_' is ambiguous" }
+}
+
+struct G {
+  int _ (int) { return 1; }
+  int _;		// { dg-warning "name-independent declarations only available with" "" { target c++23_down } }
+  void foo () { ++_; }	// { dg-error "reference to '_' is ambiguous" }
+  void bar ();
+};
+
+void
+G::bar ()
+{
+  ++_;			// { dg-error "reference to '_' is ambiguous" }
+  this->_ (0);		// { dg-error "request for member '_' is ambiguous" }
+}
+
+struct H {
+  int _ (int) { return 1; }
+  long _ (float) { return 2; }
+  int _;		// { dg-warning "name-independent declarations only available with" "" { target c++23_down } }
+  void foo () { ++_; }	// { dg-error "reference to '_' is ambiguous" }
+  void bar ();
+};
+
+void
+H::bar ()
+{
+  ++_;			// { dg-error "reference to '_' is ambiguous" }
+  this->_ (0);		// { dg-error "request for member '_' is ambiguous" }
+}
--- gcc/testsuite/g++.dg/cpp26/feat-cxx26.C.jj	2023-11-24 08:43:01.997951745 +0100
+++ gcc/testsuite/g++.dg/cpp26/feat-cxx26.C	2023-11-29 15:51:49.415879997 +0100
@@ -584,7 +584,7 @@ 
 #  error "__cpp_auto_cast != 202110"
 #endif
 
-//  C++23 attributes:
+// C++23 attributes:
 
 #ifdef __has_cpp_attribute
 #  if ! __has_cpp_attribute(assume)
@@ -595,3 +595,11 @@ 
 #else
 #  error "__has_cpp_attribute"
 #endif
+
+// C++26 features:
+
+#ifndef __cpp_placeholder_variables
+#  error "__cpp_placeholder_variables"
+#elif __cpp_placeholder_variables != 202306
+#  error "__cpp_placeholder_variables != 202306"
+#endif