The problem here was that when looking for unexpanded packs, we looked into IF_STMT_EXTRA_ARGS of a constexpr if, which includes the bindings for function parameter packs, but not in a way that uses them. So we shouldn't look there for unexpanded packs.
Trying to write a smaller testcase revealed another bug, whereby collecting the bindings for captured variables wasn't respecting unevaluated context. Tested x86_64-pc-linux-gnu, applying to trunk.
commit c63bbedf903c28225d9cc273c14d3023e6074fa5 Author: Jason Merrill <ja...@redhat.com> Date: Fri Jul 13 23:22:26 2018 +1000 PR c++/86480 - nested variadic lambda and constexpr if. * pt.c (find_parameter_packs_r) [IF_STMT]: Don't walk into IF_STMT_EXTRA_ARGS. * tree.c (cp_walk_subtrees) [DECLTYPE_TYPE]: Set cp_unevaluated_operand. [ALIGNOF_EXPR] [SIZEOF_EXPR] [NOEXCEPT_EXPR]: Likewise. diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 7e858a19d76..2b885793d3f 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -3865,6 +3865,17 @@ find_parameter_packs_r (tree *tp, int *walk_subtrees, void* data) return NULL_TREE; } + case IF_STMT: + cp_walk_tree (&IF_COND (t), &find_parameter_packs_r, + ppd, ppd->visited); + cp_walk_tree (&THEN_CLAUSE (t), &find_parameter_packs_r, + ppd, ppd->visited); + cp_walk_tree (&ELSE_CLAUSE (t), &find_parameter_packs_r, + ppd, ppd->visited); + /* Don't walk into IF_STMT_EXTRA_ARGS. */ + *walk_subtrees = 0; + return NULL_TREE; + default: return NULL_TREE; } diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index b1333f55e39..7e2a77bf67b 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -4865,7 +4865,19 @@ cp_walk_subtrees (tree *tp, int *walk_subtrees_p, walk_tree_fn func, break; case DECLTYPE_TYPE: - WALK_SUBTREE (DECLTYPE_TYPE_EXPR (*tp)); + ++cp_unevaluated_operand; + /* We can't use WALK_SUBTREE here because of the goto. */ + result = cp_walk_tree (&DECLTYPE_TYPE_EXPR (*tp), func, data, pset); + --cp_unevaluated_operand; + *walk_subtrees_p = 0; + break; + + case ALIGNOF_EXPR: + case SIZEOF_EXPR: + case NOEXCEPT_EXPR: + ++cp_unevaluated_operand; + result = cp_walk_tree (&TREE_OPERAND (*tp, 0), func, data, pset); + --cp_unevaluated_operand; *walk_subtrees_p = 0; break; diff --git a/gcc/testsuite/g++.dg/cpp1z/constexpr-if24.C b/gcc/testsuite/g++.dg/cpp1z/constexpr-if24.C new file mode 100644 index 00000000000..cbdb38d95c3 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/constexpr-if24.C @@ -0,0 +1,21 @@ +// PR c++/86480 +// { dg-additional-options -std=c++17 } + +template <class...> constexpr bool val = true; + +template <class... T> +void f() +{ + [](auto... p) + { + []{ + if constexpr (val<T..., decltype(p)...>) { return true; } + return false; + }(); + }(42); +} + +int main() +{ + f<int>(); +}