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;