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

Reply via email to