EricWF retitled this revision from "[RFC] Add _LIBCPP_NO_DISCARD and apply it to unique_ptr<T>::release()" to "[RFC] Add _LIBCPP_NO_DISCARD and apply it to `Container::empty()`, `unique_ptr<T>::release()`, and `Lockable::try_lock()` ". EricWF updated the summary for this revision. EricWF updated this revision to Diff 77760. EricWF added a comment.
- Allow groups of no-discard checks to be enabled/disabled using group specific macros. (As requested by @chandlerc) - Add documentation for `_LIBCPP_NO_DISCARD` and friends. - Apply no-discard checks in more places to show new feature macro example. @chandlerc Would this approach be sufficient? https://reviews.llvm.org/D26596 Files: docs/UsingLibcxx.rst include/__config include/__mutex_base include/forward_list include/list include/map include/memory include/mutex include/set include/shared_mutex include/string include/unordered_map include/unordered_set include/vector test/libcxx/containers/no-discard-disable.fail.cpp test/libcxx/containers/no-discard.fail.cpp test/libcxx/test/config.py test/libcxx/thread/thread.mutex/try_lock_no_discard.fail.cpp test/libcxx/thread/thread.mutex/try_lock_no_discard_disabled.fail.cpp test/libcxx/utilities/memory/unique.ptr/unique.ptr.runtime/unique.ptr.runtime.modifiers/release.fail.cpp test/libcxx/utilities/memory/unique.ptr/unique.ptr.single/unique.ptr.single.modifiers/release.fail.cpp
Index: test/libcxx/utilities/memory/unique.ptr/unique.ptr.single/unique.ptr.single.modifiers/release.fail.cpp =================================================================== --- /dev/null +++ test/libcxx/utilities/memory/unique.ptr/unique.ptr.single/unique.ptr.single.modifiers/release.fail.cpp @@ -0,0 +1,25 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// <memory> + +// unique_ptr + +// test release + +#include <memory> +#include <cassert> + +int main() +{ + std::unique_ptr<int> p(new int(3)); + int* i = p.get(); + p.release(); // expected-warning {{ignoring return value of function declared with 'warn_unused_result' attribute}} + delete i; +} Index: test/libcxx/utilities/memory/unique.ptr/unique.ptr.runtime/unique.ptr.runtime.modifiers/release.fail.cpp =================================================================== --- /dev/null +++ test/libcxx/utilities/memory/unique.ptr/unique.ptr.runtime/unique.ptr.runtime.modifiers/release.fail.cpp @@ -0,0 +1,25 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// <memory> + +// unique_ptr + +// test release + +#include <memory> +#include <cassert> + +int main() +{ + std::unique_ptr<int[]> p(new int[3]); + int* i = p.get(); + p.release(); // expected-warning {{ignoring return value of function declared with 'warn_unused_result' attribute}} + delete [] i; +} Index: test/libcxx/thread/thread.mutex/try_lock_no_discard_disabled.fail.cpp =================================================================== --- /dev/null +++ test/libcxx/thread/thread.mutex/try_lock_no_discard_disabled.fail.cpp @@ -0,0 +1,105 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: libcpp-has-no-threads +// REQUIRES: verify-diagnostics + +// test the generated [[no_discard]] warnings + +#define _LIBCPP_DISABLE_NO_DISCARD_TRY_LOCK +#include <mutex> +#include <shared_mutex> + +#include "test_macros.h" + +int main() { + // expected-no-diagnostics + { + std::mutex m; + m.try_lock(); + m.unlock(); + } + { + std::recursive_mutex m; + m.try_lock(); + m.unlock(); + } + { + std::timed_mutex m; + m.try_lock(); + m.unlock(); + m.try_lock_for(std::chrono::seconds(1)); + m.unlock(); + m.try_lock_until(std::chrono::steady_clock::now() + std::chrono::seconds(1)); + m.unlock(); + } + { + std::recursive_timed_mutex m; + m.try_lock(); + m.unlock(); + m.try_lock_for(std::chrono::seconds(1)); + m.unlock(); + m.try_lock_until(std::chrono::steady_clock::now() + std::chrono::seconds(1)); + m.unlock(); + } + { + std::mutex m; + std::unique_lock<std::mutex> lk(m); + lk.unlock(); + lk.try_lock(); + } + { + std::timed_mutex m; + std::unique_lock<std::timed_mutex> lk(m); + lk.unlock(); + lk.try_lock(); + lk.unlock(); + lk.try_lock_for(std::chrono::seconds(1)); + lk.unlock(); + lk.try_lock_until(std::chrono::steady_clock::now() + std::chrono::seconds(1)); + lk.unlock(); + } +#if TEST_STD_VER > 11 + { + std::shared_timed_mutex m; + m.try_lock(); + m.unlock(); + m.try_lock_for(std::chrono::seconds(1)); + m.unlock(); + m.try_lock_until(std::chrono::steady_clock::now() + std::chrono::seconds(1)); + m.unlock(); + m.try_lock_shared(); + m.unlock(); + m.try_lock_shared_for(std::chrono::seconds(1)); + m.unlock(); + m.try_lock_shared_until(std::chrono::steady_clock::now() + std::chrono::seconds(1)); + m.unlock(); + } + { + std::shared_timed_mutex m; + std::shared_lock<std::shared_timed_mutex> lk(m); + lk.unlock(); + lk.try_lock(); + lk.unlock(); + lk.try_lock_for(std::chrono::seconds(1)); + lk.unlock(); + lk.try_lock_until(std::chrono::steady_clock::now() + std::chrono::seconds(1)); + lk.unlock(); + } +#endif +#if TEST_STD_VER > 14 + { + std::shared_mutex m; + m.try_lock(); + m.unlock(); + m.try_lock_shared(); + m.unlock(); + }; +#endif +} \ No newline at end of file Index: test/libcxx/thread/thread.mutex/try_lock_no_discard.fail.cpp =================================================================== --- /dev/null +++ test/libcxx/thread/thread.mutex/try_lock_no_discard.fail.cpp @@ -0,0 +1,103 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: libcpp-has-no-threads +// REQUIRES: verify-diagnostics + +// test the generated [[no_discard]] warnings + +#include <mutex> +#include <shared_mutex> + +#include "test_macros.h" + +int main() { + { + std::mutex m; + m.try_lock(); // expected-warning {{ignoring return value}} + m.unlock(); + } + { + std::recursive_mutex m; + m.try_lock(); // expected-warning {{ignoring return value}} + m.unlock(); + } + { + std::timed_mutex m; + m.try_lock(); // expected-warning {{ignoring return value}} + m.unlock(); + m.try_lock_for(std::chrono::seconds(1)); // expected-warning {{ignoring return value}} + m.unlock(); + m.try_lock_until(std::chrono::steady_clock::now() + std::chrono::seconds(1)); // expected-warning {{ignoring return value}} + m.unlock(); + } + { + std::recursive_timed_mutex m; + m.try_lock(); // expected-warning {{ignoring return value}} + m.unlock(); + m.try_lock_for(std::chrono::seconds(1)); // expected-warning {{ignoring return value}} + m.unlock(); + m.try_lock_until(std::chrono::steady_clock::now() + std::chrono::seconds(1)); // expected-warning {{ignoring return value}} + m.unlock(); + } + { + std::mutex m; + std::unique_lock<std::mutex> lk(m); + lk.unlock(); + lk.try_lock(); // expected-warning {{ignoring return value}} + } + { + std::timed_mutex m; + std::unique_lock<std::timed_mutex> lk(m); + lk.unlock(); + lk.try_lock(); // expected-warning {{ignoring return value}} + lk.unlock(); + lk.try_lock_for(std::chrono::seconds(1)); // expected-warning {{ignoring return value}} + lk.unlock(); + lk.try_lock_until(std::chrono::steady_clock::now() + std::chrono::seconds(1)); // expected-warning {{ignoring return value}} + lk.unlock(); + } +#if TEST_STD_VER > 11 + { + std::shared_timed_mutex m; + m.try_lock(); // expected-warning {{ignoring return value}} + m.unlock(); + m.try_lock_for(std::chrono::seconds(1)); // expected-warning {{ignoring return value}} + m.unlock(); + m.try_lock_until(std::chrono::steady_clock::now() + std::chrono::seconds(1)); // expected-warning {{ignoring return value}} + m.unlock(); + m.try_lock_shared(); // expected-warning {{ignoring return value}} + m.unlock(); + m.try_lock_shared_for(std::chrono::seconds(1)); // expected-warning {{ignoring return value}} + m.unlock(); + m.try_lock_shared_until(std::chrono::steady_clock::now() + std::chrono::seconds(1)); // expected-warning {{ignoring return value}} + m.unlock(); + } + { + std::shared_timed_mutex m; + std::shared_lock<std::shared_timed_mutex> lk(m); + lk.unlock(); + lk.try_lock(); // expected-warning {{ignoring return value}} + lk.unlock(); + lk.try_lock_for(std::chrono::seconds(1)); // expected-warning {{ignoring return value}} + lk.unlock(); + lk.try_lock_until(std::chrono::steady_clock::now() + std::chrono::seconds(1)); // expected-warning {{ignoring return value}} + lk.unlock(); + } +#endif +#if TEST_STD_VER > 14 + { + std::shared_mutex m; + m.try_lock(); // expected-warning {{ignoring return value}} + m.unlock(); + m.try_lock_shared(); // expected-warning {{ignoring return value}} + m.unlock(); + }; +#endif +} \ No newline at end of file Index: test/libcxx/test/config.py =================================================================== --- test/libcxx/test/config.py +++ test/libcxx/test/config.py @@ -249,6 +249,8 @@ ['-Xclang', '-verify-ignore-unexpected']) self.lit_config.note( "inferred use_clang_verify as: %r" % self.use_clang_verify) + if self.use_clang_verify: + self.config.available_features.add('verify-diagnostics') def configure_use_thread_safety(self): '''If set, run clang with -verify on failing tests.''' Index: test/libcxx/containers/no-discard.fail.cpp =================================================================== --- /dev/null +++ test/libcxx/containers/no-discard.fail.cpp @@ -0,0 +1,68 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// REQUIRES: verify-diagnostics + +// test the generated [[no_discard]] warnings + +#include <vector> +#include <deque> +#include <list> +#include <forward_list> +#include <set> +#include <map> +#include <unordered_set> +#include <unordered_map> +#include <string> + +// Note: -Wunused-result is not emitted from within function templates so +// we instead use a macro to avoid duplication. +#define TEST_WARNING4(...) \ + do { __VA_ARGS__ C; C.empty(); C.size(); C.capacity(); C.max_size(); } while (false) + +#define TEST_WARNING3(...) \ + do { __VA_ARGS__ C; C.empty(); C.size(); C.max_size(); } while (false) + +int main() { + // std::vector + { + TEST_WARNING4(std::vector<int>); // expected-warning 4 {{ignoring return value}} + TEST_WARNING4(std::vector<bool>); // expected-warning 4 {{ignoring return value}} + } + // std::string + { + TEST_WARNING4(std::string); // expected-warning 4 {{ignoring return value}} + std::string s; + s.length(); // expected-warning {{ignoring return value}} + } + { + TEST_WARNING3(std::list<int>); // expected-warning 3 {{ignoring return value}} + } + { + std::forward_list<int> C; + C.empty(); // expected-warning {{ignoring return value}} + C.max_size(); // expected-warning {{ignoring return value}} + } + { + TEST_WARNING3(std::set<int>); // expected-warning 3 {{ignoring return value}} + TEST_WARNING3(std::multiset<int>); // expected-warning 3 {{ignoring return value}} + } + { + TEST_WARNING3(std::map<int, int>); // expected-warning 3 {{ignoring return value}} + TEST_WARNING3(std::multimap<int, int>); // expected-warning 3 {{ignoring return value}} + } + { + TEST_WARNING3(std::unordered_set<int>); // expected-warning 3 {{ignoring return value}} + TEST_WARNING3(std::unordered_multiset<int>); // expected-warning 3 {{ignoring return value}} + } + { + TEST_WARNING3(std::unordered_map<int, int>); // expected-warning 3 {{ignoring return value}} + TEST_WARNING3(std::unordered_multimap<int, int>); // expected-warning 3 {{ignoring return value}} + } +} \ No newline at end of file Index: test/libcxx/containers/no-discard-disable.fail.cpp =================================================================== --- /dev/null +++ test/libcxx/containers/no-discard-disable.fail.cpp @@ -0,0 +1,70 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// REQUIRES: verify-diagnostics + +// test the generated [[no_discard]] warnings + +#define _LIBCPP_DISABLE_NO_DISCARD_CONTAINER_OBSERVERS +#include <vector> +#include <deque> +#include <list> +#include <forward_list> +#include <set> +#include <map> +#include <unordered_set> +#include <unordered_map> +#include <string> + +// Note: -Wunused-result is not emitted from within function templates so +// we instead use a macro to avoid duplication. +#define TEST_WARNING4(...) \ + do { __VA_ARGS__ C; C.empty(); C.size(); C.capacity(); C.max_size(); } while (false) + +#define TEST_WARNING3(...) \ + do { __VA_ARGS__ C; C.empty(); C.size(); C.max_size(); } while (false) + +int main() { + // expected-no-diagnostics + // std::vector + { + TEST_WARNING4(std::vector<int>); + TEST_WARNING4(std::vector<bool>); + } + // std::string + { + TEST_WARNING4(std::string); + std::string s; + s.length(); + } + { + TEST_WARNING3(std::list<int>); + } + { + std::forward_list<int> C; + C.empty(); + C.max_size(); + } + { + TEST_WARNING3(std::set<int>); + TEST_WARNING3(std::multiset<int>); + } + { + TEST_WARNING3(std::map<int, int>); + TEST_WARNING3(std::multimap<int, int>); + } + { + TEST_WARNING3(std::unordered_set<int>); + TEST_WARNING3(std::unordered_multiset<int>); + } + { + TEST_WARNING3(std::unordered_map<int, int>); + TEST_WARNING3(std::unordered_multimap<int, int>); + } +} \ No newline at end of file Index: include/vector =================================================================== --- include/vector +++ include/vector @@ -627,16 +627,16 @@ const_reverse_iterator crend() const _NOEXCEPT {return rend();} - _LIBCPP_INLINE_VISIBILITY + _LIBCPP_NO_DISCARD_CONTAINER_OBSERVERS _LIBCPP_INLINE_VISIBILITY size_type size() const _NOEXCEPT {return static_cast<size_type>(this->__end_ - this->__begin_);} - _LIBCPP_INLINE_VISIBILITY + _LIBCPP_NO_DISCARD_CONTAINER_OBSERVERS _LIBCPP_INLINE_VISIBILITY size_type capacity() const _NOEXCEPT {return __base::capacity();} - _LIBCPP_INLINE_VISIBILITY + _LIBCPP_NO_DISCARD_CONTAINER_OBSERVERS _LIBCPP_INLINE_VISIBILITY bool empty() const _NOEXCEPT {return this->__begin_ == this->__end_;} - size_type max_size() const _NOEXCEPT; + _LIBCPP_NO_DISCARD_CONTAINER_OBSERVERS size_type max_size() const _NOEXCEPT; void reserve(size_type __n); void shrink_to_fit() _NOEXCEPT; @@ -2242,14 +2242,14 @@ _LIBCPP_INLINE_VISIBILITY allocator_type get_allocator() const _NOEXCEPT {return allocator_type(this->__alloc());} - size_type max_size() const _NOEXCEPT; - _LIBCPP_INLINE_VISIBILITY + _LIBCPP_NO_DISCARD_CONTAINER_OBSERVERS size_type max_size() const _NOEXCEPT; + _LIBCPP_NO_DISCARD_CONTAINER_OBSERVERS _LIBCPP_INLINE_VISIBILITY size_type capacity() const _NOEXCEPT {return __internal_cap_to_external(__cap());} - _LIBCPP_INLINE_VISIBILITY + _LIBCPP_NO_DISCARD_CONTAINER_OBSERVERS _LIBCPP_INLINE_VISIBILITY size_type size() const _NOEXCEPT {return __size_;} - _LIBCPP_INLINE_VISIBILITY + _LIBCPP_NO_DISCARD_CONTAINER_OBSERVERS _LIBCPP_INLINE_VISIBILITY bool empty() const _NOEXCEPT {return __size_ == 0;} void reserve(size_type __n); Index: include/unordered_set =================================================================== --- include/unordered_set +++ include/unordered_set @@ -454,11 +454,11 @@ allocator_type get_allocator() const _NOEXCEPT {return allocator_type(__table_.__node_alloc());} - _LIBCPP_INLINE_VISIBILITY + _LIBCPP_NO_DISCARD_CONTAINER_OBSERVERS _LIBCPP_INLINE_VISIBILITY bool empty() const _NOEXCEPT {return __table_.size() == 0;} - _LIBCPP_INLINE_VISIBILITY + _LIBCPP_NO_DISCARD_CONTAINER_OBSERVERS _LIBCPP_INLINE_VISIBILITY size_type size() const _NOEXCEPT {return __table_.size();} - _LIBCPP_INLINE_VISIBILITY + _LIBCPP_NO_DISCARD_CONTAINER_OBSERVERS _LIBCPP_INLINE_VISIBILITY size_type max_size() const _NOEXCEPT {return __table_.max_size();} _LIBCPP_INLINE_VISIBILITY @@ -992,11 +992,11 @@ allocator_type get_allocator() const _NOEXCEPT {return allocator_type(__table_.__node_alloc());} - _LIBCPP_INLINE_VISIBILITY + _LIBCPP_NO_DISCARD_CONTAINER_OBSERVERS _LIBCPP_INLINE_VISIBILITY bool empty() const _NOEXCEPT {return __table_.size() == 0;} - _LIBCPP_INLINE_VISIBILITY + _LIBCPP_NO_DISCARD_CONTAINER_OBSERVERS _LIBCPP_INLINE_VISIBILITY size_type size() const _NOEXCEPT {return __table_.size();} - _LIBCPP_INLINE_VISIBILITY + _LIBCPP_NO_DISCARD_CONTAINER_OBSERVERS _LIBCPP_INLINE_VISIBILITY size_type max_size() const _NOEXCEPT {return __table_.max_size();} _LIBCPP_INLINE_VISIBILITY Index: include/unordered_map =================================================================== --- include/unordered_map +++ include/unordered_map @@ -893,11 +893,11 @@ allocator_type get_allocator() const _NOEXCEPT {return allocator_type(__table_.__node_alloc());} - _LIBCPP_INLINE_VISIBILITY + _LIBCPP_NO_DISCARD_CONTAINER_OBSERVERS _LIBCPP_INLINE_VISIBILITY bool empty() const _NOEXCEPT {return __table_.size() == 0;} - _LIBCPP_INLINE_VISIBILITY + _LIBCPP_NO_DISCARD_CONTAINER_OBSERVERS _LIBCPP_INLINE_VISIBILITY size_type size() const _NOEXCEPT {return __table_.size();} - _LIBCPP_INLINE_VISIBILITY + _LIBCPP_NO_DISCARD_CONTAINER_OBSERVERS _LIBCPP_INLINE_VISIBILITY size_type max_size() const _NOEXCEPT {return __table_.max_size();} _LIBCPP_INLINE_VISIBILITY @@ -1647,11 +1647,11 @@ allocator_type get_allocator() const _NOEXCEPT {return allocator_type(__table_.__node_alloc());} - _LIBCPP_INLINE_VISIBILITY + _LIBCPP_NO_DISCARD_CONTAINER_OBSERVERS _LIBCPP_INLINE_VISIBILITY bool empty() const _NOEXCEPT {return __table_.size() == 0;} - _LIBCPP_INLINE_VISIBILITY + _LIBCPP_NO_DISCARD_CONTAINER_OBSERVERS _LIBCPP_INLINE_VISIBILITY size_type size() const _NOEXCEPT {return __table_.size();} - _LIBCPP_INLINE_VISIBILITY + _LIBCPP_NO_DISCARD_CONTAINER_OBSERVERS _LIBCPP_INLINE_VISIBILITY size_type max_size() const _NOEXCEPT {return __table_.max_size();} _LIBCPP_INLINE_VISIBILITY Index: include/string =================================================================== --- include/string +++ include/string @@ -879,11 +879,15 @@ const_reverse_iterator crend() const _NOEXCEPT {return rend();} - _LIBCPP_INLINE_VISIBILITY size_type size() const _NOEXCEPT + _LIBCPP_NO_DISCARD_CONTAINER_OBSERVERS _LIBCPP_INLINE_VISIBILITY + size_type size() const _NOEXCEPT {return __is_long() ? __get_long_size() : __get_short_size();} - _LIBCPP_INLINE_VISIBILITY size_type length() const _NOEXCEPT {return size();} - _LIBCPP_INLINE_VISIBILITY size_type max_size() const _NOEXCEPT; - _LIBCPP_INLINE_VISIBILITY size_type capacity() const _NOEXCEPT + _LIBCPP_NO_DISCARD_CONTAINER_OBSERVERS _LIBCPP_INLINE_VISIBILITY + size_type length() const _NOEXCEPT {return size();} + _LIBCPP_NO_DISCARD_CONTAINER_OBSERVERS _LIBCPP_INLINE_VISIBILITY + size_type max_size() const _NOEXCEPT; + _LIBCPP_NO_DISCARD_CONTAINER_OBSERVERS _LIBCPP_INLINE_VISIBILITY + size_type capacity() const _NOEXCEPT {return (__is_long() ? __get_long_cap() : static_cast<size_type>(__min_cap)) - 1;} @@ -895,7 +899,8 @@ void shrink_to_fit() _NOEXCEPT {reserve();} _LIBCPP_INLINE_VISIBILITY void clear() _NOEXCEPT; - _LIBCPP_INLINE_VISIBILITY bool empty() const _NOEXCEPT {return size() == 0;} + _LIBCPP_NO_DISCARD_CONTAINER_OBSERVERS _LIBCPP_INLINE_VISIBILITY + bool empty() const _NOEXCEPT {return size() == 0;} _LIBCPP_INLINE_VISIBILITY const_reference operator[](size_type __pos) const _NOEXCEPT; _LIBCPP_INLINE_VISIBILITY reference operator[](size_type __pos) _NOEXCEPT; Index: include/shared_mutex =================================================================== --- include/shared_mutex +++ include/shared_mutex @@ -159,12 +159,12 @@ // Exclusive ownership void lock(); // blocking - bool try_lock(); + _LIBCPP_NO_DISCARD bool try_lock(); void unlock(); // Shared ownership void lock_shared(); // blocking - bool try_lock_shared(); + _LIBCPP_NO_DISCARD bool try_lock_shared(); void unlock_shared(); // typedef implementation-defined native_handle_type; // See 30.2.3 @@ -185,12 +185,14 @@ // Exclusive ownership _LIBCPP_INLINE_VISIBILITY void lock() { return __base.lock(); } - _LIBCPP_INLINE_VISIBILITY bool try_lock() { return __base.try_lock(); } + _LIBCPP_NO_DISCARD_TRY_LOCK _LIBCPP_INLINE_VISIBILITY + bool try_lock() { return __base.try_lock(); } _LIBCPP_INLINE_VISIBILITY void unlock() { return __base.unlock(); } // Shared ownership _LIBCPP_INLINE_VISIBILITY void lock_shared() { return __base.lock_shared(); } - _LIBCPP_INLINE_VISIBILITY bool try_lock_shared() { return __base.try_lock_shared(); } + _LIBCPP_NO_DISCARD_TRY_LOCK _LIBCPP_INLINE_VISIBILITY + bool try_lock_shared() { return __base.try_lock_shared(); } _LIBCPP_INLINE_VISIBILITY void unlock_shared() { return __base.unlock_shared(); } // typedef __shared_mutex_base::native_handle_type native_handle_type; @@ -211,31 +213,31 @@ // Exclusive ownership void lock(); - bool try_lock(); + _LIBCPP_NO_DISCARD_TRY_LOCK bool try_lock(); template <class _Rep, class _Period> - _LIBCPP_INLINE_VISIBILITY + _LIBCPP_NO_DISCARD_TRY_LOCK _LIBCPP_INLINE_VISIBILITY bool try_lock_for(const chrono::duration<_Rep, _Period>& __rel_time) { return try_lock_until(chrono::steady_clock::now() + __rel_time); } template <class _Clock, class _Duration> - bool + _LIBCPP_NO_DISCARD_TRY_LOCK bool try_lock_until(const chrono::time_point<_Clock, _Duration>& __abs_time); void unlock(); // Shared ownership void lock_shared(); - bool try_lock_shared(); + _LIBCPP_NO_DISCARD_TRY_LOCK bool try_lock_shared(); template <class _Rep, class _Period> - _LIBCPP_INLINE_VISIBILITY + _LIBCPP_NO_DISCARD_TRY_LOCK _LIBCPP_INLINE_VISIBILITY bool try_lock_shared_for(const chrono::duration<_Rep, _Period>& __rel_time) { return try_lock_shared_until(chrono::steady_clock::now() + __rel_time); } template <class _Clock, class _Duration> - bool + _LIBCPP_NO_DISCARD_TRY_LOCK bool try_lock_shared_until(const chrono::time_point<_Clock, _Duration>& __abs_time); void unlock_shared(); }; @@ -391,10 +393,12 @@ } void lock(); - bool try_lock(); + _LIBCPP_NO_DISCARD_TRY_LOCK bool try_lock(); template <class Rep, class Period> + _LIBCPP_NO_DISCARD_TRY_LOCK bool try_lock_for(const chrono::duration<Rep, Period>& rel_time); template <class Clock, class Duration> + _LIBCPP_NO_DISCARD_TRY_LOCK bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time); void unlock(); Index: include/set =================================================================== --- include/set +++ include/set @@ -579,11 +579,11 @@ _LIBCPP_INLINE_VISIBILITY const_reverse_iterator crend() const _NOEXCEPT {return rend();} - _LIBCPP_INLINE_VISIBILITY + _LIBCPP_NO_DISCARD_CONTAINER_OBSERVERS _LIBCPP_INLINE_VISIBILITY bool empty() const _NOEXCEPT {return __tree_.size() == 0;} - _LIBCPP_INLINE_VISIBILITY + _LIBCPP_NO_DISCARD_CONTAINER_OBSERVERS _LIBCPP_INLINE_VISIBILITY size_type size() const _NOEXCEPT {return __tree_.size();} - _LIBCPP_INLINE_VISIBILITY + _LIBCPP_NO_DISCARD_CONTAINER_OBSERVERS _LIBCPP_INLINE_VISIBILITY size_type max_size() const _NOEXCEPT {return __tree_.max_size();} // modifiers: @@ -991,11 +991,11 @@ _LIBCPP_INLINE_VISIBILITY const_reverse_iterator crend() const _NOEXCEPT {return rend();} - _LIBCPP_INLINE_VISIBILITY + _LIBCPP_NO_DISCARD_CONTAINER_OBSERVERS _LIBCPP_INLINE_VISIBILITY bool empty() const _NOEXCEPT {return __tree_.size() == 0;} - _LIBCPP_INLINE_VISIBILITY + _LIBCPP_NO_DISCARD_CONTAINER_OBSERVERS _LIBCPP_INLINE_VISIBILITY size_type size() const _NOEXCEPT {return __tree_.size();} - _LIBCPP_INLINE_VISIBILITY + _LIBCPP_NO_DISCARD_CONTAINER_OBSERVERS _LIBCPP_INLINE_VISIBILITY size_type max_size() const _NOEXCEPT {return __tree_.max_size();} // modifiers: Index: include/mutex =================================================================== --- include/mutex +++ include/mutex @@ -218,7 +218,7 @@ public: void lock(); - bool try_lock() _NOEXCEPT; + _LIBCPP_NO_DISCARD_TRY_LOCK bool try_lock() _NOEXCEPT; void unlock() _NOEXCEPT; typedef __libcpp_mutex_t* native_handle_type; @@ -241,12 +241,13 @@ public: void lock(); - bool try_lock() _NOEXCEPT; + _LIBCPP_NO_DISCARD_TRY_LOCK bool try_lock() _NOEXCEPT; template <class _Rep, class _Period> - _LIBCPP_INLINE_VISIBILITY + _LIBCPP_NO_DISCARD_TRY_LOCK _LIBCPP_INLINE_VISIBILITY bool try_lock_for(const chrono::duration<_Rep, _Period>& __d) {return try_lock_until(chrono::steady_clock::now() + __d);} template <class _Clock, class _Duration> + _LIBCPP_NO_DISCARD_TRY_LOCK bool try_lock_until(const chrono::time_point<_Clock, _Duration>& __t); void unlock() _NOEXCEPT; }; @@ -284,12 +285,13 @@ public: void lock(); - bool try_lock() _NOEXCEPT; + _LIBCPP_NO_DISCARD_TRY_LOCK bool try_lock() _NOEXCEPT; template <class _Rep, class _Period> - _LIBCPP_INLINE_VISIBILITY + _LIBCPP_NO_DISCARD_TRY_LOCK _LIBCPP_INLINE_VISIBILITY bool try_lock_for(const chrono::duration<_Rep, _Period>& __d) {return try_lock_until(chrono::steady_clock::now() + __d);} template <class _Clock, class _Duration> + _LIBCPP_NO_DISCARD_TRY_LOCK bool try_lock_until(const chrono::time_point<_Clock, _Duration>& __t); void unlock() _NOEXCEPT; }; Index: include/memory =================================================================== --- include/memory +++ include/memory @@ -2768,6 +2768,9 @@ _LIBCPP_EXPLICIT operator bool() const _NOEXCEPT {return __ptr_.first() != nullptr;} +#ifndef _LIBCPP_DISABLE_NO_DISCARD_UNIQUE_PTR_RELEASE + _LIBCPP_NO_DISCARD +#endif _LIBCPP_INLINE_VISIBILITY pointer release() _NOEXCEPT { pointer __t = __ptr_.first(); @@ -2959,6 +2962,9 @@ _LIBCPP_EXPLICIT operator bool() const _NOEXCEPT {return __ptr_.first() != nullptr;} +#ifndef _LIBCPP_DISABLE_NO_DISCARD_UNIQUE_PTR_RELEASE + _LIBCPP_NO_DISCARD +#endif _LIBCPP_INLINE_VISIBILITY pointer release() _NOEXCEPT { pointer __t = __ptr_.first(); Index: include/map =================================================================== --- include/map +++ include/map @@ -1018,11 +1018,11 @@ _LIBCPP_INLINE_VISIBILITY const_reverse_iterator crend() const _NOEXCEPT {return rend();} - _LIBCPP_INLINE_VISIBILITY + _LIBCPP_NO_DISCARD_CONTAINER_OBSERVERS _LIBCPP_INLINE_VISIBILITY bool empty() const _NOEXCEPT {return __tree_.size() == 0;} - _LIBCPP_INLINE_VISIBILITY + _LIBCPP_NO_DISCARD_CONTAINER_OBSERVERS _LIBCPP_INLINE_VISIBILITY size_type size() const _NOEXCEPT {return __tree_.size();} - _LIBCPP_INLINE_VISIBILITY + _LIBCPP_NO_DISCARD_CONTAINER_OBSERVERS _LIBCPP_INLINE_VISIBILITY size_type max_size() const _NOEXCEPT {return __tree_.max_size();} mapped_type& operator[](const key_type& __k); @@ -1744,11 +1744,11 @@ _LIBCPP_INLINE_VISIBILITY const_reverse_iterator crend() const _NOEXCEPT {return rend();} - _LIBCPP_INLINE_VISIBILITY + _LIBCPP_NO_DISCARD_CONTAINER_OBSERVERS _LIBCPP_INLINE_VISIBILITY bool empty() const _NOEXCEPT {return __tree_.size() == 0;} - _LIBCPP_INLINE_VISIBILITY + _LIBCPP_NO_DISCARD_CONTAINER_OBSERVERS _LIBCPP_INLINE_VISIBILITY size_type size() const _NOEXCEPT {return __tree_.size();} - _LIBCPP_INLINE_VISIBILITY + _LIBCPP_NO_DISCARD_CONTAINER_OBSERVERS _LIBCPP_INLINE_VISIBILITY size_type max_size() const _NOEXCEPT {return __tree_.max_size();} _LIBCPP_INLINE_VISIBILITY Index: include/list =================================================================== --- include/list +++ include/list @@ -898,11 +898,11 @@ _LIBCPP_INLINE_VISIBILITY allocator_type get_allocator() const _NOEXCEPT; - _LIBCPP_INLINE_VISIBILITY + _LIBCPP_NO_DISCARD_CONTAINER_OBSERVERS _LIBCPP_INLINE_VISIBILITY size_type size() const _NOEXCEPT {return base::__sz();} - _LIBCPP_INLINE_VISIBILITY + _LIBCPP_NO_DISCARD_CONTAINER_OBSERVERS _LIBCPP_INLINE_VISIBILITY bool empty() const _NOEXCEPT {return base::empty();} - _LIBCPP_INLINE_VISIBILITY + _LIBCPP_NO_DISCARD_CONTAINER_OBSERVERS _LIBCPP_INLINE_VISIBILITY size_type max_size() const _NOEXCEPT {return numeric_limits<difference_type>::max();} Index: include/forward_list =================================================================== --- include/forward_list +++ include/forward_list @@ -730,10 +730,10 @@ const_iterator cbefore_begin() const _NOEXCEPT {return const_iterator(base::__before_begin());} - _LIBCPP_INLINE_VISIBILITY + _LIBCPP_NO_DISCARD_CONTAINER_OBSERVERS _LIBCPP_INLINE_VISIBILITY bool empty() const _NOEXCEPT {return base::__before_begin()->__next_ == nullptr;} - _LIBCPP_INLINE_VISIBILITY + _LIBCPP_NO_DISCARD_CONTAINER_OBSERVERS _LIBCPP_INLINE_VISIBILITY size_type max_size() const _NOEXCEPT {return numeric_limits<size_type>::max();} Index: include/__mutex_base =================================================================== --- include/__mutex_base +++ include/__mutex_base @@ -32,6 +32,12 @@ # endif #endif // _LIBCPP_THREAD_SAFETY_ANNOTATION +#ifndef _LIBCPP_DISABLE_NO_DISCARD_TRY_LOCK +# define _LIBCPP_NO_DISCARD_TRY_LOCK _LIBCPP_NO_DISCARD +#else +# define _LIBCPP_NO_DISCARD_TRY_LOCK +#endif + class _LIBCPP_TYPE_VIS _LIBCPP_THREAD_SAFETY_ANNOTATION(capability("mutex")) mutex { #ifndef _LIBCPP_HAS_NO_CONSTEXPR @@ -55,6 +61,7 @@ public: void lock() _LIBCPP_THREAD_SAFETY_ANNOTATION(acquire_capability()); + _LIBCPP_NO_DISCARD_TRY_LOCK bool try_lock() _NOEXCEPT _LIBCPP_THREAD_SAFETY_ANNOTATION(try_acquire_capability(true)); void unlock() _NOEXCEPT _LIBCPP_THREAD_SAFETY_ANNOTATION(release_capability()); @@ -182,11 +189,13 @@ #endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES void lock(); - bool try_lock(); + _LIBCPP_NO_DISCARD_TRY_LOCK bool try_lock(); template <class _Rep, class _Period> + _LIBCPP_NO_DISCARD_TRY_LOCK bool try_lock_for(const chrono::duration<_Rep, _Period>& __d); template <class _Clock, class _Duration> + _LIBCPP_NO_DISCARD_TRY_LOCK bool try_lock_until(const chrono::time_point<_Clock, _Duration>& __t); void unlock(); Index: include/__config =================================================================== --- include/__config +++ include/__config @@ -900,6 +900,21 @@ #define _LIBCPP_SAFE_STATIC #endif +#ifndef _LIBCPP_NO_DISCARD +# if !defined(_LIBCPP_DISABLE_NO_DISCARD) && \ + (__has_attribute(warn_unused_result) || _GNUC_VER > 408) +# define _LIBCPP_NO_DISCARD __attribute__((__warn_unused_result__)) +# else +# define _LIBCPP_NO_DISCARD +# endif +#endif // !defined(_LIBCPP_NO_DISCARD) + +#ifndef _LIBCPP_DISABLE_NO_DISCARD_CONTAINER_OBSERVERS +# define _LIBCPP_NO_DISCARD_CONTAINER_OBSERVERS _LIBCPP_NO_DISCARD +#else +# define _LIBCPP_NO_DISCARD_CONTAINER_OBSERVERS +#endif + #if !__has_builtin(__builtin_addressof) && _GNUC_VER < 700 #define _LIBCPP_HAS_NO_BUILTIN_ADDRESSOF #endif Index: docs/UsingLibcxx.rst =================================================================== --- docs/UsingLibcxx.rst +++ docs/UsingLibcxx.rst @@ -149,3 +149,24 @@ This macro is used to enable -Wthread-safety annotations on libc++'s ``std::mutex`` and ``std::lock_guard``. By default these annotations are disabled and must be manually enabled by the user. + +**_LIBCPP_NO_DISCARD** + This macro is used to annotate various libc++ functions as having a + non-discardable return value. This macro is enabled by default. + + **Overriding**: To fully disable libc++'s no-discard attribute users can + define `_LIBCPP_DISABLE_NO_DISCARD` before including any headers. It's also + possible to disable groups of no-discard checks by defining one of the + macros below: + + * **_LIBCPP_DISABLE_NO_DISCARD_UNIQUE_PTR_RELEASE**: Disables no-discard on + ``std::unique_ptr<T>::release()``. + + * **_LIBCPP_DISABLE_NO_DISCARD_CONTAINER_OBSERVERS**: Disables + no-discard on non-modifying container operations such as the ``size()``, + ``empty()``, and ``capacity()`` methods of ``std::vector`` or + ``std::string``. + + * **_LIBCPP_DISABLE_NO_DISCARD_TRY_LOCK**: Disables no-discard on the + ``try_lock()``, ``try_lock_for()``, and ``try_lock_until()`` + members of lockable types.
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits