PR c++/85149 - generic lambda and constexpr if.
authorJason Merrill <jason@redhat.com>
Tue, 3 Apr 2018 17:41:12 +0000 (13:41 -0400)
committerJason Merrill <jason@gcc.gnu.org>
Tue, 3 Apr 2018 17:41:12 +0000 (13:41 -0400)
* pt.c (build_extra_args, add_extra_args): Split from
tsubst_pack_expansion.
(tsubst_expr) [IF_STMT]: Use them.
* cp-tree.h (IF_STMT_EXTRA_ARGS): New.

From-SVN: r259043

gcc/cp/ChangeLog
gcc/cp/cp-tree.h
gcc/cp/pt.c
gcc/testsuite/g++.dg/cpp1z/constexpr-if17.C [new file with mode: 0644]

index 405cf82b5d200b0e45b2151699244516f5b89db2..9dbb215154e59826737599356a47a5d67bb11b24 100644 (file)
@@ -1,5 +1,11 @@
 2018-04-03  Jason Merrill  <jason@redhat.com>
 
+       PR c++/85149 - generic lambda and constexpr if.
+       * pt.c (build_extra_args, add_extra_args): Split from
+       tsubst_pack_expansion.
+       (tsubst_expr) [IF_STMT]: Use them.
+       * cp-tree.h (IF_STMT_EXTRA_ARGS): New.
+
        * typeck.c (merge_types): Limit matching attribute shortcut to
        the default case.
 
index db79338035da28c9a86a8556ee3acf367e0a2f00..f7bacd08c8f896153b653f285cbfd975b6390784 100644 (file)
@@ -4866,6 +4866,10 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter)
 #define IF_SCOPE(NODE)         TREE_OPERAND (IF_STMT_CHECK (NODE), 3)
 #define IF_STMT_CONSTEXPR_P(NODE) TREE_LANG_FLAG_0 (IF_STMT_CHECK (NODE))
 
+/* Like PACK_EXPANSION_EXTRA_ARGS, for constexpr if.  IF_SCOPE is used while
+   building an IF_STMT; IF_STMT_EXTRA_ARGS is used after it is complete.  */
+#define IF_STMT_EXTRA_ARGS(NODE) IF_SCOPE (NODE)
+
 /* WHILE_STMT accessors. These give access to the condition of the
    while statement and the body of the while statement, respectively.  */
 #define WHILE_COND(NODE)       TREE_OPERAND (WHILE_STMT_CHECK (NODE), 0)
index f4edb39f6e3236035ad8dff7182c4d92d415e492..4c0d298cfcc58af357af92a48a43ff51f2569f2d 100644 (file)
@@ -11663,6 +11663,46 @@ extract_local_specs (tree pattern, tsubst_flags_t complain)
   return data.extra;
 }
 
+/* Extract any uses of local_specializations from PATTERN and add them to ARGS
+   for use in PACK_EXPANSION_EXTRA_ARGS.  */
+
+tree
+build_extra_args (tree pattern, tree args, tsubst_flags_t complain)
+{
+  tree extra = args;
+  if (local_specializations)
+    if (tree locals = extract_local_specs (pattern, complain))
+      extra = tree_cons (NULL_TREE, extra, locals);
+  return extra;
+}
+
+/* Apply any local specializations from PACK_EXPANSION_EXTRA_ARGS and add the
+   normal template args to ARGS.  */
+
+tree
+add_extra_args (tree extra, tree args)
+{
+  if (extra && TREE_CODE (extra) == TREE_LIST)
+    {
+      for (tree elt = TREE_CHAIN (extra); elt; elt = TREE_CHAIN (elt))
+       {
+         /* The partial instantiation involved local declarations collected in
+            extract_local_specs; map from the general template to our local
+            context.  */
+         tree gen = TREE_PURPOSE (elt);
+         tree inst = TREE_VALUE (elt);
+         if (DECL_P (inst))
+           if (tree local = retrieve_local_specialization (inst))
+             inst = local;
+         /* else inst is already a full instantiation of the pack.  */
+         register_local_specialization (inst, gen);
+       }
+      gcc_assert (!TREE_PURPOSE (extra));
+      extra = TREE_VALUE (extra);
+    }
+  return add_to_template_args (extra, args);
+}
+
 /* Substitute ARGS into T, which is an pack expansion
    (i.e. TYPE_PACK_EXPANSION or EXPR_PACK_EXPANSION). Returns a
    TREE_VEC with the substituted arguments, a PACK_EXPANSION_* node
@@ -11686,26 +11726,7 @@ tsubst_pack_expansion (tree t, tree args, tsubst_flags_t complain,
   pattern = PACK_EXPANSION_PATTERN (t);
 
   /* Add in any args remembered from an earlier partial instantiation.  */
