[PR87322] move cp_evaluated up to tsubst all lambda parms
authorAlexandre Oliva <aoliva@redhat.com>
Wed, 13 Feb 2019 17:42:39 +0000 (17:42 +0000)
committerAlexandre Oliva <aoliva@gcc.gnu.org>
Wed, 13 Feb 2019 17:42:39 +0000 (17:42 +0000)
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

gcc/cp/ChangeLog
gcc/cp/pt.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/cpp0x/lambda/lambda-variadic5.C
gcc/testsuite/g++.dg/cpp1y/pr87322.C [new file with mode: 0644]

index 8533fa81ee6fdb6f88b3d7ad82ba49090ff9269f..9627f3b1444bc567d4ed5d088cd34a72b9a14206 100644 (file)
@@ -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
index e6782fe785bfa9cf70e0501e0b8b159b37f331c2..48cbf3d9892c2e42a7265ac673bd13518820aeac 100644 (file)
@@ -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 ();
index bda30c8eae7cb626a386bc739ff21344deefbbe6..ad25ccb7dc5b25246be2e08cc1fb97ba23bc4d0e 100644 (file)
@@ -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
index 97f64cd761a7af041d52709ea8c0e4f7f0fb54b3..1f931757b72f22aee819c291205b9c9e88f82ccb 100644 (file)
@@ -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 (file)
index 0000000..8f52e0e
--- /dev/null
@@ -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;
+    });
+  }); 
+  
+}