From bfd6aa9903fa2292fe12561fcff59aaff0cb67bc Mon Sep 17 00:00:00 2001 From: Alistair Bell Date: Sun, 22 Jun 2025 17:03:27 -0400 Subject: [PATCH 1/2] Fix C++1 generation of function pointers. --- ...bugfix-for-function-returning-funcptr.cpp2 | 32 +++++++++ ...-bugfix-for-function-returning-funcptr.cpp | 72 +++++++++++++++++++ ...for-function-returning-funcptr.cpp2.output | 2 + source/parse.h | 7 +- source/to_cpp1.h | 5 +- 5 files changed, 113 insertions(+), 5 deletions(-) create mode 100644 regression-tests/pure2-bugfix-for-function-returning-funcptr.cpp2 create mode 100644 regression-tests/test-results/pure2-bugfix-for-function-returning-funcptr.cpp create mode 100644 regression-tests/test-results/pure2-bugfix-for-function-returning-funcptr.cpp2.output diff --git a/regression-tests/pure2-bugfix-for-function-returning-funcptr.cpp2 b/regression-tests/pure2-bugfix-for-function-returning-funcptr.cpp2 new file mode 100644 index 000000000..aa01b279c --- /dev/null +++ b/regression-tests/pure2-bugfix-for-function-returning-funcptr.cpp2 @@ -0,0 +1,32 @@ +g_inttemplate: std::optional = std::nullopt; +g_template: std::optional<*(_: int) -> void> = std::nullopt; +g_signal_handlers: std::unordered_map void> = (); + +intfuncptr: type == *(_: int) -> void; + +set_signal: (signum: int, handler: *(_: int) -> void) -> *(_: int) -> void = { + default_handler := :(foo: int) -> void = { + // Default handler does nothing + _ = foo; + }; + old_handler: intfuncptr = default_handler; + if g_signal_handlers.find(signum) != g_signal_handlers.end() { + old_handler = g_signal_handlers[signum]; + } + g_signal_handlers[signum] = handler; + return old_handler; +} + +g_signal: i64 = 0; +inc_signal: (signum: int) -> void = { + g_signal += signum; +} +dec_signal: (signum: int) -> void = { + g_signal -= signum; +} + +main: () -> int = { + _ = set_signal(1, inc_signal); + cmpx := set_signal(1, dec_signal); + return cmpx != inc_signal; +} diff --git a/regression-tests/test-results/pure2-bugfix-for-function-returning-funcptr.cpp b/regression-tests/test-results/pure2-bugfix-for-function-returning-funcptr.cpp new file mode 100644 index 000000000..fee74ea77 --- /dev/null +++ b/regression-tests/test-results/pure2-bugfix-for-function-returning-funcptr.cpp @@ -0,0 +1,72 @@ + +#define CPP2_IMPORT_STD Yes + +//=== Cpp2 type declarations ==================================================== + + +#include "cpp2util.h" + +#line 1 "pure2-bugfix-for-function-returning-funcptr.cpp2" + + +//=== Cpp2 type definitions and function declarations =========================== + +#line 1 "pure2-bugfix-for-function-returning-funcptr.cpp2" +extern std::optional g_inttemplate; +#line 2 "pure2-bugfix-for-function-returning-funcptr.cpp2" +extern std::optional unnamed_param_1)> g_template; +extern std::unordered_map unnamed_param_1)> g_signal_handlers; + +using intfuncptr = void(*)([[maybe_unused]] cpp2::impl::in unnamed_param_1); + +[[nodiscard]] auto set_signal(cpp2::impl::in signum, void(*handler)([[maybe_unused]] cpp2::impl::in unnamed_param_1)) -> void(*)([[maybe_unused]] cpp2::impl::in unnamed_param_1); + +#line 20 "pure2-bugfix-for-function-returning-funcptr.cpp2" +extern cpp2::i64 g_signal; +auto inc_signal(cpp2::impl::in signum) -> void; + +#line 24 "pure2-bugfix-for-function-returning-funcptr.cpp2" +auto dec_signal(cpp2::impl::in signum) -> void; + +#line 28 "pure2-bugfix-for-function-returning-funcptr.cpp2" +[[nodiscard]] auto main() -> int; + +//=== Cpp2 function definitions ================================================= + +#line 1 "pure2-bugfix-for-function-returning-funcptr.cpp2" +std::optional g_inttemplate {std::nullopt}; +#line 2 "pure2-bugfix-for-function-returning-funcptr.cpp2" +std::optional unnamed_param_1)> g_template {std::nullopt}; +std::unordered_map unnamed_param_1)> g_signal_handlers {}; + +#line 7 "pure2-bugfix-for-function-returning-funcptr.cpp2" +[[nodiscard]] auto set_signal(cpp2::impl::in signum, void(*handler)([[maybe_unused]] cpp2::impl::in unnamed_param_1)) -> void(*)([[maybe_unused]] cpp2::impl::in unnamed_param_1){ + auto default_handler {[](cpp2::impl::in foo) -> void{ + // Default handler does nothing + static_cast(foo); + }}; + intfuncptr old_handler {cpp2::move(default_handler)}; + if (CPP2_UFCS(find)(g_signal_handlers, signum) != CPP2_UFCS(end)(g_signal_handlers)) { + old_handler = CPP2_ASSERT_IN_BOUNDS(g_signal_handlers, signum); + } + CPP2_ASSERT_IN_BOUNDS(g_signal_handlers, signum) = handler; + return old_handler; +} + +cpp2::i64 g_signal {0}; +#line 21 "pure2-bugfix-for-function-returning-funcptr.cpp2" +auto inc_signal(cpp2::impl::in signum) -> void{ + g_signal += signum; +} +#line 24 "pure2-bugfix-for-function-returning-funcptr.cpp2" +auto dec_signal(cpp2::impl::in signum) -> void{ + g_signal -= signum; +} + +#line 28 "pure2-bugfix-for-function-returning-funcptr.cpp2" +[[nodiscard]] auto main() -> int{ + static_cast(set_signal(1, inc_signal)); + auto cmpx {set_signal(1, dec_signal)}; + return cpp2::move(cmpx) != inc_signal; +} + diff --git a/regression-tests/test-results/pure2-bugfix-for-function-returning-funcptr.cpp2.output b/regression-tests/test-results/pure2-bugfix-for-function-returning-funcptr.cpp2.output new file mode 100644 index 000000000..ba1b049ee --- /dev/null +++ b/regression-tests/test-results/pure2-bugfix-for-function-returning-funcptr.cpp2.output @@ -0,0 +1,2 @@ +pure2-bugfix-for-function-returning-funcptr.cpp2... ok (all Cpp2, passes safety checks) + diff --git a/source/parse.h b/source/parse.h index 4102558ed..831321b0b 100644 --- a/source/parse.h +++ b/source/parse.h @@ -7266,7 +7266,8 @@ class parser auto type_id( bool allow_omitting_type_name = false, bool allow_constraint = false, - bool allow_function_type = false + bool allow_function_type = false, + bool allow_qualified_function_type = true ) -> std::unique_ptr { @@ -7339,7 +7340,9 @@ class parser assert (n->id.index() == type_id_node::unqualified); } else if (std::unique_ptr id = {}; - allow_function_type + (allow_function_type || + (allow_qualified_function_type && + !n->pc_qualifiers.empty())) && (id = function_type({})) != nullptr ) { diff --git a/source/to_cpp1.h b/source/to_cpp1.h index 74ab07acf..2796eb943 100644 --- a/source/to_cpp1.h +++ b/source/to_cpp1.h @@ -1978,9 +1978,8 @@ class cppfront // Handle function types if (n.is_function_typeid()) { - // If identifier is nonempty, we're doing a local variable with a (pointer to) - // function typeid, so stick in the pointers here for inside-out Cpp1 declarations - if (!identifier.empty()) { + // If there are qualifiers, stick in the pointers here for inside-out Cpp1 declarations + if (n.pc_qualifiers.size() > 0) { for (auto q: n.pc_qualifiers) { if (*q == "const") { identifier = " " + identifier; } identifier = q->as_string_view() + identifier; From 76f9e6d80cbd272a201df61d60bdd2f7acd30ebe Mon Sep 17 00:00:00 2001 From: Herb Sutter Date: Sun, 27 Jul 2025 17:30:17 -0400 Subject: [PATCH 2/2] Update regression test results --- .../pure2-bugfix-for-function-returning-funcptr.cpp.output | 1 + 1 file changed, 1 insertion(+) create mode 100644 regression-tests/test-results/msvc-2022-c++latest/pure2-bugfix-for-function-returning-funcptr.cpp.output diff --git a/regression-tests/test-results/msvc-2022-c++latest/pure2-bugfix-for-function-returning-funcptr.cpp.output b/regression-tests/test-results/msvc-2022-c++latest/pure2-bugfix-for-function-returning-funcptr.cpp.output new file mode 100644 index 000000000..e426e229b --- /dev/null +++ b/regression-tests/test-results/msvc-2022-c++latest/pure2-bugfix-for-function-returning-funcptr.cpp.output @@ -0,0 +1 @@ +pure2-bugfix-for-function-returning-funcptr.cpp