Description
Describe the bug
If the definitive last use of a variable is inside a fold expression, cppfront will still emit cpp2::move(<variable>)
even though this will most likely lead to multiple moves from <variable>
.
To Reproduce
Compile the following cpp2 code:
foo: (forward item: _) = {
std::print(" {}", std::is_rvalue_reference_v<decltype(item)>);
}
bar_fold: <Is...: std::size_t>() = {
test := 42;
((Is, foo(test)), ...);
}
int main() {
bar_fold<0, 1>();
}
This will generate this cpp1 code (omitting forward declarations):
auto foo(auto&& item) -> void{
std::print(" {}", std::is_rvalue_reference_v<decltype(CPP2_FORWARD(item))>);
}
template<std::size_t ...Is> auto bar_fold() -> void{
auto test {42};
((Is, foo(cpp2::move(test))), ...);
}
int main() {
bar_fold<0, 1>();
}
which prints " true true"
Expected Behavior
I think one of the following should happen:
- It behaves like an "equivalent" for loop -> it prints " false false"
- It behaves like an "equivalent" manually unrolled implementation -> it prints " false true"
The first would just require not emitting cpp2::move
in fold expressions. The latter could be achieved by generating code somewhere along the lines of:
namespace cpp2 {
template<bool Condition>
constexpr decltype(auto) move_if(auto&& val) {
if constexpr(Condition) {
return move(val);
} else {
return val;
}
}
}
template<std::size_t... Is>
void bar() {
auto test{ 42 };
[&]<std::size_t... GeneratedIndices>(std::index_sequence<GeneratedIndices...>) -> decltype(auto) {
return ((Is, foo(cpp2::move_if<GeneratedIndices + 1 == sizeof...(Is)>(test))), ...);
}(std::make_index_sequence<sizeof...(Is)>{});
}
Link to Godbolt with the complete example: https://cpp2.godbolt.org/z/fcjWPfhsh
P.S. How can I silence the warning left operand of comma operator has no effect
using cpp2
Syntax? I tried static_cast<void>(Is)
which lead to cppfront suggesting Is as void
, which didn't work.