From: Jason Merrill Date: Tue, 3 Apr 2018 17:41:12 +0000 (-0400) Subject: PR c++/85149 - generic lambda and constexpr if. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=1456e764105702a0bb6c9be13d8eef7f21990a79;p=gcc.git 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 --- diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 405cf82b5d2..9dbb215154e 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,5 +1,11 @@ 2018-04-03 Jason Merrill + 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 db79338035d..f7bacd08c8f 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 f4edb39f6e3..4c0d298cfcc 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 00000000000..c6ebf1ebab2 --- /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 struct is_void { static constexpr bool value = false; }; +template <> struct is_void { static constexpr bool value = true; }; + +template +constexpr decltype(auto) pipeline(S source, T target) +{ + return [=](auto... args) + { + if constexpr(false + && is_void::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(); +}