From bb6a6ee9db925bea82bba47b1b3cdd3555fb539b Mon Sep 17 00:00:00 2001 From: Adam Butcher Date: Fri, 27 Jan 2017 07:59:06 +0000 Subject: [PATCH] re PR c++/64382 (ICE due to use of `this` inside a lambda that captures everything by ref inside a member function of a class template) Fix PR c++/64382 PR c++/64382 * cp/parser.c (parsing_default_capturing_generic_lambda_in_template): New function. * cp/cp-tree.h: Declare it. * cp/semantics.c (finish_id_expression): Resolve names within a default capturing generic lambda defined within a template prior to instantiation to allow for captures to be added to the closure type. PR c++/64382 * g++.dg/cpp1y/pr64382.C: New test. From-SVN: r244962 --- gcc/cp/ChangeLog | 10 ++++++++++ gcc/cp/cp-tree.h | 1 + gcc/cp/parser.c | 27 +++++++++++++++++++++++++++ gcc/cp/semantics.c | 10 +++++++--- gcc/testsuite/ChangeLog | 5 +++++ gcc/testsuite/g++.dg/cpp1y/pr64382.C | 23 +++++++++++++++++++++++ 6 files changed, 73 insertions(+), 3 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp1y/pr64382.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 443df6980ea..406d382135f 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,13 @@ +2017-01-27 Adam Butcher + + PR c++/64382 + * cp/parser.c (parsing_default_capturing_generic_lambda_in_template): + New function. + * cp/cp-tree.h: Declare it. + * cp/semantics.c (finish_id_expression): Resolve names within a default + capturing generic lambda defined within a template prior to + instantiation to allow for captures to be added to the closure type. + 2017-01-26 Jakub Jelinek PR c++/68727 diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index f91b83027aa..f412ddd6e4a 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -6118,6 +6118,7 @@ extern bool maybe_clone_body (tree); /* In parser.c */ extern tree cp_convert_range_for (tree, tree, tree, tree, unsigned int, bool); extern bool parsing_nsdmi (void); +extern bool parsing_default_capturing_generic_lambda_in_template (void); extern void inject_this_parameter (tree, cp_cv_quals); /* in pt.c */ diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 9a61eb1604b..7f685506bc1 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -20454,6 +20454,33 @@ parsing_nsdmi (void) return false; } +/* Return true iff our current scope is a default capturing generic lambda + defined within a template. FIXME: This is part of a workaround (see + semantics.c) to handle building lambda closure types correctly in templates + which we ultimately want to defer to instantiation time. */ + +bool +parsing_default_capturing_generic_lambda_in_template (void) +{ + if (!processing_template_decl || !current_class_type) + return false; + + tree lam = CLASSTYPE_LAMBDA_EXPR (current_class_type); + if (!lam || LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (lam) == CPLD_NONE) + return false; + + tree callop = lambda_function (lam); + if (!callop) + return false; + + return (DECL_TEMPLATE_INFO (callop) + && (DECL_TEMPLATE_RESULT (DECL_TI_TEMPLATE (callop)) == callop) + && ((current_nonlambda_class_type () + && CLASSTYPE_TEMPLATE_INFO (current_nonlambda_class_type ())) + || ((current_nonlambda_function () + && DECL_TEMPLATE_INFO (current_nonlambda_function ()))))); +} + /* Parse a late-specified return type, if any. This is not a separate non-terminal, but part of a function declarator, which looks like diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 6d5ea955db3..42b555c5883 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -3563,9 +3563,13 @@ finish_id_expression (tree id_expression, ? CP_ID_KIND_UNQUALIFIED_DEPENDENT : CP_ID_KIND_UNQUALIFIED))); - /* If the name was dependent on a template parameter, we will - resolve the name at instantiation time. */ - if (dependent_p) + /* If the name was dependent on a template parameter and we're not in a + default capturing generic lambda within a template, we will resolve the + name at instantiation time. FIXME: For lambdas, we should defer + building the closure type until instantiation time then we won't need + the extra test here. */ + if (dependent_p + && !parsing_default_capturing_generic_lambda_in_template ()) { if (DECL_P (decl) && any_dependent_type_attributes_p (DECL_ATTRIBUTES (decl))) diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 0bf4dfb01eb..71ef013f098 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2017-01-27 Adam Butcher + + PR c++/64382 + * g++.dg/cpp1y/pr64382.C: New test. + 2017-01-26 Martin Sebor PR middle-end/78703 diff --git a/gcc/testsuite/g++.dg/cpp1y/pr64382.C b/gcc/testsuite/g++.dg/cpp1y/pr64382.C new file mode 100644 index 00000000000..8f2e931e048 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/pr64382.C @@ -0,0 +1,23 @@ +// PR c++/64382 +// { dg-do compile { target c++14 } } + +template +struct my_queue +{ + void push(T) + { + } + void ice() + { + auto L = [=](auto &&v) { + push(v); + }; + trav(L); + } + template + void trav(F &&f) + { + f(T()); + } +}; +template struct my_queue; -- 2.30.2