Skip to content

[BUG] Move on definitive last use in fold expressions #1279

Open
@Velocirobtor

Description

@Velocirobtor

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions