Commit 60378a96 by Alexandre Oliva Committed by Alexandre Oliva

[PR87322] move cp_evaluated up to tsubst all lambda parms

A lambda capture variable initialized with a lambda expr taking more
than one parameter got us confused.

The first problem was that the parameter list was cut short during
tsubsting because we tsubsted it with cp_unevaluated_operand.  We
reset it right after, to tsubst the function body, so I've moved the
reset up so that it's in effect while processing the parameters as
well.

The second problem was that the lambda expr appeared twice, once in a
decltype that gave the capture variable its type, and once in its
initializer.  This caused us to instantiate two separate lambda exprs
and closure types, and then to flag that the lambda expr in the
initializer could not be converted to the unrelated closure type
determined for the capture variable.  Recording the tsubsted expr in
the local specialization map, and retrieving it for reuse fixed it.
However, that required some care to avoid reusing the lambda expr
across different indices in pack expansions.


for  gcc/cp/ChangeLog

	PR c++/87322
	* pt.c (tsubst_lambda_expr): Avoid duplicate tsubsting.
	Move cp_evaluated resetting before signature tsubsting.
	(gen_elem_of_pack_expansion_instantiation): Separate local
	specializations per index.

for  gcc/testsuite/ChangeLog

	PR c++/87322
	* g++.dg/cpp1y/pr87322.C: New.
	* g++.dg/cpp0x/lambda/lambda-variadic5.C: Test that we
	instantiate the expected number of lambda functions.

From-SVN: r268850
parent 2db698ce
2019-02-13 Alexandre Oliva <aoliva@redhat.com>
PR c++/87322
* pt.c (tsubst_lambda_expr): Avoid duplicate tsubsting.
Move cp_evaluated resetting before signature tsubsting.
(gen_elem_of_pack_expansion_instantiation): Separate local
specializations per index.
2019-02-13 David Malcolm <dmalcolm@redhat.com> 2019-02-13 David Malcolm <dmalcolm@redhat.com>
PR c++/89036 PR c++/89036
......
...@@ -11700,6 +11700,10 @@ gen_elem_of_pack_expansion_instantiation (tree pattern, ...@@ -11700,6 +11700,10 @@ gen_elem_of_pack_expansion_instantiation (tree pattern,
ARGUMENT_PACK_SELECT_INDEX (aps) = index; ARGUMENT_PACK_SELECT_INDEX (aps) = index;
} }
// Any local specialization bindings arising from this substitution
// cannot be reused for a different INDEX.
local_specialization_stack lss (lss_copy);
/* Substitute into the PATTERN with the (possibly altered) /* Substitute into the PATTERN with the (possibly altered)
arguments. */ arguments. */
if (pattern == in_decl) if (pattern == in_decl)
...@@ -17932,8 +17936,17 @@ tsubst_lambda_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl) ...@@ -17932,8 +17936,17 @@ tsubst_lambda_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl)
tree oldfn = lambda_function (t); tree oldfn = lambda_function (t);
in_decl = oldfn; in_decl = oldfn;
/* If we have already specialized this lambda expr, reuse it. See
PR c++/87322. */
if (local_specializations)
if (tree r = retrieve_local_specialization (t))
return r;
tree r = build_lambda_expr (); tree r = build_lambda_expr ();
if (local_specializations)
register_local_specialization (r, t);
LAMBDA_EXPR_LOCATION (r) LAMBDA_EXPR_LOCATION (r)
= LAMBDA_EXPR_LOCATION (t); = LAMBDA_EXPR_LOCATION (t);
LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (r) LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (r)
...@@ -18025,6 +18038,11 @@ tsubst_lambda_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl) ...@@ -18025,6 +18038,11 @@ tsubst_lambda_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl)
r = error_mark_node; r = error_mark_node;
else else
{ {
/* The body of a lambda-expression is not a subexpression of the
enclosing expression. Parms are to have DECL_CHAIN tsubsted,
which would be skipped if cp_unevaluated_operand. */
cp_evaluated ev;
/* Fix the type of 'this'. */ /* Fix the type of 'this'. */
fntype = build_memfn_type (fntype, type, fntype = build_memfn_type (fntype, type,
type_memfn_quals (fntype), type_memfn_quals (fntype),
...@@ -18046,10 +18064,6 @@ tsubst_lambda_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl) ...@@ -18046,10 +18064,6 @@ tsubst_lambda_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl)
/* Let finish_function set this. */ /* Let finish_function set this. */
DECL_DECLARED_CONSTEXPR_P (fn) = false; DECL_DECLARED_CONSTEXPR_P (fn) = false;
/* The body of a lambda-expression is not a subexpression of the
enclosing expression. */
cp_evaluated ev;
bool nested = cfun; bool nested = cfun;
if (nested) if (nested)
push_function_context (); push_function_context ();
......
2019-02-13 Alexandre Oliva <aoliva@redhat.com>
PR c++/87322
* g++.dg/cpp1y/pr87322.C: New.
* g++.dg/cpp0x/lambda/lambda-variadic5.C: Test that we
instantiate the expected number of lambda functions.
2019-02-13 Marek Polacek <polacek@redhat.com> 2019-02-13 Marek Polacek <polacek@redhat.com>
PR c++/77304 PR c++/77304
......
// PR c++/47226 // PR c++/47226
// { dg-do compile { target c++11 } } // { dg-do compile { target c++11 } }
// { dg-options "-fdump-tree-original" }
// { dg-final { scan-tree-dump-times "::<lambda\\(\\)> \\(null\\)" 6 "original" } }
template<class T> template<class T>
void print(const T&) {} void print(const T&) {}
......
// { dg-do compile { target c++14 } }
#include <array>
#include <algorithm>
int main()
{
constexpr std::array<std::array<double,2>,3> my_mat {
{ { 1., 1. },
{ 1., 1. },
{ 1., 1. }, }
};
std::for_each(my_mat.begin(), my_mat.end(), [
inner_func = [] (auto a, auto b) { return a + b; } ](auto& row) {
std::for_each(row.begin(), row.end(), [&,
inner_func2 = [] (auto a, auto b) { return a + b; } ]
(const double&) {
return;
});
});
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment