diff --git a/libcxx/include/variant b/libcxx/include/variant index df587ccf23843..b93009b3353cb 100644 --- a/libcxx/include/variant +++ b/libcxx/include/variant @@ -288,7 +288,7 @@ _LIBCPP_BEGIN_UNVERSIONED_NAMESPACE_STD class _LIBCPP_EXPORTED_FROM_ABI bad_variant_access : public exception { public: - const char* what() const _NOEXCEPT override; + [[__nodiscard__]] const char* what() const _NOEXCEPT override; }; _LIBCPP_END_UNVERSIONED_NAMESPACE_STD @@ -1282,11 +1282,11 @@ public: return __impl_.template __emplace<_Ip>(__il, std::forward<_Args>(__args)...); } - _LIBCPP_HIDE_FROM_ABI constexpr bool valueless_by_exception() const noexcept { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool valueless_by_exception() const noexcept { return __impl_.valueless_by_exception(); } - _LIBCPP_HIDE_FROM_ABI constexpr size_t index() const noexcept { return __impl_.index(); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr size_t index() const noexcept { return __impl_.index(); } template < bool _Dummy = true, enable_if_t< __all<(__dependent_type, _Dummy>::value && @@ -1329,7 +1329,7 @@ _LIBCPP_HIDE_FROM_ABI constexpr bool __holds_alternative(const variant<_Types... } template -_LIBCPP_HIDE_FROM_ABI constexpr bool holds_alternative(const variant<_Types...>& __v) noexcept { +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool holds_alternative(const variant<_Types...>& __v) noexcept { return std::__holds_alternative<__find_exactly_one_t<_Tp, _Types...>::value>(__v); } @@ -1343,21 +1343,23 @@ _LIBCPP_HIDE_FROM_ABI constexpr auto&& __generic_get(_Vp&& __v) { } template -_LIBCPP_HIDE_FROM_ABI constexpr variant_alternative_t<_Ip, variant<_Types...>>& get(variant<_Types...>& __v) { +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr variant_alternative_t<_Ip, variant<_Types...>>& +get(variant<_Types...>& __v) { static_assert(_Ip < sizeof...(_Types)); static_assert(!is_void_v>>); return std::__generic_get<_Ip>(__v); } template -_LIBCPP_HIDE_FROM_ABI constexpr variant_alternative_t<_Ip, variant<_Types...>>&& get(variant<_Types...>&& __v) { +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr variant_alternative_t<_Ip, variant<_Types...>>&& +get(variant<_Types...>&& __v) { static_assert(_Ip < sizeof...(_Types)); static_assert(!is_void_v>>); return std::__generic_get<_Ip>(std::move(__v)); } template -_LIBCPP_HIDE_FROM_ABI constexpr const variant_alternative_t<_Ip, variant<_Types...>>& +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr const variant_alternative_t<_Ip, variant<_Types...>>& get(const variant<_Types...>& __v) { static_assert(_Ip < sizeof...(_Types)); static_assert(!is_void_v>>); @@ -1365,7 +1367,7 @@ get(const variant<_Types...>& __v) { } template -_LIBCPP_HIDE_FROM_ABI constexpr const variant_alternative_t<_Ip, variant<_Types...>>&& +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr const variant_alternative_t<_Ip, variant<_Types...>>&& get(const variant<_Types...>&& __v) { static_assert(_Ip < sizeof...(_Types)); static_assert(!is_void_v>>); @@ -1373,25 +1375,25 @@ get(const variant<_Types...>&& __v) { } template -_LIBCPP_HIDE_FROM_ABI constexpr _Tp& get(variant<_Types...>& __v) { +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp& get(variant<_Types...>& __v) { static_assert(!is_void_v<_Tp>); return std::get<__find_exactly_one_t<_Tp, _Types...>::value>(__v); } template -_LIBCPP_HIDE_FROM_ABI constexpr _Tp&& get(variant<_Types...>&& __v) { +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp&& get(variant<_Types...>&& __v) { static_assert(!is_void_v<_Tp>); return std::get<__find_exactly_one_t<_Tp, _Types...>::value>(std::move(__v)); } template -_LIBCPP_HIDE_FROM_ABI constexpr const _Tp& get(const variant<_Types...>& __v) { +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr const _Tp& get(const variant<_Types...>& __v) { static_assert(!is_void_v<_Tp>); return std::get<__find_exactly_one_t<_Tp, _Types...>::value>(__v); } template -_LIBCPP_HIDE_FROM_ABI constexpr const _Tp&& get(const variant<_Types...>&& __v) { +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr const _Tp&& get(const variant<_Types...>&& __v) { static_assert(!is_void_v<_Tp>); return std::get<__find_exactly_one_t<_Tp, _Types...>::value>(std::move(__v)); } @@ -1403,7 +1405,7 @@ _LIBCPP_HIDE_FROM_ABI constexpr auto* __generic_get_if(_Vp* __v) noexcept { } template -_LIBCPP_HIDE_FROM_ABI constexpr add_pointer_t>> +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr add_pointer_t>> get_if(variant<_Types...>* __v) noexcept { static_assert(_Ip < sizeof...(_Types)); static_assert(!is_void_v>>); @@ -1411,7 +1413,7 @@ get_if(variant<_Types...>* __v) noexcept { } template -_LIBCPP_HIDE_FROM_ABI constexpr add_pointer_t>> +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr add_pointer_t>> get_if(const variant<_Types...>* __v) noexcept { static_assert(_Ip < sizeof...(_Types)); static_assert(!is_void_v>>); @@ -1419,13 +1421,13 @@ get_if(const variant<_Types...>* __v) noexcept { } template -_LIBCPP_HIDE_FROM_ABI constexpr add_pointer_t<_Tp> get_if(variant<_Types...>* __v) noexcept { +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr add_pointer_t<_Tp> get_if(variant<_Types...>* __v) noexcept { static_assert(!is_void_v<_Tp>); return std::get_if<__find_exactly_one_t<_Tp, _Types...>::value>(__v); } template -_LIBCPP_HIDE_FROM_ABI constexpr add_pointer_t get_if(const variant<_Types...>* __v) noexcept { +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr add_pointer_t get_if(const variant<_Types...>* __v) noexcept { static_assert(!is_void_v<_Tp>); return std::get_if<__find_exactly_one_t<_Tp, _Types...>::value>(__v); } @@ -1606,7 +1608,7 @@ struct hash< __enable_hash_helper, remove_const_t<_Types>...> using result_type _LIBCPP_DEPRECATED_IN_CXX17 = size_t; # endif - _LIBCPP_HIDE_FROM_ABI size_t operator()(const variant<_Types...>& __v) const { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI size_t operator()(const variant<_Types...>& __v) const { using __variant_detail::__visitation::__variant; size_t __res = __v.valueless_by_exception() diff --git a/libcxx/test/libcxx/utilities/variant/nodiscard.verify.cpp b/libcxx/test/libcxx/utilities/variant/nodiscard.verify.cpp new file mode 100644 index 0000000000000..b74a66f446311 --- /dev/null +++ b/libcxx/test/libcxx/utilities/variant/nodiscard.verify.cpp @@ -0,0 +1,74 @@ +//===----------------------------------------------------------------------===// +// +// 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++17 + +// Check that functions are marked [[nodiscard]] + +#include + +#include + +void test() { + { + std::bad_variant_access ex; + + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + ex.what(); + } + + { + struct First {}; + struct Second {}; + + std::variant v; + const std::variant cv; + + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + cv.valueless_by_exception(); + + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + cv.index(); + + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + std::holds_alternative(v); + + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + std::get<0>(v); + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + std::get<0>(cv); + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + std::get<0>(std::move(v)); + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + std::get<0>(std::move(cv)); + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + std::get(v); + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + std::get(cv); + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + std::get(std::move(v)); + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + std::get(std::move(cv)); + + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + std::get_if<0>(&v); + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + std::get_if<0>(&cv); + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + std::get_if(&v); + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + std::get_if(&cv); + } + + { + std::hash< std::variant> hash; + + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + hash(std::variant{}); + } +}