diff --git a/libcxx/include/tuple b/libcxx/include/tuple index 670b90fc7b3b9..e02e45f425f4f 100644 --- a/libcxx/include/tuple +++ b/libcxx/include/tuple @@ -1113,28 +1113,32 @@ swap(const tuple<_Tp...>& __lhs, // get template -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 typename tuple_element<_Ip, tuple<_Tp...> >::type& +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 +typename tuple_element<_Ip, tuple<_Tp...> >::type& get(tuple<_Tp...>& __t) _NOEXCEPT { using type _LIBCPP_NODEBUG = typename tuple_element<_Ip, tuple<_Tp...> >::type; return static_cast<__tuple_leaf<_Ip, type>&>(__t.__base_).get(); } template -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 const typename tuple_element<_Ip, tuple<_Tp...> >::type& +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI +_LIBCPP_CONSTEXPR_SINCE_CXX14 const typename tuple_element<_Ip, tuple<_Tp...> >::type& get(const tuple<_Tp...>& __t) _NOEXCEPT { using type _LIBCPP_NODEBUG = typename tuple_element<_Ip, tuple<_Tp...> >::type; return static_cast&>(__t.__base_).get(); } template -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 typename tuple_element<_Ip, tuple<_Tp...> >::type&& +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 +typename tuple_element<_Ip, tuple<_Tp...> >::type&& get(tuple<_Tp...>&& __t) _NOEXCEPT { using type _LIBCPP_NODEBUG = typename tuple_element<_Ip, tuple<_Tp...> >::type; return static_cast(static_cast<__tuple_leaf<_Ip, type>&&>(__t.__base_).get()); } template -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 const typename tuple_element<_Ip, tuple<_Tp...> >::type&& +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI +_LIBCPP_CONSTEXPR_SINCE_CXX14 const typename tuple_element<_Ip, tuple<_Tp...> >::type&& get(const tuple<_Tp...>&& __t) _NOEXCEPT { using type _LIBCPP_NODEBUG = typename tuple_element<_Ip, tuple<_Tp...> >::type; return static_cast(static_cast&&>(__t.__base_).get()); @@ -1143,22 +1147,22 @@ get(const tuple<_Tp...>&& __t) _NOEXCEPT { # if _LIBCPP_STD_VER >= 14 template -inline _LIBCPP_HIDE_FROM_ABI constexpr _T1& get(tuple<_Args...>& __tup) noexcept { +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI constexpr _T1& get(tuple<_Args...>& __tup) noexcept { return std::get<__find_exactly_one_t<_T1, _Args...>::value>(__tup); } template -inline _LIBCPP_HIDE_FROM_ABI constexpr _T1 const& get(tuple<_Args...> const& __tup) noexcept { +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI constexpr _T1 const& get(tuple<_Args...> const& __tup) noexcept { return std::get<__find_exactly_one_t<_T1, _Args...>::value>(__tup); } template -inline _LIBCPP_HIDE_FROM_ABI constexpr _T1&& get(tuple<_Args...>&& __tup) noexcept { +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI constexpr _T1&& get(tuple<_Args...>&& __tup) noexcept { return std::get<__find_exactly_one_t<_T1, _Args...>::value>(std::move(__tup)); } template -inline _LIBCPP_HIDE_FROM_ABI constexpr _T1 const&& get(tuple<_Args...> const&& __tup) noexcept { +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI constexpr _T1 const&& get(tuple<_Args...> const&& __tup) noexcept { return std::get<__find_exactly_one_t<_T1, _Args...>::value>(std::move(__tup)); } @@ -1167,18 +1171,19 @@ inline _LIBCPP_HIDE_FROM_ABI constexpr _T1 const&& get(tuple<_Args...> const&& _ // tie template -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 tuple<_Tp&...> tie(_Tp&... __t) _NOEXCEPT { +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 tuple<_Tp&...> tie(_Tp&... __t) _NOEXCEPT { return tuple<_Tp&...>(__t...); } template -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 tuple<__unwrap_ref_decay_t<_Tp>...> +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 tuple<__unwrap_ref_decay_t<_Tp>...> make_tuple(_Tp&&... __t) { return tuple<__unwrap_ref_decay_t<_Tp>...>(std::forward<_Tp>(__t)...); } template -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 tuple<_Tp&&...> forward_as_tuple(_Tp&&... __t) _NOEXCEPT { +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 tuple<_Tp&&...> +forward_as_tuple(_Tp&&... __t) _NOEXCEPT { return tuple<_Tp&&...>(std::forward<_Tp>(__t)...); } @@ -1300,7 +1305,7 @@ template using __tuple_cat_return_t _LIBCPP_NODEBUG = typename __tuple_cat_return_impl, __remove_cvref_t<_Tuples>...>::type; -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 tuple<> tuple_cat() { return tuple<>(); } +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 tuple<> tuple_cat() { return tuple<>(); } template struct __tuple_cat_return_ref_imp; @@ -1368,7 +1373,7 @@ __tuple_cat_select_element_wise(_TupleSrc&& __src, __index_sequence<_Indices...> } template -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 __tuple_cat_return_t<_Tuple0, _Tuples...> +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 __tuple_cat_return_t<_Tuple0, _Tuples...> tuple_cat(_Tuple0&& __t0, _Tuples&&... __tpls) { using _T0 _LIBCPP_NODEBUG = __libcpp_remove_reference_t<_Tuple0>; using _TRet _LIBCPP_NODEBUG = __tuple_cat_return_t<_Tuple0, _Tuples...>; @@ -1435,7 +1440,7 @@ template template >> // strengthen #endif // _LIBCPP_STD_VER >= 20 -inline _LIBCPP_HIDE_FROM_ABI constexpr _Tp make_from_tuple(_Tuple&& __t) +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI constexpr _Tp make_from_tuple(_Tuple&& __t) noexcept(noexcept(std::__make_from_tuple_impl<_Tp>(std::forward<_Tuple>(__t), make_index_sequence>>()))) { #if _LIBCPP_STD_VER >= 23 diff --git a/libcxx/test/libcxx/utilities/tuple/nodiscard.verify.cpp b/libcxx/test/libcxx/utilities/tuple/nodiscard.verify.cpp new file mode 100644 index 0000000000000..102031e308dca --- /dev/null +++ b/libcxx/test/libcxx/utilities/tuple/nodiscard.verify.cpp @@ -0,0 +1,66 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// REQUIRES: std-at-least-c++11 + +// Check that functions are marked [[nodiscard]] + +#include + +#include "test_macros.h" + +void test() { + struct First {}; + struct Second {}; + struct Third {}; + + std::tuple t; + const std::tuple ct; + + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + std::get<0>(t); + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + std::get<0>(ct); + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + std::get<0>(std::move(t)); + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + std::get<0>(std::move(t)); +#if TEST_STD_VER >= 14 + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + std::get(t); + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + std::get(ct); + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + std::get(std::move(t)); + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + std::get(std::move(t)); +#endif + + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + std::tie(ct); + + First e1; + Second e2; + Third e3; + + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + std::make_tuple(e1, e2, e3); + + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + std::forward_as_tuple(First{}, Second{}, Third{}); + + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + std::tuple_cat(); + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + std::tuple_cat(std::tuple{}, std::tuple{}); + +#if TEST_STD_VER >= 17 + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + std::make_from_tuple(std::tuple{}); +#endif +} diff --git a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/recursion_depth.pass.cpp b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/recursion_depth.pass.cpp index 57d37079c9f0c..ed44344edd0ad 100644 --- a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/recursion_depth.pass.cpp +++ b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/recursion_depth.pass.cpp @@ -22,8 +22,10 @@ constexpr void CreateTuple(std::index_sequence) { using LargeTuple = std::tuple...>; using TargetTuple = std::tuple; LargeTuple tuple(std::integral_constant{}...); - assert(std::get<0>(tuple).value == 0); - assert(std::get(tuple).value == sizeof...(I)-1); + auto e1 = std::get<0>(tuple); + assert(e1.value == 0); + auto e2 = std::get(tuple); + assert(e2.value == sizeof...(I) - 1); TargetTuple t1 = tuple; // converting copy constructor from & TargetTuple t2 = static_cast(tuple); // converting copy constructor from const&