cppfront
cppfront copied to clipboard
[BUG] Multiple return values failed to work in presence of lambda
When dealing with multiple return values cppfront creates local cpp2::deferred_init values and moves them on the return of the function.
It works in the below code:
fun: () -> (ri : int) = {
ri = 0;
ri = 42;
return;
}
main: () -> int = {
r := fun(1);
return r.ri;
}
and generates
// ----- Cpp2 support -----
#include "cpp2util.h"
#line 1 "tests/get_declarations_return_vals.cpp2"
struct fun__ret {
int ri;
};
#line 2 "tests/get_declarations_return_vals.cpp2"
[[nodiscard]] auto fun() -> fun__ret;
#line 9 "tests/get_declarations_return_vals.cpp2"
[[nodiscard]] auto main() -> int;
//=== Cpp2 definitions ==========================================================
#line 1 "tests/get_declarations_return_vals.cpp2"
[[nodiscard]] auto fun() -> fun__ret{
cpp2::deferred_init<int> ri;
#line 2 "tests/get_declarations_return_vals.cpp2"
ri.construct(0);
ri.value() = 42;
return { std::move(ri.value()) };
}
[[nodiscard]] auto main() -> int{
auto r { fun(1) };
return r.ri;
}
Adding a lambda between two assignments to ri variable (skipping boilerplate):
fun: () -> (ri : int) = {
ri = 0;
pred := :(e:_) -> bool = { return e == 1; };
ri = 42;
return;
}
breaks that and generates (skipping boilerplate):
#line 1 "tests/get_declarations_return_vals.cpp2"
[[nodiscard]] auto fun() -> fun__ret{
cpp2::deferred_init<int> ri;
#line 2 "tests/get_declarations_return_vals.cpp2"
ri.construct(0);
auto pred { [](auto const& e) -> bool{return e == 1; } };
ri = 42;
return { std::move(ri.value()) };
}
The above code does not compile as cpp2::deferred_init<int> has no operator= defined. cppfront does not add a call to deferred_init::value() method and generates ri = 42; call that does not compile.
If we remove the first assignment and run cppfront on the code:
fun: () -> (ri : int) = {
pred := :(e:_) -> bool = { return e == 1; };
ri = 42;
return;
}
then cppfront will generate:
#line 1 "tests/get_declarations_return_vals.cpp2"
[[nodiscard]] auto fun() -> fun__ret{
cpp2::deferred_init<int> ri;
#line 2 "tests/get_declarations_return_vals.cpp2"
auto pred { [](auto const& e) -> bool{return e == 1; } };
ri.construct(42);
return { std::move(ri.value()) };
}
And will successfully compile.
We can also move the setting of the initial value to the declaration of multiple return values:
fun: () -> (ri : int = 0) = {
pred := :(e:_) -> bool = { return e == 1; };
ri = 42;
return;
}
and cppfront will generate:
#line 1 "/tests/get_declarations_return_vals.cpp2"
[[nodiscard]] auto fun() -> fun__ret{
int ri = 0;
#line 2 "tests/get_declarations_return_vals.cpp2"
auto pred { [](auto const& e) -> bool{return e == 1; } };
ri = 42;
return { std::move(ri.value()) };
}
The cpp2::deferred_init is not created at all and the int value is created - and that is fine as a variable is initialized. Unfortunately, cppfront calls the deferred_init::value() method on the return statement.