public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH] c++: constrained auto in lambda using outer tparms [PR103706]
@ 2022-02-02 17:09 Patrick Palka
  2022-02-02 18:21 ` Patrick Palka
  0 siblings, 1 reply; 4+ messages in thread
From: Patrick Palka @ 2022-02-02 17:09 UTC (permalink / raw)
  To: gcc-patches

Here we're crashing during satisfaction of the lambda's placeholder type
constraints because the constraints depend on the template arguments
from the enclosing scope, which aren't a part of the lambda's
DECL_TI_ARGS.  So when inside a lambda, do_auto_deduction needs to add
the "regenerating" template arguments to the set of outer template
arguments, like we already do in satisfy_declaration_constraints.

Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
trunk and perhaps 11?

	PR c++/103706

gcc/cp/ChangeLog:

	* constraint.cc (satisfy_declaration_constraints): Use
	lambda_regenerating_args instead.
	* cp-tree.h (lambda_regenerating_args): Declare.
	* pt.cc (add_to_template_args): Handle NULL_TREE extra_args
	gracefully.
	(lambda_regenerating_args): Define, split out from
	satisfy_declaration_constraints.
	(do_auto_deduction): Use lambda_regenerating_args to obtain the
	full set of outer template arguments when checking the
	constraint on a placeholder type within a lambda.

gcc/testsuite/ChangeLog:

	* g++.dg/cpp2a/concepts-lambda18.C: New test.
---
 gcc/cp/constraint.cc                          |  9 +----
 gcc/cp/cp-tree.h                              |  1 +
 gcc/cp/pt.cc                                  | 37 ++++++++++++++++---
 .../g++.dg/cpp2a/concepts-lambda18.C          | 14 +++++++
 4 files changed, 48 insertions(+), 13 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-lambda18.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index cc4df4216ef..c41ee02b910 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3148,18 +3148,13 @@ satisfy_declaration_constraints (tree t, sat_info info)
 	args = add_outermost_template_args (args, inh_ctor_targs);
     }
 
-  if (regenerated_lambda_fn_p (t))
+  if (LAMBDA_FUNCTION_P (t))
     {
       /* The TI_ARGS of a regenerated lambda contains only the innermost
 	 set of template arguments.  Augment this with the outer template
 	 arguments that were used to regenerate the lambda.  */
       gcc_assert (!args || TMPL_ARGS_DEPTH (args) == 1);
-      tree lambda = CLASSTYPE_LAMBDA_EXPR (DECL_CONTEXT (t));
-      tree outer_args = TI_ARGS (LAMBDA_EXPR_REGEN_INFO (lambda));
-      if (args)
-	args = add_to_template_args (outer_args, args);
-      else
-	args = outer_args;
+      args = add_to_template_args (lambda_regenerating_args (t), args);
     }
 
   /* If any arguments depend on template parameters, we can't
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index b9eb71fbc3a..7a7fe5ba599 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -7715,6 +7715,7 @@ extern void finish_lambda_scope			(void);
 extern tree start_lambda_function		(tree fn, tree lambda_expr);
 extern void finish_lambda_function		(tree body);
 extern bool regenerated_lambda_fn_p		(tree);
+extern tree lambda_regenerating_args		(tree);
 extern tree most_general_lambda			(tree);
 extern tree finish_omp_target			(location_t, tree, tree, bool);
 extern void finish_omp_target_clauses		(location_t, tree, tree *);
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 6e129da1d05..c919d2de68f 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -573,6 +573,9 @@ add_to_template_args (tree args, tree extra_args)
   if (args == NULL_TREE || extra_args == error_mark_node)
     return extra_args;
 
+  if (extra_args == NULL_TREE)
+    return args;
+
   extra_depth = TMPL_ARGS_DEPTH (extra_args);
   new_args = make_tree_vec (TMPL_ARGS_DEPTH (args) + extra_depth);
 
@@ -14442,6 +14445,21 @@ most_general_lambda (tree t)
   return t;
 }
 
+/* Return the set of template arguments used to regenerate the lambda T
+   from its most general lambda.  */
+
+tree
+lambda_regenerating_args (tree t)
+{
+  if (LAMBDA_FUNCTION_P (t))
+    t = CLASSTYPE_LAMBDA_EXPR (DECL_CONTEXT (t));
+  gcc_assert (TREE_CODE (t) == LAMBDA_EXPR);
+  if (tree ti = LAMBDA_EXPR_REGEN_INFO (t))
+    return TI_ARGS (ti);
+  else
+    return NULL_TREE;
+}
+
 /* We're instantiating a variable from template function TCTX.  Return the
    corresponding current enclosing scope.  We can match them up using
    DECL_SOURCE_LOCATION because lambdas only ever have one source location, and
@@ -30100,12 +30118,19 @@ do_auto_deduction (tree type, tree init, tree auto_node,
 	    return type;
 	}
 
-      if ((context == adc_return_type
-	   || context == adc_variable_type
-	   || context == adc_decomp_type)
-	  && current_function_decl
-	  && DECL_TEMPLATE_INFO (current_function_decl))
-	outer_targs = DECL_TI_ARGS (current_function_decl);
+      if (context == adc_return_type
+	  || context == adc_variable_type
+	  || context == adc_decomp_type)
+	if (tree fn = current_function_decl)
+	  if (DECL_TEMPLATE_INFO (fn) || LAMBDA_FUNCTION_P (fn))
+	    {
+	      outer_targs
+		= DECL_TEMPLATE_INFO (fn) ? DECL_TI_ARGS (fn) : NULL_TREE;
+	      if (LAMBDA_FUNCTION_P (fn))
+		/* As in satisfy_declaration_constraints.  */
+		outer_targs = add_to_template_args (lambda_regenerating_args (fn),
+						    outer_targs);
+	    }
 
       tree full_targs = add_to_template_args (outer_targs, targs);
 
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-lambda18.C b/gcc/testsuite/g++.dg/cpp2a/concepts-lambda18.C
new file mode 100644
index 00000000000..0e883c2039d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-lambda18.C
@@ -0,0 +1,14 @@
+// PR c++/103706
+// { dg-do compile { target c++20 } }
+
+template<class T, class U> concept C = __is_same(T, int) && __is_same(U, int);
+
+template<class T> void f() {
+  []() -> C<T> auto {
+    C<T> auto x = T(); // { dg-error "constraints" }
+    return T(); // { dg-error "constraints" }
+  }();
+}
+
+template void f<int>(); // { dg-bogus "" }
+template void f<char>(); // { dg-message "required from here" }
-- 
2.35.0


^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH] c++: constrained auto in lambda using outer tparms [PR103706]
  2022-02-02 17:09 [PATCH] c++: constrained auto in lambda using outer tparms [PR103706] Patrick Palka
@ 2022-02-02 18:21 ` Patrick Palka
  2022-02-02 20:48   ` Jason Merrill
  0 siblings, 1 reply; 4+ messages in thread
From: Patrick Palka @ 2022-02-02 18:21 UTC (permalink / raw)
  To: Patrick Palka; +Cc: gcc-patches, jason

On Wed, 2 Feb 2022, Patrick Palka wrote:

> Here we're crashing during satisfaction of the lambda's placeholder type
> constraints because the constraints depend on the template arguments
> from the enclosing scope, which aren't a part of the lambda's
> DECL_TI_ARGS.  So when inside a lambda, do_auto_deduction needs to add
> the "regenerating" template arguments to the set of outer template
> arguments, like we already do in satisfy_declaration_constraints.
> 
> Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
> trunk and perhaps 11?
> 
> 	PR c++/103706
> 
> gcc/cp/ChangeLog:
> 
> 	* constraint.cc (satisfy_declaration_constraints): Use
> 	lambda_regenerating_args instead.
> 	* cp-tree.h (lambda_regenerating_args): Declare.
> 	* pt.cc (add_to_template_args): Handle NULL_TREE extra_args
> 	gracefully.
> 	(lambda_regenerating_args): Define, split out from
> 	satisfy_declaration_constraints.
> 	(do_auto_deduction): Use lambda_regenerating_args to obtain the
> 	full set of outer template arguments when checking the
> 	constraint on a placeholder type within a lambda.
> 
> gcc/testsuite/ChangeLog:
> 
> 	* g++.dg/cpp2a/concepts-lambda18.C: New test.
> ---
>  gcc/cp/constraint.cc                          |  9 +----
>  gcc/cp/cp-tree.h                              |  1 +
>  gcc/cp/pt.cc                                  | 37 ++++++++++++++++---
>  .../g++.dg/cpp2a/concepts-lambda18.C          | 14 +++++++
>  4 files changed, 48 insertions(+), 13 deletions(-)
>  create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-lambda18.C
> 
> diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
> index cc4df4216ef..c41ee02b910 100644
> --- a/gcc/cp/constraint.cc
> +++ b/gcc/cp/constraint.cc
> @@ -3148,18 +3148,13 @@ satisfy_declaration_constraints (tree t, sat_info info)
>  	args = add_outermost_template_args (args, inh_ctor_targs);
>      }
>  
> -  if (regenerated_lambda_fn_p (t))
> +  if (LAMBDA_FUNCTION_P (t))
>      {
>        /* The TI_ARGS of a regenerated lambda contains only the innermost
>  	 set of template arguments.  Augment this with the outer template
>  	 arguments that were used to regenerate the lambda.  */
>        gcc_assert (!args || TMPL_ARGS_DEPTH (args) == 1);
> -      tree lambda = CLASSTYPE_LAMBDA_EXPR (DECL_CONTEXT (t));
> -      tree outer_args = TI_ARGS (LAMBDA_EXPR_REGEN_INFO (lambda));
> -      if (args)
> -	args = add_to_template_args (outer_args, args);
> -      else
> -	args = outer_args;
> +      args = add_to_template_args (lambda_regenerating_args (t), args);
>      }
>  
>    /* If any arguments depend on template parameters, we can't
> diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
> index b9eb71fbc3a..7a7fe5ba599 100644
> --- a/gcc/cp/cp-tree.h
> +++ b/gcc/cp/cp-tree.h
> @@ -7715,6 +7715,7 @@ extern void finish_lambda_scope			(void);
>  extern tree start_lambda_function		(tree fn, tree lambda_expr);
>  extern void finish_lambda_function		(tree body);
>  extern bool regenerated_lambda_fn_p		(tree);
> +extern tree lambda_regenerating_args		(tree);
>  extern tree most_general_lambda			(tree);
>  extern tree finish_omp_target			(location_t, tree, tree, bool);
>  extern void finish_omp_target_clauses		(location_t, tree, tree *);
> diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
> index 6e129da1d05..c919d2de68f 100644
> --- a/gcc/cp/pt.cc
> +++ b/gcc/cp/pt.cc
> @@ -573,6 +573,9 @@ add_to_template_args (tree args, tree extra_args)
>    if (args == NULL_TREE || extra_args == error_mark_node)
>      return extra_args;
>  
> +  if (extra_args == NULL_TREE)
> +    return args;
> +

Whoops, this last-minute change to add_to_template_args turned out to
be a bad idea as some callers apparently rely on add_to_template_args
treating NULL_TREE extra_args as a depth 1 targ vector (whereas for
the calls in satisfy_declaration_constraints and do_auto_deduction we
want NULL_TREE extra_args to be treated as a depth 0 targ vector).

Please consider the below patch instead, which doesn't attempt to change
the behavior of add_to_template_args:

-- >8 --

Subject: [PATCH] c++: constrained auto in lambda using outer tparms [PR103706]

Here we're crashing during satisfaction of the lambda's placeholder type
constraints because the constraints depend on the template arguments
from the enclosing scope, which aren't part of the lambda's DECL_TI_ARGS.
So when inside a lambda, do_auto_deduction needs to add its
"regenerating" template arguments to the set of outer template
arguments, like we already do in satisfy_declaration_constraints.

	PR c++/103706

gcc/cp/ChangeLog:

	* constraint.cc (satisfy_declaration_constraints): Use
	lambda_regenerating_args instead.
	* cp-tree.h (lambda_regenerating_args): Declare.
	* pt.cc (lambda_regenerating_args): Define, split out from
	satisfy_declaration_constraints.
	(do_auto_deduction): Use lambda_regenerating_args to obtain the
	full set of outer template arguments for satisfaction.

gcc/testsuite/ChangeLog:

	* g++.dg/cpp2a/concepts-lambda18.C: New test.
---
 gcc/cp/constraint.cc                          |  9 ++---
 gcc/cp/cp-tree.h                              |  1 +
 gcc/cp/pt.cc                                  | 39 ++++++++++++++++---
 .../g++.dg/cpp2a/concepts-lambda18.C          | 14 +++++++
 4 files changed, 52 insertions(+), 11 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-lambda18.C

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index cc4df4216ef..c0ebe63a0a2 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3148,18 +3148,17 @@ satisfy_declaration_constraints (tree t, sat_info info)
 	args = add_outermost_template_args (args, inh_ctor_targs);
     }
 
-  if (regenerated_lambda_fn_p (t))
+  if (LAMBDA_FUNCTION_P (t))
     {
       /* The TI_ARGS of a regenerated lambda contains only the innermost
 	 set of template arguments.  Augment this with the outer template
 	 arguments that were used to regenerate the lambda.  */
       gcc_assert (!args || TMPL_ARGS_DEPTH (args) == 1);
-      tree lambda = CLASSTYPE_LAMBDA_EXPR (DECL_CONTEXT (t));
-      tree outer_args = TI_ARGS (LAMBDA_EXPR_REGEN_INFO (lambda));
+      tree regen_args = lambda_regenerating_args (t);
       if (args)
-	args = add_to_template_args (outer_args, args);
+	args = add_to_template_args (regen_args, args);
       else
-	args = outer_args;
+	args = regen_args;
     }
 
   /* If any arguments depend on template parameters, we can't
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index b9eb71fbc3a..7a7fe5ba599 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -7715,6 +7715,7 @@ extern void finish_lambda_scope			(void);
 extern tree start_lambda_function		(tree fn, tree lambda_expr);
 extern void finish_lambda_function		(tree body);
 extern bool regenerated_lambda_fn_p		(tree);
+extern tree lambda_regenerating_args		(tree);
 extern tree most_general_lambda			(tree);
 extern tree finish_omp_target			(location_t, tree, tree, bool);
 extern void finish_omp_target_clauses		(location_t, tree, tree *);
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 6e129da1d05..46754c611e7 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -14442,6 +14442,21 @@ most_general_lambda (tree t)
   return t;
 }
 
+/* Return the set of template arguments used to regenerate the lambda T
+   from its most general lambda.  */
+
+tree
+lambda_regenerating_args (tree t)
+{
+  if (LAMBDA_FUNCTION_P (t))
+    t = CLASSTYPE_LAMBDA_EXPR (DECL_CONTEXT (t));
+  gcc_assert (TREE_CODE (t) == LAMBDA_EXPR);
+  if (tree ti = LAMBDA_EXPR_REGEN_INFO (t))
+    return TI_ARGS (ti);
+  else
+    return NULL_TREE;
+}
+
 /* We're instantiating a variable from template function TCTX.  Return the
    corresponding current enclosing scope.  We can match them up using
    DECL_SOURCE_LOCATION because lambdas only ever have one source location, and
@@ -30100,12 +30115,24 @@ do_auto_deduction (tree type, tree init, tree auto_node,
 	    return type;
 	}
 
-      if ((context == adc_return_type
-	   || context == adc_variable_type
-	   || context == adc_decomp_type)
-	  && current_function_decl
-	  && DECL_TEMPLATE_INFO (current_function_decl))
-	outer_targs = DECL_TI_ARGS (current_function_decl);
+      if (context == adc_return_type
+	  || context == adc_variable_type
+	  || context == adc_decomp_type)
+	if (tree fn = current_function_decl)
+	  if (DECL_TEMPLATE_INFO (fn) || LAMBDA_FUNCTION_P (fn))
+	    {
+	      outer_targs
+		= DECL_TEMPLATE_INFO (fn) ? DECL_TI_ARGS (fn) : NULL_TREE;
+	      if (LAMBDA_FUNCTION_P (fn))
+		{
+		  /* As in satisfy_declaration_constraints.  */
+		  tree regen_args = lambda_regenerating_args (fn);
+		  if (outer_targs)
+		    outer_targs = add_to_template_args (regen_args, outer_targs);
+		  else
+		    outer_targs = regen_args;
+		}
+	    }
 
       tree full_targs = add_to_template_args (outer_targs, targs);
 
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-lambda18.C b/gcc/testsuite/g++.dg/cpp2a/concepts-lambda18.C
new file mode 100644
index 00000000000..f1058daf317
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-lambda18.C
@@ -0,0 +1,14 @@
+// PR c++/103706
+// { dg-do compile { target c++20 } }
+
+template<class T, class U> concept C = __is_same(U, int);
+
+template<class T> void f() {
+  []() -> C<T> auto {
+    C<T> auto x = T(); // { dg-error "constraints" }
+    return T(); // { dg-error "constraints" }
+  }();
+}
+
+template void f<int>(); // { dg-bogus "" }
+template void f<char>(); // { dg-message "required from here" }
-- 
2.35.0


^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH] c++: constrained auto in lambda using outer tparms [PR103706]
  2022-02-02 18:21 ` Patrick Palka
