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:
parent
3f759575d3
commit
1456e76410
@ -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.
|
||||
|
||||
|
@ -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)
|
||||
|
84
gcc/cp/pt.c
84
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
|
||||
|
33
gcc/testsuite/g++.dg/cpp1z/constexpr-if17.C
Normal file
33
gcc/testsuite/g++.dg/cpp1z/constexpr-if17.C
Normal 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();
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user