cppfront
cppfront copied to clipboard
[BUG] Need `decltype(auto)` for perfect backwarding
Title: Need decltype(auto) for perfect backwarding.
Description:
At first, a Cpp2 -> forward _ return-list lowered to the Cpp1 return type auto&&.
#175 noted this was unsafe,
and commit b59f539f7275b880d4e623adb473864e49756546 changed it to decltype(auto).
#274 noted that this makes accessors return by copy,
then commit 413de0ed5747a74e8226c6474072925cf21bacd8 changed it back to auto&&,
and commit 43cdf3e651ebe51cf1d68efbe50128c248f63364 addressed some safety concerns of #175.
Now perfect backwarding doesn't work or returns a temporary.
This means we can't implement std::invoke or simpler equivalents.
For example, implementing a simple function_ref: https://cpp2.godbolt.org/z/r53zfnxbT.
Minimal reproducer (https://cpp2.godbolt.org/z/bjjfqEc9e):
f: (x: int) x;
f: (x: long) _ = x;
g: (x) -> forward _ = f(x);
main: () = {
_ = g(0);
_ = g(0L);
}
Commands:
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 -I . main.cpp
Expected result: Perfect backwarding to work.
Actual result and error:
Cpp2 lowered to Cpp1:
//=== Cpp2 type declarations ====================================================
#include "cpp2util.h"
#line 1 "/app/example.cpp2"
//=== Cpp2 type definitions and function declarations ===========================
#line 1 "/app/example.cpp2"
[[nodiscard]] auto f(cpp2::in<int> x) -> auto;
#line 2 "/app/example.cpp2"
[[nodiscard]] auto f(cpp2::in<long> x) -> auto;
[[nodiscard]] auto g(auto const& x) -> auto&&;
auto main() -> int;
//=== Cpp2 function definitions =================================================
#line 1 "/app/example.cpp2"
[[nodiscard]] auto f(cpp2::in<int> x) -> auto { return x; }
#line 2 "/app/example.cpp2"
[[nodiscard]] auto f(cpp2::in<long> x) -> auto { return static_cast<void>(x); }
[[nodiscard]] auto g(auto const& x) -> auto&& { return f(x); }
auto main() -> int{
static_cast<void>(g(0));
static_cast<void>(g(0L));
}
main.cpp2:3:56: warning: returning reference to local temporary object [-Wreturn-stack-address]
3 | [[nodiscard]] auto g(auto const& x) -> auto&& { return f(x); }
| ^~~~
main.cpp2:5:21: note: in instantiation of function template specialization 'g<int>' requested here
5 | static_cast<void>(g(0));
| ^
main.cpp2:3:44: error: cannot form a reference to 'void'
3 | [[nodiscard]] auto g(auto const& x) -> auto&& { return f(x); }
| ^
main.cpp2:6:21: note: in instantiation of function template specialization 'g<long>' requested here
6 | static_cast<void>(g(0L));
| ^
1 warning and 1 error generated.
See also:
- #175.
- Commit b59f539f7275b880d4e623adb473864e49756546.
- #274.
- Commit 413de0ed5747a74e8226c6474072925cf21bacd8.
- Commit 43cdf3e651ebe51cf1d68efbe50128c248f63364.
An alternative is to change back to decltype(auto)
and lower returned member names in parentheses.
That should make -> forward _ return-list "work as expected" more.
The relevant features are https://en.cppreference.com/w/cpp/language/auto and https://en.cppreference.com/w/cpp/language/decltype.
Yet another alternative is to change back to decltype(auto),
but reject returning unparenthesized member names.
They should be (member) or (copy member) (https://github.com/hsutter/cppfront/issues/466#copy).