diff options
author | Patrick Palka <ppalka@redhat.com> | 2022-02-08 08:46:13 -0500 |
---|---|---|
committer | Patrick Palka <ppalka@redhat.com> | 2022-02-08 08:46:13 -0500 |
commit | 34ba3d9a2bf72742b1c150a2dd17d10e3e3f0964 (patch) | |
tree | 96d3de214b499a8a4bcfab81c3b7031a429884f1 /gcc | |
parent | 61b783995fac5355827ada1f8544052119a23606 (diff) | |
download | gcc-34ba3d9a2bf72742b1c150a2dd17d10e3e3f0964.zip gcc-34ba3d9a2bf72742b1c150a2dd17d10e3e3f0964.tar.gz gcc-34ba3d9a2bf72742b1c150a2dd17d10e3e3f0964.tar.bz2 |
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.
This patch fixes this by making do_auto_deduction consider the
"regenerating" template arguments of a lambda for satisfaction,
mirroring what's done 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 when
inside a lambda.
gcc/testsuite/ChangeLog:
* g++.dg/cpp2a/concepts-lambda18.C: New test.
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/cp/constraint.cc | 7 | ||||
-rw-r--r-- | gcc/cp/cp-tree.h | 1 | ||||
-rw-r--r-- | gcc/cp/pt.cc | 39 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp2a/concepts-lambda18.C | 14 |
4 files changed, 51 insertions, 10 deletions
diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc index cc4df42..b7b9439 100644 --- a/gcc/cp/constraint.cc +++ b/gcc/cp/constraint.cc @@ -3154,12 +3154,11 @@ satisfy_declaration_constraints (tree t, sat_info info) 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 d71be0a..f09055e 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -7742,6 +7742,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 c7af471..b58067d 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -14446,6 +14446,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 @@ -30127,12 +30142,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 0000000..f1058da --- /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" } |