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
This commit is contained in:
Jason Merrill 2018-04-03 13:41:12 -04:00 committed by Jason Merrill
parent 3f759575d3
commit 1456e76410
4 changed files with 102 additions and 25 deletions

View 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.

View 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)

View 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

View File

@ -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();
}