c++: processing_template_decl vs template depth [PR103408]

Message ID 20211210191239.233081-1-ppalka@redhat.com
State New
Headers
Series c++: processing_template_decl vs template depth [PR103408] |

Commit Message

Patrick Palka Dec. 10, 2021, 7:12 p.m. UTC
  We use processing_template_decl in two slightly different ways: as
a flag to signal that we're dealing with templated trees, and its
magnitude is also used as a proxy for the current syntactic template
depth.  This overloaded meaning of p_t_d is conceptually confusing and
leads to bugs that we end up working around in an ad-hoc fashion.

This patch replaces all uses of processing_template_decl that care about
its magnitude to instead look at the depth of current_template_parms
via a new current_template_depth macro.  This allows us to eliminate 3
workarounds in the concepts code: two about non-templated
requires-expressions (in constraint.cc) and one about lambdas inside
constraints (in cp_parser_requires_clause_expression etc).

The replacement was mostly mechanical.  There were two gotchas:

  * In synthesize_implicit_template_parm, when introducing a new template
    parameter list for an abbreviated function template, we need to add a
    new level of current_template_parms before calling
    process_template_parm since this function now looks at
    current_template_depth to determine the level of the new parameter.

  * In instantiate_class_template_1 when instantiating a template
    friend, we need to set current_template_parms instead of
    processing_template_decl so that the friend_depth computation in
    make_friend_class remains correct.

Bootstrpped and regtested on x86_64-pc-linux-gnu, does this look OK for
trunk?  Also tested on cmcstl2 and rangev3.

	PR c++/103408

gcc/cp/ChangeLog:

	* constraint.cc (type_deducible_p): Remove workaround for
	non-templated requires-expressions.
	(normalize_placeholder_type_constraints): Likewise.
	* cp-tree.h (current_template_depth): Define.
	* decl.c (start_decl): Inspect current_template_depth instead of
	the magnitude of processing_template_decl.
	(grokfndecl): Likewise.
	(grokvardecl): Likewise.
	(grokdeclarator): Likewise.
	* friend.c (make_friend_class): Likewise.
	(do_friend): Likewise.
	* parser.c (cp_parser_requires_clause_expression): Remove
	workaround for lambdas inside constraints.
	(cp_parser_constraint_expression): Likewise.
	(cp_parser_requires_expression): Likewise.
	(synthesize_implicit_template_parm): Add to current_template_parms
	before calling process_template_parm.
	* pt.c (inline_needs_template_parms): Inspect
	current_template_depth instead of the magnitude of
	processing_template_decl.
	(push_inline_template_parms_recursive): Likewise.
	(maybe_begin_member_template_processing): Likewise.
	(begin_template_parm_list): Likewise.
	(process_template_parm): Likewise.
	(end_template_parm_list): Likewise.
	(add_inherited_template_parms): Likewise.
	(instantiate_class_template_1): Rename
	adjust_processing_template_decl to adjust_template_depth.  Set
	current_template_parms instead of processing_template_decl when
	adjust_template_depth.
	(make_auto_1): Inspect current_template_depth instead of the
	magnitude of processing_template_decl.
	(splice_late_return_type): Likewise.
	* semantics.c (fixup_template_type): Likewise.

gcc/testsuite/ChangeLog:

	* g++.dg/concepts/diagnostic18.C: Expect a "constraints on a
	non-templated function" error.
	* g++.dg/cpp23/auto-fncast10.C: New test.
---
 gcc/cp/constraint.cc                         | 16 ------
 gcc/cp/cp-tree.h                             |  2 +
 gcc/cp/decl.c                                | 10 ++--
 gcc/cp/friend.c                              |  4 +-
 gcc/cp/parser.c                              | 28 ++++------
 gcc/cp/pt.c                                  | 54 +++++++++++---------
 gcc/cp/semantics.c                           |  2 +-
 gcc/testsuite/g++.dg/concepts/diagnostic18.C |  2 +-
 gcc/testsuite/g++.dg/cpp23/auto-fncast10.C   | 19 +++++++
 9 files changed, 70 insertions(+), 67 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp23/auto-fncast10.C
  

Comments

Jason Merrill Dec. 12, 2021, 9:23 p.m. UTC | #1
On 12/10/21 14:12, Patrick Palka wrote:
> We use processing_template_decl in two slightly different ways: as
> a flag to signal that we're dealing with templated trees, and its
> magnitude is also used as a proxy for the current syntactic template
> depth.  This overloaded meaning of p_t_d is conceptually confusing and
> leads to bugs that we end up working around in an ad-hoc fashion.
> 
> This patch replaces all uses of processing_template_decl that care about
> its magnitude to instead look at the depth of current_template_parms
> via a new current_template_depth macro.  This allows us to eliminate 3
> workarounds in the concepts code: two about non-templated
> requires-expressions (in constraint.cc) and one about lambdas inside
> constraints (in cp_parser_requires_clause_expression etc).
> 
> The replacement was mostly mechanical.  There were two gotchas:
> 
>    * In synthesize_implicit_template_parm, when introducing a new template
>      parameter list for an abbreviated function template, we need to add a
>      new level of current_template_parms before calling
>      process_template_parm since this function now looks at
>      current_template_depth to determine the level of the new parameter.
> 
>    * In instantiate_class_template_1 when instantiating a template
>      friend, we need to set current_template_parms instead of
>      processing_template_decl so that the friend_depth computation in
>      make_friend_class remains correct.

Hmm, it looks like both before and after your patch we end up with a 
wrong value of friend_depth in make_friend_class for member templates of 
class templates, but it doesn't actually seem to matter.  Instead of 
building a fake tparm level, we might add a flag parameter to 
make_friend_class to force treatment as a friend template?

