Since, during partial instantiation of a generic lambda, we don't substitute into the body of a constexpr if, we don't do lambda capture as part of substitution. But extract_locals_r is supposed to do it as part of remembering the substitution context to be used later.
As it turns out, this was failing because walk_tree_1 expects the DECL_INITIAL of a local variable to be walked in the context of the BIND_EXPR, but we don't build BIND_EXPRs for compound-statements in a template. So in a template, let's walk the fields of a VAR_DECL from its DECL_EXPR. Tested x86_64-pc-linux-gnu, applying to trunk.
commit a99a47e6326b7278d660dcebba8ebcbec863f04a Author: Jason Merrill <ja...@redhat.com> Date: Wed Apr 4 14:24:34 2018 -0400 PR c++/85200 - ICE with constexpr if in generic lambda. * tree.c (cp_walk_subtrees): Walk into DECL_EXPR in templates. diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index 7ddc2cb5e2d..d0835cfaa29 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -4894,10 +4894,12 @@ cp_walk_subtrees (tree *tp, int *walk_subtrees_p, walk_tree_fn func, /* User variables should be mentioned in BIND_EXPR_VARS and their initializers and sizes walked when walking the containing BIND_EXPR. Compiler temporaries are - handled here. */ + handled here. And also normal variables in templates, + since do_poplevel doesn't build a BIND_EXPR then. */ if (VAR_P (TREE_OPERAND (*tp, 0)) - && DECL_ARTIFICIAL (TREE_OPERAND (*tp, 0)) - && !TREE_STATIC (TREE_OPERAND (*tp, 0))) + && (processing_template_decl + || (DECL_ARTIFICIAL (TREE_OPERAND (*tp, 0)) + && !TREE_STATIC (TREE_OPERAND (*tp, 0))))) { tree decl = TREE_OPERAND (*tp, 0); WALK_SUBTREE (DECL_INITIAL (decl)); diff --git a/gcc/testsuite/g++.dg/cpp1z/constexpr-if18.C b/gcc/testsuite/g++.dg/cpp1z/constexpr-if18.C new file mode 100644 index 00000000000..03ad620e8d9 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/constexpr-if18.C @@ -0,0 +1,15 @@ +// PR c++/85200 +// { dg-additional-options -std=c++17 } + +template <typename T> +void f(){ + [](auto v, auto b){ + if constexpr (sizeof(v) == sizeof(int)) { + auto x = b; + } + }(0, 1); +} + +int main(){ + f<int>(); +}