aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorJason Merrill <jason@redhat.com>2018-04-03 13:41:12 -0400
committerJason Merrill <jason@gcc.gnu.org>2018-04-03 13:41:12 -0400
commit1456e764105702a0bb6c9be13d8eef7f21990a79 (patch)
treea2a7b1c3ad63b40b6b58d47dad2b0efcbde9f65e /gcc
parent3f759575d3675150e665be997dd1e404e5c011f4 (diff)
downloadgcc-1456e764105702a0bb6c9be13d8eef7f21990a79.zip
gcc-1456e764105702a0bb6c9be13d8eef7f21990a79.tar.gz
gcc-1456e764105702a0bb6c9be13d8eef7f21990a79.tar.bz2
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. From-SVN: r259043
Diffstat (limited to 'gcc')
-rw-r--r--gcc/cp/ChangeLog6
-rw-r--r--gcc/cp/cp-tree.h4
-rw-r--r--gcc/cp/pt.c84
-rw-r--r--gcc/testsuite/g++.dg/cpp1z/constexpr-if17.C33
4 files changed, 102 insertions, 25 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 405cf82..9dbb215 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -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.
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index db79338..f7bacd0 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -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)
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index f4edb39..4c0d298 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -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
index 0000000..c6ebf1e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/constexpr-if17.C
@@ -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();
+}