Hi Jason, I've reopened 64382 and unhooked it from 61636 (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=64382#c6).
This is a rebase of my original patch for 64382 from April 2015 against latest master. My query about caching parsing_default_capturing_generic_lambda_in_template() still applies. It is currently called once for each id-expression that is dependent but its result will be consistent within a particular lambda body. It feels like we should compute the state once when entering a lambda body and refer to the cached state thereafter (resetting/restoring it on descent/return from each lambda we come across). Cheers, Adam 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. --- gcc/cp/cp-tree.h | 1 + gcc/cp/parser.c | 25 +++++++++++++++++++++++++ gcc/cp/semantics.c | 8 +++++--- gcc/testsuite/g++.dg/cpp1y/pr64382.C | 23 +++++++++++++++++++++++ 4 files changed, 54 insertions(+), 3 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp1y/pr64382.C diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 9c4436710dd..77d20d4d3dc 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -6110,6 +6110,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 29dcfea283f..5cc0ddacc2b 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -20450,6 +20450,31 @@ parsing_nsdmi (void) return false; } +/* Return true iff our current scope is a default capturing generic lambda + defined within a template. */ + +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 42024755e4f..3c0bd7e751c 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -3562,9 +3562,11 @@ 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. */ + 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/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<typename T> +struct my_queue +{ + void push(T) + { + } + void ice() + { + auto L = [=](auto &&v) { + push(v); + }; + trav(L); + } + template<typename F> + void trav(F &&f) + { + f(T()); + } +}; +template struct my_queue<int>; -- 2.11.0