@ 2022-02-02 20:48   ` Jason Merrill
  2022-02-03 17:17     ` Patrick Palka
  0 siblings, 1 reply; 4+ messages in thread
From: Jason Merrill @ 2022-02-02 20:48 UTC (permalink / raw)
  To: Patrick Palka; +Cc: gcc-patches

On 2/2/22 13:21, Patrick Palka wrote:
> On Wed, 2 Feb 2022, Patrick Palka wrote:
> 
>> Here we're crashing during satisfaction of the lambda's placeholder type
>> constraints because the constraints depend on the template arguments
>> from the enclosing scope, which aren't a part of the lambda's
>> DECL_TI_ARGS.  So when inside a lambda, do_auto_deduction needs to add
>> the "regenerating" template arguments to the set of outer template
>> arguments, like we already do in satisfy_declaration_constraints.
>>
>> Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
>> trunk and perhaps 11?
>>
>> 	PR c++/103706
>>
>> gcc/cp/ChangeLog:
>>
>> 	* constraint.cc (satisfy_declaration_constraints): Use
>> 	lambda_regenerating_args instead.
>> 	* cp-tree.h (lambda_regenerating_args): Declare.
>> 	* pt.cc (add_to_template_args): Handle NULL_TREE extra_args
>> 	gracefully.
>> 	(lambda_regenerating_args): Define, split out from
>> 	satisfy_declaration_constraints.
>> 	(do_auto_deduction): Use lambda_regenerating_args to obtain the
>> 	full set of outer template arguments when checking the
>> 	constraint on a placeholder type within a lambda.
>>
>> gcc/testsuite/ChangeLog:
>>
>> 	* g++.dg/cpp2a/concepts-lambda18.C: New test.
>> ---
>>   gcc/cp/constraint.cc                          |  9 +----
>>   gcc/cp/cp-tree.h                              |  1 +
>>   gcc/cp/pt.cc                                  | 37 ++++++++++++++++---
>>   .../g++.dg/cpp2a/concepts-lambda18.C          | 14 +++++++
>>   4 files changed, 48 insertions(+), 13 deletions(-)
>>   create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-lambda18.C
>>
>> diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
>> index cc4df4216ef..c41ee02b910 100644
>> --- a/gcc/cp/constraint.cc
>> +++ b/gcc/cp/constraint.cc
>> @@ -3148,18 +3148,13 @@ satisfy_declaration_constraints (tree t, sat_info info)
>>   	args = add_outermost_template_args (args, inh_ctor_targs);
>>       }
>>   
>> -  if (regenerated_lambda_fn_p (t))
>> +  if (LAMBDA_FUNCTION_P (t))
>>       {
>>         /* The TI_ARGS of a regenerated lambda contains only the innermost
>>   	 set of template arguments.  Augment this with the outer template
>>   	 arguments that were used to regenerate the lambda.  */
>>         gcc_assert (!args || TMPL_ARGS_DEPTH (args) == 1);
>> -      tree lambda = CLASSTYPE_LAMBDA_EXPR (DECL_CONTEXT (t));
>> -      tree outer_args = TI_ARGS (LAMBDA_EXPR_REGEN_INFO (lambda));
>> -      if (args)
>> -	args = add_to_template_args (outer_args, args);
>> -      else
>> -	args = outer_args;
>> +      args = add_to_template_args (lambda_regenerating_args (t), args);
>>       }
>>   
>>     /* If any arguments depend on template parameters, we can't
>> diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
>> index b9eb71fbc3a..7a7fe5ba599 100644
>> --- a/gcc/cp/cp-tree.h
>> +++ b/gcc/cp/cp-tree.h
>> @@ -7715,6 +7715,7 @@ extern void finish_lambda_scope			(void);
>>   extern tree start_lambda_function		(tree fn, tree lambda_expr);
>>   extern void finish_lambda_function		(tree body);
>>   extern bool regenerated_lambda_fn_p		(tree);
>> +extern tree lambda_regenerating_args		(tree);
>>   extern tree most_general_lambda			(tree);
>>   extern tree finish_omp_target			(location_t, tree, tree, bool);
>>   extern void finish_omp_target_clauses		(location_t, tree, tree *);
>> diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
>> index 6e129da1d05..c919d2de68f 100644
>> --- a/gcc/cp/pt.cc
>> +++ b/gcc/cp/pt.cc
>> @@ -573,6 +573,9 @@ add_to_template_args (tree args, tree extra_args)
>>     if (args == NULL_TREE || extra_args == error_mark_node)
>>       return extra_args;
>>   
>> +  if (extra_args == NULL_TREE)
>> +    return args;
>> +
> 
> Whoops, this last-minute change to add_to_template_args turned out to
> be a bad idea as some callers apparently rely on add_to_template_args
> treating NULL_TREE extra_args as a depth 1 targ vector (whereas for
> the calls in satisfy_declaration_constraints and do_auto_deduction we
> want NULL_TREE extra_args to be treated as a depth 0 targ vector).
> 
> Please consider the below patch instead, which doesn't attempt to change
> the behavior of add_to_template_args:
> 
> -- >8 --
> 
> Subject: [PATCH] c++: constrained auto in lambda using outer tparms [PR103706]
> 
> Here we're crashing during satisfaction of the lambda's placeholder type
> constraints because the constraints depend on the template arguments
> from the enclosing scope, which aren't part of the lambda's DECL_TI_ARGS.
> So when inside a lambda, do_auto_deduction needs to add its
> "regenerating" template arguments to the set of outer template
> arguments, like we already do in satisfy_declaration_constraints.
> 
> 	PR c++/103706
> 
> gcc/cp/ChangeLog:
> 
> 	* constraint.cc (satisfy_declaration_constraints): Use
> 	lambda_regenerating_args instead.
> 	* cp-tree.h (lambda_regenerating_args): Declare.
> 	* pt.cc (lambda_regenerating_args): Define, split out from
> 	satisfy_declaration_constraints.
> 	(do_auto_deduction): Use lambda_regenerating_args to obtain the
> 	full set of outer template arguments for satisfaction.
> 
> gcc/testsuite/ChangeLog:
> 
> 	* g++.dg/cpp2a/concepts-lambda18.C: New test.
> ---
>   gcc/cp/constraint.cc                          |  9 ++---
>   gcc/cp/cp-tree.h                              |  1 +
>   gcc/cp/pt.cc                                  | 39 ++++++++++++++++---
>   .../g++.dg/cpp2a/concepts-lambda18.C          | 14 +++++++
>   4 files changed, 52 insertions(+), 11 deletions(-)
>   create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-lambda18.C
> 
> diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
> index cc4df4216ef..c0ebe63a0a2 100644
> --- a/gcc/cp/constraint.cc
> +++ b/gcc/cp/constraint.cc
> @@ -3148,18 +3148,17 @@ satisfy_declaration_constraints (tree t, sat_info info)
>   	args = add_outermost_template_args (args, inh_ctor_targs);
>       }
>   
> -  if (regenerated_lambda_fn_p (t))
> +  if (LAMBDA_FUNCTION_P (t))

I wonder why you changed this test?  OK either way.

>       {
>         /* The TI_ARGS of a regenerated lambda contains only the innermost
>   	 set of template arguments.  Augment this with the outer template
>   	 arguments that were used to regenerate the lambda.  */
>         gcc_assert (!args || TMPL_ARGS_DEPTH (args) == 1);
> -      tree lambda = CLASSTYPE_LAMBDA_EXPR (DECL_CONTEXT (t));
> -      tree outer_args = TI_ARGS (LAMBDA_EXPR_REGEN_INFO (lambda));
> +      tree regen_args = lambda_regenerating_args (t);
>         if (args)
> -	args = add_to_template_args (outer_args, args);
> +	args = add_to_template_args (regen_args, args);
>         else
> -	args = outer_args;
> +	args = regen_args;
>       }
>   
>     /* If any arguments depend on template parameters, we can't
> diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
> index b9eb71fbc3a..7a7fe5ba599 100644
> --- a/gcc/cp/cp-tree.h
> +++ b/gcc/cp/cp-tree.h
> @@ -7715,6 +7715,7 @@ extern void finish_lambda_scope			(void);
>   extern tree start_lambda_function		(tree fn, tree lambda_expr);
>   extern void finish_lambda_function		(tree body);
>   extern bool regenerated_lambda_fn_p		(tree);
> +extern tree lambda_regenerating_args		(tree);
>   extern tree most_general_lambda			(tree);
>   extern tree finish_omp_target			(location_t, tree, tree, bool);
>   extern void finish_omp_target_clauses		(location_t, tree, tree *);
> diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
> index 6e129da1d05..46754c611e7 100644
> --- a/gcc/cp/pt.cc
> +++ b/gcc/cp/pt.cc
> @@ -14442,6 +14442,21 @@ most_general_lambda (tree t)
>     return t;
>   }
>   
> +/* Return the set of template arguments used to regenerate the lambda T
> +   from its most general lambda.  */
> +
> +tree
> +lambda_regenerating_args (tree t)
> +{
> +  if (LAMBDA_FUNCTION_P (t))
> +    t = CLASSTYPE_LAMBDA_EXPR (DECL_CONTEXT (t));
> +  gcc_assert (TREE_CODE (t) == LAMBDA_EXPR);
> +  if (tree ti = LAMBDA_EXPR_REGEN_INFO (t))
> +    return TI_ARGS (ti);
> +  else
> +    return NULL_TREE;
> +}
> +
>   /* We're instantiating a variable from template function TCTX.  Return the
>      corresponding current enclosing scope.  We can match them up using
>      DECL_SOURCE_LOCATION because lambdas only ever have one source location, and
> @@ -30100,12 +30115,24 @@ do_auto_deduction (tree type, tree init, tree auto_node,
>   	    return type;
>   	}
>   
> -      if ((context == adc_return_type
> -	   || context == adc_variable_type
> -	   || context == adc_decomp_type)
> -	  && current_function_decl
> -	  && DECL_TEMPLATE_INFO (current_function_decl))
> -	outer_targs = DECL_TI_ARGS (current_function_decl);
> +      if (context == adc_return_type
> +	  || context == adc_variable_type
> +	  || context == adc_decomp_type)
> +	if (tree fn = current_function_decl)
> +	  if (DECL_TEMPLATE_INFO (fn) || LAMBDA_FUNCTION_P (fn))
> +	    {
> +	      outer_targs
> +		= DECL_TEMPLATE_INFO (fn) ? DECL_TI_ARGS (fn) : NULL_TREE;
> +	      if (LAMBDA_FUNCTION_P (fn))
> +		{
> +		  /* As in satisfy_declaration_constraints.  */
> +		  tree regen_args = lambda_regenerating_args (fn);
> +		  if (outer_targs)
> +		    outer_targs = add_to_template_args (regen_args, outer_targs);
> +		  else
> +		    outer_targs = regen_args;
> +		}
> +	    }
>   
>         tree full_targs = add_to_template_args (outer_targs, targs);
>   
> diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-lambda18.C b/gcc/testsuite/g++.dg/cpp2a/concepts-lambda18.C
> new file mode 100644
> index 00000000000..f1058daf317
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-lambda18.C
> @@ -0,0 +1,14 @@
> +// PR c++/103706
> +// { dg-do compile { target c++20 } }
> +
> +template<class T, class U> concept C = __is_same(U, int);
> +
> +template<class T> void f() {
> +  []() -> C<T> auto {
> +    C<T> auto x = T(); // { dg-error "constraints" }
> +    return T(); // { dg-error "constraints" }
> +  }();
> +}
> +
> +template void f<int>(); // { dg-bogus "" }
> +template void f<char>(); // { dg-message "required from here" }


