diff --git a/libcxx/docs/UsingLibcxx.rst b/libcxx/docs/UsingLibcxx.rst --- a/libcxx/docs/UsingLibcxx.rst +++ b/libcxx/docs/UsingLibcxx.rst @@ -287,15 +287,15 @@ 1. Backporting ``[[nodiscard]]`` to entities declared as such by the standard in newer dialects, but not in the present one. -2. Extended applications of ``[[nodiscard]]``, at the libraries discretion, +2. Extended applications of ``[[nodiscard]]``, at the library's discretion, applied to entities never declared as such by the standard. Users may also opt-out of additional applications ``[[nodiscard]]`` using additional macros. Applications of the first form, which backport ``[[nodiscard]]`` from a newer -dialect may be disabled using macros specific to the dialect it was added. For -example ``_LIBCPP_DISABLE_NODISCARD_AFTER_CXX17``. +dialect, may be disabled using macros specific to the dialect in which it was +added. For example, ``_LIBCPP_DISABLE_NODISCARD_AFTER_CXX17``. Applications of the second form, which are pure extensions, may be disabled by defining ``_LIBCPP_DISABLE_NODISCARD_EXT``. @@ -346,3 +346,10 @@ * ``unique`` * ``upper_bound`` * ``lock_guard``'s constructors +* ``as_const`` +* ``forward`` +* ``move`` +* ``move_if_noexcept`` +* ``identity::operator()`` +* ``to_integer`` +* ``to_underlying`` diff --git a/libcxx/include/cstddef b/libcxx/include/cstddef --- a/libcxx/include/cstddef +++ b/libcxx/include/cstddef @@ -152,7 +152,7 @@ { return static_cast(static_cast(static_cast(__lhs) >> __shift)); } template > - constexpr _Integer + _LIBCPP_NODISCARD_EXT constexpr _Integer to_integer(byte __b) noexcept { return static_cast<_Integer>(__b); } } diff --git a/libcxx/include/functional b/libcxx/include/functional --- a/libcxx/include/functional +++ b/libcxx/include/functional @@ -3213,7 +3213,7 @@ // [func.identity] struct identity { template - constexpr _Tp&& operator()(_Tp&& __t) const noexcept + _LIBCPP_NODISCARD_EXT constexpr _Tp&& operator()(_Tp&& __t) const noexcept { return _VSTD::forward<_Tp>(__t); } diff --git a/libcxx/include/type_traits b/libcxx/include/type_traits --- a/libcxx/include/type_traits +++ b/libcxx/include/type_traits @@ -2784,7 +2784,7 @@ // move template -inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR +_LIBCPP_NODISCARD_EXT inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR typename remove_reference<_Tp>::type&& move(_Tp&& __t) _NOEXCEPT { @@ -2793,7 +2793,7 @@ } template -inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR +_LIBCPP_NODISCARD_EXT inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR _Tp&& forward(typename remove_reference<_Tp>::type& __t) _NOEXCEPT { @@ -2801,12 +2801,12 @@ } template -inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR +_LIBCPP_NODISCARD_EXT inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR _Tp&& forward(typename remove_reference<_Tp>::type&& __t) _NOEXCEPT { static_assert(!is_lvalue_reference<_Tp>::value, - "can not forward an rvalue as an lvalue"); + "cannot forward an rvalue as an lvalue"); return static_cast<_Tp&&>(__t); } diff --git a/libcxx/include/utility b/libcxx/include/utility --- a/libcxx/include/utility +++ b/libcxx/include/utility @@ -260,7 +260,7 @@ // move_if_noexcept template -inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 +_LIBCPP_NODISCARD_EXT inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 #ifndef _LIBCPP_CXX03_LANG typename conditional < @@ -277,8 +277,11 @@ } #if _LIBCPP_STD_VER > 14 -template constexpr add_const_t<_Tp>& as_const(_Tp& __t) noexcept { return __t; } -template void as_const(const _Tp&&) = delete; +template +_LIBCPP_NODISCARD_EXT constexpr add_const_t<_Tp>& as_const(_Tp& __t) noexcept { return __t; } + +template +void as_const(const _Tp&&) = delete; #endif struct _LIBCPP_TEMPLATE_VIS piecewise_construct_t { explicit piecewise_construct_t() = default; }; @@ -1636,7 +1639,7 @@ #if _LIBCPP_STD_VER > 20 template -_LIBCPP_INLINE_VISIBILITY constexpr underlying_type_t<_Tp> +_LIBCPP_NODISCARD_EXT _LIBCPP_INLINE_VISIBILITY constexpr underlying_type_t<_Tp> to_underlying(_Tp __val) noexcept { return _VSTD::__to_underlying(__val); } diff --git a/libcxx/test/libcxx/diagnostics/nodiscard_extensions.pass.cpp b/libcxx/test/libcxx/diagnostics/nodiscard_extensions.pass.cpp --- a/libcxx/test/libcxx/diagnostics/nodiscard_extensions.pass.cpp +++ b/libcxx/test/libcxx/diagnostics/nodiscard_extensions.pass.cpp @@ -23,9 +23,11 @@ // be listed in `UsingLibcxx.rst` in the documentation for the extension. #include -#include +#include // to_integer +#include // identity #include #include +#include // to_underlying #include "test_macros.h" @@ -33,7 +35,7 @@ bool operator()(int) const { return false; } }; -int main(int, char**) { +void test_algorithms() { int arr[1] = { 1 }; std::adjacent_find(std::begin(arr), std::end(arr)); @@ -144,6 +146,51 @@ std::unique(std::begin(arr), std::end(arr), std::greater()); std::upper_bound(std::begin(arr), std::end(arr), 1); std::upper_bound(std::begin(arr), std::end(arr), 1, std::greater()); +} + +template +void test_template_cast_wrappers(LV&& lv, RV&& rv) { + std::forward(lv); + std::forward(rv); + std::move(lv); + std::move(rv); + std::move_if_noexcept(lv); + std::move_if_noexcept(rv); + +#if TEST_STD_VER >= 17 + std::as_const(lv); + std::as_const(rv); +#endif + +#if TEST_STD_VER >= 20 + std::identity()(lv); + std::identity()(rv); +#endif +} + +void test_nontemplate_cast_wrappers() +{ +#if TEST_STD_VER >= 17 + std::byte b{42}; + std::to_integer(b); +#endif + +#if TEST_STD_VER >= 20 + // std::bit_cast(42); +#endif + +#if TEST_STD_VER > 20 + enum E { Apple, Orange } e = Apple; + std::to_underlying(e); +#endif +} + +int main(int, char**) { + test_algorithms(); + + int i = 42; + test_template_cast_wrappers(i, std::move(i)); + test_nontemplate_cast_wrappers(); return 0; } diff --git a/libcxx/test/libcxx/diagnostics/nodiscard_extensions.verify.cpp b/libcxx/test/libcxx/diagnostics/nodiscard_extensions.verify.cpp --- a/libcxx/test/libcxx/diagnostics/nodiscard_extensions.verify.cpp +++ b/libcxx/test/libcxx/diagnostics/nodiscard_extensions.verify.cpp @@ -23,9 +23,11 @@ // ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_NODISCARD #include -#include +#include // to_integer +#include // identity #include #include +#include // to_underlying #include "test_macros.h" @@ -33,7 +35,7 @@ bool operator()(int) const { return false; } }; -int main(int, char**) { +void test_algorithms() { int arr[1] = { 1 }; // expected-warning-re@+1 {{ignoring return value of function declared with {{'nodiscard'|warn_unused_result}} attribute}} @@ -291,6 +293,63 @@ // expected-warning-re@+1 {{ignoring return value of function declared with {{'nodiscard'|warn_unused_result}} attribute}} std::upper_bound(std::begin(arr), std::end(arr), 1, std::greater()); +} + +template +void test_template_cast_wrappers(LV&& lv, RV&& rv) { + // expected-warning-re@+1 {{ignoring return value of function declared with {{'nodiscard'|warn_unused_result}} attribute}} + std::forward(lv); + // expected-warning-re@+1 {{ignoring return value of function declared with {{'nodiscard'|warn_unused_result}} attribute}} + std::forward(rv); + // expected-warning-re@+1 {{ignoring return value of function declared with {{'nodiscard'|warn_unused_result}} attribute}} + std::move(lv); + // expected-warning-re@+1 {{ignoring return value of function declared with {{'nodiscard'|warn_unused_result}} attribute}} + std::move(rv); + // expected-warning-re@+1 {{ignoring return value of function declared with {{'nodiscard'|warn_unused_result}} attribute}} + std::move_if_noexcept(lv); + // expected-warning-re@+1 {{ignoring return value of function declared with {{'nodiscard'|warn_unused_result}} attribute}} + std::move_if_noexcept(rv); + +#if TEST_STD_VER >= 17 + // expected-warning-re@+1 {{ignoring return value of function declared with {{'nodiscard'|warn_unused_result}} attribute}} + std::as_const(lv); + // expected-warning-re@+1 {{ignoring return value of function declared with {{'nodiscard'|warn_unused_result}} attribute}} + std::as_const(rv); +#endif + +#if TEST_STD_VER >= 20 + // expected-warning-re@+1 {{ignoring return value of function declared with {{'nodiscard'|warn_unused_result}} attribute}} + std::identity()(lv); + // expected-warning-re@+1 {{ignoring return value of function declared with {{'nodiscard'|warn_unused_result}} attribute}} + std::identity()(rv); +#endif +} + +void test_nontemplate_cast_wrappers() +{ +#if TEST_STD_VER >= 17 + std::byte b{42}; + // expected-warning-re@+1 {{ignoring return value of function declared with {{'nodiscard'|warn_unused_result}} attribute}} + std::to_integer(b); +#endif + +#if TEST_STD_VER >= 20 + // std::bit_cast(42); +#endif + +#if TEST_STD_VER > 20 + enum E { Apple, Orange } e = Apple; + // expected-warning-re@+1 {{ignoring return value of function declared with {{'nodiscard'|warn_unused_result}} attribute}} + std::to_underlying(e); +#endif +} + +int main(int, char**) { + test_algorithms(); + + int i = 42; + test_template_cast_wrappers(i, std::move(i)); + test_nontemplate_cast_wrappers(); return 0; } diff --git a/libcxx/test/std/utilities/utility/forward/forward.fail.cpp b/libcxx/test/std/utilities/utility/forward/forward.fail.cpp --- a/libcxx/test/std/utilities/utility/forward/forward.fail.cpp +++ b/libcxx/test/std/utilities/utility/forward/forward.fail.cpp @@ -23,7 +23,7 @@ { { std::forward(source()); // expected-note {{requested here}} - // expected-error-re@type_traits:* 1 {{static_assert failed{{.*}} "can not forward an rvalue as an lvalue"}} + // expected-error-re@type_traits:* 1 {{static_assert failed{{.*}} "cannot forward an rvalue as an lvalue"}} } { const A ca = A();