From 441e44db3442043eb23c19a76acbc58fc3e99e9f Mon Sep 17 00:00:00 2001 From: Hristo Hristov Date: Thu, 4 Dec 2025 07:41:50 +0200 Subject: [PATCH] [libc++][pair] Applied `[[nodiscard]]` `[[nodiscard]]` should be applied to functions where discarding the return value is most likely a correctness issue. - https://libcxx.llvm.org/CodingGuidelines.html - https://wg21.link/pairs --- libcxx/include/__utility/pair.h | 32 +++++++----- .../utility/pairs/nodiscard.verify.cpp | 52 +++++++++++++++++++ 2 files changed, 70 insertions(+), 14 deletions(-) create mode 100644 libcxx/test/libcxx/utilities/utility/pairs/nodiscard.verify.cpp diff --git a/libcxx/include/__utility/pair.h b/libcxx/include/__utility/pair.h index d3914f655f2a6..a8232bc9da9fa 100644 --- a/libcxx/include/__utility/pair.h +++ b/libcxx/include/__utility/pair.h @@ -539,8 +539,8 @@ swap(const pair<_T1, _T2>& __x, const pair<_T1, _T2>& __y) noexcept(noexcept(__x #endif template -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<__unwrap_ref_decay_t<_T1>, __unwrap_ref_decay_t<_T2> > -make_pair(_T1&& __t1, _T2&& __t2) { +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 +pair<__unwrap_ref_decay_t<_T1>, __unwrap_ref_decay_t<_T2> > make_pair(_T1&& __t1, _T2&& __t2) { return pair<__unwrap_ref_decay_t<_T1>, __unwrap_ref_decay_t<_T2> >(std::forward<_T1>(__t1), std::forward<_T2>(__t2)); } @@ -612,67 +612,71 @@ struct __get_pair<1> { }; template -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 typename tuple_element<_Ip, pair<_T1, _T2> >::type& +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 +typename tuple_element<_Ip, pair<_T1, _T2> >::type& get(pair<_T1, _T2>& __p) _NOEXCEPT { return __get_pair<_Ip>::get(__p); } template -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 const typename tuple_element<_Ip, pair<_T1, _T2> >::type& +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI +_LIBCPP_CONSTEXPR_SINCE_CXX14 const typename tuple_element<_Ip, pair<_T1, _T2> >::type& get(const pair<_T1, _T2>& __p) _NOEXCEPT { return __get_pair<_Ip>::get(__p); } template -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 typename tuple_element<_Ip, pair<_T1, _T2> >::type&& +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 +typename tuple_element<_Ip, pair<_T1, _T2> >::type&& get(pair<_T1, _T2>&& __p) _NOEXCEPT { return __get_pair<_Ip>::get(std::move(__p)); } template -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 const typename tuple_element<_Ip, pair<_T1, _T2> >::type&& +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI +_LIBCPP_CONSTEXPR_SINCE_CXX14 const typename tuple_element<_Ip, pair<_T1, _T2> >::type&& get(const pair<_T1, _T2>&& __p) _NOEXCEPT { return __get_pair<_Ip>::get(std::move(__p)); } #if _LIBCPP_STD_VER >= 14 template -inline _LIBCPP_HIDE_FROM_ABI constexpr _T1& get(pair<_T1, _T2>& __p) _NOEXCEPT { +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI constexpr _T1& get(pair<_T1, _T2>& __p) _NOEXCEPT { return __p.first; } template -inline _LIBCPP_HIDE_FROM_ABI constexpr _T1 const& get(pair<_T1, _T2> const& __p) _NOEXCEPT { +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI constexpr _T1 const& get(pair<_T1, _T2> const& __p) _NOEXCEPT { return __p.first; } template -inline _LIBCPP_HIDE_FROM_ABI constexpr _T1&& get(pair<_T1, _T2>&& __p) _NOEXCEPT { +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI constexpr _T1&& get(pair<_T1, _T2>&& __p) _NOEXCEPT { return std::forward<_T1&&>(__p.first); } template -inline _LIBCPP_HIDE_FROM_ABI constexpr _T1 const&& get(pair<_T1, _T2> const&& __p) _NOEXCEPT { +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI constexpr _T1 const&& get(pair<_T1, _T2> const&& __p) _NOEXCEPT { return std::forward<_T1 const&&>(__p.first); } template -inline _LIBCPP_HIDE_FROM_ABI constexpr _T2& get(pair<_T1, _T2>& __p) _NOEXCEPT { +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI constexpr _T2& get(pair<_T1, _T2>& __p) _NOEXCEPT { return __p.second; } template -inline _LIBCPP_HIDE_FROM_ABI constexpr _T2 const& get(pair<_T1, _T2> const& __p) _NOEXCEPT { +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI constexpr _T2 const& get(pair<_T1, _T2> const& __p) _NOEXCEPT { return __p.second; } template -inline _LIBCPP_HIDE_FROM_ABI constexpr _T2&& get(pair<_T1, _T2>&& __p) _NOEXCEPT { +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI constexpr _T2&& get(pair<_T1, _T2>&& __p) _NOEXCEPT { return std::forward<_T2&&>(__p.second); } template -inline _LIBCPP_HIDE_FROM_ABI constexpr _T2 const&& get(pair<_T1, _T2> const&& __p) _NOEXCEPT { +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI constexpr _T2 const&& get(pair<_T1, _T2> const&& __p) _NOEXCEPT { return std::forward<_T2 const&&>(__p.second); } diff --git a/libcxx/test/libcxx/utilities/utility/pairs/nodiscard.verify.cpp b/libcxx/test/libcxx/utilities/utility/pairs/nodiscard.verify.cpp new file mode 100644 index 0000000000000..87ecbcb01ac43 --- /dev/null +++ b/libcxx/test/libcxx/utilities/utility/pairs/nodiscard.verify.cpp @@ -0,0 +1,52 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// Check that functions are marked [[nodiscard]] + +#include + +#include + +void test() { + struct First {}; + struct Second {}; + + std::pair p; + const std::pair cp; + + std::make_pair(94, 82); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} + +#if TEST_STD_VER >= 11 + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + std::get<0>(p); + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + std::get<0>(cp); + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + std::get<0>(std::move(p)); + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + std::get<0>(std::move(cp)); +#endif // TEST_STD_VER >= 11 +#if TEST_STD_VER >= 14 + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + std::get(p); + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + std::get(cp); + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + std::get(std::move(p)); + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + std::get(std::move(cp)); + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + std::get(p); + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + std::get(cp); + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + std::get(std::move(p)); + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + std::get(std::move(cp)); +#endif // TEST_STD_VER >= 14 +}