^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH] c++: constrained auto in lambda using outer tparms [PR103706]
  2022-02-02 20:48   ` Jason Merrill
@ 2022-02-03 17:17     ` Patrick Palka
  0 siblings, 0 replies; 4+ messages in thread
From: Patrick Palka @ 2022-02-03 17:17 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Patrick Palka, gcc-patches



On Wed, 2 Feb 2022, Jason Merrill wrote:

> On 2/2/22 13:21, Patrick Palka wrote:
> > On Wed, 2 Feb 2022, Patrick Palka wrote:
> > 
> > > Here we're crashing during satisfaction of the lambda's placeholder type
> > > constraints because the constraints depend on the template arguments
> > > from the enclosing scope, which aren't a part of the lambda's
> > > DECL_TI_ARGS.  So when inside a lambda, do_auto_deduction needs to add
> > > the "regenerating" template arguments to the set of outer template
> > > arguments, like we already do in satisfy_declaration_constraints.
> > > 
> > > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
> > > trunk and perhaps 11?
> > > 
> > > 	PR c++/103706
> > > 
> > > gcc/cp/ChangeLog:
> > > 
> > > 	* constraint.cc (satisfy_declaration_constraints): Use
> > > 	lambda_regenerating_args instead.
> > > 	* cp-tree.h (lambda_regenerating_args): Declare.
> > > 	* pt.cc (add_to_template_args): Handle NULL_TREE extra_args
> > > 	gracefully.
> > > 	(lambda_regenerating_args): Define, split out from
> > > 	satisfy_declaration_constraints.
> > > 	(do_auto_deduction): Use lambda_regenerating_args to obtain the
> > > 	full set of outer template arguments when checking the
> > > 	constraint on a placeholder type within a lambda.
> > > 
> > > gcc/testsuite/ChangeLog:
> > > 
> > > 	* g++.dg/cpp2a/concepts-lambda18.C: New test.
> > > ---
> > >   gcc/cp/constraint.cc                          |  9 +----
> > >   gcc/cp/cp-tree.h                              |  1 +
> > >   gcc/cp/pt.cc                                  | 37 ++++++++++++++++---
> > >   .../g++.dg/cpp2a/concepts-lambda18.C          | 14 +++++++
> > >   4 files changed, 48 insertions(+), 13 deletions(-)
> > >   create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-lambda18.C
> > > 
> > > diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
> > > index cc4df4216ef..c41ee02b910 100644
> > > --- a/gcc/cp/constraint.cc
> > > +++ b/gcc/cp/constraint.cc
> > > @@ -3148,18 +3148,13 @@ satisfy_declaration_constraints (tree t, sat_info
> > > info)
> > >   	args = add_outermost_template_args (args, inh_ctor_targs);
> > >       }
> > >   -  if (regenerated_lambda_fn_p (t))
> > > +  if (LAMBDA_FUNCTION_P (t))
> > >       {
> > >         /* The TI_ARGS of a regenerated lambda contains only the innermost
> > >   	 set of template arguments.  Augment this with the outer template
> > >   	 arguments that were used to regenerate the lambda.  */
> > >         gcc_assert (!args || TMPL_ARGS_DEPTH (args) == 1);
> > > -      tree lambda = CLASSTYPE_LAMBDA_EXPR (DECL_CONTEXT (t));
> > > -      tree outer_args = TI_ARGS (LAMBDA_EXPR_REGEN_INFO (lambda));
> > > -      if (args)
> > > -	args = add_to_template_args (outer_args, args);
> > > -      else
> > > -	args = outer_args;
> > > +      args = add_to_template_args (lambda_regenerating_args (t), args);
> > >       }
> > >       /* If any arguments depend on template parameters, we can't
> > > diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
> > > index b9eb71fbc3a..7a7fe5ba599 100644
> > > --- a/gcc/cp/cp-tree.h
> > > +++ b/gcc/cp/cp-tree.h
> > > @@ -7715,6 +7715,7 @@ extern void finish_lambda_scope
> > > (void);
> > >   extern tree start_lambda_function		(tree fn, tree lambda_expr);
> > >   extern void finish_lambda_function		(tree body);
> > >   extern bool regenerated_lambda_fn_p		(tree);
> > > +extern tree lambda_regenerating_args		(tree);
> > >   extern tree most_general_lambda			(tree);
> > >   extern tree finish_omp_target			(location_t, tree,
> > > tree, bool);
> > >   extern void finish_omp_target_clauses		(location_t, tree,
> > > tree *);
> > > diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
> > > index 6e129da1d05..c919d2de68f 100644
> > > --- a/gcc/cp/pt.cc
> > > +++ b/gcc/cp/pt.cc
> > > @@ -573,6 +573,9 @@ add_to_template_args (tree args, tree extra_args)
> > >     if (args == NULL_TREE || extra_args == error_mark_node)
> > >       return extra_args;
> > >   +  if (extra_args == NULL_TREE)
> > > +    return args;
> > > +
> > 
> > Whoops, this last-minute change to add_to_template_args turned out to
> > be a bad idea as some callers apparently rely on add_to_template_args
> > treating NULL_TREE extra_args as a depth 1 targ vector (whereas for
> > the calls in satisfy_declaration_constraints and do_auto_deduction we
> > want NULL_TREE extra_args to be treated as a depth 0 targ vector).
> > 
> > Please consider the below patch instead, which doesn't attempt to change
> > the behavior of add_to_template_args:
> > 
> > -- >8 --
> > 
> > Subject: [PATCH] c++: constrained auto in lambda using outer tparms
> > [PR103706]
> > 
> > Here we're crashing during satisfaction of the lambda's placeholder type
> > constraints because the constraints depend on the template arguments
> > from the enclosing scope, which aren't part of the lambda's DECL_TI_ARGS.
> > So when inside a lambda, do_auto_deduction needs to add its
> > "regenerating" template arguments to the set of outer template
> > arguments, like we already do in satisfy_declaration_constraints.
> > 
> > 	PR c++/103706
> > 
> > gcc/cp/ChangeLog:
> > 
> > 	* constraint.cc (satisfy_declaration_constraints): Use
> > 	lambda_regenerating_args instead.
> > 	* cp-tree.h (lambda_regenerating_args): Declare.
> > 	* pt.cc (lambda_regenerating_args): Define, split out from
> > 	satisfy_declaration_constraints.
> > 	(do_auto_deduction): Use lambda_regenerating_args to obtain the
> > 	full set of outer template arguments for satisfaction.
> > 
> > gcc/testsuite/ChangeLog:
> > 
> > 	* g++.dg/cpp2a/concepts-lambda18.C: New test.
> > ---
> >   gcc/cp/constraint.cc                          |  9 ++---
> >   gcc/cp/cp-tree.h                              |  1 +
> >   gcc/cp/pt.cc                                  | 39 ++++++++++++++++---
> >   .../g++.dg/cpp2a/concepts-lambda18.C          | 14 +++++++
> >   4 files changed, 52 insertions(+), 11 deletions(-)
> >   create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-lambda18.C
> > 
> > diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
> > index cc4df4216ef..c0ebe63a0a2 100644
> > --- a/gcc/cp/constraint.cc
> > +++ b/gcc/cp/constraint.cc
> > @@ -3148,18 +3148,17 @@ satisfy_declaration_constraints (tree t, sat_info
> > info)
> >   	args = add_outermost_template_args (args, inh_ctor_targs);
> >       }
> >   -  if (regenerated_lambda_fn_p (t))
> > +  if (LAMBDA_FUNCTION_P (t))
> 
> I wonder why you changed this test?  OK either way.

No good reason, it shouldn't make a functional difference so I'll drop
this no-op change.

> 
> >       {
> >         /* The TI_ARGS of a regenerated lambda contains only the innermost
> >   	 set of template arguments.  Augment this with the outer template
> >   	 arguments that were used to regenerate the lambda.  */
> >         gcc_assert (!args || TMPL_ARGS_DEPTH (args) == 1);
> > -      tree lambda = CLASSTYPE_LAMBDA_EXPR (DECL_CONTEXT (t));
> > -      tree outer_args = TI_ARGS (LAMBDA_EXPR_REGEN_INFO (lambda));
> > +      tree regen_args = lambda_regenerating_args (t);
> >         if (args)
> > -	args = add_to_template_args (outer_args, args);
> > +	args = add_to_template_args (regen_args, args);
> >         else
> > -	args = outer_args;
> > +	args = regen_args;
> >       }
> >       /* If any arguments depend on template parameters, we can't
> > diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
> > index b9eb71fbc3a..7a7fe5ba599 100644
> > --- a/gcc/cp/cp-tree.h
> > +++ b/gcc/cp/cp-tree.h
> > @@ -7715,6 +7715,7 @@ extern void finish_lambda_scope
> > (void);
> >   extern tree start_lambda_function		(tree fn, tree lambda_expr);
> >   extern void finish_lambda_function		(tree body);
> >   extern bool regenerated_lambda_fn_p		(tree);
> > +extern tree lambda_regenerating_args		(tree);
> >   extern tree most_general_lambda			(tree);
> >   extern tree finish_omp_target			(location_t, tree,
> > tree, bool);
> >   extern void finish_omp_target_clauses		(location_t, tree,
> > tree *);
> > diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
> > index 6e129da1d05..46754c611e7 100644
> > --- a/gcc/cp/pt.cc
> > +++ b/gcc/cp/pt.cc
> > @@ -14442,6 +14442,21 @@ most_general_lambda (tree t)
> >     return t;
> >   }
> >   +/* Return the set of template arguments used to regenerate the lambda T
> > +   from its most general lambda.  */
> > +
> > +tree
> > +lambda_regenerating_args (tree t)
> > +{
> > +  if (LAMBDA_FUNCTION_P (t))
> > +    t = CLASSTYPE_LAMBDA_EXPR (DECL_CONTEXT (t));
> > +  gcc_assert (TREE_CODE (t) == LAMBDA_EXPR);
> > +  if (tree ti = LAMBDA_EXPR_REGEN_INFO (t))
> > +    return TI_ARGS (ti);
> > +  else
> > +    return NULL_TREE;
> > +}
> > +
> >   /* We're instantiating a variable from template function TCTX.  Return the
> >      corresponding current enclosing scope.  We can match them up using
> >      DECL_SOURCE_LOCATION because lambdas only ever have one source
> > location, and
> > @@ -30100,12 +30115,24 @@ do_auto_deduction (tree type, tree init, tree
> > auto_node,
> >   	    return type;
> >   	}
> >   -      if ((context == adc_return_type
> > -	   || context == adc_variable_type
> > -	   || context == adc_decomp_type)
> > -	  && current_function_decl
> > -	  && DECL_TEMPLATE_INFO (current_function_decl))
> > -	outer_targs = DECL_TI_ARGS (current_function_decl);
> > +      if (context == adc_return_type
> > +	  || context == adc_variable_type
> > +	  || context == adc_decomp_type)
> > +	if (tree fn = current_function_decl)
> > +	  if (DECL_TEMPLATE_INFO (fn) || LAMBDA_FUNCTION_P (fn))
> > +	    {
> > +	      outer_targs
> > +		= DECL_TEMPLATE_INFO (fn) ? DECL_TI_ARGS (fn) : NULL_TREE;
> > +	      if (LAMBDA_FUNCTION_P (fn))
> > +		{
> > +		  /* As in satisfy_declaration_constraints.  */
> > +		  tree regen_args = lambda_regenerating_args (fn);
> > +		  if (outer_targs)
> > +		    outer_targs = add_to_template_args (regen_args,
> > outer_targs);
> > +		  else
> > +		    outer_targs = regen_args;
> > +		}
> > +	    }
> >           tree full_targs = add_to_template_args (outer_targs, targs);
> >   diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-lambda18.C
> > b/gcc/testsuite/g++.dg/cpp2a/concepts-lambda18.C
> > new file mode 100644
> > index 00000000000..f1058daf317
> > --- /dev/null
> > +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-lambda18.C
> > @@ -0,0 +1,14 @@
> > +// PR c++/103706
> > +// { dg-do compile { target c++20 } }
> > +
> > +template<class T, class U> concept C = __is_same(U, int);
> > +
> > +template<class T> void f() {
> > +  []() -> C<T> auto {
> > +    C<T> auto x = T(); // { dg-error "constraints" }
> > +    return T(); // { dg-error "constraints" }
> > +  }();
> > +}
> > +
> > +template void f<int>(); // { dg-bogus "" }
> > +template void f<char>(); // { dg-message "required from here" }
> 
> 


^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2022-02-03 17:17 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-02-02 17:09 [PATCH] c++: constrained auto in lambda using outer tparms [PR103706] Patrick Palka
2022-02-02 18:21 ` Patrick Palka
2022-02-02 20:48   ` Jason Merrill
2022-02-03 17:17     ` Patrick Palka

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).