Tested x86_64-pc-linux-gnu, applying to trunk. Patrick, can you verify that this resolves 109506 and add whatever testcase(s) seem appropriate from that PR?
-- 8< -- Here it turns out I also needed to adjust cfun when stepping out of the member function to instantiate the DMI. But instead of adding that tweak, let's unify with instantiate_body and just push_to_top_level instead of trying to do the minimum subset of it. There was no measurable change in compile time on stdc++.h. This should also resolve 109506 without yet another tweak. PR c++/109666 gcc/cp/ChangeLog: * name-lookup.cc (maybe_push_to_top_level) (maybe_pop_from_top_level): Split out... * pt.cc (instantiate_body): ...from here. * init.cc (maybe_instantiate_nsdmi_init): Use them. * name-lookup.h: Declare them.. gcc/testsuite/ChangeLog: * g++.dg/cpp0x/nsdmi-array2.C: New test. --- gcc/cp/name-lookup.h | 2 ++ gcc/cp/init.cc | 25 ++------------- gcc/cp/name-lookup.cc | 37 +++++++++++++++++++++++ gcc/cp/pt.cc | 20 ++---------- gcc/testsuite/g++.dg/cpp0x/nsdmi-array2.C | 15 +++++++++ 5 files changed, 58 insertions(+), 41 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp0x/nsdmi-array2.C diff --git a/gcc/cp/name-lookup.h b/gcc/cp/name-lookup.h index c234cd44356..b3e708561d8 100644 --- a/gcc/cp/name-lookup.h +++ b/gcc/cp/name-lookup.h @@ -466,6 +466,8 @@ extern void push_nested_namespace (tree); extern void pop_nested_namespace (tree); extern void push_to_top_level (void); extern void pop_from_top_level (void); +extern bool maybe_push_to_top_level (tree); +extern void maybe_pop_from_top_level (bool); extern void push_using_decl_bindings (tree, tree); /* Lower level interface for modules. */ diff --git a/gcc/cp/init.cc b/gcc/cp/init.cc index 1dd24e30d7c..0b35e1092e9 100644 --- a/gcc/cp/init.cc +++ b/gcc/cp/init.cc @@ -597,32 +597,14 @@ maybe_instantiate_nsdmi_init (tree member, tsubst_flags_t complain) bool pushed = false; tree ctx = type_context_for_name_lookup (member); - processing_template_decl_sentinel ptds (/*reset*/false); + bool push_to_top = maybe_push_to_top_level (member); if (!currently_open_class (ctx)) { - 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; } - /* If we didn't push_to_top_level, still step out of constructor - scope so build_base_path doesn't try to use its __in_chrg. */ - tree cfd = current_function_decl; - auto cbl = current_binding_level; - if (at_function_scope_p ()) - { - current_function_decl - = decl_function_context (current_function_decl); - while (current_binding_level->kind != sk_class) - current_binding_level = current_binding_level->level_chain; - } - inject_this_parameter (ctx, TYPE_UNQUALIFIED); start_lambda_scope (member); @@ -639,15 +621,12 @@ maybe_instantiate_nsdmi_init (tree member, tsubst_flags_t complain) if (init != error_mark_node) DECL_INITIAL (member) = init; - current_function_decl = cfd; - current_binding_level = cbl; if (pushed) { pop_deferring_access_checks (); pop_nested_class (); - if (!LOCAL_CLASS_P (ctx)) - pop_from_top_level (); } + maybe_pop_from_top_level (push_to_top); input_location = sloc; } diff --git a/gcc/cp/name-lookup.cc b/gcc/cp/name-lookup.cc index 477cddd7543..7c61bc3bf61 100644 --- a/gcc/cp/name-lookup.cc +++ b/gcc/cp/name-lookup.cc @@ -8236,6 +8236,43 @@ pop_from_top_level (void) free_saved_scope = s; } +/* Like push_to_top_level, but not if D is function-local. Returns whether we + did push to top. */ + +bool +maybe_push_to_top_level (tree d) +{ + /* Push if D isn't function-local, or is a lambda function, for which name + resolution is already done. */ + bool push_to_top + = !(current_function_decl + && !LAMBDA_FUNCTION_P (d) + && decl_function_context (d) == current_function_decl); + + if (push_to_top) + push_to_top_level (); + else + { + gcc_assert (!processing_template_decl); + push_function_context (); + cp_unevaluated_operand = 0; + c_inhibit_evaluation_warnings = 0; + } + + return push_to_top; +} + +/* Return from whatever maybe_push_to_top_level did. */ + +void +maybe_pop_from_top_level (bool push_to_top) +{ + if (push_to_top) + pop_from_top_level (); + else + pop_function_context (); +} + /* Push into the scope of the namespace NS, even if it is deeply nested within another namespace. */ diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index 6df16fef0dd..3f1cf139bbd 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -26815,20 +26815,7 @@ instantiate_body (tree pattern, tree args, tree d, bool nested_p) if (current_function_decl) save_omp_privatization_clauses (omp_privatization_save); - bool push_to_top - = !(current_function_decl - && !LAMBDA_FUNCTION_P (d) - && decl_function_context (d) == current_function_decl); - - if (push_to_top) - push_to_top_level (); - else - { - gcc_assert (!processing_template_decl); - push_function_context (); - cp_unevaluated_operand = 0; - c_inhibit_evaluation_warnings = 0; - } + bool push_to_top = maybe_push_to_top_level (d); mark_template_arguments_used (pattern, args); @@ -26942,10 +26929,7 @@ instantiate_body (tree pattern, tree args, tree d, bool nested_p) if (!nested_p) TI_PENDING_TEMPLATE_FLAG (DECL_TEMPLATE_INFO (d)) = 0; - if (push_to_top) - pop_from_top_level (); - else - pop_function_context (); + maybe_pop_from_top_level (push_to_top); if (current_function_decl) restore_omp_privatization_clauses (omp_privatization_save); diff --git a/gcc/testsuite/g++.dg/cpp0x/nsdmi-array2.C b/gcc/testsuite/g++.dg/cpp0x/nsdmi-array2.C new file mode 100644 index 00000000000..5ad60f56510 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/nsdmi-array2.C @@ -0,0 +1,15 @@ +// PR c++/109666 +// { dg-do compile { target c++11 } } + +struct Point { + int value_; +}; +template <int n> struct StaticVector { + static StaticVector create() { + StaticVector output; + return output; + } + Point _M_elems[n]{}; + +}; +void f() { StaticVector<3>::create(); } base-commit: 14e881eb0305090e5b184806b917d492373d32ea -- 2.31.1