From: Jason Merrill Date: Thu, 31 Aug 2017 15:39:04 +0000 (-0400) Subject: PR c++/82029 - __PRETTY_FUNCTION__ in lambda in template X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=b54d4018b17c8e7be96cedd211e7c9dd5d1c3e43;p=gcc.git PR c++/82029 - __PRETTY_FUNCTION__ in lambda in template * pt.c (enclosing_instantiation_of, lambda_fn_in_template_p) (regenerated_lambda_fn_p): New. (tsubst_decl) [VAR_DECL]: Use enclosing_instantiation_of. (tsubst_copy) [VAR_DECL]: Likewise. From-SVN: r251567 --- diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index a8c13672b5f..4a791ddbbb4 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,5 +1,11 @@ 2017-08-30 Jason Merrill + PR c++/82029 - __PRETTY_FUNCTION__ in lambda in template + * pt.c (enclosing_instantiation_of, lambda_fn_in_template_p) + (regenerated_lambda_fn_p): New. + (tsubst_decl) [VAR_DECL]: Use enclosing_instantiation_of. + (tsubst_copy) [VAR_DECL]: Likewise. + PR c++/82030 - ICE inheriting from multiple lambdas PR c++/80767 * call.c (compare_ics): Handle null candidate. diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index f4868abfda2..d5ab93985a3 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -12587,6 +12587,63 @@ tsubst_template_decl (tree t, tree args, tsubst_flags_t complain, return r; } +/* True if FN is the op() for a lambda in an uninstantiated template. */ + +bool +lambda_fn_in_template_p (tree fn) +{ + if (!LAMBDA_FUNCTION_P (fn)) + return false; + tree closure = DECL_CONTEXT (fn); + return CLASSTYPE_TEMPLATE_INFO (closure) != NULL_TREE; +} + +/* True if FN is the op() for a lambda regenerated from a lambda in an + uninstantiated template. */ + +bool +regenerated_lambda_fn_p (tree fn) +{ + return (LAMBDA_FUNCTION_P (fn) + && !DECL_TEMPLATE_INSTANTIATION (fn)); +} + +/* We're instantiating a variable from template function TCTX. Return the + corresponding current enclosing scope. This gets complicated because lambda + functions in templates are regenerated rather than instantiated, but generic + lambda functions are subsequently instantiated. */ + +static tree +enclosing_instantiation_of (tree tctx) +{ + tree fn = current_function_decl; + int lambda_count = 0; + + for (; tctx && lambda_fn_in_template_p (tctx); + tctx = decl_function_context (tctx)) + ++lambda_count; + for (; fn; fn = decl_function_context (fn)) + { + tree lambda = fn; + int flambda_count = 0; + for (; fn && regenerated_lambda_fn_p (fn); + fn = decl_function_context (fn)) + ++flambda_count; + if (DECL_TEMPLATE_INFO (fn) + ? most_general_template (fn) != most_general_template (tctx) + : fn != tctx) + continue; + if (lambda_count) + { + fn = lambda; + while (flambda_count-- > lambda_count) + fn = decl_function_context (fn); + } + return fn; + } + gcc_unreachable (); +} + /* Substitute the ARGS into the T, which is a _DECL. Return the result of the substitution. Issue error and warning messages under control of COMPLAIN. */ @@ -12955,7 +13012,7 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain) enclosing function, in which case we need to fill it in now. */ if (TREE_STATIC (t)) { - tree fn = tsubst (DECL_CONTEXT (t), args, complain, in_decl); + tree fn = enclosing_instantiation_of (DECL_CONTEXT (t)); if (fn != current_function_decl) ctx = fn; } @@ -14734,9 +14791,7 @@ tsubst_copy (tree t, tree args, tsubst_flags_t complain, tree in_decl) if (r && !is_capture_proxy (r)) { /* Make sure that the one we found is the one we want. */ - tree ctx = DECL_CONTEXT (t); - if (DECL_LANG_SPECIFIC (ctx) && DECL_TEMPLATE_INFO (ctx)) - ctx = tsubst (ctx, args, complain, in_decl); + tree ctx = enclosing_instantiation_of (DECL_CONTEXT (t)); if (ctx != DECL_CONTEXT (r)) r = NULL_TREE; } diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-__func__2.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-__func__2.C new file mode 100644 index 00000000000..bc0e3b2a55b --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-__func__2.C @@ -0,0 +1,13 @@ +// PR c++/82029 +// { dg-do compile { target c++11 } } + +template struct A { + void m_fn1() { + [] { return __func__; }(); + } +}; +struct B { + A a; + void m_fn2(); +}; +void B::m_fn2() { a.m_fn1(); }