get_nsdmi instantiates default member initializers on demand. It tries to push into the context of the class before doing so, so access checking works properly, but since my patch for 90479 not for local classes. We should only be doing this when any template parameters have arguments. But in this case, we get here while regenerating a generic lambda, so processing_template_decl is true, even though the class and its DMI are non-dependent at this point. And so we crashed. So let's do more of the pushing into the context of the class even for local classes.
Tested x86_64-pc-linux-gnu, applying to trunk. gcc/cp/ChangeLog: PR c++/100054 PR c++/90479 * init.c (get_nsdmi): Do more context adjustment for local classes. gcc/testsuite/ChangeLog: PR c++/100054 * g++.dg/cpp1y/lambda-generic-local-class1.C: New test. --- gcc/cp/init.c | 17 +++++++++++------ .../g++.dg/cpp1y/lambda-generic-local-class1.C | 10 ++++++++++ 2 files changed, 21 insertions(+), 6 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp1y/lambda-generic-local-class1.C diff --git a/gcc/cp/init.c b/gcc/cp/init.c index 91b45a1a695..a85f4d50750 100644 --- a/gcc/cp/init.c +++ b/gcc/cp/init.c @@ -586,17 +586,21 @@ get_nsdmi (tree member, bool in_ctor, tsubst_flags_t complain) bool pushed = false; tree ctx = DECL_CONTEXT (member); - if (!currently_open_class (ctx) - && !LOCAL_CLASS_P (ctx)) + + processing_template_decl_sentinel ptds (/*reset*/false); + if (!currently_open_class (ctx)) { - push_to_top_level (); + if (!LOCAL_CLASS_P (ctx)) + push_to_top_level (); + else + /* push_to_top_level would lose the necessary function context, + just reset processing_template_decl. */ + processing_template_decl = 0; push_nested_class (ctx); push_deferring_access_checks (dk_no_deferred); pushed = true; } - gcc_checking_assert (!processing_template_decl); - inject_this_parameter (ctx, TYPE_UNQUALIFIED); start_lambda_scope (member); @@ -619,7 +623,8 @@ get_nsdmi (tree member, bool in_ctor, tsubst_flags_t complain) { pop_deferring_access_checks (); pop_nested_class (); - pop_from_top_level (); + if (!LOCAL_CLASS_P (ctx)) + pop_from_top_level (); } input_location = sloc; diff --git a/gcc/testsuite/g++.dg/cpp1y/lambda-generic-local-class1.C b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-local-class1.C new file mode 100644 index 00000000000..7498327981b --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-local-class1.C @@ -0,0 +1,10 @@ +// PR c++/100054 +// { dg-do compile { target c++14 } } + +template <class T> +void f() { + struct A { T m{}; }; + [](auto){ return A{}; }; +} + +template void f<int>(); base-commit: 0851ac6df0596df1e3b640e58094cf94ebb790b8 -- 2.27.0