From c55038244a3c34888a44cc4f1aae4d6871d58236 Mon Sep 17 00:00:00 2001 From: Hristo Hristov Date: Fri, 28 Nov 2025 07:06:49 +0200 Subject: [PATCH] [libc++][map] 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#apply-nodiscard-where-relevant https://wg21.link/map --- .../is_generic_transparent_comparator.h | 2 +- libcxx/include/map | 104 ++++++++------- .../associative/map/at.abort.pass.cpp | 2 +- .../associative/map/at.const.abort.pass.cpp | 2 +- .../diagnostics/map.nodiscard.verify.cpp | 126 ++++++++++++++++-- .../multimap.nodiscard.verify copy.cpp | 18 +++ 6 files changed, 198 insertions(+), 56 deletions(-) create mode 100644 libcxx/test/libcxx/diagnostics/multimap.nodiscard.verify copy.cpp diff --git a/libcxx/include/__type_traits/is_generic_transparent_comparator.h b/libcxx/include/__type_traits/is_generic_transparent_comparator.h index fd02c0b0423d1..7c1f0e984ed4b 100644 --- a/libcxx/include/__type_traits/is_generic_transparent_comparator.h +++ b/libcxx/include/__type_traits/is_generic_transparent_comparator.h @@ -17,7 +17,7 @@ _LIBCPP_BEGIN_NAMESPACE_STD -// This traits returns true if the given _Comparator is known to accept any two types for compaison. This is separate +// This trait returns true if the given _Comparator is known to accept any two types for comparison. This is separate // from `__is_transparent_v`, since that only enables overloads of specific functions, but doesn't give any semantic // guarantees. This trait guarantess that the comparator simply calls the appropriate comparison functions for any two // types. diff --git a/libcxx/include/map b/libcxx/include/map index 0dca11cabd12e..27fc7c0dea6ec 100644 --- a/libcxx/include/map +++ b/libcxx/include/map @@ -1027,33 +1027,37 @@ public: _LIBCPP_HIDE_FROM_ABI ~map() { static_assert(sizeof(std::__diagnose_non_const_comparator<_Key, _Compare>()), ""); } - _LIBCPP_HIDE_FROM_ABI iterator begin() _NOEXCEPT { return __tree_.begin(); } - _LIBCPP_HIDE_FROM_ABI const_iterator begin() const _NOEXCEPT { return __tree_.begin(); } - _LIBCPP_HIDE_FROM_ABI iterator end() _NOEXCEPT { return __tree_.end(); } - _LIBCPP_HIDE_FROM_ABI const_iterator end() const _NOEXCEPT { return __tree_.end(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI iterator begin() _NOEXCEPT { return __tree_.begin(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_iterator begin() const _NOEXCEPT { return __tree_.begin(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI iterator end() _NOEXCEPT { return __tree_.end(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_iterator end() const _NOEXCEPT { return __tree_.end(); } - _LIBCPP_HIDE_FROM_ABI reverse_iterator rbegin() _NOEXCEPT { return reverse_iterator(end()); } - _LIBCPP_HIDE_FROM_ABI const_reverse_iterator rbegin() const _NOEXCEPT { return const_reverse_iterator(end()); } - _LIBCPP_HIDE_FROM_ABI reverse_iterator rend() _NOEXCEPT { return reverse_iterator(begin()); } - _LIBCPP_HIDE_FROM_ABI const_reverse_iterator rend() const _NOEXCEPT { return const_reverse_iterator(begin()); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI reverse_iterator rbegin() _NOEXCEPT { return reverse_iterator(end()); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_reverse_iterator rbegin() const _NOEXCEPT { + return const_reverse_iterator(end()); + } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI reverse_iterator rend() _NOEXCEPT { return reverse_iterator(begin()); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_reverse_iterator rend() const _NOEXCEPT { + return const_reverse_iterator(begin()); + } - _LIBCPP_HIDE_FROM_ABI const_iterator cbegin() const _NOEXCEPT { return begin(); } - _LIBCPP_HIDE_FROM_ABI const_iterator cend() const _NOEXCEPT { return end(); } - _LIBCPP_HIDE_FROM_ABI const_reverse_iterator crbegin() const _NOEXCEPT { return rbegin(); } - _LIBCPP_HIDE_FROM_ABI const_reverse_iterator crend() const _NOEXCEPT { return rend(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_iterator cbegin() const _NOEXCEPT { return begin(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_iterator cend() const _NOEXCEPT { return end(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_reverse_iterator crbegin() const _NOEXCEPT { return rbegin(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_reverse_iterator crend() const _NOEXCEPT { return rend(); } [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool empty() const _NOEXCEPT { return __tree_.size() == 0; } - _LIBCPP_HIDE_FROM_ABI size_type size() const _NOEXCEPT { return __tree_.size(); } - _LIBCPP_HIDE_FROM_ABI size_type max_size() const _NOEXCEPT { return __tree_.max_size(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI size_type size() const _NOEXCEPT { return __tree_.size(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI size_type max_size() const _NOEXCEPT { return __tree_.max_size(); } - _LIBCPP_HIDE_FROM_ABI mapped_type& operator[](const key_type& __k); + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI mapped_type& operator[](const key_type& __k); # ifndef _LIBCPP_CXX03_LANG - _LIBCPP_HIDE_FROM_ABI mapped_type& operator[](key_type&& __k); + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI mapped_type& operator[](key_type&& __k); # endif template >, int> = 0> - _LIBCPP_HIDE_FROM_ABI mapped_type& at(_Arg&& __arg) { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI mapped_type& at(_Arg&& __arg) { auto [_, __child] = __tree_.__find_equal(__arg); if (__child == nullptr) std::__throw_out_of_range("map::at: key not found"); @@ -1062,19 +1066,23 @@ public: template >, int> = 0> - _LIBCPP_HIDE_FROM_ABI const mapped_type& at(_Arg&& __arg) const { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const mapped_type& at(_Arg&& __arg) const { auto [_, __child] = __tree_.__find_equal(__arg); if (__child == nullptr) std::__throw_out_of_range("map::at: key not found"); return static_cast<__node_pointer>(__child)->__get_value().second; } - _LIBCPP_HIDE_FROM_ABI mapped_type& at(const key_type& __k); - _LIBCPP_HIDE_FROM_ABI const mapped_type& at(const key_type& __k) const; + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI mapped_type& at(const key_type& __k); + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const mapped_type& at(const key_type& __k) const; - _LIBCPP_HIDE_FROM_ABI allocator_type get_allocator() const _NOEXCEPT { return allocator_type(__tree_.__alloc()); } - _LIBCPP_HIDE_FROM_ABI key_compare key_comp() const { return __tree_.value_comp().key_comp(); } - _LIBCPP_HIDE_FROM_ABI value_compare value_comp() const { return value_compare(__tree_.value_comp().key_comp()); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI allocator_type get_allocator() const _NOEXCEPT { + return allocator_type(__tree_.__alloc()); + } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI key_compare key_comp() const { return __tree_.value_comp().key_comp(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI value_compare value_comp() const { + return value_compare(__tree_.value_comp().key_comp()); + } # ifndef _LIBCPP_CXX03_LANG template @@ -1226,10 +1234,10 @@ public: "node_type with incompatible allocator passed to map::insert()"); return __tree_.template __node_handle_insert_unique(__hint.__i_, std::move(__nh)); } - _LIBCPP_HIDE_FROM_ABI node_type extract(key_type const& __key) { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI node_type extract(key_type const& __key) { return __tree_.template __node_handle_extract(__key); } - _LIBCPP_HIDE_FROM_ABI node_type extract(const_iterator __it) { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI node_type extract(const_iterator __it) { return __tree_.template __node_handle_extract(__it.__i_); } template @@ -1260,44 +1268,48 @@ public: _LIBCPP_HIDE_FROM_ABI void swap(map& __m) _NOEXCEPT_(__is_nothrow_swappable_v<__base>) { __tree_.swap(__m.__tree_); } - _LIBCPP_HIDE_FROM_ABI iterator find(const key_type& __k) { return __tree_.find(__k); } - _LIBCPP_HIDE_FROM_ABI const_iterator find(const key_type& __k) const { return __tree_.find(__k); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI iterator find(const key_type& __k) { return __tree_.find(__k); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_iterator find(const key_type& __k) const { return __tree_.find(__k); } # if _LIBCPP_STD_VER >= 14 template || __is_transparently_comparable_v<_Compare, key_type, _K2>, int> = 0> - _LIBCPP_HIDE_FROM_ABI iterator find(const _K2& __k) { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI iterator find(const _K2& __k) { return __tree_.find(__k); } template || __is_transparently_comparable_v<_Compare, key_type, _K2>, int> = 0> - _LIBCPP_HIDE_FROM_ABI const_iterator find(const _K2& __k) const { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_iterator find(const _K2& __k) const { return __tree_.find(__k); } # endif - _LIBCPP_HIDE_FROM_ABI size_type count(const key_type& __k) const { return __tree_.__count_unique(__k); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI size_type count(const key_type& __k) const { + return __tree_.__count_unique(__k); + } # if _LIBCPP_STD_VER >= 14 template , int> = 0> - _LIBCPP_HIDE_FROM_ABI size_type count(const _K2& __k) const { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI size_type count(const _K2& __k) const { return __tree_.__count_multi(__k); } # endif # if _LIBCPP_STD_VER >= 20 - _LIBCPP_HIDE_FROM_ABI bool contains(const key_type& __k) const { return find(__k) != end(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool contains(const key_type& __k) const { return find(__k) != end(); } template || __is_transparently_comparable_v<_Compare, key_type, _K2>, int> = 0> - _LIBCPP_HIDE_FROM_ABI bool contains(const _K2& __k) const { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool contains(const _K2& __k) const { return find(__k) != end(); } # endif // _LIBCPP_STD_VER >= 20 - _LIBCPP_HIDE_FROM_ABI iterator lower_bound(const key_type& __k) { return __tree_.__lower_bound_unique(__k); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI iterator lower_bound(const key_type& __k) { + return __tree_.__lower_bound_unique(__k); + } - _LIBCPP_HIDE_FROM_ABI const_iterator lower_bound(const key_type& __k) const { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_iterator lower_bound(const key_type& __k) const { return __tree_.__lower_bound_unique(__k); } @@ -1307,21 +1319,23 @@ public: template || __is_transparently_comparable_v<_Compare, key_type, _K2>, int> = 0> - _LIBCPP_HIDE_FROM_ABI iterator lower_bound(const _K2& __k) { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI iterator lower_bound(const _K2& __k) { return __tree_.__lower_bound_multi(__k); } template || __is_transparently_comparable_v<_Compare, key_type, _K2>, int> = 0> - _LIBCPP_HIDE_FROM_ABI const_iterator lower_bound(const _K2& __k) const { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_iterator lower_bound(const _K2& __k) const { return __tree_.__lower_bound_multi(__k); } # endif - _LIBCPP_HIDE_FROM_ABI iterator upper_bound(const key_type& __k) { return __tree_.__upper_bound_unique(__k); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI iterator upper_bound(const key_type& __k) { + return __tree_.__upper_bound_unique(__k); + } - _LIBCPP_HIDE_FROM_ABI const_iterator upper_bound(const key_type& __k) const { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_iterator upper_bound(const key_type& __k) const { return __tree_.__upper_bound_unique(__k); } @@ -1329,30 +1343,30 @@ public: template || __is_transparently_comparable_v<_Compare, key_type, _K2>, int> = 0> - _LIBCPP_HIDE_FROM_ABI iterator upper_bound(const _K2& __k) { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI iterator upper_bound(const _K2& __k) { return __tree_.__upper_bound_multi(__k); } template || __is_transparently_comparable_v<_Compare, key_type, _K2>, int> = 0> - _LIBCPP_HIDE_FROM_ABI const_iterator upper_bound(const _K2& __k) const { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_iterator upper_bound(const _K2& __k) const { return __tree_.__upper_bound_multi(__k); } # endif - _LIBCPP_HIDE_FROM_ABI pair equal_range(const key_type& __k) { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI pair equal_range(const key_type& __k) { return __tree_.__equal_range_unique(__k); } - _LIBCPP_HIDE_FROM_ABI pair equal_range(const key_type& __k) const { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI pair equal_range(const key_type& __k) const { return __tree_.__equal_range_unique(__k); } # if _LIBCPP_STD_VER >= 14 template , int> = 0> - _LIBCPP_HIDE_FROM_ABI pair equal_range(const _K2& __k) { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI pair equal_range(const _K2& __k) { return __tree_.__equal_range_multi(__k); } template , int> = 0> - _LIBCPP_HIDE_FROM_ABI pair equal_range(const _K2& __k) const { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI pair equal_range(const _K2& __k) const { return __tree_.__equal_range_multi(__k); } # endif diff --git a/libcxx/test/libcxx/containers/associative/map/at.abort.pass.cpp b/libcxx/test/libcxx/containers/associative/map/at.abort.pass.cpp index d68ee5f528599..fae3370805dd3 100644 --- a/libcxx/test/libcxx/containers/associative/map/at.abort.pass.cpp +++ b/libcxx/test/libcxx/containers/associative/map/at.abort.pass.cpp @@ -28,6 +28,6 @@ void exit_success(int) { std::_Exit(EXIT_SUCCESS); } int main(int, char**) { std::signal(SIGABRT, exit_success); std::map map; - map.at(1); + (void)map.at(1); return EXIT_FAILURE; } diff --git a/libcxx/test/libcxx/containers/associative/map/at.const.abort.pass.cpp b/libcxx/test/libcxx/containers/associative/map/at.const.abort.pass.cpp index bbc8c7c4d726a..d50faeff79496 100644 --- a/libcxx/test/libcxx/containers/associative/map/at.const.abort.pass.cpp +++ b/libcxx/test/libcxx/containers/associative/map/at.const.abort.pass.cpp @@ -28,6 +28,6 @@ void exit_success(int) { std::_Exit(EXIT_SUCCESS); } int main(int, char**) { std::signal(SIGABRT, exit_success); std::map const map; - map.at(1); + (void)map.at(1); return EXIT_FAILURE; } diff --git a/libcxx/test/libcxx/diagnostics/map.nodiscard.verify.cpp b/libcxx/test/libcxx/diagnostics/map.nodiscard.verify.cpp index 78a8dd78f98a7..f973982381316 100644 --- a/libcxx/test/libcxx/diagnostics/map.nodiscard.verify.cpp +++ b/libcxx/test/libcxx/diagnostics/map.nodiscard.verify.cpp @@ -8,16 +8,126 @@ // UNSUPPORTED: c++03 -// check that functions are marked [[nodiscard]] +// Check that functions are marked [[nodiscard]] #include +#include +#include -void map_test() { - std::map map; - map.empty(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} -} +#include "test_macros.h" + +template +struct TransparentKey { + T t; + + constexpr explicit operator T() const { return t; } +}; + +struct TransparentCompare { + using is_transparent = void; // This makes the comparator transparent + + template + constexpr bool operator()(const T& t, const TransparentKey& transparent) const { + return t < transparent.t; + } + + template + constexpr bool operator()(const TransparentKey& transparent, const T& t) const { + return transparent.t < t; + } + + template + constexpr bool operator()(const T& t1, const T& t2) const { + return t1 < t2; + } +}; + +void test() { + std::map m; + const std::map cm{}; + + m.begin(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} + cm.begin(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} + m.end(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} + cm.end(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} + + m.rbegin(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} + cm.rbegin(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} + m.rend(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} + cm.rend(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} + + cm.cbegin(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} + cm.cend(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} + cm.crbegin(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} + cm.crend(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} + + m.empty(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} + m.size(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} + m.max_size(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} + + int key = 0; + + m[key]; // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} + m[std::move(key)]; // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} + +#if TEST_STD_VER >= 14 + std::map> strMap; + const std::map> cstrMap{}; + + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + strMap.at("zmt"); + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + cstrMap.at("hkt"); +#endif + m.at(key); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} + cm.at(key); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} + + m.get_allocator(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} + m.key_comp(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} + m.value_comp(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} + +#if TEST_STD_VER >= 17 + m.extract(key); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} + m.extract(m.cend()); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} +#endif + + m.find(key); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} + cm.find(key); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} +#if TEST_STD_VER >= 14 + TransparentKey tkey; + + m.find(tkey); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} + cm.find(tkey); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} +#endif + + m.count(key); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} +#if TEST_STD_VER >= 14 + m.count(tkey); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} +#endif + +#if TEST_STD_VER >= 20 + m.contains(key); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} + m.contains(tkey); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} +#endif + + m.lower_bound(key); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} + cm.lower_bound(key); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} +#if TEST_STD_VER >= 14 + m.lower_bound(tkey); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} + cm.lower_bound(tkey); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} +#endif + + m.upper_bound(key); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} + cm.upper_bound(key); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} +#if TEST_STD_VER >= 14 + m.upper_bound(tkey); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} + cm.upper_bound(tkey); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} +#endif -void multimap_test() { - std::multimap multimap; - multimap.empty(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} + m.equal_range(key); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} + cm.equal_range(key); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} +#if TEST_STD_VER >= 14 + m.equal_range(tkey); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} + cm.equal_range(tkey); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} +#endif } diff --git a/libcxx/test/libcxx/diagnostics/multimap.nodiscard.verify copy.cpp b/libcxx/test/libcxx/diagnostics/multimap.nodiscard.verify copy.cpp new file mode 100644 index 0000000000000..70e934645d4f9 --- /dev/null +++ b/libcxx/test/libcxx/diagnostics/multimap.nodiscard.verify copy.cpp @@ -0,0 +1,18 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03 + +// Check that functions are marked [[nodiscard]] + +#include + +void test() { + std::multimap multimap; + multimap.empty(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} +}