* [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).