Closed
Description
In the current implementation of cppfront (aa70d09), the following code:
t2 : type = {
public x : *int;
operator=:(out this, p : *int) = {
x = p;
}
ptr1: (inout this, p : *int) -> *int = std::exchange(x, p);
}
ptr_ext: (inout o : t2, p : *int) -> *int = std::exchange(o.x, p);
main :() = {
n := 42;
a : t2 = (n&);
m := 24;
a.ptr1(m&); // no warning
ptr_ext(a, m&); // warning: ignoring return value of function declared with 'nodiscard' attribute
a;
}
Generates (skipping boilerplate):
class t2 {
public: int* x;
public: explicit t2(cpp2::in<int*> p)
: x{ p }
#line 4 "../tests/bug_ufcs_disable_nodiscard.cpp2"
{
}
#line 4 "../tests/bug_ufcs_disable_nodiscard.cpp2"
public: auto operator=(cpp2::in<int*> p) -> t2& {
x = p;
return *this;
#line 6 "../tests/bug_ufcs_disable_nodiscard.cpp2"
}
public: [[nodiscard]] auto ptr1(cpp2::in<int*> p) -> int* { return std::exchange(x, p); }
};
[[nodiscard]] auto ptr_ext(t2& o, cpp2::in<int*> p) -> int* { return std::exchange(o.x, p); }
auto main() -> int{
auto n {42};
t2 a {&n};
auto m {24};
CPP2_UFCS(ptr1, a, &m);// no warning
ptr_ext(a, &m); // warning
std::move(a);
}
And when compile with cpp1 compiler (clang++-14 in my case):
../tests/bug_ufcs_disable_nodiscard.cpp2:19:5: warning: ignoring return value of function declared with 'nodiscard' attribute [-Wunused-result]
ptr_ext(a, &m); // warning
^~~~~~~ ~~~~~
1 warning generated.
Only one unused result is identified - CPP2_UFCS(ptr1, a, &m);
generates no warning.
The issue is caused by CPP2_UFCS()
macros are eventually lambdas called in-place (Immediately Invoked Function Expressions). The lambda has no [[nodiscard]]
attribute - this is already proposed: P2173R0. I have checked on my compiler - I modified the macro to (notice that [[nodiscard]]
is added after the capture list):
#define CPP2_UFCS(FUNCNAME,PARAM1,...) \
[&][[nodiscard]](auto&& obj, auto&& ...params) CPP2_FORCE_INLINE_LAMBDA -> decltype(auto) { \
if constexpr (requires{ std::forward<decltype(obj)>(obj).FUNCNAME(std::forward<decltype(params)>(params)...); }) { \
return std::forward<decltype(obj)>(obj).FUNCNAME(std::forward<decltype(params)>(params)...); \
} else { \
return FUNCNAME(std::forward<decltype(obj)>(obj), std::forward<decltype(params)>(params)...); \
} \
}(PARAM1, __VA_ARGS__)
And the result is:
../tests/bug_ufcs_disable_nodiscard.cpp2:17:5: warning: an attribute specifier sequence in this position is a C++2b extension [-Wc++2b-extensions]
CPP2_UFCS(ptr1, a, &m);// no warning
^
include/cpp2util.h:651:4: note: expanded from macro 'CPP2_UFCS'
[&][[nodiscard]](auto&& obj, auto&& ...params) CPP2_FORCE_INLINE_LAMBDA -> decltype(auto) { \
^
../tests/bug_ufcs_disable_nodiscard.cpp2:17:5: warning: ignoring return value of function declared with 'nodiscard' attribute [-Wunused-result]
CPP2_UFCS(ptr1, a, &m);// no warning
^~~~~~~~~~~~~~~~~~~~~~
include/cpp2util.h:657:2: note: expanded from macro 'CPP2_UFCS'
}(PARAM1, __VA_ARGS__)
~^~~~~~~~~~~~~~~~~~~~~
../tests/bug_ufcs_disable_nodiscard.cpp2:19:5: warning: ignoring return value of function declared with 'nodiscard' attribute [-Wunused-result]
ptr_ext(a, &m); // warning
^~~~~~~ ~~~~~
3 warnings generated.