aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorAlexandre Oliva <aoliva@redhat.com>2019-02-13 17:42:39 +0000
committerAlexandre Oliva <aoliva@gcc.gnu.org>2019-02-13 17:42:39 +0000
commit60378a964a2a6b32b9d05de053e181d691f68d52 (patch)
tree15235c60c3d0ca6c9c6eb290ebe34f1ff02366b9 /gcc
parent2db698cefc5b7e2a66ca64d8485dd9156ee7442f (diff)
downloadgcc-60378a964a2a6b32b9d05de053e181d691f68d52.zip
gcc-60378a964a2a6b32b9d05de053e181d691f68d52.tar.gz
gcc-60378a964a2a6b32b9d05de053e181d691f68d52.tar.bz2
[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
Diffstat (limited to 'gcc')
-rw-r--r--gcc/cp/ChangeLog8
-rw-r--r--gcc/cp/pt.c22
-rw-r--r--gcc/testsuite/ChangeLog7
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/lambda/lambda-variadic5.C2
-rw-r--r--gcc/testsuite/g++.dg/cpp1y/pr87322.C23
5 files changed, 58 insertions, 4 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 8533fa8..9627f3b 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,11 @@
+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>
PR c++/89036
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index e6782fe..48cbf3d 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -11700,6 +11700,10 @@ gen_elem_of_pack_expansion_instantiation (tree pattern,
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)
arguments. */
if (pattern == 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);
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 ();
+ if (local_specializations)
+ register_local_specialization (r, t);
+
LAMBDA_EXPR_LOCATION (r)
= LAMBDA_EXPR_LOCATION (t);
LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (r)
@@ -18025,6 +18038,11 @@ tsubst_lambda_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl)
r = error_mark_node;
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'. */
fntype = build_memfn_type (fntype, type,
type_memfn_quals (fntype),
@@ -18046,10 +18064,6 @@ tsubst_lambda_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl)
/* Let finish_function set this. */
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;
if (nested)
push_function_context ();
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index bda30c8..ad25ccb 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,10 @@
+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>
PR c++/77304
diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-variadic5.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-variadic5.C
index 97f64cd..1f93175 100644
--- a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-variadic5.C
+++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-variadic5.C
@@ -1,5 +1,7 @@
// PR c++/47226
// { dg-do compile { target c++11 } }
+// { dg-options "-fdump-tree-original" }
+// { dg-final { scan-tree-dump-times "::<lambda\\(\\)> \\(null\\)" 6 "original" } }
template<class T>
void print(const T&) {}
diff --git a/gcc/testsuite/g++.dg/cpp1y/pr87322.C b/gcc/testsuite/g++.dg/cpp1y/pr87322.C
new file mode 100644
index 0000000..8f52e0e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/pr87322.C
@@ -0,0 +1,23 @@
+// { 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;
+ });
+ });
+
+}