hsutter / cppfront

A personal experimental C++ Syntax 2 -> Syntax 1 compiler
Other
5.39k stars 232 forks source link

[BUG] Implicit move/forward interferes with main UFCS branch #888

Closed JohelEGP closed 6 months ago

JohelEGP commented 8 months ago

Title: Implicit move/forward interferes with main UFCS branch.

Description:

The semantics of x.f() are that if x.f() is well-formed, it is that, otherwise it is f(x).

When f is a local subject to implicit move/forward, the inserted std:: call makes the main branch never be taken.

Currently, #832 prevents that from being tested.

Minimal reproducer (https://cpp2.godbolt.org/z/h14vYev4M):

t: @struct type = {
  f: (this) -> int == 2;
}
main: () = {
  {
    f := :(_) -> _ == 1;
    assert(0.f() == 1);
  }
  {
    f := :(_) -> _ == 1;
    assert(t.f() == 2);
  }
}

Commands: ```bash cppfront main.cpp2 clang++18 -std=c++23 -stdlib=libc++ -lc++abi -pedantic-errors -Wall -Wextra -Wconversion -Werror=unused-result -Werror=unused-value -Werror=unused-parameter -Werror=unused-variable -I . main.cpp ```

Expected result: The UFCS macro to consider x.f() instead of x.std::move(f).

Actual result and error:

Output:

main.cpp2(10,5): error: local variable f is not used; consider changing its name to '_' to make it explicitly anonymous, or removing it entirely if its side effects are not needed

See also:

JohelEGP commented 8 months ago

A more realistic example (https://cpp2.godbolt.org/z/b4q6fK3nP):

algo: (copy r: std::string, copy size: int) = {
  // ...
  _ = r.size();
  // ...
}
main: () = {}

With #887, I get (https://cpp1.godbolt.org/z/na3ejEGn7):

Cpp1 ```C++ //=== Cpp2 type declarations ==================================================== #include "cpp2util.h" #line 1 "x.cpp2" //=== Cpp2 type definitions and function declarations =========================== #line 1 "x.cpp2" auto algo(std::string r, int size) -> void; #line 6 "x.cpp2" auto main() -> int; //=== Cpp2 function definitions ================================================= #line 1 "x.cpp2" auto algo(std::string r, int size) -> void{ // ... #line 3 "x.cpp2" static_cast(CPP2_UFCS(std::move(size))(std::move(r))); // ... } auto main() -> int{} ```
x.cpp2:3:21: error: no matching function for call to object of type '(lambda at x.cpp2:3:21)'
  static_cast<void>(CPP2_UFCS(std::move(size))(std::move(r)));
                    ^~~~~~~~~~~~~~~~~~~~~~~~~~
../root/include/cpp2util.h:854:59: note: expanded from macro 'CPP2_UFCS'
#define CPP2_UFCS(...)                                    CPP2_UFCS_(&,(),,__VA_ARGS__)
                                                          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
../root/include/cpp2util.h:838:53: note: expanded from macro 'CPP2_UFCS_'
#define CPP2_UFCS_(LAMBDADEFCAPT,QUALID,TEMPKW,...) \
                                                    ^
x.cpp2:3:21: note: candidate template ignored: constraints not satisfied [with Obj = typename std::remove_reference<basic_string<char> &>::type, Params = <>]
../root/include/cpp2util.h:854:59: note: expanded from macro 'CPP2_UFCS'
#define CPP2_UFCS(...)                                    CPP2_UFCS_(&,(),,__VA_ARGS__)
                                                          ^
../root/include/cpp2util.h:838:53: note: expanded from macro 'CPP2_UFCS_'
#define CPP2_UFCS_(LAMBDADEFCAPT,QUALID,TEMPKW,...) \
                                                    ^
x.cpp2:3:36: note: because 'std::forward<decltype(obj)>(obj).std::move(size)(std::forward<decltype(params)>(params)...)' would be invalid: qualified member access refers to a member in namespace 'std'
  static_cast<void>(CPP2_UFCS(std::move(size))(std::move(r)));
                                   ^
x.cpp2:3:31: note: and 'std::move(size)(std::forward<decltype(obj)>(obj), std::forward<decltype(params)>(params)...)' would be invalid: called object type 'typename std::remove_reference<int &>::type' (aka 'int') is not a function or function pointer
  static_cast<void>(CPP2_UFCS(std::move(size))(std::move(r)));
                              ^
1 error generated.