> Bootstrpped and regtested on x86_64-pc-linux-gnu, does this look OK for
> trunk?  Also tested on cmcstl2 and rangev3.
> 
> 	PR c++/103408
> 
> gcc/cp/ChangeLog:
> 
> 	* constraint.cc (type_deducible_p): Remove workaround for
> 	non-templated requires-expressions.
> 	(normalize_placeholder_type_constraints): Likewise.
> 	* cp-tree.h (current_template_depth): Define.
> 	* decl.c (start_decl): Inspect current_template_depth instead of
> 	the magnitude of processing_template_decl.
> 	(grokfndecl): Likewise.
> 	(grokvardecl): Likewise.
> 	(grokdeclarator): Likewise.
> 	* friend.c (make_friend_class): Likewise.
> 	(do_friend): Likewise.
> 	* parser.c (cp_parser_requires_clause_expression): Remove
> 	workaround for lambdas inside constraints.
> 	(cp_parser_constraint_expression): Likewise.
> 	(cp_parser_requires_expression): Likewise.
> 	(synthesize_implicit_template_parm): Add to current_template_parms
> 	before calling process_template_parm.
> 	* pt.c (inline_needs_template_parms): Inspect
> 	current_template_depth instead of the magnitude of
> 	processing_template_decl.
> 	(push_inline_template_parms_recursive): Likewise.
> 	(maybe_begin_member_template_processing): Likewise.
> 	(begin_template_parm_list): Likewise.
> 	(process_template_parm): Likewise.
> 	(end_template_parm_list): Likewise.
> 	(add_inherited_template_parms): Likewise.
> 	(instantiate_class_template_1): Rename
> 	adjust_processing_template_decl to adjust_template_depth.  Set
> 	current_template_parms instead of processing_template_decl when
> 	adjust_template_depth.
> 	(make_auto_1): Inspect current_template_depth instead of the
> 	magnitude of processing_template_decl.
> 	(splice_late_return_type): Likewise.
> 	* semantics.c (fixup_template_type): Likewise.
> 
> gcc/testsuite/ChangeLog:
> 
> 	* g++.dg/concepts/diagnostic18.C: Expect a "constraints on a
> 	non-templated function" error.
> 	* g++.dg/cpp23/auto-fncast10.C: New test.
> ---
>   gcc/cp/constraint.cc                         | 16 ------
>   gcc/cp/cp-tree.h                             |  2 +
>   gcc/cp/decl.c                                | 10 ++--
>   gcc/cp/friend.c                              |  4 +-
>   gcc/cp/parser.c                              | 28 ++++------
>   gcc/cp/pt.c                                  | 54 +++++++++++---------
>   gcc/cp/semantics.c                           |  2 +-
>   gcc/testsuite/g++.dg/concepts/diagnostic18.C |  2 +-
>   gcc/testsuite/g++.dg/cpp23/auto-fncast10.C   | 19 +++++++
>   9 files changed, 70 insertions(+), 67 deletions(-)
>   create mode 100644 gcc/testsuite/g++.dg/cpp23/auto-fncast10.C
> 
> diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
> index 2896efdd7f2..566f4e38fac 100644
> --- a/gcc/cp/constraint.cc
> +++ b/gcc/cp/constraint.cc
> @@ -2016,14 +2016,6 @@ type_deducible_p (tree expr, tree type, tree placeholder, tree args,
>        references are preserved in the result.  */
>     expr = force_paren_expr_uneval (expr);
>   
> -  /* When args is NULL, we're evaluating a non-templated requires expression,
> -     but even those are parsed under processing_template_decl == 1, and so the
> -     placeholder 'auto' inside this return-type-requirement has level 2.  In
> -     order to have all parms and arguments match up for satisfaction, we need
> -     to pass an empty level of OUTER_TARGS in this case.  */
> -  if (!args)
> -    args = make_tree_vec (0);
> -
>     tree deduced_type = do_auto_deduction (type, expr, placeholder,
>   					 info.complain, adc_requirement,
>   					 /*outer_targs=*/args);
> @@ -3064,14 +3056,6 @@ normalize_placeholder_type_constraints (tree t, bool diag)
>        parameters for normalization.  */
>     tree initial_parms = TREE_PURPOSE (ci);
>   
> -  if (!initial_parms && TEMPLATE_TYPE_LEVEL (t) == 2)
> -    /* This is a return-type-requirement of a non-templated requires-expression,
> -       which are parsed under processing_template_decl == 1 and empty
> -       current_template_parms; hence the 'auto' has level 2 and initial_parms
> -       is empty.  Fix up initial_parms to be consistent with the value of
> -       processing_template_decl whence the 'auto' was created.  */
> -    initial_parms = build_tree_list (size_int (1), make_tree_vec (0));
> -
>     /* The 'auto' itself is used as the first argument in its own constraints,
>        and its level is one greater than its template depth.  So in order to
>        capture all used template parameters, we need to add an extra level of
> diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
> index b1c3bc5ed1f..9e10a947a43 100644
> --- a/gcc/cp/cp-tree.h
> +++ b/gcc/cp/cp-tree.h
> @@ -1887,6 +1887,8 @@ extern GTY(()) struct saved_scope *scope_chain;
>      stored in the TREE_VALUE.  */
>   
>   #define current_template_parms scope_chain->template_parms
> +#define current_template_depth \
> +  (current_template_parms ? TMPL_PARMS_DEPTH (current_template_parms) : 0)
>   
>   #define processing_template_decl scope_chain->x_processing_template_decl
>   #define processing_specialization scope_chain->x_processing_specialization
> diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
> index 56f80775ca0..7c2048c6acb 100644
> --- a/gcc/cp/decl.c
> +++ b/gcc/cp/decl.c
> @@ -5567,7 +5567,7 @@ start_decl (const cp_declarator *declarator,
>   
>     if (TYPE_P (context) && COMPLETE_TYPE_P (complete_type (context)))
>       {
> -      bool this_tmpl = (processing_template_decl
> +      bool this_tmpl = (current_template_depth
>   			> template_class_depth (context));
>         if (VAR_P (decl))
>   	{
> @@ -9878,7 +9878,7 @@ grokfndecl (tree ctype,
>         tree ctx = friendp ? current_class_type : ctype;
>         bool block_local = TREE_CODE (current_scope ()) == FUNCTION_DECL;
>         bool memtmpl = (!block_local
> -		      && (processing_template_decl
> +		      && (current_template_depth
>   			  > template_class_depth (ctx)));
>         if (memtmpl)
>   	{
> @@ -10300,7 +10300,7 @@ grokfndecl (tree ctype,
>     if (ctype != NULL_TREE && check)
>       {
>         tree old_decl = check_classfn (ctype, decl,
> -				     (processing_template_decl
> +				     (current_template_depth
>   				      > template_class_depth (ctype))
>   				     ? current_template_parms
>   				     : NULL_TREE);
> @@ -10576,7 +10576,7 @@ grokvardecl (tree type,
>           }
>       }
>     else if (flag_concepts
> -	   && processing_template_decl > template_class_depth (scope))
> +	   && current_template_depth > template_class_depth (scope))
>       {
>         tree reqs = TEMPLATE_PARMS_CONSTRAINTS (current_template_parms);
>         tree ci = build_constraints (reqs, NULL_TREE);
> @@ -13975,7 +13975,7 @@ grokdeclarator (const cp_declarator *declarator,
>   		  }
>   
>   		/* Set the constraints on the declaration.  */
> -		bool memtmpl = (processing_template_decl
> +		bool memtmpl = (current_template_depth
>   				> template_class_depth (current_class_type));
>   		if (memtmpl)
>   		  {
> diff --git a/gcc/cp/friend.c b/gcc/cp/friend.c
> index 4f6288414d9..e970fdce0cc 100644
> --- a/gcc/cp/friend.c
> +++ b/gcc/cp/friend.c
> @@ -261,7 +261,7 @@ make_friend_class (tree type, tree friend_type, bool complain)
>        The friend is a template friend iff FRIEND_DEPTH is nonzero.  */
>   
>     int class_template_depth = template_class_depth (type);
> -  int friend_depth = processing_template_decl - class_template_depth;
> +  int friend_depth = current_template_depth - class_template_depth;
>   
>     if (! MAYBE_CLASS_TYPE_P (friend_type)
>         && TREE_CODE (friend_type) != TEMPLATE_TEMPLATE_PARM)
> @@ -517,7 +517,7 @@ do_friend (tree ctype, tree declarator, tree decl,
>   	 3. TEMPLATE_MEMBER_P is true (for `W').  */
>   
>         int class_template_depth = template_class_depth (current_class_type);
> -      int friend_depth = processing_template_decl - class_template_depth;
> +      int friend_depth = current_template_depth - class_template_depth;
>         /* We will figure this out later.  */
>         bool template_member_p = false;
>   
> diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
> index de464afdb54..aedfab209ba 100644
> --- a/gcc/cp/parser.c
> +++ b/gcc/cp/parser.c
> @@ -29779,14 +29779,9 @@ static tree
>   cp_parser_requires_clause_expression (cp_parser *parser, bool lambda_p)
>   {
>     processing_constraint_expression_sentinel parsing_constraint;
> -  temp_override<int> ovr (processing_template_decl);
> -  if (!processing_template_decl)
> -    /* Adjust processing_template_decl so that we always obtain template
> -       trees here.  We don't do the usual ++processing_template_decl
> -       because that would skew the template parameter depth of a lambda
> -       within if we're already inside a template.  */
> -    processing_template_decl = 1;
> +  ++processing_template_decl;
>     cp_expr expr = cp_parser_constraint_logical_or_expression (parser, lambda_p);
> +  --processing_template_decl;
>     if (check_for_bare_parameter_packs (expr))
>       expr = error_mark_node;
>     return expr;
> @@ -29805,12 +29800,10 @@ static tree
>   cp_parser_constraint_expression (cp_parser *parser)
>   {
>     processing_constraint_expression_sentinel parsing_constraint;
> -  temp_override<int> ovr (processing_template_decl);
> -  if (!processing_template_decl)
> -    /* As in cp_parser_requires_clause_expression.  */
> -    processing_template_decl = 1;
> +  ++processing_template_decl;
>     cp_expr expr = cp_parser_binary_expression (parser, false, true,
>   					      PREC_NOT_OPERATOR, NULL);
> +  --processing_template_decl;
>     if (check_for_bare_parameter_packs (expr))
>       expr = error_mark_node;
>     expr.maybe_add_location_wrapper ();
> @@ -29924,11 +29917,9 @@ cp_parser_requires_expression (cp_parser *parser)
>         parms = NULL_TREE;
>   
>       /* Parse the requirement body. */
> -    temp_override<int> ovr (processing_template_decl);
> -    if (!processing_template_decl)
> -      /* As in cp_parser_requires_clause_expression.  */
> -      processing_template_decl = 1;
> +    ++processing_template_decl;
>       reqs = cp_parser_requirement_body (parser);
> +    --processing_template_decl;
>       if (reqs == error_mark_node)
>         return error_mark_node;
>     }
> @@ -48091,6 +48082,10 @@ synthesize_implicit_template_parm  (cp_parser *parser, tree constr)
>     gcc_assert(!proto || TREE_CODE (proto) == TYPE_DECL);
>     synth_tmpl_parm = finish_template_type_parm (class_type_node, synth_id);
>   
> +  if (become_template)
> +    current_template_parms = tree_cons (size_int (current_template_depth + 1),
> +					NULL_TREE, current_template_parms);
> +
>     /* Attach the constraint to the parm before processing.  */
>     tree node = build_tree_list (NULL_TREE, synth_tmpl_parm);
>     TREE_TYPE (node) = constr;
> @@ -48130,8 +48125,7 @@ synthesize_implicit_template_parm  (cp_parser *parser, tree constr)
>   
>         tree new_parms = make_tree_vec (1);
>         TREE_VEC_ELT (new_parms, 0) = parser->implicit_template_parms;
> -      current_template_parms = tree_cons (size_int (processing_template_decl),
> -					  new_parms, current_template_parms);
> +      TREE_VALUE (current_template_parms) = new_parms;
>       }
>     else
>       {
> diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
> index 9834baf34db..85294f72ba6 100644
> --- a/gcc/cp/pt.c
> +++ b/gcc/cp/pt.c
> @@ -448,7 +448,7 @@ inline_needs_template_parms (tree decl, bool nsdmi)
>       return false;
>   
>     return (TMPL_PARMS_DEPTH (DECL_TEMPLATE_PARMS (most_general_template (decl)))
> -	  > (processing_template_decl + DECL_TEMPLATE_SPECIALIZATION (decl)));
> +	  > (current_template_depth + DECL_TEMPLATE_SPECIALIZATION (decl)));
>   }
>   
>   /* Subroutine of maybe_begin_member_template_processing.
> @@ -467,7 +467,7 @@ push_inline_template_parms_recursive (tree parmlist, int levels)
>   
>     ++processing_template_decl;
>     current_template_parms
> -    = tree_cons (size_int (processing_template_decl),
> +    = tree_cons (size_int (current_template_depth + 1),
>   		 parms, current_template_parms);
>     TEMPLATE_PARMS_FOR_INLINE (current_template_parms) = 1;
>   
> @@ -523,7 +523,7 @@ maybe_begin_member_template_processing (tree decl)
>     if (inline_needs_template_parms (decl, nsdmi))
>       {
>         parms = DECL_TEMPLATE_PARMS (most_general_template (decl));
> -      levels = TMPL_PARMS_DEPTH (parms) - processing_template_decl;
> +      levels = TMPL_PARMS_DEPTH (parms) - current_template_depth;
>   
>         if (DECL_TEMPLATE_SPECIALIZATION (decl))
>   	{
> @@ -716,7 +716,7 @@ begin_template_parm_list (void)
>   
>     /* Add a dummy parameter level while we process the parameter list.  */
>     current_template_parms
> -    = tree_cons (size_int (processing_template_decl),
> +    = tree_cons (size_int (current_template_depth + 1),
>   		 make_tree_vec (0),
>   		 current_template_parms);
>   }
> @@ -4613,8 +4613,8 @@ process_template_parm (tree list, location_t parm_loc, tree parm,
>         TREE_CONSTANT (decl) = 1;
>         TREE_READONLY (decl) = 1;
>         DECL_INITIAL (parm) = DECL_INITIAL (decl)
> -	= build_template_parm_index (idx, processing_template_decl,
> -				     processing_template_decl,
> +	= build_template_parm_index (idx, current_template_depth,
> +				     current_template_depth,
>   				     decl, TREE_TYPE (parm));
>   
>         TEMPLATE_PARM_PARAMETER_PACK (DECL_INITIAL (parm))
> @@ -4655,8 +4655,8 @@ process_template_parm (tree list, location_t parm_loc, tree parm,
>         TYPE_STUB_DECL (t) = decl;
>         parm = decl;
>         TEMPLATE_TYPE_PARM_INDEX (t)
> -	= build_template_parm_index (idx, processing_template_decl,
> -				     processing_template_decl,
> +	= build_template_parm_index (idx, current_template_depth,
> +				     current_template_depth,
>   				     decl, TREE_TYPE (parm));
>         TEMPLATE_TYPE_PARAMETER_PACK (t) = is_parameter_pack;
>         if (TREE_CODE (t) == TEMPLATE_TEMPLATE_PARM)
> @@ -4705,7 +4705,7 @@ end_template_parm_list (tree parms)
>     current_template_parms = TREE_CHAIN (current_template_parms);
>   
>     current_template_parms
> -    = tree_cons (size_int (processing_template_decl),
> +    = tree_cons (size_int (current_template_depth + 1),
>   		 saved_parmlist, current_template_parms);
>   
>     for (unsigned ix = 0; parms; ix++)
> @@ -6157,7 +6157,7 @@ add_inherited_template_parms (tree fn, tree inherited)
>       = INNERMOST_TEMPLATE_PARMS (DECL_TEMPLATE_PARMS (inherited));
>     inner_parms = copy_node (inner_parms);
>     tree parms
> -    = tree_cons (size_int (processing_template_decl + 1),
> +    = tree_cons (size_int (current_template_depth + 1),
>   		 inner_parms, current_template_parms);
>     tree tmpl = build_template_decl (fn, parms, /*member*/true);
>     tree args = template_parms_to_args (parms);
> @@ -12165,13 +12165,13 @@ instantiate_class_template_1 (tree type)
>   	      /* Build new CLASSTYPE_FRIEND_CLASSES.  */
>   
>   	      tree friend_type = t;
> -	      bool adjust_processing_template_decl = false;
> +	      bool adjust_template_depth = false;
>   
>   	      if (TREE_CODE (friend_type) == TEMPLATE_DECL)
>   		{
>   		  /* template <class T> friend class C;  */
>   		  friend_type = tsubst_friend_class (friend_type, args);
> -		  adjust_processing_template_decl = true;
> +		  adjust_template_depth = true;
>   		}
>   	      else if (TREE_CODE (friend_type) == UNBOUND_CLASS_TEMPLATE)
>   		{
> @@ -12180,7 +12180,7 @@ instantiate_class_template_1 (tree type)
>   					tf_warning_or_error, NULL_TREE);
>   		  if (TREE_CODE (friend_type) == TEMPLATE_DECL)
>   		    friend_type = TREE_TYPE (friend_type);
> -		  adjust_processing_template_decl = true;
> +		  adjust_template_depth = true;
>   		}
>   	      else if (TREE_CODE (friend_type) == TYPENAME_TYPE
>   		       || TREE_CODE (friend_type) == TEMPLATE_TYPE_PARM)
> @@ -12200,7 +12200,7 @@ instantiate_class_template_1 (tree type)
>   		  friend_type = tsubst (friend_type, args,
>   					tf_warning_or_error, NULL_TREE);
>   		  if (dependent_type_p (friend_type))
> -		    adjust_processing_template_decl = true;
> +		    adjust_template_depth = true;
>   		  --processing_template_decl;
>   		}
>   	      else if (uses_template_parms (friend_type))
> @@ -12218,19 +12218,23 @@ instantiate_class_template_1 (tree type)
>   
>   		 We don't have to do anything in these cases.  */
>   
> -	      if (adjust_processing_template_decl)
> -		/* Trick make_friend_class into realizing that the friend
> -		   we're adding is a template, not an ordinary class.  It's
> -		   important that we use make_friend_class since it will
> -		   perform some error-checking and output cross-reference
> -		   information.  */
> -		++processing_template_decl;
> +	      if (adjust_template_depth)
> +		{
> +		  /* Trick make_friend_class into realizing that the friend
> +		     we're adding is a template, not an ordinary class.  It's
> +		     important that we use make_friend_class since it will
> +		     perform some error-checking and output cross-reference
> +		     information.  */
> +		  gcc_assert (!current_template_parms);
> +		  current_template_parms
> +		    = build_tree_list (size_int (1), make_tree_vec (0));
> +		}
>   
>   	      if (friend_type != error_mark_node)
>   		make_friend_class (type, friend_type, /*complain=*/false);
>   
> -	      if (adjust_processing_template_decl)
> -		--processing_template_decl;
> +	      if (adjust_template_depth)
> +		current_template_parms = TREE_CHAIN (current_template_parms);
>   	    }
>   	  else
>   	    {
> @@ -28417,7 +28421,7 @@ make_auto_1 (tree name, bool set_canonical)
>     TYPE_NAME (au) = build_decl (input_location, TYPE_DECL, name, au);
>     TYPE_STUB_DECL (au) = TYPE_NAME (au);
>     TEMPLATE_TYPE_PARM_INDEX (au) = build_template_parm_index
> -    (0, processing_template_decl + 1, processing_template_decl + 1,
> +    (0, current_template_depth + 1, current_template_depth + 1,
>        TYPE_NAME (au), NULL_TREE);
>     if (set_canonical)
>       TYPE_CANONICAL (au) = canonical_type_parameter (au);
> @@ -30070,7 +30074,7 @@ splice_late_return_type (tree type, tree late_return_type)
>       }
>   
>     if (tree auto_node = find_type_usage (type, is_auto))
> -    if (TEMPLATE_TYPE_LEVEL (auto_node) <= processing_template_decl)
> +    if (TEMPLATE_TYPE_LEVEL (auto_node) <= current_template_depth)
>         {
>   	/* In an abbreviated function template we didn't know we were dealing
>   	   with a function template when we saw the auto return type, so rebuild
> diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
> index cdf63c15e21..d8b20ff5b1b 100644
> --- a/gcc/cp/semantics.c
> +++ b/gcc/cp/semantics.c
> @@ -3629,7 +3629,7 @@ fixup_template_type (tree type)
>     // the scope we're trying to enter.
>     tree parms = current_template_parms;
>     int depth = template_class_depth (type);
> -  for (int n = processing_template_decl; n > depth && parms; --n)
> +  for (int n = current_template_depth; n > depth && parms; --n)
>       parms = TREE_CHAIN (parms);
>     if (!parms)
>       return type;
> diff --git a/gcc/testsuite/g++.dg/concepts/diagnostic18.C b/gcc/testsuite/g++.dg/concepts/diagnostic18.C
> index 79f371b8092..4ac706f8e2d 100644
> --- a/gcc/testsuite/g++.dg/concepts/diagnostic18.C
> +++ b/gcc/testsuite/g++.dg/concepts/diagnostic18.C
> @@ -4,4 +4,4 @@
>   void foo(auto&& arg) requires({}); // { dg-error "statement-expressions are not allowed|braced-groups" }
>   
>   template <auto = 0> requires ([]{}()); // { dg-error "expected unqualified-id" }
> -auto f() requires ([]{}());
> +auto f() requires ([]{}()); // { dg-error "constraints on a non-templated" }
> diff --git a/gcc/testsuite/g++.dg/cpp23/auto-fncast10.C b/gcc/testsuite/g++.dg/cpp23/auto-fncast10.C
> new file mode 100644
> index 00000000000..669dda14035
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp23/auto-fncast10.C
> @@ -0,0 +1,19 @@
> +// PR c++/103408
> +// { dg-do compile { target c++23 } }
> +
> +static_assert(requires { auto(0); });
> +static_assert(requires { auto{0}; });
> +
> +static_assert(requires { auto(auto(0)); });
> +static_assert(requires { auto{auto{0}}; });
> +
> +static_assert(requires { auto(auto(auto(0))); });
> +static_assert(requires { auto{auto{auto{0}}}; });
> +
> +static_assert(requires { requires auto(true); });
> +static_assert(requires { requires auto(auto(true)); });
> +
> +static_assert(!requires { requires auto(false); });
> +static_assert(!requires { requires auto(auto(false)); });
> +
> +auto f() requires (auto(false)); // { dg-error "constraints on non-templated" }
  
Patrick Palka Dec. 13, 2021, 9:28 p.m. UTC | #2
On Sun, 12 Dec 2021, Jason Merrill wrote:

> On 12/10/21 14:12, Patrick Palka wrote:
> > We use processing_template_decl in two slightly different ways: as
> > a flag to signal that we're dealing with templated trees, and its
> > magnitude is also used as a proxy for the current syntactic template
> > depth.  This overloaded meaning of p_t_d is conceptually confusing and
> > leads to bugs that we end up working around in an ad-hoc fashion.
> > 
> > This patch replaces all uses of processing_template_decl that care about
> > its magnitude to instead look at the depth of current_template_parms
> > via a new current_template_depth macro.  This allows us to eliminate 3
> > workarounds in the concepts code: two about non-templated
> > requires-expressions (in constraint.cc) and one about lambdas inside
> > constraints (in cp_parser_requires_clause_expression etc).
> > 
> > The replacement was mostly mechanical.  There were two gotchas:
> > 
> >    * In synthesize_implicit_template_parm, when introducing a new template
> >      parameter list for an abbreviated function template, we need to add a
> >      new level of current_template_parms before calling
> >      process_template_parm since this function now looks at
> >      current_template_depth to determine the level of the new parameter.
> > 
> >    * In instantiate_class_template_1 when instantiating a template
> >      friend, we need to set current_template_parms instead of
> >      processing_template_decl so that the friend_depth computation in
> >      make_friend_class remains correct.
> 
> Hmm, it looks like both before and after your patch we end up with a wrong
> value of friend_depth in make_friend_class for member templates of class
> templates, but it doesn't actually seem to matter.

Ah, I see what you mean.

>  Instead of building a fake
> tparm level, we might add a flag parameter to make_friend_class to force
> treatment as a friend template?

That works well, but I wonder if we could get away with not needing the
flag parameter -- it looks like at instantiation time we can compute
friend_depth exactly by just looking at the tparm with the highest level
within the substituted friend type.  This approach doesn't work at parse
time because in the member template of class template case, i.e.

  template<class T> template<class U> friend class A<T>::B;

FRIEND_TYPE is a TYPENAME_TYPE that is indistinguishable from

  template<class T> friend class A<T>::B;

But at instantiation time, FRIEND_TYPE is a TEMPLATE_DECL in the former
case and a TYPENAME_TYPE in the latter case apparently.  So using
uses_template_parms_level gives us the right answer at instantiation time!

v2: Avoid needing to mess with processing_template_decl /
    current_template_parms around the call to make_friend_class in
    instantiate_class_template by reworking the calculation of
    friend_depth in make_friend_class.

    Also replace processing_template_decl with
    current_template_decl in PROCESSING_REAL_TEMPLATE_DECL_P,
    start_preparsed_function and push_template_decl.  These were
    missed in the original patch because I hadn't considered grepping
    for uses of processing_template_decl that pass it as a function
    argument.

-- >8 --

Subject: [PATCH] c++: processing_template_decl vs template depth [PR103408]

We use processing_template_decl in two slightly different ways: as a
flag to signal that we're dealing with templated trees, and as a measure
of the current syntactic template nesting depth.  This overloaded
meaning of p_t_d is conceptually confusing and leads to bugs
up working around in an ad-hoc fashion.

This patch replaces all uses of processing_template_decl that care about
its magnitude to instead look at the depth of current_template_parms
via a new macro current_template_depth.  This allows us to eliminate 3
workarounds in the concepts code: two about non-templated
requires-expressions (in constraint.cc) and one about lambdas inside
constraints (in cp_parser_requires_clause_expression etc).

The replacement was mostly mechanical.  There were two gotchas:

  * In synthesize_implicit_template_parm, when introducing a new template
    parameter list for an abbreviated function template, we need to add a
    new level of current_template_parms before calling
    process_template_parm since this function now looks at
    current_template_depth to determine the level of the new parameter.

  * In instantiate_class_template_1 after substituting a template
    friend declaration, we currently increment processing_template_decl
    around the call to make_friend_class so that the friend_depth
    computation within this subroutine yields a nonzero value.  We could
    just replace this with an equivalent manipulation of
    current_template_depth, but this patch instead rewrites the
    friend_depth calculation within make_friend_class to not depend on
    p_t_d / c_t_d at all when called from instantiate_class_template_1.

	PR c++/103408

gcc/cp/ChangeLog:

	* constraint.cc (type_deducible_p): Remove workaround for
	non-templated requires-expressions.
	(normalize_placeholder_type_constraints): Likewise.
	* cp-tree.h (current_template_depth): Define.
	(PROCESSING_REAL_TEMPLATE_DECL): Inspect current_template_depth
	instead of the magnitude of processing_template_decl.
	* decl.c (start_decl): Likewise.
	(grokfndecl): Likewise.
	(grokvardecl): Likewise.
	(grokdeclarator): Likewise.
	(start_preparsed_function): Likewise.
	* friend.c (make_friend_class): Likewise.  Calculate
	friend_depth differently when called at instantiation time
	instead of parse time.
	(do_friend): Likewise.
	* parser.c (cp_parser_requires_clause_expression): Remove
	workaround for lambdas inside constraints.
	(cp_parser_constraint_expression): Likewise.
	(cp_parser_requires_expression): Likewise.
	(synthesize_implicit_template_parm): Add to current_template_parms
	before calling process_template_parm.
	* pt.c (inline_needs_template_parms): Inspect
	current_template_depth instead of the magnitude of
	processing_template_decl.
	(push_inline_template_parms_recursive): Likewise.
	(maybe_begin_member_template_processing): Likewise.
	(begin_template_parm_list): Likewise.
	(process_template_parm): Likewise.
	(end_template_parm_list): Likewise.
	(push_template_decl): Likewise.
	(add_inherited_template_parms): Likewise.
	(instantiate_class_template_1): Don't adjust
	processing_template_decl around the call to make_friend_class.
	adjust_processing_template_decl to adjust_template_depth.  Set
	current_template_parms instead of processing_template_decl when
	adjust_template_depth.
	(make_auto_1): Inspect current_template_depth instead of the
	magnitude of processing_template_decl.
	(splice_late_return_type): Likewise.
	* semantics.c (fixup_template_type): Likewise.

gcc/testsuite/ChangeLog:

	* g++.dg/concepts/diagnostic18.C: Expect a "constraints on a
	non-templated function" error.
	* g++.dg/cpp23/auto-fncast10.C: New test.
---
 gcc/cp/constraint.cc                         | 16 --------
 gcc/cp/cp-tree.h                             |  4 +-
 gcc/cp/decl.c                                | 12 +++---
 gcc/cp/friend.c                              | 26 ++++++++++--
 gcc/cp/parser.c                              | 28 +++++--------
 gcc/cp/pt.c                                  | 43 ++++++--------------
 gcc/cp/semantics.c                           |  2 +-
 gcc/testsuite/g++.dg/concepts/diagnostic18.C |  4 +-
 gcc/testsuite/g++.dg/cpp23/auto-fncast10.C   | 19 +++++++++
 9 files changed, 77 insertions(+), 77 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp23/auto-fncast10.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 2896efdd7f2..566f4e38fac 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -2016,14 +2016,6 @@ type_deducible_p (tree expr, tree type, tree placeholder, tree args,
      references are preserved in the result.  */
   expr = force_paren_expr_uneval (expr);
 
-  /* When args is NULL, we're evaluating a non-templated requires expression,
-     but even those are parsed under processing_template_decl == 1, and so the
-     placeholder 'auto' inside this return-type-requirement has level 2.  In
-     order to have all parms and arguments match up for satisfaction, we need
-     to pass an empty level of OUTER_TARGS in this case.  */
-  if (!args)
-    args = make_tree_vec (0);
-
   tree deduced_type = do_auto_deduction (type, expr, placeholder,
 					 info.complain, adc_requirement,
 					 /*outer_targs=*/args);
@@ -3064,14 +3056,6 @@ normalize_placeholder_type_constraints (tree t, bool diag)
      parameters for normalization.  */
   tree initial_parms = TREE_PURPOSE (ci);
 
-  if (!initial_parms && TEMPLATE_TYPE_LEVEL (t) == 2)
-    /* This is a return-type-requirement of a non-templated requires-expression,
-       which are parsed under processing_template_decl == 1 and empty
-       current_template_parms; hence the 'auto' has level 2 and initial_parms
-       is empty.  Fix up initial_parms to be consistent with the value of
-       processing_template_decl whence the 'auto' was created.  */
-    initial_parms = build_tree_list (size_int (1), make_tree_vec (0));
-
   /* The 'auto' itself is used as the first argument in its own constraints,
      and its level is one greater than its template depth.  So in order to
      capture all used template parameters, we need to add an extra level of
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index b1c3bc5ed1f..e5d615281fe 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -1887,6 +1887,8 @@ extern GTY(()) struct saved_scope *scope_chain;
    stored in the TREE_VALUE.  */
 
 #define current_template_parms scope_chain->template_parms
+#define current_template_depth \
+  (current_template_parms ? TMPL_PARMS_DEPTH (current_template_parms) : 0)
 
 #define processing_template_decl scope_chain->x_processing_template_decl
 #define processing_specialization scope_chain->x_processing_specialization
@@ -5105,7 +5107,7 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter)
    full specialization.  */
 #define PROCESSING_REAL_TEMPLATE_DECL_P() \
   (!processing_template_parmlist \
-   && processing_template_decl > template_class_depth (current_scope ()))
+   && current_template_depth > template_class_depth (current_scope ()))
 
 /* Nonzero if this VAR_DECL or FUNCTION_DECL has already been
    instantiated, i.e. its definition has been generated from the
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 56f80775ca0..421b223c68f 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -5567,7 +5567,7 @@ start_decl (const cp_declarator *declarator,
 
   if (TYPE_P (context) && COMPLETE_TYPE_P (complete_type (context)))
     {
-      bool this_tmpl = (processing_template_decl
+      bool this_tmpl = (current_template_depth
 			> template_class_depth (context));
       if (VAR_P (decl))
 	{
@@ -9878,7 +9878,7 @@ grokfndecl (tree ctype,
       tree ctx = friendp ? current_class_type : ctype;
       bool block_local = TREE_CODE (current_scope ()) == FUNCTION_DECL;
       bool memtmpl = (!block_local
-		      && (processing_template_decl
+		      && (current_template_depth
 			  > template_class_depth (ctx)));
       if (memtmpl)
 	{
@@ -10300,7 +10300,7 @@ grokfndecl (tree ctype,
   if (ctype != NULL_TREE && check)
     {
       tree old_decl = check_classfn (ctype, decl,
-				     (processing_template_decl
+				     (current_template_depth
 				      > template_class_depth (ctype))
 				     ? current_template_parms
 				     : NULL_TREE);
@@ -10576,7 +10576,7 @@ grokvardecl (tree type,
         }
     }
   else if (flag_concepts
-	   && processing_template_decl > template_class_depth (scope))
+	   && current_template_depth > template_class_depth (scope))
     {
       tree reqs = TEMPLATE_PARMS_CONSTRAINTS (current_template_parms);
       tree ci = build_constraints (reqs, NULL_TREE);
@@ -13975,7 +13975,7 @@ grokdeclarator (const cp_declarator *declarator,
 		  }
 
 		/* Set the constraints on the declaration.  */
-		bool memtmpl = (processing_template_decl
+		bool memtmpl = (current_template_depth
 				> template_class_depth (current_class_type));
 		if (memtmpl)
 		  {
@@ -16938,7 +16938,7 @@ start_preparsed_function (tree decl1, tree attrs, int flags)
      CFUN set up, and our per-function variables initialized.
      FIXME factor out the non-RTL stuff.  */
   cp_binding_level *bl = current_binding_level;
-  allocate_struct_function (decl1, processing_template_decl);
+  allocate_struct_function (decl1, current_template_depth);
 
   /* Initialize the language data structures.  Whenever we start
      a new function, we destroy temporaries in the usual way.  */
diff --git a/gcc/cp/friend.c b/gcc/cp/friend.c
index 4f6288414d9..613b9f054e2 100644
--- a/gcc/cp/friend.c
+++ b/gcc/cp/friend.c
@@ -261,7 +261,20 @@ make_friend_class (tree type, tree friend_type, bool complain)
      The friend is a template friend iff FRIEND_DEPTH is nonzero.  */
 
   int class_template_depth = template_class_depth (type);
-  int friend_depth = processing_template_decl - class_template_depth;
+  int friend_depth = 0;
+  if (current_template_depth)
+    /* When processing a friend declaration at parse time, just compare the
+       current depth to that of the class template.  */
+    friend_depth = current_template_depth - class_template_depth;
+  else
+    {
+      /* Otherwise, we got here from instantiate_class_template.  Determine
+	 the friend depth by looking at the template parameters used within
+	 FRIEND_TYPE.  */
+      gcc_checking_assert (class_template_depth == 0);
+      while (uses_template_parms_level (friend_type, friend_depth + 1))
+	++friend_depth;
+    }
 
   if (! MAYBE_CLASS_TYPE_P (friend_type)
       && TREE_CODE (friend_type) != TEMPLATE_TEMPLATE_PARM)
@@ -351,8 +364,13 @@ make_friend_class (tree type, tree friend_type, bool complain)
 	  tree name = TYPE_IDENTIFIER (friend_type);
 	  tree decl;
 
-	  if (!uses_template_parms_level (ctype, class_template_depth
-						 + friend_depth))
+	  /* When parsing the template friend, we need to distinguish a
+	     TYPENAME_TYPE for the non-template class B in
+	       template<class T> friend class A<T>::B;
+	     vs for the class template B in
+	       template<class T> template<class U> friend class A<T>::B;  */
+	  if (current_template_depth
+	      && !uses_template_parms_level (ctype, current_template_depth))
 	    template_member_p = true;
 
 	  if (class_template_depth)
@@ -517,7 +535,7 @@ do_friend (tree ctype, tree declarator, tree decl,
 	 3. TEMPLATE_MEMBER_P is true (for `W').  */
 
       int class_template_depth = template_class_depth (current_class_type);
-      int friend_depth = processing_template_decl - class_template_depth;
+      int friend_depth = current_template_depth - class_template_depth;
       /* We will figure this out later.  */
       bool template_member_p = false;
 
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index de464afdb54..aedfab209ba 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -29779,14 +29779,9 @@ static tree
 cp_parser_requires_clause_expression (cp_parser *parser, bool lambda_p)
 {
   processing_constraint_expression_sentinel parsing_constraint;
-  temp_override<int> ovr (processing_template_decl);
-  if (!processing_template_decl)
-    /* Adjust processing_template_decl so that we always obtain template
-       trees here.  We don't do the usual ++processing_template_decl
-       because that would skew the template parameter depth of a lambda
-       within if we're already inside a template.  */
-    processing_template_decl = 1;
+  ++processing_template_decl;
   cp_expr expr = cp_parser_constraint_logical_or_expression (parser, lambda_p);
+  --processing_template_decl;
   if (check_for_bare_parameter_packs (expr))
     expr = error_mark_node;
   return expr;
@@ -29805,12 +29800,10 @@ static tree
 cp_parser_constraint_expression (cp_parser *parser)
 {
   processing_constraint_expression_sentinel parsing_constraint;
-  temp_override<int> ovr (processing_template_decl);
-  if (!processing_template_decl)
-    /* As in cp_parser_requires_clause_expression.  */
-    processing_template_decl = 1;
+  ++processing_template_decl;
   cp_expr expr = cp_parser_binary_expression (parser, false, true,
 					      PREC_NOT_OPERATOR, NULL);
+  --processing_template_decl;
   if (check_for_bare_parameter_packs (expr))
     expr = error_mark_node;
   expr.maybe_add_location_wrapper ();
@@ -29924,11 +29917,9 @@ cp_parser_requires_expression (cp_parser *parser)
       parms = NULL_TREE;
 
     /* Parse the requirement body. */
-    temp_override<int> ovr (processing_template_decl);
-    if (!processing_template_decl)
-      /* As in cp_parser_requires_clause_expression.  */
-      processing_template_decl = 1;
+    ++processing_template_decl;
     reqs = cp_parser_requirement_body (parser);
+    --processing_template_decl;
     if (reqs == error_mark_node)
       return error_mark_node;
   }
@@ -48091,6 +48082,10 @@ synthesize_implicit_template_parm  (cp_parser *parser, tree constr)
   gcc_assert(!proto || TREE_CODE (proto) == TYPE_DECL);
   synth_tmpl_parm = finish_template_type_parm (class_type_node, synth_id);
 
+  if (become_template)
+    current_template_parms = tree_cons (size_int (current_template_depth + 1),
+					NULL_TREE, current_template_parms);
+
   /* Attach the constraint to the parm before processing.  */
   tree node = build_tree_list (NULL_TREE, synth_tmpl_parm);
   TREE_TYPE (node) = constr;
@@ -48130,8 +48125,7 @@ synthesize_implicit_template_parm  (cp_parser *parser, tree constr)
 
       tree new_parms = make_tree_vec (1);
       TREE_VEC_ELT (new_parms, 0) = parser->implicit_template_parms;
-      current_template_parms = tree_cons (size_int (processing_template_decl),
-					  new_parms, current_template_parms);
+      TREE_VALUE (current_template_parms) = new_parms;
     }
   else
     {
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 9834baf34db..fd41d4bd0bf 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -448,7 +448,7 @@ inline_needs_template_parms (tree decl, bool nsdmi)
     return false;
 
   return (TMPL_PARMS_DEPTH (DECL_TEMPLATE_PARMS (most_general_template (decl)))
-	  > (processing_template_decl + DECL_TEMPLATE_SPECIALIZATION (decl)));
+	  > (current_template_depth + DECL_TEMPLATE_SPECIALIZATION (decl)));
 }
 
 /* Subroutine of maybe_begin_member_template_processing.
@@ -467,7 +467,7 @@ push_inline_template_parms_recursive (tree parmlist, int levels)
 
   ++processing_template_decl;
   current_template_parms
-    = tree_cons (size_int (processing_template_decl),
+    = tree_cons (size_int (current_template_depth + 1),
 		 parms, current_template_parms);
   TEMPLATE_PARMS_FOR_INLINE (current_template_parms) = 1;
 
@@ -523,7 +523,7 @@ maybe_begin_member_template_processing (tree decl)
   if (inline_needs_template_parms (decl, nsdmi))
     {
       parms = DECL_TEMPLATE_PARMS (most_general_template (decl));
-      levels = TMPL_PARMS_DEPTH (parms) - processing_template_decl;
+      levels = TMPL_PARMS_DEPTH (parms) - current_template_depth;
 
       if (DECL_TEMPLATE_SPECIALIZATION (decl))
 	{
@@ -716,7 +716,7 @@ begin_template_parm_list (void)
 
   /* Add a dummy parameter level while we process the parameter list.  */
   current_template_parms
-    = tree_cons (size_int (processing_template_decl),
+    = tree_cons (size_int (current_template_depth + 1),
 		 make_tree_vec (0),
 		 current_template_parms);
 }
@@ -4613,8 +4613,8 @@ process_template_parm (tree list, location_t parm_loc, tree parm,
       TREE_CONSTANT (decl) = 1;
       TREE_READONLY (decl) = 1;
       DECL_INITIAL (parm) = DECL_INITIAL (decl)
-	= build_template_parm_index (idx, processing_template_decl,
-				     processing_template_decl,
+	= build_template_parm_index (idx, current_template_depth,
+				     current_template_depth,
 				     decl, TREE_TYPE (parm));
 
       TEMPLATE_PARM_PARAMETER_PACK (DECL_INITIAL (parm))
@@ -4655,8 +4655,8 @@ process_template_parm (tree list, location_t parm_loc, tree parm,
       TYPE_STUB_DECL (t) = decl;
       parm = decl;
       TEMPLATE_TYPE_PARM_INDEX (t)
-	= build_template_parm_index (idx, processing_template_decl,
-				     processing_template_decl,
+	= build_template_parm_index (idx, current_template_depth,
+				     current_template_depth,
 				     decl, TREE_TYPE (parm));
       TEMPLATE_TYPE_PARAMETER_PACK (t) = is_parameter_pack;
       if (TREE_CODE (t) == TEMPLATE_TEMPLATE_PARM)
@@ -4705,7 +4705,7 @@ end_template_parm_list (tree parms)
   current_template_parms = TREE_CHAIN (current_template_parms);
 
   current_template_parms
-    = tree_cons (size_int (processing_template_decl),
+    = tree_cons (size_int (current_template_depth + 1),
 		 saved_parmlist, current_template_parms);
 
   for (unsigned ix = 0; parms; ix++)
@@ -5747,7 +5747,7 @@ push_template_decl (tree decl, bool is_friend)
   /* See if this is a primary template.  */
   bool is_primary = false;
   if (is_friend && ctx
-      && uses_template_parms_level (ctx, processing_template_decl))
+      && uses_template_parms_level (ctx, current_template_depth))
     /* A friend template that specifies a class context, i.e.
          template <typename T> friend void A<T>::f();
        is not primary.  */
@@ -6157,7 +6157,7 @@ add_inherited_template_parms (tree fn, tree inherited)
     = INNERMOST_TEMPLATE_PARMS (DECL_TEMPLATE_PARMS (inherited));
   inner_parms = copy_node (inner_parms);
   tree parms
-    = tree_cons (size_int (processing_template_decl + 1),
+    = tree_cons (size_int (current_template_depth + 1),
 		 inner_parms, current_template_parms);
   tree tmpl = build_template_decl (fn, parms, /*member*/true);
   tree args = template_parms_to_args (parms);
@@ -12165,13 +12165,10 @@ instantiate_class_template_1 (tree type)
 	      /* Build new CLASSTYPE_FRIEND_CLASSES.  */
 
 	      tree friend_type = t;
-	      bool adjust_processing_template_decl = false;
-
 	      if (TREE_CODE (friend_type) == TEMPLATE_DECL)
 		{
 		  /* template <class T> friend class C;  */
 		  friend_type = tsubst_friend_class (friend_type, args);
-		  adjust_processing_template_decl = true;
 		}
 	      else if (TREE_CODE (friend_type) == UNBOUND_CLASS_TEMPLATE)
 		{
@@ -12180,7 +12177,6 @@ instantiate_class_template_1 (tree type)
 					tf_warning_or_error, NULL_TREE);
 		  if (TREE_CODE (friend_type) == TEMPLATE_DECL)
 		    friend_type = TREE_TYPE (friend_type);
-		  adjust_processing_template_decl = true;
 		}
 	      else if (TREE_CODE (friend_type) == TYPENAME_TYPE
 		       || TREE_CODE (friend_type) == TEMPLATE_TYPE_PARM)
@@ -12199,8 +12195,6 @@ instantiate_class_template_1 (tree type)
 		  ++processing_template_decl;
 		  friend_type = tsubst (friend_type, args,
 					tf_warning_or_error, NULL_TREE);
-		  if (dependent_type_p (friend_type))
-		    adjust_processing_template_decl = true;
 		  --processing_template_decl;
 		}
 	      else if (uses_template_parms (friend_type))
@@ -12218,19 +12212,8 @@ instantiate_class_template_1 (tree type)
 
 		 We don't have to do anything in these cases.  */
 
-	      if (adjust_processing_template_decl)
-		/* Trick make_friend_class into realizing that the friend
-		   we're adding is a template, not an ordinary class.  It's
-		   important that we use make_friend_class since it will
-		   perform some error-checking and output cross-reference
-		   information.  */
-		++processing_template_decl;
-
 	      if (friend_type != error_mark_node)
 		make_friend_class (type, friend_type, /*complain=*/false);
-
-	      if (adjust_processing_template_decl)
-		--processing_template_decl;
 	    }
 	  else
 	    {
@@ -28417,7 +28400,7 @@ make_auto_1 (tree name, bool set_canonical)
   TYPE_NAME (au) = build_decl (input_location, TYPE_DECL, name, au);
   TYPE_STUB_DECL (au) = TYPE_NAME (au);
   TEMPLATE_TYPE_PARM_INDEX (au) = build_template_parm_index
-    (0, processing_template_decl + 1, processing_template_decl + 1,
+    (0, current_template_depth + 1, current_template_depth + 1,
      TYPE_NAME (au), NULL_TREE);
   if (set_canonical)
     TYPE_CANONICAL (au) = canonical_type_parameter (au);
@@ -30070,7 +30053,7 @@ splice_late_return_type (tree type, tree late_return_type)
     }
 
   if (tree auto_node = find_type_usage (type, is_auto))
-    if (TEMPLATE_TYPE_LEVEL (auto_node) <= processing_template_decl)
+    if (TEMPLATE_TYPE_LEVEL (auto_node) <= current_template_depth)
       {
 	/* In an abbreviated function template we didn't know we were dealing
 	   with a function template when we saw the auto return type, so rebuild
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index cdf63c15e21..d8b20ff5b1b 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -3629,7 +3629,7 @@ fixup_template_type (tree type)
   // the scope we're trying to enter.
   tree parms = current_template_parms;
   int depth = template_class_depth (type);
-  for (int n = processing_template_decl; n > depth && parms; --n)
+  for (int n = current_template_depth; n > depth && parms; --n)
     parms = TREE_CHAIN (parms);
   if (!parms)
     return type;
diff --git a/gcc/testsuite/g++.dg/concepts/diagnostic18.C b/gcc/testsuite/g++.dg/concepts/diagnostic18.C
index 79f371b8092..c13b0472a64 100644
--- a/gcc/testsuite/g++.dg/concepts/diagnostic18.C
+++ b/gcc/testsuite/g++.dg/concepts/diagnostic18.C
@@ -1,7 +1,7 @@
 // PR c++/100055
 // { dg-do compile { target concepts } }
 
-void foo(auto&& arg) requires({}); // { dg-error "statement-expressions are not allowed|braced-groups" }
+void foo(auto&& arg) requires({}); // { dg-error "statement-expressions are not allowed|braced-groups|non-templated" }
 
 template <auto = 0> requires ([]{}()); // { dg-error "expected unqualified-id" }
-auto f() requires ([]{}());
+auto f() requires ([]{}()); // { dg-error "constraints on a non-templated" }
diff --git a/gcc/testsuite/g++.dg/cpp23/auto-fncast10.C b/gcc/testsuite/g++.dg/cpp23/auto-fncast10.C
new file mode 100644
index 00000000000..669dda14035
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp23/auto-fncast10.C
@@ -0,0 +1,19 @@
+// PR c++/103408
+// { dg-do compile { target c++23 } }
+
+static_assert(requires { auto(0); });
+static_assert(requires { auto{0}; });
+
+static_assert(requires { auto(auto(0)); });
+static_assert(requires { auto{auto{0}}; });
+
+static_assert(requires { auto(auto(auto(0))); });
+static_assert(requires { auto{auto{auto{0}}}; });
+
+static_assert(requires { requires auto(true); });
+static_assert(requires { requires auto(auto(true)); });
+
+static_assert(!requires { requires auto(false); });
+static_assert(!requires { requires auto(auto(false)); });
+
+auto f() requires (auto(false)); // { dg-error "constraints on non-templated" }
  
Jason Merrill Dec. 13, 2021, 11:01 p.m. UTC | #3
On 12/13/21 16:28, Patrick Palka wrote:
> On Sun, 12 Dec 2021, Jason Merrill wrote:
> 
>> On 12/10/21 14:12, Patrick Palka wrote:
>>> We use processing_template_decl in two slightly different ways: as
>>> a flag to signal that we're dealing with templated trees, and its
>>> magnitude is also used as a proxy for the current syntactic template
>>> depth.  This overloaded meaning of p_t_d is conceptually confusing and
>>> leads to bugs that we end up working around in an ad-hoc fashion.
>>>
>>> This patch replaces all uses of processing_template_decl that care about
>>> its magnitude to instead look at the depth of current_template_parms
>>> via a new current_template_depth macro.  This allows us to eliminate 3
>>> workarounds in the concepts code: two about non-templated
>>> requires-expressions (in constraint.cc) and one about lambdas inside
>>> constraints (in cp_parser_requires_clause_expression etc).
>>>
>>> The replacement was mostly mechanical.  There were two gotchas:
>>>
>>>     * In synthesize_implicit_template_parm, when introducing a new template
>>>       parameter list for an abbreviated function template, we need to add a
>>>       new level of current_template_parms before calling
>>>       process_template_parm since this function now looks at
>>>       current_template_depth to determine the level of the new parameter.
>>>
>>>     * In instantiate_class_template_1 when instantiating a template
>>>       friend, we need to set current_template_parms instead of
>>>       processing_template_decl so that the friend_depth computation in
>>>       make_friend_class remains correct.
>>
>> Hmm, it looks like both before and after your patch we end up with a wrong
>> value of friend_depth in make_friend_class for member templates of class
>> templates, but it doesn't actually seem to matter.
> 
> Ah, I see what you mean.
> 
>>   Instead of building a fake
>> tparm level, we might add a flag parameter to make_friend_class to force
>> treatment as a friend template?
> 
> That works well, but I wonder if we could get away with not needing the
> flag parameter -- it looks like at instantiation time we can compute
> friend_depth exactly by just looking at the tparm with the highest level
> within the substituted friend type.  This approach doesn't work at parse
> time because in the member template of class template case, i.e.
> 
>    template<class T> template<class U> friend class A<T>::B;
> 
> FRIEND_TYPE is a TYPENAME_TYPE that is indistinguishable from
> 
>    template<class T> friend class A<T>::B;
> 
> But at instantiation time, FRIEND_TYPE is a TEMPLATE_DECL in the former
> case and a TYPENAME_TYPE in the latter case apparently.  So using
> uses_template_parms_level gives us the right answer at instantiation time!
> 
> v2: Avoid needing to mess with processing_template_decl /
>      current_template_parms around the call to make_friend_class in
>      instantiate_class_template by reworking the calculation of
>      friend_depth in make_friend_class.
> 
>      Also replace processing_template_decl with
>      current_template_decl in PROCESSING_REAL_TEMPLATE_DECL_P,
>      start_preparsed_function and push_template_decl.  These were
>      missed in the original patch because I hadn't considered grepping
>      for uses of processing_template_decl that pass it as a function
>      argument.

The use in start_preparsed_function is passing it to a bool parameter, 
so we don't care about the depth; we might leave that one as 
processing_template_decl, or use current_template_parms directly.  OK 
whichever way you prefer.

> -- >8 --
> 
> Subject: [PATCH] c++: processing_template_decl vs template depth [PR103408]
> 
> We use processing_template_decl in two slightly different ways: as a
> flag to signal that we're dealing with templated trees, and as a measure
> of the current syntactic template nesting depth.  This overloaded
> meaning of p_t_d is conceptually confusing and leads to bugs
> up working around in an ad-hoc fashion.
> 
> This patch replaces all uses of processing_template_decl that care about
> its magnitude to instead look at the depth of current_template_parms
> via a new macro current_template_depth.  This allows us to eliminate 3
> workarounds in the concepts code: two about non-templated
> requires-expressions (in constraint.cc) and one about lambdas inside
> constraints (in cp_parser_requires_clause_expression etc).
> 
> The replacement was mostly mechanical.  There were two gotchas:
> 
>    * In synthesize_implicit_template_parm, when introducing a new template
>      parameter list for an abbreviated function template, we need to add a
>      new level of current_template_parms before calling
>      process_template_parm since this function now looks at
>      current_template_depth to determine the level of the new parameter.
> 
>    * In instantiate_class_template_1 after substituting a template
>      friend declaration, we currently increment processing_template_decl
>      around the call to make_friend_class so that the friend_depth
>      computation within this subroutine yields a nonzero value.  We could
>      just replace this with an equivalent manipulation of
>      current_template_depth, but this patch instead rewrites the
>      friend_depth calculation within make_friend_class to not depend on
>      p_t_d / c_t_d at all when called from instantiate_class_template_1.
> 
> 	PR c++/103408
> 
> gcc/cp/ChangeLog:
> 
> 	* constraint.cc (type_deducible_p): Remove workaround for
> 	non-templated requires-expressions.
> 	(normalize_placeholder_type_constraints): Likewise.
> 	* cp-tree.h (current_template_depth): Define.
> 	(PROCESSING_REAL_TEMPLATE_DECL): Inspect current_template_depth
> 	instead of the magnitude of processing_template_decl.
> 	* decl.c (start_decl): Likewise.
> 	(grokfndecl): Likewise.
> 	(grokvardecl): Likewise.
> 	(grokdeclarator): Likewise.
> 	(start_preparsed_function): Likewise.
> 	* friend.c (make_friend_class): Likewise.  Calculate
> 	friend_depth differently when called at instantiation time
> 	instead of parse time.
> 	(do_friend): Likewise.
> 	* parser.c (cp_parser_requires_clause_expression): Remove
> 	workaround for lambdas inside constraints.
> 	(cp_parser_constraint_expression): Likewise.
> 	(cp_parser_requires_expression): Likewise.
> 	(synthesize_implicit_template_parm): Add to current_template_parms
> 	before calling process_template_parm.
> 	* pt.c (inline_needs_template_parms): Inspect
> 	current_template_depth instead of the magnitude of
> 	processing_template_decl.
> 	(push_inline_template_parms_recursive): Likewise.
> 	(maybe_begin_member_template_processing): Likewise.
> 	(begin_template_parm_list): Likewise.
> 	(process_template_parm): Likewise.
> 	(end_template_parm_list): Likewise.
> 	(push_template_decl): Likewise.
> 	(add_inherited_template_parms): Likewise.
> 	(instantiate_class_template_1): Don't adjust
> 	processing_template_decl around the call to make_friend_class.
> 	adjust_processing_template_decl to adjust_template_depth.  Set
> 	current_template_parms instead of processing_template_decl when
> 	adjust_template_depth.
> 	(make_auto_1): Inspect current_template_depth instead of the
> 	magnitude of processing_template_decl.
> 	(splice_late_return_type): Likewise.
> 	* semantics.c (fixup_template_type): Likewise.
> 
> gcc/testsuite/ChangeLog:
> 
> 	* g++.dg/concepts/diagnostic18.C: Expect a "constraints on a
> 	non-templated function" error.
> 	* g++.dg/cpp23/auto-fncast10.C: New test.
> ---
>   gcc/cp/constraint.cc                         | 16 --------
>   gcc/cp/cp-tree.h                             |  4 +-
>   gcc/cp/decl.c                                | 12 +++---
>   gcc/cp/friend.c                              | 26 ++++++++++--
>   gcc/cp/parser.c                              | 28 +++++--------
>   gcc/cp/pt.c                                  | 43 ++++++--------------
>   gcc/cp/semantics.c                           |  2 +-
>   gcc/testsuite/g++.dg/concepts/diagnostic18.C |  4 +-
>   gcc/testsuite/g++.dg/cpp23/auto-fncast10.C   | 19 +++++++++
>   9 files changed, 77 insertions(+), 77 deletions(-)
>   create mode 100644 gcc/testsuite/g++.dg/cpp23/auto-fncast10.C
> 
> diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
> index 2896efdd7f2..566f4e38fac 100644
> --- a/gcc/cp/constraint.cc
> +++ b/gcc/cp/constraint.cc
> @@ -2016,14 +2016,6 @@ type_deducible_p (tree expr, tree type, tree placeholder, tree args,
>        references are preserved in the result.  */
>     expr = force_paren_expr_uneval (expr);
>   
> -  /* When args is NULL, we're evaluating a non-templated requires expression,
> -     but even those are parsed under processing_template_decl == 1, and so the
> -     placeholder 'auto' inside this return-type-requirement has level 2.  In
> -     order to have all parms and arguments match up for satisfaction, we need
> -     to pass an empty level of OUTER_TARGS in this case.  */
> -  if (!args)
> -    args = make_tree_vec (0);
> -
>     tree deduced_type = do_auto_deduction (type, expr, placeholder,
>   					 info.complain, adc_requirement,
>   					 /*outer_targs=*/args);
> @@ -3064,14 +3056,6 @@ normalize_placeholder_type_constraints (tree t, bool diag)
>        parameters for normalization.  */
>     tree initial_parms = TREE_PURPOSE (ci);
>   
> -  if (!initial_parms && TEMPLATE_TYPE_LEVEL (t) == 2)
> -    /* This is a return-type-requirement of a non-templated requires-expression,
> -       which are parsed under processing_template_decl == 1 and empty
> -       current_template_parms; hence the 'auto' has level 2 and initial_parms
> -       is empty.  Fix up initial_parms to be consistent with the value of
> -       processing_template_decl whence the 'auto' was created.  */
> -    initial_parms = build_tree_list (size_int (1), make_tree_vec (0));
> -
>     /* The 'auto' itself is used as the first argument in its own constraints,
>        and its level is one greater than its template depth.  So in order to
>        capture all used template parameters, we need to add an extra level of
> diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
> index b1c3bc5ed1f..e5d615281fe 100644
> --- a/gcc/cp/cp-tree.h
> +++ b/gcc/cp/cp-tree.h
> @@ -1887,6 +1887,8 @@ extern GTY(()) struct saved_scope *scope_chain;
>      stored in the TREE_VALUE.  */
>   
>   #define current_template_parms scope_chain->template_parms
> +#define current_template_depth \
> +  (current_template_parms ? TMPL_PARMS_DEPTH (current_template_parms) : 0)
>   
>   #define processing_template_decl scope_chain->x_processing_template_decl
>   #define processing_specialization scope_chain->x_processing_specialization
> @@ -5105,7 +5107,7 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter)
>      full specialization.  */
>   #define PROCESSING_REAL_TEMPLATE_DECL_P() \
>     (!processing_template_parmlist \
> -   && processing_template_decl > template_class_depth (current_scope ()))
> +   && current_template_depth > template_class_depth (current_scope ()))
>   
>   /* Nonzero if this VAR_DECL or FUNCTION_DECL has already been
>      instantiated, i.e. its definition has been generated from the
> diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
> index 56f80775ca0..421b223c68f 100644
> --- a/gcc/cp/decl.c
> +++ b/gcc/cp/decl.c
> @@ -5567,7 +5567,7 @@ start_decl (const cp_declarator *declarator,
>   
>     if (TYPE_P (context) && COMPLETE_TYPE_P (complete_type (context)))
>       {
> -      bool this_tmpl = (processing_template_decl
> +      bool this_tmpl = (current_template_depth
>   			> template_class_depth (context));
>         if (VAR_P (decl))
>   	{
> @@ -9878,7 +9878,7 @@ grokfndecl (tree ctype,
>         tree ctx = friendp ? current_class_type : ctype;
>         bool block_local = TREE_CODE (current_scope ()) == FUNCTION_DECL;
>         bool memtmpl = (!block_local
> -		      && (processing_template_decl
> +		      && (current_template_depth
>   			  > template_class_depth (ctx)));
>         if (memtmpl)
>   	{
> @@ -10300,7 +10300,7 @@ grokfndecl (tree ctype,
>     if (ctype != NULL_TREE && check)
>       {
>         tree old_decl = check_classfn (ctype, decl,
> -				     (processing_template_decl
> +				     (current_template_depth
>   				      > template_class_depth (ctype))
>   				     ? current_template_parms
>   				     : NULL_TREE);
> @@ -10576,7 +10576,7 @@ grokvardecl (tree type,
>           }
>       }
>     else if (flag_concepts
> -	   && processing_template_decl > template_class_depth (scope))
> +	   && current_template_depth > template_class_depth (scope))
>       {
>         tree reqs = TEMPLATE_PARMS_CONSTRAINTS (current_template_parms);
>         tree ci = build_constraints (reqs, NULL_TREE);
> @@ -13975,7 +13975,7 @@ grokdeclarator (const cp_declarator *declarator,
>   		  }
>   
>   		/* Set the constraints on the declaration.  */
> -		bool memtmpl = (processing_template_decl
> +		bool memtmpl = (current_template_depth
>   				> template_class_depth (current_class_type));
>   		if (memtmpl)
>   		  {
> @@ -16938,7 +16938,7 @@ start_preparsed_function (tree decl1, tree attrs, int flags)
>        CFUN set up, and our per-function variables initialized.
>        FIXME factor out the non-RTL stuff.  */
>     cp_binding_level *bl = current_binding_level;
> -  allocate_struct_function (decl1, processing_template_decl);
> +  allocate_struct_function (decl1, current_template_depth);
>   
>     /* Initialize the language data structures.  Whenever we start
>        a new function, we destroy temporaries in the usual way.  */
> diff --git a/gcc/cp/friend.c b/gcc/cp/friend.c
> index 4f6288414d9..613b9f054e2 100644
> --- a/gcc/cp/friend.c
> +++ b/gcc/cp/friend.c
> @@ -261,7 +261,20 @@ make_friend_class (tree type, tree friend_type, bool complain)
>        The friend is a template friend iff FRIEND_DEPTH is nonzero.  */
>   
>     int class_template_depth = template_class_depth (type);
> -  int friend_depth = processing_template_decl - class_template_depth;
> +  int friend_depth = 0;
> +  if (current_template_depth)
> +    /* When processing a friend declaration at parse time, just compare the
> +       current depth to that of the class template.  */
> +    friend_depth = current_template_depth - class_template_depth;
> +  else
> +    {
> +      /* Otherwise, we got here from instantiate_class_template.  Determine
> +	 the friend depth by looking at the template parameters used within
> +	 FRIEND_TYPE.  */
> +      gcc_checking_assert (class_template_depth == 0);
> +      while (uses_template_parms_level (friend_type, friend_depth + 1))
> +	++friend_depth;
> +    }
>   
>     if (! MAYBE_CLASS_TYPE_P (friend_type)
>         && TREE_CODE (friend_type) != TEMPLATE_TEMPLATE_PARM)
> @@ -351,8 +364,13 @@ make_friend_class (tree type, tree friend_type, bool complain)
>   	  tree name = TYPE_IDENTIFIER (friend_type);
>   	  tree decl;
>   
> -	  if (!uses_template_parms_level (ctype, class_template_depth
> -						 + friend_depth))
> +	  /* When parsing the template friend, we need to distinguish a
> +	     TYPENAME_TYPE for the non-template class B in
> +	       template<class T> friend class A<T>::B;
> +	     vs for the class template B in
> +	       template<class T> template<class U> friend class A<T>::B;  */
> +	  if (current_template_depth
> +	      && !uses_template_parms_level (ctype, current_template_depth))
>   	    template_member_p = true;
>   
>   	  if (class_template_depth)
> @@ -517,7 +535,7 @@ do_friend (tree ctype, tree declarator, tree decl,
>   	 3. TEMPLATE_MEMBER_P is true (for `W').  */
>   
>         int class_template_depth = template_class_depth (current_class_type);
> -      int friend_depth = processing_template_decl - class_template_depth;
> +      int friend_depth = current_template_depth - class_template_depth;
>         /* We will figure this out later.  */
>         bool template_member_p = false;
>   
> diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
> index de464afdb54..aedfab209ba 100644
> --- a/gcc/cp/parser.c
> +++ b/gcc/cp/parser.c
> @@ -29779,14 +29779,9 @@ static tree
>   cp_parser_requires_clause_expression (cp_parser *parser, bool lambda_p)
>   {
>     processing_constraint_expression_sentinel parsing_constraint;
> -  temp_override<int> ovr (processing_template_decl);
> -  if (!processing_template_decl)
> -    /* Adjust processing_template_decl so that we always obtain template
> -       trees here.  We don't do the usual ++processing_template_decl
> -       because that would skew the template parameter depth of a lambda
> -       within if we're already inside a template.  */
> -    processing_template_decl = 1;
> +  ++processing_template_decl;
>     cp_expr expr = cp_parser_constraint_logical_or_expression (parser, lambda_p);
> +  --processing_template_decl;
>     if (check_for_bare_parameter_packs (expr))
>       expr = error_mark_node;
>     return expr;
> @@ -29805,12 +29800,10 @@ static tree
>   cp_parser_constraint_expression (cp_parser *parser)
>   {
>     processing_constraint_expression_sentinel parsing_constraint;
> -  temp_override<int> ovr (processing_template_decl);
> -  if (!processing_template_decl)
> -    /* As in cp_parser_requires_clause_expression.  */
> -    processing_template_decl = 1;
> +  ++processing_template_decl;
>     cp_expr expr = cp_parser_binary_expression (parser, false, true,
>   					      PREC_NOT_OPERATOR, NULL);
> +  --processing_template_decl;
>     if (check_for_bare_parameter_packs (expr))
>       expr = error_mark_node;
>     expr.maybe_add_location_wrapper ();
> @@ -29924,11 +29917,9 @@ cp_parser_requires_expression (cp_parser *parser)
>         parms = NULL_TREE;
>   
>       /* Parse the requirement body. */
> -    temp_override<int> ovr (processing_template_decl);
> -    if (!processing_template_decl)
> -      /* As in cp_parser_requires_clause_expression.  */
> -      processing_template_decl = 1;
> +    ++processing_template_decl;
>       reqs = cp_parser_requirement_body (parser);
> +    --processing_template_decl;
>       if (reqs == error_mark_node)
>         return error_mark_node;
>     }
> @@ -48091,6 +48082,10 @@ synthesize_implicit_template_parm  (cp_parser *parser, tree constr)
>     gcc_assert(!proto || TREE_CODE (proto) == TYPE_DECL);
>     synth_tmpl_parm = finish_template_type_parm (class_type_node, synth_id);
>   
> +  if (become_template)
> +    current_template_parms = tree_cons (size_int (current_template_depth + 1),
> +					NULL_TREE, current_template_parms);
> +
>     /* Attach the constraint to the parm before processing.  */
>     tree node = build_tree_list (NULL_TREE, synth_tmpl_parm);
>     TREE_TYPE (node) = constr;
> @@ -48130,8 +48125,7 @@ synthesize_implicit_template_parm  (cp_parser *parser, tree constr)
>   
>         tree new_parms = make_tree_vec (1);
>         TREE_VEC_ELT (new_parms, 0) = parser->implicit_template_parms;
> -      current_template_parms = tree_cons (size_int (processing_template_decl),
> -					  new_parms, current_template_parms);
> +      TREE_VALUE (current_template_parms) = new_parms;
>       }
>     else
>       {
> diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
> index 9834baf34db..fd41d4bd0bf 100644
> --- a/gcc/cp/pt.c
> +++ b/gcc/cp/pt.c
> @@ -448,7 +448,7 @@ inline_needs_template_parms (tree decl, bool nsdmi)
>       return false;
>   
>     return (TMPL_PARMS_DEPTH (DECL_TEMPLATE_PARMS (most_general_template (decl)))
> -	  > (processing_template_decl + DECL_TEMPLATE_SPECIALIZATION (decl)));
> +	  > (current_template_depth + DECL_TEMPLATE_SPECIALIZATION (decl)));
>   }
>   
>   /* Subroutine of maybe_begin_member_template_processing.
> @@ -467,7 +467,7 @@ push_inline_template_parms_recursive (tree parmlist, int levels)
>   
>     ++processing_template_decl;
>     current_template_parms
> -    = tree_cons (size_int (processing_template_decl),
> +    = tree_cons (size_int (current_template_depth + 1),
>   		 parms, current_template_parms);
>     TEMPLATE_PARMS_FOR_INLINE (current_template_parms) = 1;
>   
> @@ -523,7 +523,7 @@ maybe_begin_member_template_processing (tree decl)
>     if (inline_needs_template_parms (decl, nsdmi))
>       {
>         parms = DECL_TEMPLATE_PARMS (most_general_template (decl));
> -      levels = TMPL_PARMS_DEPTH (parms) - processing_template_decl;
> +      levels = TMPL_PARMS_DEPTH (parms) - current_template_depth;
>   
>         if (DECL_TEMPLATE_SPECIALIZATION (decl))
>   	{
> @@ -716,7 +716,7 @@ begin_template_parm_list (void)
>   
>     /* Add a dummy parameter level while we process the parameter list.  */
>     current_template_parms
> -    = tree_cons (size_int (processing_template_decl),
> +    = tree_cons (size_int (current_template_depth + 1),
>   		 make_tree_vec (0),
>   		 current_template_parms);
>   }
> @@ -4613,8 +4613,8 @@ process_template_parm (tree list, location_t parm_loc, tree parm,
>         TREE_CONSTANT (decl) = 1;
>         TREE_READONLY (decl) = 1;
>         DECL_INITIAL (parm) = DECL_INITIAL (decl)
> -	= build_template_parm_index (idx, processing_template_decl,
> -				     processing_template_decl,
> +	= build_template_parm_index (idx, current_template_depth,
> +				     current_template_depth,
>   				     decl, TREE_TYPE (parm));
>   
>         TEMPLATE_PARM_PARAMETER_PACK (DECL_INITIAL (parm))
> @@ -4655,8 +4655,8 @@ process_template_parm (tree list, location_t parm_loc, tree parm,
>         TYPE_STUB_DECL (t) = decl;
>         parm = decl;
>         TEMPLATE_TYPE_PARM_INDEX (t)
> -	= build_template_parm_index (idx, processing_template_decl,
> -				     processing_template_decl,
> +	= build_template_parm_index (idx, current_template_depth,
> +				     current_template_depth,
>   				     decl, TREE_TYPE (parm));
>         TEMPLATE_TYPE_PARAMETER_PACK (t) = is_parameter_pack;
>         if (TREE_CODE (t) == TEMPLATE_TEMPLATE_PARM)
> @@ -4705,7 +4705,7 @@ end_template_parm_list (tree parms)
>     current_template_parms = TREE_CHAIN (current_template_parms);
>   
>     current_template_parms
> -    = tree_cons (size_int (processing_template_decl),
> +    = tree_cons (size_int (current_template_depth + 1),
>   		 saved_parmlist, current_template_parms);
>   
>     for (unsigned ix = 0; parms; ix++)
> @@ -5747,7 +5747,7 @@ push_template_decl (tree decl, bool is_friend)
>     /* See if this is a primary template.  */
>     bool is_primary = false;
>     if (is_friend && ctx
> -      && uses_template_parms_level (ctx, processing_template_decl))
> +      && uses_template_parms_level (ctx, current_template_depth))
>       /* A friend template that specifies a class context, i.e.
>            template <typename T> friend void A<T>::f();
>          is not primary.  */
> @@ -6157,7 +6157,7 @@ add_inherited_template_parms (tree fn, tree inherited)
>       = INNERMOST_TEMPLATE_PARMS (DECL_TEMPLATE_PARMS (inherited));
>     inner_parms = copy_node (inner_parms);
>     tree parms
> -    = tree_cons (size_int (processing_template_decl + 1),
> +    = tree_cons (size_int (current_template_depth + 1),
>   		 inner_parms, current_template_parms);
>     tree tmpl = build_template_decl (fn, parms, /*member*/true);
>     tree args = template_parms_to_args (parms);
> @@ -12165,13 +12165,10 @@ instantiate_class_template_1 (tree type)
>   	      /* Build new CLASSTYPE_FRIEND_CLASSES.  */
>   
>   	      tree friend_type = t;
> -	      bool adjust_processing_template_decl = false;
> -
>   	      if (TREE_CODE (friend_type) == TEMPLATE_DECL)
>   		{
>   		  /* template <class T> friend class C;  */
>   		  friend_type = tsubst_friend_class (friend_type, args);
> -		  adjust_processing_template_decl = true;
>   		}
>   	      else if (TREE_CODE (friend_type) == UNBOUND_CLASS_TEMPLATE)
>   		{
> @@ -12180,7 +12177,6 @@ instantiate_class_template_1 (tree type)
>   					tf_warning_or_error, NULL_TREE);
>   		  if (TREE_CODE (friend_type) == TEMPLATE_DECL)
>   		    friend_type = TREE_TYPE (friend_type);
> -		  adjust_processing_template_decl = true;
>   		}
>   	      else if (TREE_CODE (friend_type) == TYPENAME_TYPE
>   		       || TREE_CODE (friend_type) == TEMPLATE_TYPE_PARM)
> @@ -12199,8 +12195,6 @@ instantiate_class_template_1 (tree type)
>   		  ++processing_template_decl;
>   		  friend_type = tsubst (friend_type, args,
>   					tf_warning_or_error, NULL_TREE);
> -		  if (dependent_type_p (friend_type))
> -		    adjust_processing_template_decl = true;
>   		  --processing_template_decl;
>   		}
>   	      else if (uses_template_parms (friend_type))
> @@ -12218,19 +12212,8 @@ instantiate_class_template_1 (tree type)
>   
>   		 We don't have to do anything in these cases.  */
>   
> -	      if (adjust_processing_template_decl)
> -		/* Trick make_friend_class into realizing that the friend
> -		   we're adding is a template, not an ordinary class.  It's
> -		   important that we use make_friend_class since it will
> -		   perform some error-checking and output cross-reference
> -		   information.  */
> -		++processing_template_decl;
> -
>   	      if (friend_type != error_mark_node)
>   		make_friend_class (type, friend_type, /*complain=*/false);
> -
> -	      if (adjust_processing_template_decl)
> -		--processing_template_decl;
>   	    }
>   	  else
>   	    {
> @@ -28417,7 +28400,7 @@ make_auto_1 (tree name, bool set_canonical)
>     TYPE_NAME (au) = build_decl (input_location, TYPE_DECL, name, au);
>     TYPE_STUB_DECL (au) = TYPE_NAME (au);
>     TEMPLATE_TYPE_PARM_INDEX (au) = build_template_parm_index
> -    (0, processing_template_decl + 1, processing_template_decl + 1,
> +    (0, current_template_depth + 1, current_template_depth + 1,
>        TYPE_NAME (au), NULL_TREE);
>     if (set_canonical)
>       TYPE_CANONICAL (au) = canonical_type_parameter (au);
> @@ -30070,7 +30053,7 @@ splice_late_return_type (tree type, tree late_return_type)
>       }
>   
>     if (tree auto_node = find_type_usage (type, is_auto))
> -    if (TEMPLATE_TYPE_LEVEL (auto_node) <= processing_template_decl)
> +    if (TEMPLATE_TYPE_LEVEL (auto_node) <= current_template_depth)
>         {
>   	/* In an abbreviated function template we didn't know we were dealing
>   	   with a function template when we saw the auto return type, so rebuild
> diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
> index cdf63c15e21..d8b20ff5b1b 100644
> --- a/gcc/cp/semantics.c
> +++ b/gcc/cp/semantics.c
> @@ -3629,7 +3629,7 @@ fixup_template_type (tree type)
>     // the scope we're trying to enter.
>     tree parms = current_template_parms;
>     int depth = template_class_depth (type);
> -  for (int n = processing_template_decl; n > depth && parms; --n)
> +  for (int n = current_template_depth; n > depth && parms; --n)
>       parms = TREE_CHAIN (parms);
>     if (!parms)
>       return type;
> diff --git a/gcc/testsuite/g++.dg/concepts/diagnostic18.C b/gcc/testsuite/g++.dg/concepts/diagnostic18.C
> index 79f371b8092..c13b0472a64 100644
> --- a/gcc/testsuite/g++.dg/concepts/diagnostic18.C
> +++ b/gcc/testsuite/g++.dg/concepts/diagnostic18.C
> @@ -1,7 +1,7 @@
>   // PR c++/100055
>   // { dg-do compile { target concepts } }
>   
> -void foo(auto&& arg) requires({}); // { dg-error "statement-expressions are not allowed|braced-groups" }
> +void foo(auto&& arg) requires({}); // { dg-error "statement-expressions are not allowed|braced-groups|non-templated" }
>   
>   template <auto = 0> requires ([]{}()); // { dg-error "expected unqualified-id" }
> -auto f() requires ([]{}());
> +auto f() requires ([]{}()); // { dg-error "constraints on a non-templated" }
> diff --git a/gcc/testsuite/g++.dg/cpp23/auto-fncast10.C b/gcc/testsuite/g++.dg/cpp23/auto-fncast10.C
> new file mode 100644
> index 00000000000..669dda14035
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp23/auto-fncast10.C
> @@ -0,0 +1,19 @@
> +// PR c++/103408
> +// { dg-do compile { target c++23 } }
> +
> +static_assert(requires { auto(0); });
> +static_assert(requires { auto{0}; });
> +
> +static_assert(requires { auto(auto(0)); });
> +static_assert(requires { auto{auto{0}}; });
> +
> +static_assert(requires { auto(auto(auto(0))); });
> +static_assert(requires { auto{auto{auto{0}}}; });
> +
> +static_assert(requires { requires auto(true); });
> +static_assert(requires { requires auto(auto(true)); });
> +
> +static_assert(!requires { requires auto(false); });
> +static_assert(!requires { requires auto(auto(false)); });
> +
> +auto f() requires (auto(false)); // { dg-error "constraints on non-templated" }
  
Jakub Jelinek Dec. 15, 2021, 10:22 a.m. UTC | #4
On Mon, Dec 13, 2021 at 04:28:26PM -0500, Patrick Palka via Gcc-patches wrote:
> 	* g++.dg/concepts/diagnostic18.C: Expect a "constraints on a
> 	non-templated function" error.
> 	* g++.dg/cpp23/auto-fncast10.C: New test.

This test fails:
+FAIL: g++.dg/cpp23/auto-fncast11.C  -std=c++2b  (test for errors, line 19)
+FAIL: g++.dg/cpp23/auto-fncast11.C  -std=c++2b (test for excess errors)
because the regex in dg-error was missing an indefinite article.

Tested with
GXX_TESTSUITE_STDS=98,11,14,17,20,2b make check-g++ RUNTESTFLAGS="dg.exp=auto-fncast11.C"
and committed to trunk as obvious:

2021-12-15  Jakub Jelinek  <jakub@redhat.com>

	PR c++/103408
	* g++.dg/cpp23/auto-fncast11.C: Fix expected diagnostic wording.

--- gcc/testsuite/g++.dg/cpp23/auto-fncast11.C.jj	2021-12-14 18:40:21.399133909 +0100
+++ gcc/testsuite/g++.dg/cpp23/auto-fncast11.C	2021-12-15 11:16:36.401592355 +0100
@@ -16,4 +16,4 @@ static_assert(requires { requires auto(a
 static_assert(!requires { requires auto(false); });
 static_assert(!requires { requires auto(auto(false)); });
 
-auto f() requires (auto(false)); // { dg-error "constraints on non-templated" }
+auto f() requires (auto(false)); // { dg-error "constraints on a non-templated" }


	Jakub
  
Patrick Palka Dec. 15, 2021, 1:58 p.m. UTC | #5
On Wed, 15 Dec 2021, Jakub Jelinek wrote:

> On Mon, Dec 13, 2021 at 04:28:26PM -0500, Patrick Palka via Gcc-patches wrote:
> > 	* g++.dg/concepts/diagnostic18.C: Expect a "constraints on a
> > 	non-templated function" error.
> > 	* g++.dg/cpp23/auto-fncast10.C: New test.
> 
> This test fails:
> +FAIL: g++.dg/cpp23/auto-fncast11.C  -std=c++2b  (test for errors, line 19)
> +FAIL: g++.dg/cpp23/auto-fncast11.C  -std=c++2b (test for excess errors)
> because the regex in dg-error was missing an indefinite article.
> 
> Tested with
> GXX_TESTSUITE_STDS=98,11,14,17,20,2b make check-g++ RUNTESTFLAGS="dg.exp=auto-fncast11.C"
> and committed to trunk as obvious:

Oops, thanks Jakub, I didn't realize we don't run the testsuite with
-std=c++23 yet.

I guess it'd be too expensive to add another std to the testing matrix
at this point, but I wonder if the test harness should at least run the
testcases inside cpp23/ with -std=c++23?  Something like the following
seems to work.

(And since -std=c++11 also isn't part of the default testing matrix
anymore, perhaps we could give the testscases inside cpp0x/ a similar
treatment too?)

-- >8 --

Subject: [PATCH] testsuite: run testcases in g++.dg/cpp23/ with -std=c++23

gcc/testsuite/ChangeLog:

	* lib/g++-dg.exp (g++-dg-runtest): Add -std=c++23 to option_list
	for testcases in cpp23/.
---
 gcc/testsuite/lib/g++-dg.exp | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/gcc/testsuite/lib/g++-dg.exp b/gcc/testsuite/lib/g++-dg.exp
index fd06d278faa..79fe3db014e 100644
--- a/gcc/testsuite/lib/g++-dg.exp
+++ b/gcc/testsuite/lib/g++-dg.exp
@@ -38,6 +38,8 @@ proc g++-dg-runtest { testcases flags default-extra-flags } {
 	    continue
 	}
 
+	set nshort [file tail [file dirname $test]]/[file tail $test]
+
 	# If the testcase specifies a standard, use that one.
 	# If not, run it under both standards, allowing GNU extensions
 	# if there's a dg-options line.
@@ -61,12 +63,13 @@ proc g++-dg-runtest { testcases flags default-extra-flags } {
 		} elseif { $x eq "impcx" } then { set x "23 -fimplicit-constexpr" }
 		lappend option_list "${std_prefix}$x"
 	    }
+	    if [string match "cpp23/*" $nshort] {
+		lappend option_list "${std_prefix}23"
+	    }
 	} else {
 	    set option_list { "" }
 	}
 
-	set nshort [file tail [file dirname $test]]/[file tail $test]
-
 	foreach flags_t $option_list {
 	    verbose "Testing $nshort, $flags $flags_t" 1
 	    dg-test $test "$flags $flags_t" ${default-extra-flags}
  
Jakub Jelinek Dec. 15, 2021, 2:09 p.m. UTC | #6
On Wed, Dec 15, 2021 at 08:58:45AM -0500, Patrick Palka wrote:
> Oops, thanks Jakub, I didn't realize we don't run the testsuite with
> -std=c++23 yet.
> 
> I guess it'd be too expensive to add another std to the testing matrix
> at this point, but I wonder if the test harness should at least run the
> testcases inside cpp23/ with -std=c++23?  Something like the following
> seems to work.
> 
> (And since -std=c++11 also isn't part of the default testing matrix
> anymore, perhaps we could give the testscases inside cpp0x/ a similar
> treatment too?)

I think up to Jason, but I'd say if we do it, we should do it for all those
language version subdirectories and make sure we only add those extra modes
temporarily (for that subdir files only) and only if they aren't already
present in the list we cycle through (to avoid running it e.g. with
-std=c++23 twice).

> Subject: [PATCH] testsuite: run testcases in g++.dg/cpp23/ with -std=c++23
> 
> gcc/testsuite/ChangeLog:
> 
> 	* lib/g++-dg.exp (g++-dg-runtest): Add -std=c++23 to option_list
> 	for testcases in cpp23/.
> ---
>  gcc/testsuite/lib/g++-dg.exp | 7 +++++--
>  1 file changed, 5 insertions(+), 2 deletions(-)
> 
> diff --git a/gcc/testsuite/lib/g++-dg.exp b/gcc/testsuite/lib/g++-dg.exp
> index fd06d278faa..79fe3db014e 100644
> --- a/gcc/testsuite/lib/g++-dg.exp
> +++ b/gcc/testsuite/lib/g++-dg.exp
> @@ -38,6 +38,8 @@ proc g++-dg-runtest { testcases flags default-extra-flags } {
>  	    continue
>  	}
>  
> +	set nshort [file tail [file dirname $test]]/[file tail $test]
> +
>  	# If the testcase specifies a standard, use that one.
>  	# If not, run it under both standards, allowing GNU extensions
>  	# if there's a dg-options line.
> @@ -61,12 +63,13 @@ proc g++-dg-runtest { testcases flags default-extra-flags } {
>  		} elseif { $x eq "impcx" } then { set x "23 -fimplicit-constexpr" }
>  		lappend option_list "${std_prefix}$x"
>  	    }
> +	    if [string match "cpp23/*" $nshort] {
> +		lappend option_list "${std_prefix}23"
> +	    }
>  	} else {
>  	    set option_list { "" }
>  	}
>  
> -	set nshort [file tail [file dirname $test]]/[file tail $test]
> -
>  	foreach flags_t $option_list {
>  	    verbose "Testing $nshort, $flags $flags_t" 1
>  	    dg-test $test "$flags $flags_t" ${default-extra-flags}

	Jakub
  
Jason Merrill Dec. 15, 2021, 10:03 p.m. UTC | #7
On 12/15/21 09:09, Jakub Jelinek wrote:
> On Wed, Dec 15, 2021 at 08:58:45AM -0500, Patrick Palka wrote:
>> Oops, thanks Jakub, I didn't realize we don't run the testsuite with
>> -std=c++23 yet.
>>
>> I guess it'd be too expensive to add another std to the testing matrix
>> at this point, but I wonder if the test harness should at least run the
>> testcases inside cpp23/ with -std=c++23?  Something like the following
>> seems to work.
>>
>> (And since -std=c++11 also isn't part of the default testing matrix
>> anymore, perhaps we could give the testscases inside cpp0x/ a similar
>> treatment too?)
> 
> I think up to Jason, but I'd say if we do it, we should do it for all those
> language version subdirectories and make sure we only add those extra modes
> temporarily (for that subdir files only) and only if they aren't already
> present in the list we cycle through (to avoid running it e.g. with
> -std=c++23 twice).

Sounds good.

Note that there's also the 'check-c++-all' make target to run the full 
set of standards.

>> Subject: [PATCH] testsuite: run testcases in g++.dg/cpp23/ with -std=c++23
>>
>> gcc/testsuite/ChangeLog:
>>
>> 	* lib/g++-dg.exp (g++-dg-runtest): Add -std=c++23 to option_list
>> 	for testcases in cpp23/.
>> ---
>>   gcc/testsuite/lib/g++-dg.exp | 7 +++++--
>>   1 file changed, 5 insertions(+), 2 deletions(-)
>>
>> diff --git a/gcc/testsuite/lib/g++-dg.exp b/gcc/testsuite/lib/g++-dg.exp
>> index fd06d278faa..79fe3db014e 100644
>> --- a/gcc/testsuite/lib/g++-dg.exp
>> +++ b/gcc/testsuite/lib/g++-dg.exp
>> @@ -38,6 +38,8 @@ proc g++-dg-runtest { testcases flags default-extra-flags } {
>>   	    continue
>>   	}
>>   
>> +	set nshort [file tail [file dirname $test]]/[file tail $test]
>> +
>>   	# If the testcase specifies a standard, use that one.
>>   	# If not, run it under both standards, allowing GNU extensions
>>   	# if there's a dg-options line.
>> @@ -61,12 +63,13 @@ proc g++-dg-runtest { testcases flags default-extra-flags } {
>>   		} elseif { $x eq "impcx" } then { set x "23 -fimplicit-constexpr" }
>>   		lappend option_list "${std_prefix}$x"
>>   	    }
>> +	    if [string match "cpp23/*" $nshort] {
>> +		lappend option_list "${std_prefix}23"
>> +	    }
>>   	} else {
>>   	    set option_list { "" }
>>   	}
>>   
>> -	set nshort [file tail [file dirname $test]]/[file tail $test]
>> -
>>   	foreach flags_t $option_list {
>>   	    verbose "Testing $nshort, $flags $flags_t" 1
>>   	    dg-test $test "$flags $flags_t" ${default-extra-flags}
> 
> 	Jakub
>
  

Patch

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 2896efdd7f2..566f4e38fac 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -2016,14 +2016,6 @@  type_deducible_p (tree expr, tree type, tree placeholder, tree args,
      references are preserved in the result.  */
   expr = force_paren_expr_uneval (expr);
 
-  /* When args is NULL, we're evaluating a non-templated requires expression,
-     but even those are parsed under processing_template_decl == 1, and so the
-     placeholder 'auto' inside this return-type-requirement has level 2.  In
-     order to have all parms and arguments match up for satisfaction, we need
-     to pass an empty level of OUTER_TARGS in this case.  */
-  if (!args)
-    args = make_tree_vec (0);
-
   tree deduced_type = do_auto_deduction (type, expr, placeholder,
 					 info.complain, adc_requirement,
 					 /*outer_targs=*/args);
@@ -3064,14 +3056,6 @@  normalize_placeholder_type_constraints (tree t, bool diag)
      parameters for normalization.  */
   tree initial_parms = TREE_PURPOSE (ci);
 
-  if (!initial_parms && TEMPLATE_TYPE_LEVEL (t) == 2)
-    /* This is a return-type-requirement of a non-templated requires-expression,
-       which are parsed under processing_template_decl == 1 and empty
-       current_template_parms; hence the 'auto' has level 2 and initial_parms
-       is empty.  Fix up initial_parms to be consistent with the value of
-       processing_template_decl whence the 'auto' was created.  */
-    initial_parms = build_tree_list (size_int (1), make_tree_vec (0));
-
   /* The 'auto' itself is used as the first argument in its own constraints,
      and its level is one greater than its template depth.  So in order to
      capture all used template parameters, we need to add an extra level of
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index b1c3bc5ed1f..9e10a947a43 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -1887,6 +1887,8 @@  extern GTY(()) struct saved_scope *scope_chain;
    stored in the TREE_VALUE.  */
 
 #define current_template_parms scope_chain->template_parms
+#define current_template_depth \
+  (current_template_parms ? TMPL_PARMS_DEPTH (current_template_parms) : 0)
 
 #define processing_template_decl scope_chain->x_processing_template_decl
 #define processing_specialization scope_chain->x_processing_specialization
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 56f80775ca0..7c2048c6acb 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -5567,7 +5567,7 @@  start_decl (const cp_declarator *declarator,
 
   if (TYPE_P (context) && COMPLETE_TYPE_P (complete_type (context)))
     {
-      bool this_tmpl = (processing_template_decl
+      bool this_tmpl = (current_template_depth
 			> template_class_depth (context));
       if (VAR_P (decl))
 	{
@@ -9878,7 +9878,7 @@  grokfndecl (tree ctype,
       tree ctx = friendp ? current_class_type : ctype;
       bool block_local = TREE_CODE (current_scope ()) == FUNCTION_DECL;
       bool memtmpl = (!block_local
-		      && (processing_template_decl
+		      && (current_template_depth
 			  > template_class_depth (ctx)));
       if (memtmpl)
 	{
@@ -10300,7 +10300,7 @@  grokfndecl (tree ctype,
   if (ctype != NULL_TREE && check)
     {
       tree old_decl = check_classfn (ctype, decl,
-				     (processing_template_decl
+				     (current_template_depth
 				      > template_class_depth (ctype))
 				     ? current_template_parms
 				     : NULL_TREE);
@@ -10576,7 +10576,7 @@  grokvardecl (tree type,
         }
     }
   else if (flag_concepts
-	   && processing_template_decl > template_class_depth (scope))
+	   && current_template_depth > template_class_depth (scope))
     {
       tree reqs = TEMPLATE_PARMS_CONSTRAINTS (current_template_parms);
       tree ci = build_constraints (reqs, NULL_TREE);
@@ -13975,7 +13975,7 @@  grokdeclarator (const cp_declarator *declarator,
 		  }
 
 		/* Set the constraints on the declaration.  */
-		bool memtmpl = (processing_template_decl
+		bool memtmpl = (current_template_depth
 				> template_class_depth (current_class_type));
 		if (memtmpl)
 		  {
diff --git a/gcc/cp/friend.c b/gcc/cp/friend.c
index 4f6288414d9..e970fdce0cc 100644
--- a/gcc/cp/friend.c
+++ b/gcc/cp/friend.c
@@ -261,7 +261,7 @@  make_friend_class (tree type, tree friend_type, bool complain)
      The friend is a template friend iff FRIEND_DEPTH is nonzero.  */
 
   int class_template_depth = template_class_depth (type);
-  int friend_depth = processing_template_decl - class_template_depth;
+  int friend_depth = current_template_depth - class_template_depth;
 
   if (! MAYBE_CLASS_TYPE_P (friend_type)
       && TREE_CODE (friend_type) != TEMPLATE_TEMPLATE_PARM)
@@ -517,7 +517,7 @@  do_friend (tree ctype, tree declarator, tree decl,
 	 3. TEMPLATE_MEMBER_P is true (for `W').  */
 
       int class_template_depth = template_class_depth (current_class_type);
-      int friend_depth = processing_template_decl - class_template_depth;
+      int friend_depth = current_template_depth - class_template_depth;
       /* We will figure this out later.  */
       bool template_member_p = false;
 
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index de464afdb54..aedfab209ba 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -29779,14 +29779,9 @@  static tree
 cp_parser_requires_clause_expression (cp_parser *parser, bool lambda_p)
 {
   processing_constraint_expression_sentinel parsing_constraint;
-  temp_override<int> ovr (processing_template_decl);
-  if (!processing_template_decl)
-    /* Adjust processing_template_decl so that we always obtain template
-       trees here.  We don't do the usual ++processing_template_decl
-       because that would skew the template parameter depth of a lambda
-       within if we're already inside a template.  */
-    processing_template_decl = 1;
+  ++processing_template_decl;
   cp_expr expr = cp_parser_constraint_logical_or_expression (parser, lambda_p);
+  --processing_template_decl;
   if (check_for_bare_parameter_packs (expr))
     expr = error_mark_node;
   return expr;
@@ -29805,12 +29800,10 @@  static tree
 cp_parser_constraint_expression (cp_parser *parser)
 {
   processing_constraint_expression_sentinel parsing_constraint;
-  temp_override<int> ovr (processing_template_decl);
-  if (!processing_template_decl)
-    /* As in cp_parser_requires_clause_expression.  */
-    processing_template_decl = 1;
+  ++processing_template_decl;
   cp_expr expr = cp_parser_binary_expression (parser, false, true,
 					      PREC_NOT_OPERATOR, NULL);
+  --processing_template_decl;
   if (check_for_bare_parameter_packs (expr))
     expr = error_mark_node;
   expr.maybe_add_location_wrapper ();
@@ -29924,11 +29917,9 @@  cp_parser_requires_expression (cp_parser *parser)
       parms = NULL_TREE;
 
     /* Parse the requirement body. */
-    temp_override<int> ovr (processing_template_decl);
-    if (!processing_template_decl)
-      /* As in cp_parser_requires_clause_expression.  */
-      processing_template_decl = 1;
+    ++processing_template_decl;
     reqs = cp_parser_requirement_body (parser);
+    --processing_template_decl;
     if (reqs == error_mark_node)
       return error_mark_node;
   }
@@ -48091,6 +48082,10 @@  synthesize_implicit_template_parm  (cp_parser *parser, tree constr)
   gcc_assert(!proto || TREE_CODE (proto) == TYPE_DECL);
   synth_tmpl_parm = finish_template_type_parm (class_type_node, synth_id);
 
+  if (become_template)
+    current_template_parms = tree_cons (size_int (current_template_depth + 1),
+					NULL_TREE, current_template_parms);
+
   /* Attach the constraint to the parm before processing.  */
   tree node = build_tree_list (NULL_TREE, synth_tmpl_parm);
   TREE_TYPE (node) = constr;
@@ -48130,8 +48125,7 @@  synthesize_implicit_template_parm  (cp_parser *parser, tree constr)
 
       tree new_parms = make_tree_vec (1);
       TREE_VEC_ELT (new_parms, 0) = parser->implicit_template_parms;
-      current_template_parms = tree_cons (size_int (processing_template_decl),
-					  new_parms, current_template_parms);
+      TREE_VALUE (current_template_parms) = new_parms;
     }
   else
     {
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 9834baf34db..85294f72ba6 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -448,7 +448,7 @@  inline_needs_template_parms (tree decl, bool nsdmi)
     return false;
 
   return (TMPL_PARMS_DEPTH (DECL_TEMPLATE_PARMS (most_general_template (decl)))
-	  > (processing_template_decl + DECL_TEMPLATE_SPECIALIZATION (decl)));
+	  > (current_template_depth + DECL_TEMPLATE_SPECIALIZATION (decl)));
 }
 
 /* Subroutine of maybe_begin_member_template_processing.
@@ -467,7 +467,7 @@  push_inline_template_parms_recursive (tree parmlist, int levels)
 
   ++processing_template_decl;
   current_template_parms
-    = tree_cons (size_int (processing_template_decl),
+    = tree_cons (size_int (current_template_depth + 1),
 		 parms, current_template_parms);
   TEMPLATE_PARMS_FOR_INLINE (current_template_parms) = 1;
 
@@ -523,7 +523,7 @@  maybe_begin_member_template_processing (tree decl)
   if (inline_needs_template_parms (decl, nsdmi))
     {
       parms = DECL_TEMPLATE_PARMS (most_general_template (decl));
-      levels = TMPL_PARMS_DEPTH (parms) - processing_template_decl;
+      levels = TMPL_PARMS_DEPTH (parms) - current_template_depth;
 
       if (DECL_TEMPLATE_SPECIALIZATION (decl))
 	{
@@ -716,7 +716,7 @@  begin_template_parm_list (void)
 
   /* Add a dummy parameter level while we process the parameter list.  */
   current_template_parms
-    = tree_cons (size_int (processing_template_decl),
+    = tree_cons (size_int (current_template_depth + 1),
 		 make_tree_vec (0),
 		 current_template_parms);
 }
@@ -4613,8 +4613,8 @@  process_template_parm (tree list, location_t parm_loc, tree parm,
       TREE_CONSTANT (decl) = 1;
       TREE_READONLY (decl) = 1;
       DECL_INITIAL (parm) = DECL_INITIAL (decl)
-	= build_template_parm_index (idx, processing_template_decl,
-				     processing_template_decl,
+	= build_template_parm_index (idx, current_template_depth,
+				     current_template_depth,
 				     decl, TREE_TYPE (parm));
 
       TEMPLATE_PARM_PARAMETER_PACK (DECL_INITIAL (parm))
@@ -4655,8 +4655,8 @@  process_template_parm (tree list, location_t parm_loc, tree parm,
       TYPE_STUB_DECL (t) = decl;
       parm = decl;
       TEMPLATE_TYPE_PARM_INDEX (t)
-	= build_template_parm_index (idx, processing_template_decl,
-				     processing_template_decl,
+	= build_template_parm_index (idx, current_template_depth,
+				     current_template_depth,
 				     decl, TREE_TYPE (parm));
       TEMPLATE_TYPE_PARAMETER_PACK (t) = is_parameter_pack;
       if (TREE_CODE (t) == TEMPLATE_TEMPLATE_PARM)
@@ -4705,7 +4705,7 @@  end_template_parm_list (tree parms)
   current_template_parms = TREE_CHAIN (current_template_parms);
 
   current_template_parms
-    = tree_cons (size_int (processing_template_decl),
+    = tree_cons (size_int (current_template_depth + 1),
 		 saved_parmlist, current_template_parms);
 
   for (unsigned ix = 0; parms; ix++)
@@ -6157,7 +6157,7 @@  add_inherited_template_parms (tree fn, tree inherited)
     = INNERMOST_TEMPLATE_PARMS (DECL_TEMPLATE_PARMS (inherited));
   inner_parms = copy_node (inner_parms);
   tree parms
-    = tree_cons (size_int (processing_template_decl + 1),
+    = tree_cons (size_int (current_template_depth + 1),
 		 inner_parms, current_template_parms);
   tree tmpl = build_template_decl (fn, parms, /*member*/true);
   tree args = template_parms_to_args (parms);
@@ -12165,13 +12165,13 @@  instantiate_class_template_1 (tree type)
 	      /* Build new CLASSTYPE_FRIEND_CLASSES.  */
 
 	      tree friend_type = t;
-	      bool adjust_processing_template_decl = false;
+	      bool adjust_template_depth = false;
 
 	      if (TREE_CODE (friend_type) == TEMPLATE_DECL)
 		{
 		  /* template <class T> friend class C;  */
 		  friend_type = tsubst_friend_class (friend_type, args);
-		  adjust_processing_template_decl = true;
+		  adjust_template_depth = true;
 		}
 	      else if (TREE_CODE (friend_type) == UNBOUND_CLASS_TEMPLATE)
 		{
@@ -12180,7 +12180,7 @@  instantiate_class_template_1 (tree type)
 					tf_warning_or_error, NULL_TREE);
 		  if (TREE_CODE (friend_type) == TEMPLATE_DECL)
 		    friend_type = TREE_TYPE (friend_type);
-		  adjust_processing_template_decl = true;
+		  adjust_template_depth = true;
 		}
 	      else if (TREE_CODE (friend_type) == TYPENAME_TYPE
 		       || TREE_CODE (friend_type) == TEMPLATE_TYPE_PARM)
@@ -12200,7 +12200,7 @@  instantiate_class_template_1 (tree type)
 		  friend_type = tsubst (friend_type, args,
 					tf_warning_or_error, NULL_TREE);
 		  if (dependent_type_p (friend_type))
-		    adjust_processing_template_decl = true;
+		    adjust_template_depth = true;
 		  --processing_template_decl;
 		}
 	      else if (uses_template_parms (friend_type))
@@ -12218,19 +12218,23 @@  instantiate_class_template_1 (tree type)
 
 		 We don't have to do anything in these cases.  */
 
-	      if (adjust_processing_template_decl)
-		/* Trick make_friend_class into realizing that the friend
-		   we're adding is a template, not an ordinary class.  It's
-		   important that we use make_friend_class since it will
-		   perform some error-checking and output cross-reference
-		   information.  */
-		++processing_template_decl;
+	      if (adjust_template_depth)
+		{
+		  /* Trick make_friend_class into realizing that the friend
+		     we're adding is a template, not an ordinary class.  It's
+		     important that we use make_friend_class since it will
+		     perform some error-checking and output cross-reference
+		     information.  */
+		  gcc_assert (!current_template_parms);
+		  current_template_parms
+		    = build_tree_list (size_int (1), make_tree_vec (0));
+		}
 
 	      if (friend_type != error_mark_node)
 		make_friend_class (type, friend_type, /*complain=*/false);
 
-	      if (adjust_processing_template_decl)
-		--processing_template_decl;
+	      if (adjust_template_depth)
+		current_template_parms = TREE_CHAIN (current_template_parms);
 	    }
 	  else
 	    {
@@ -28417,7 +28421,7 @@  make_auto_1 (tree name, bool set_canonical)
   TYPE_NAME (au) = build_decl (input_location, TYPE_DECL, name, au);
   TYPE_STUB_DECL (au) = TYPE_NAME (au);
   TEMPLATE_TYPE_PARM_INDEX (au) = build_template_parm_index
-    (0, processing_template_decl + 1, processing_template_decl + 1,
+    (0, current_template_depth + 1, current_template_depth + 1,
      TYPE_NAME (au), NULL_TREE);
   if (set_canonical)
     TYPE_CANONICAL (au) = canonical_type_parameter (au);
@@ -30070,7 +30074,7 @@  splice_late_return_type (tree type, tree late_return_type)
     }
 
   if (tree auto_node = find_type_usage (type, is_auto))
-    if (TEMPLATE_TYPE_LEVEL (auto_node) <= processing_template_decl)
+    if (TEMPLATE_TYPE_LEVEL (auto_node) <= current_template_depth)
       {
 	/* In an abbreviated function template we didn't know we were dealing
 	   with a function template when we saw the auto return type, so rebuild
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index cdf63c15e21..d8b20ff5b1b 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -3629,7 +3629,7 @@  fixup_template_type (tree type)
   // the scope we're trying to enter.
   tree parms = current_template_parms;
   int depth = template_class_depth (type);
-  for (int n = processing_template_decl; n > depth && parms; --n)
+  for (int n = current_template_depth; n > depth && parms; --n)
     parms = TREE_CHAIN (parms);
   if (!parms)
     return type;
diff --git a/gcc/testsuite/g++.dg/concepts/diagnostic18.C b/gcc/testsuite/g++.dg/concepts/diagnostic18.C
index 79f371b8092..4ac706f8e2d 100644
--- a/gcc/testsuite/g++.dg/concepts/diagnostic18.C
+++ b/gcc/testsuite/g++.dg/concepts/diagnostic18.C
@@ -4,4 +4,4 @@ 
 void foo(auto&& arg) requires({}); // { dg-error "statement-expressions are not allowed|braced-groups" }
 
 template <auto = 0> requires ([]{}()); // { dg-error "expected unqualified-id" }
-auto f() requires ([]{}());
+auto f() requires ([]{}()); // { dg-error "constraints on a non-templated" }
diff --git a/gcc/testsuite/g++.dg/cpp23/auto-fncast10.C b/gcc/testsuite/g++.dg/cpp23/auto-fncast10.C
new file mode 100644
index 00000000000..669dda14035
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp23/auto-fncast10.C
@@ -0,0 +1,19 @@ 
+// PR c++/103408
+// { dg-do compile { target c++23 } }
+
+static_assert(requires { auto(0); });
+static_assert(requires { auto{0}; });
+
+static_assert(requires { auto(auto(0)); });
+static_assert(requires { auto{auto{0}}; });
+
+static_assert(requires { auto(auto(auto(0))); });
+static_assert(requires { auto{auto{auto{0}}}; });
+
+static_assert(requires { requires auto(true); });
+static_assert(requires { requires auto(auto(true)); });
+
+static_assert(!requires { requires auto(false); });
+static_assert(!requires { requires auto(auto(false)); });
+
+auto f() requires (auto(false)); // { dg-error "constraints on non-templated" }