-  tree extra = PACK_EXPANSION_EXTRA_ARGS (t);
-  if (extra && TREE_CODE (extra) == TREE_LIST)
-    {
-      for (tree elt = TREE_CHAIN (extra); elt; elt = TREE_CHAIN (elt))
-       {
-         /* The partial instantiation involved local declarations collected in
-            extract_local_specs; map from the general template to our local
-            context.  */
-         tree gen = TREE_PURPOSE (elt);
-         tree inst = TREE_VALUE (elt);
-         if (DECL_P (inst))
-           if (tree local = retrieve_local_specialization (inst))
-             inst = local;
-         /* else inst is already a full instantiation of the pack.  */
-         register_local_specialization (inst, gen);
-       }
-      gcc_assert (!TREE_PURPOSE (extra));
-      extra = TREE_VALUE (extra);
-    }
-  args = add_to_template_args (extra, args);
+  args = add_extra_args (PACK_EXPANSION_EXTRA_ARGS (t), args);
 
   levels = TMPL_ARGS_DEPTH (args);
 
@@ -11881,11 +11902,8 @@ tsubst_pack_expansion (tree t, tree args, tsubst_flags_t complain,
         have values for all the packs.  So remember these until then.  */
 
       t = make_pack_expansion (pattern, complain);
-      tree extra = args;
-      if (local_specializations)
-       if (tree locals = extract_local_specs (pattern, complain))
-         extra = tree_cons (NULL_TREE, extra, locals);
-      PACK_EXPANSION_EXTRA_ARGS (t) = extra;
+      PACK_EXPANSION_EXTRA_ARGS (t)
+       = build_extra_args (pattern, args, complain);
       return t;
     }
   else if (unsubstituted_packs)
@@ -16485,8 +16503,24 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl,
     case IF_STMT:
       stmt = begin_if_stmt ();
       IF_STMT_CONSTEXPR_P (stmt) = IF_STMT_CONSTEXPR_P (t);
+      if (IF_STMT_CONSTEXPR_P (t))
+       args = add_extra_args (IF_STMT_EXTRA_ARGS (t), args);
       tmp = RECUR (IF_COND (t));
       tmp = finish_if_stmt_cond (tmp, stmt);
+      if (IF_STMT_CONSTEXPR_P (t)
+         && instantiation_dependent_expression_p (tmp))
+       {
+         /* We're partially instantiating a generic lambda, but the condition
+            of the constexpr if is still dependent.  Don't substitute into the
+            branches now, just remember the template arguments.  */
+         do_poplevel (IF_SCOPE (stmt));
+         IF_COND (stmt) = IF_COND (t);
+         THEN_CLAUSE (stmt) = THEN_CLAUSE (t);
+         ELSE_CLAUSE (stmt) = ELSE_CLAUSE (t);
+         IF_STMT_EXTRA_ARGS (stmt) = build_extra_args (t, args, complain);
+         add_stmt (stmt);
+         break;
+       }
       if (IF_STMT_CONSTEXPR_P (t) && integer_zerop (tmp))
        /* Don't instantiate the THEN_CLAUSE. */;
       else
diff --git a/gcc/testsuite/g++.dg/cpp1z/constexpr-if17.C b/gcc/testsuite/g++.dg/cpp1z/constexpr-if17.C
new file mode 100644 (file)
index 0000000..c6ebf1e
--- /dev/null
@@ -0,0 +1,33 @@
+// PR c++/85149
+// { dg-do run }
+// { dg-additional-options -std=c++17 }
+
+template <typename T> struct is_void { static constexpr bool value = false; };
+template <> struct is_void<void> { static constexpr bool value = true; };
+
+template<typename S, typename T>
+constexpr decltype(auto) pipeline(S source, T target)
+{
+  return [=](auto... args)
+    {
+      if constexpr(false
+                  && is_void<decltype(source(args...))>::value)
+       {
+         source(args...);
+         return target();
+       }
+      else
+       {
+         return target(source(args...));
+        }
+    };
+}
+
+int main() {
+  int i = 10;
+  int j = 42;
+  auto p = pipeline([&]{ return j; },
+                   [=](int val){ return val * i; });
+  if (p() != 420)
+    __builtin_abort();
+}