https://gcc.gnu.org/g:4652ca53fcbf01e236faa544688be25c63aefa06
commit r16-7034-g4652ca53fcbf01e236faa544688be25c63aefa06 Author: Nathaniel Shead <[email protected]> Date: Sat Jan 24 10:11:35 2026 +1100 c++: Fix behaviour of nested maybe_push_to_top_level [PR123663] What happens in the linked PR is that when evaluating the concept we call 'push_to_top_level', we see cfun is non-null, and so call 'push_function_context' which sets cfun to NULL and sets a flag so that we remember to pop it later. Then, when instantiating Foo's default constructor as part of the concept, we call 'maybe_push_to_top_level'. Here we see that 'Foo' is function-local, so '!push_to_top', and we call 'push_function_context'. This allocates a new cfun for some reason, and pushes that empty cfun. Eventually we 'maybe_pop_from_top_level', and restore that newly allocated cfun (instead of a NULL cfun), which means that when we start trying to build the new-expression (which requires building a statement list) we try accessing the (uninitialized) cfun's x_stmt_tree rather than the scope_chain's x_stmt_tree, and so crash. This fixes the issue by also remembering whether we had a cfun when doing maybe_push_to_top_level so that we only do push_function_context if needed. This also seems to fix PR123354. PR c++/123663 PR c++/123354 gcc/cp/ChangeLog: * name-lookup.cc (struct local_state_t): New flag has_cfun. (local_state_t::save_and_clear): Set has_cfun, call push_function_context iff there's a cfun to save. (local_state_t::restore): call pop_function_context if has_cfun is set. (maybe_push_to_top_level): Delegte push_function_context to local_state_t::save_and_clear. (maybe_pop_from_top_level): Delegate pop_function_context to local_state_t::restore. gcc/testsuite/ChangeLog: * g++.dg/cpp2a/concepts-pr123663.C: New test. * g++.dg/template/pr123354.C Reviewed-by: Jason Merrill <[email protected]> Reviewed-by: Patrick Palka <[email protected]> Signed-off-by: Nathaniel Shead <[email protected]> Diff: --- gcc/cp/name-lookup.cc | 12 +++++++----- gcc/testsuite/g++.dg/cpp2a/concepts-pr123663.C | 13 +++++++++++++ gcc/testsuite/g++.dg/template/pr123354.C | 18 ++++++++++++++++++ 3 files changed, 38 insertions(+), 5 deletions(-) diff --git a/gcc/cp/name-lookup.cc b/gcc/cp/name-lookup.cc index a1f0a0ff38e1..a187d65b509e 100644 --- a/gcc/cp/name-lookup.cc +++ b/gcc/cp/name-lookup.cc @@ -8960,6 +8960,7 @@ struct local_state_t int cp_unevaluated_operand; int c_inhibit_evaluation_warnings; int cp_noexcept_operand_; + bool has_cfun; static local_state_t save_and_clear () @@ -8971,6 +8972,9 @@ struct local_state_t ::c_inhibit_evaluation_warnings = 0; s.cp_noexcept_operand_ = ::cp_noexcept_operand; ::cp_noexcept_operand = 0; + s.has_cfun = !!cfun; + if (s.has_cfun) + push_function_context (); return s; } @@ -8980,6 +8984,8 @@ struct local_state_t ::cp_unevaluated_operand = this->cp_unevaluated_operand; ::c_inhibit_evaluation_warnings = this->c_inhibit_evaluation_warnings; ::cp_noexcept_operand = this->cp_noexcept_operand_; + if (this->has_cfun) + pop_function_context (); } }; @@ -9008,7 +9014,6 @@ maybe_push_to_top_level (tree d) else { gcc_assert (!processing_template_decl); - push_function_context (); local_state_stack.safe_push (local_state_t::save_and_clear ()); } @@ -9023,10 +9028,7 @@ maybe_pop_from_top_level (bool push_to_top) if (push_to_top) pop_from_top_level (); else - { - local_state_stack.pop ().restore (); - pop_function_context (); - } + local_state_stack.pop ().restore (); } /* Push into the scope of the namespace NS, even if it is deeply diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-pr123663.C b/gcc/testsuite/g++.dg/cpp2a/concepts-pr123663.C new file mode 100644 index 000000000000..8ac303683c08 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-pr123663.C @@ -0,0 +1,13 @@ +// PR c++/123663 +// { dg-do compile { target c++20 } } + +template <typename T> +concept TestConcept = requires { + new T[1]{}; +}; +struct base { + base() { + struct Foo {}; + TestConcept<Foo>; + } +}; diff --git a/gcc/testsuite/g++.dg/template/pr123354.C b/gcc/testsuite/g++.dg/template/pr123354.C new file mode 100644 index 000000000000..f87956a4c39b --- /dev/null +++ b/gcc/testsuite/g++.dg/template/pr123354.C @@ -0,0 +1,18 @@ +// PR c++/123354 +// { dg-do compile { target c++11 } } +// ICE with static local var referenced in NSDMI of local class + +template<typename T> +void foo() { + static constexpr int value = 42; + struct s1_t { + struct s2_t { + int dummy { 0 }; + char* ptr { static_cast<char*>(::operator new(sizeof(value)))}; + } s2; + } object; +} + +int main() { + foo<void>(); +}
