While partially instantiating a generic lambda, we can encounter pack expansions or constexpr if where we can't actually do the substitution immediately, and instead remember a partial instantiation context in *_EXTRA_ARGS. This includes any local_specializations used in the pattern or condition. In this testcase our tree walk wasn't finding the use of i because we weren't walking into the type of a CONSTRUCTOR. Fixed by moving the code for doing that from find_parameter_packs_r into cp_walk_subtrees.
Tested x86_64-pc-linux-gnu, applying to trunk. 2020-02-11 Jason Merrill <ja...@redhat.com> PR c++/92583 PR c++/92654 * tree.c (cp_walk_subtrees): Walk CONSTRUCTOR types here. * pt.c (find_parameter_packs_r): Not here. --- gcc/cp/pt.c | 3 --- gcc/cp/tree.c | 5 ++++ gcc/testsuite/g++.dg/cpp0x/nondeduced7.C | 2 +- .../g++.dg/cpp1z/constexpr-if-lambda3.C | 24 +++++++++++++++++++ 4 files changed, 30 insertions(+), 4 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp1z/constexpr-if-lambda3.C diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index c2d3a98b1c5..6e7f4555da8 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -3924,9 +3924,6 @@ find_parameter_packs_r (tree *tp, int *walk_subtrees, void* data) case TEMPLATE_DECL: if (!DECL_TEMPLATE_TEMPLATE_PARM_P (t)) return NULL_TREE; - gcc_fallthrough(); - - case CONSTRUCTOR: cp_walk_tree (&TREE_TYPE (t), &find_parameter_packs_r, ppd, ppd->visited); return NULL_TREE; diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index eb540f851ee..736ef6fe667 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -5024,6 +5024,11 @@ cp_walk_subtrees (tree *tp, int *walk_subtrees_p, walk_tree_fn func, *walk_subtrees_p = 0; break; + case CONSTRUCTOR: + if (COMPOUND_LITERAL_P (*tp)) + WALK_SUBTREE (TREE_TYPE (*tp)); + break; + case TRAIT_EXPR: WALK_SUBTREE (TRAIT_EXPR_TYPE1 (*tp)); WALK_SUBTREE (TRAIT_EXPR_TYPE2 (*tp)); diff --git a/gcc/testsuite/g++.dg/cpp0x/nondeduced7.C b/gcc/testsuite/g++.dg/cpp0x/nondeduced7.C index a8aa073c57e..eb5d5faf493 100644 --- a/gcc/testsuite/g++.dg/cpp0x/nondeduced7.C +++ b/gcc/testsuite/g++.dg/cpp0x/nondeduced7.C @@ -2,5 +2,5 @@ // { dg-do compile { target c++11 } } template<typename, int> struct A; -template<typename T> struct A<T, T{}> {}; // { dg-error "partial specialization" } +template<typename T> struct A<T, T{}> {}; // { dg-error "partial specialization|involves template parameter" } A<int, 0> a; diff --git a/gcc/testsuite/g++.dg/cpp1z/constexpr-if-lambda3.C b/gcc/testsuite/g++.dg/cpp1z/constexpr-if-lambda3.C new file mode 100644 index 00000000000..34615f71ee2 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/constexpr-if-lambda3.C @@ -0,0 +1,24 @@ +// PR c++/92583 +// { dg-do compile { target c++17 } } + +template <int> struct a { + constexpr operator int() { return 42; } +}; +template <typename> using b = int; +template <typename d, d> struct e {}; +template <typename d, d g> using h = e<d, __integer_pack(g)...>; +template <typename j, typename k, k... index> void apply(j f, e<k, index...>) { + (f(a<index>{}), ...); +} +template <auto l, typename j> void m(j f) { + using k = b<decltype(l)>; + using n = h<k, l>; + apply(f, n{}); +} +template <int, int c> void o() { + auto p = [](auto i) { + if constexpr (a<i>{}) ; + }; + m<c>(p); +} +auto q() { o<0, 1>; } base-commit: 1cd9bef89ef25b3fd506cedbc82e8bc00ff56fa8 -- 2.18.1