From 2a810dedce593e9b015a051a0dfb36dfb7e563bf Mon Sep 17 00:00:00 2001 From: Nathan Sidwell Date: Thu, 15 Dec 2016 19:50:25 +0000 Subject: [PATCH] re PR c++/77585 (g++ incorrectly decides that member function is called without object in generic lambda) PR c++/77585 * pt.c (instantiate_decl): Push to class scope lambda resides within when instantiating a generic lambda function. PR c++/77585 * g++.dg/cpp1y/pr77585.C: New. From-SVN: r243723 --- gcc/cp/ChangeLog | 6 ++++++ gcc/cp/pt.c | 21 +++++++++++++++++- gcc/testsuite/ChangeLog | 5 +++++ gcc/testsuite/g++.dg/cpp1y/pr77585.C | 41 ++++++++++++++++++++++++++++++++++++ 4 files changed, 72 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/g++.dg/cpp1y/pr77585.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index d2e8d45..9c6ee48 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,9 @@ +2016-12-15 Nathan Sidwell + + PR c++/77585 + * pt.c (instantiate_decl): Push to class scope lambda resides + within when instantiating a generic lambda function. + 2016-12-14 Martin Sebor PR c++/78774 diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index a21be81..91178ea 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -22484,6 +22484,7 @@ instantiate_decl (tree d, int defer_ok, tree tmpl_parm; tree spec_parm; tree block = NULL_TREE; + tree lambda_ctx = NULL_TREE; /* Save away the current list, in case we are instantiating one template from within the body of another. */ @@ -22497,7 +22498,23 @@ instantiate_decl (tree d, int defer_ok, && TREE_CODE (DECL_CONTEXT (code_pattern)) == FUNCTION_DECL) block = push_stmt_list (); else - start_preparsed_function (d, NULL_TREE, SF_PRE_PARSED); + { + if (LAMBDA_FUNCTION_P (d)) + { + /* When instantiating a lambda's templated function + operator, we need to push the non-lambda class scope + of the lambda itself so that the nested function + stack is sufficiently correct to deal with this + capture. */ + lambda_ctx = DECL_CONTEXT (d); + do + lambda_ctx = decl_type_context (TYPE_NAME (lambda_ctx)); + while (lambda_ctx && LAMBDA_TYPE_P (lambda_ctx)); + if (lambda_ctx) + push_nested_class (lambda_ctx); + } + start_preparsed_function (d, NULL_TREE, SF_PRE_PARSED); + } /* Some typedefs referenced from within the template code need to be access checked at template instantiation time, i.e now. These @@ -22565,6 +22582,8 @@ instantiate_decl (tree d, int defer_ok, d = finish_function (0); expand_or_defer_fn (d); } + if (lambda_ctx) + pop_nested_class (); if (DECL_OMP_DECLARE_REDUCTION_P (code_pattern)) cp_check_omp_declare_reduction (d); diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 535dc84..ac49d4d 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2016-12-15 Nathan Sidwell + + PR c++/77585 + * g++.dg/cpp1y/pr77585.C: New. + 2016-12-15 David Edelsohn * gcc.dg/tree-ssa/ssa-fre-55.c: Add -Wno-psabi. diff --git a/gcc/testsuite/g++.dg/cpp1y/pr77585.C b/gcc/testsuite/g++.dg/cpp1y/pr77585.C new file mode 100644 index 0000000..aff7a61 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/pr77585.C @@ -0,0 +1,41 @@ +// PR c++/77585 +// { dg-do run { target c++14 } } + +// Confusion about this capture when instantiating generic lambda's +// function operator + +template int Eat (F &&f) { return f (1); } + +struct Foo { + int x = 1; + int Share () { return x++; } + int Frob (int); +}; + +int Foo::Frob (int r) +{ + auto lam = [&](auto) { return Share (); }; + r += Eat (lam); + + auto lam0 = [&](auto) { + auto lam1 = [&](auto) { return Share (); }; + return Eat (lam1); }; + r += Eat (lam0); + + return r; +} + +int Frob (int r) +{ + auto lam = [&](auto) { return 1; }; + r += Eat (lam); + return r; +} + + +int main () +{ + Foo f; + + return Frob (f.Frob (0)) == 4 ? 0 : 1; +} -- 2.7.4