Closed
Description
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 b59f539 changed it to decltype(auto)
.
#274 noted that this makes accessors return by copy,
then commit 413de0e changed it back to auto&&
,
and commit 43cdf3e 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:
- All uses auto&& in function signatures potentially undefined behavior #175.
- Commit b59f539.
- [BUG] forwarding a member of class from method with const
this
returns non-const reference that dropsconst
#274. - Commit 413de0e.
- Commit 43cdf3e.