Here, we are calling template_class_depth on a FIELD_DECL corresponding to a lambda that is used inside variable template. template_class_depth however does not see that this FIELD_DECL is used inside a variable template binding because its chain of DECL_CONTEXTs does not include the corresponding VAR_DECL. So template_class_depth returns the wrong template nesting level which causes its callers to malfunction. In particular we strip a template argument level in tsubst_copy [FIELD_DECL] when we shouldn't have.
This patch makes template_class_depth look at a lambda type's LAMBDA_TYPE_EXTRA_SCOPE field instead of its TYPE_CONTEXT, so that it can iterate into an enclosing variable template, if applicable. Tested on x86_64-pc-linux gnu, no new regressions. Also tested against Boost. Is this OK to commit? gcc/cp/ChangeLog: PR c++/66786 * pt.c (template_class_depth): Given a lambda type, iterate into its LAMBDA_TYPE_EXTRA_SCOPE field instead of its TYPE_CONTEXT. Given a VAR_DECL, iterate into its CP_DECL_CONTEXT. gcc/testsuite/ChangeLog: PR c++/66786 * g++.dg/cpp1y/var-templ48.C: New test. * g++.dg/cpp1y/var-templ49.C: New test. --- gcc/cp/pt.c | 12 ++++++++---- gcc/testsuite/g++.dg/cpp1y/var-templ48.C | 5 +++++ gcc/testsuite/g++.dg/cpp1y/var-templ49.C | 9 +++++++++ 3 files changed, 22 insertions(+), 4 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp1y/var-templ48.C create mode 100644 gcc/testsuite/g++.dg/cpp1y/var-templ49.C diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 4d405cf..5c344c1 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -369,16 +369,20 @@ template_class_depth (tree type) { int depth; - for (depth = 0; - type && TREE_CODE (type) != NAMESPACE_DECL; - type = (TREE_CODE (type) == FUNCTION_DECL) - ? CP_DECL_CONTEXT (type) : CP_TYPE_CONTEXT (type)) + for (depth = 0; type && TREE_CODE (type) != NAMESPACE_DECL; ) { tree tinfo = get_template_info (type); if (tinfo && PRIMARY_TEMPLATE_P (TI_TEMPLATE (tinfo)) && uses_template_parms (INNERMOST_TEMPLATE_ARGS (TI_ARGS (tinfo)))) ++depth; + + if (VAR_OR_FUNCTION_DECL_P (type)) + type = CP_DECL_CONTEXT (type); + else if (LAMBDA_TYPE_P (type)) + type = LAMBDA_TYPE_EXTRA_SCOPE (type); + else + type = CP_TYPE_CONTEXT (type); } return depth; diff --git a/gcc/testsuite/g++.dg/cpp1y/var-templ48.C b/gcc/testsuite/g++.dg/cpp1y/var-templ48.C new file mode 100644 index 0000000..f0c7693 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/var-templ48.C @@ -0,0 +1,5 @@ +// PR c++/66786 +// { dg-do compile { target c++14 } } + +template <typename... T> auto list = [](T... xs) { [=](auto f) { f(xs...); }; }; +int main() { list<int>(0); } diff --git a/gcc/testsuite/g++.dg/cpp1y/var-templ49.C b/gcc/testsuite/g++.dg/cpp1y/var-templ49.C new file mode 100644 index 0000000..cd3f230 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/var-templ49.C @@ -0,0 +1,9 @@ +// PR c++/66786 +// { dg-do compile { target c++14 } } + +int f (int, bool); + +template <typename> +auto list = [](auto... xs) { return [=](auto f, auto... ys) { return f(xs..., ys...); }; }; + +const int &a = list<int>(0, true)(f); -- 2.7.1.257.g925a48d