[libcxx-commits] [libcxx] [libc++] Applied `[[nodiscard]]` to `<exception>`, `<stdexcept>` and `<system_error>` (PR #170837)

via libcxx-commits libcxx-commits at lists.llvm.org
Sat Dec 6 01:57:10 PST 2025


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-libcxx

Author: Hristo Hristov (H-G-Hristov)

<details>
<summary>Changes</summary>

[[nodiscard]] should be applied to functions where discarding the return value is most likely a correctness issue.

- https://libcxx.llvm.org/CodingGuidelines.html

---
Full diff: https://github.com/llvm/llvm-project/pull/170837.diff


10 Files Affected:

- (modified) libcxx/include/__exception/exception.h (+5-3) 
- (modified) libcxx/include/__exception/nested_exception.h (+1-1) 
- (modified) libcxx/include/__exception/operations.h (+5-5) 
- (modified) libcxx/include/__system_error/error_category.h (+7-7) 
- (modified) libcxx/include/__system_error/error_code.h (+5-5) 
- (modified) libcxx/include/__system_error/error_condition.h (+4-4) 
- (modified) libcxx/include/__system_error/system_error.h (+1-1) 
- (modified) libcxx/include/stdexcept (+2-2) 
- (added) libcxx/test/libcxx/diagnostics/syserr/nodiscard.verify.cpp (+108) 
- (modified) libcxx/test/libcxx/language.support/nodiscard.verify.cpp (+40-1) 


``````````diff
diff --git a/libcxx/include/__exception/exception.h b/libcxx/include/__exception/exception.h
index 161cc49979e4a..ddc34b0fa8fa1 100644
--- a/libcxx/include/__exception/exception.h
+++ b/libcxx/include/__exception/exception.h
@@ -54,7 +54,9 @@ class exception { // base of all library exceptions
 
   virtual ~exception() _NOEXCEPT {}
 
-  virtual char const* what() const _NOEXCEPT { return __data_._What ? __data_._What : "Unknown exception"; }
+  [[__nodiscard__]] virtual char const* what() const _NOEXCEPT {
+    return __data_._What ? __data_._What : "Unknown exception";
+  }
 
 private:
   __std_exception_data __data_;
@@ -76,7 +78,7 @@ class _LIBCPP_EXPORTED_FROM_ABI exception {
   _LIBCPP_HIDE_FROM_ABI exception& operator=(const exception&) _NOEXCEPT = default;
 
   virtual ~exception() _NOEXCEPT;
-  virtual const char* what() const _NOEXCEPT;
+  [[__nodiscard__]] virtual const char* what() const _NOEXCEPT;
 };
 
 class _LIBCPP_EXPORTED_FROM_ABI bad_exception : public exception {
@@ -85,7 +87,7 @@ class _LIBCPP_EXPORTED_FROM_ABI bad_exception : public exception {
   _LIBCPP_HIDE_FROM_ABI bad_exception(const bad_exception&) _NOEXCEPT            = default;
   _LIBCPP_HIDE_FROM_ABI bad_exception& operator=(const bad_exception&) _NOEXCEPT = default;
   ~bad_exception() _NOEXCEPT override;
-  const char* what() const _NOEXCEPT override;
+  [[__nodiscard__]] const char* what() const _NOEXCEPT override;
 };
 #endif // !_LIBCPP_ABI_VCRUNTIME
 
diff --git a/libcxx/include/__exception/nested_exception.h b/libcxx/include/__exception/nested_exception.h
index dc3266a27cdfd..dd84efbccde88 100644
--- a/libcxx/include/__exception/nested_exception.h
+++ b/libcxx/include/__exception/nested_exception.h
@@ -40,7 +40,7 @@ class _LIBCPP_EXPORTED_FROM_ABI nested_exception {
 
   // access functions
   [[__noreturn__]] void rethrow_nested() const;
-  _LIBCPP_HIDE_FROM_ABI exception_ptr nested_ptr() const _NOEXCEPT { return __ptr_; }
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI exception_ptr nested_ptr() const _NOEXCEPT { return __ptr_; }
 };
 
 template <class _Tp>
diff --git a/libcxx/include/__exception/operations.h b/libcxx/include/__exception/operations.h
index 29d5c698a96db..2b93ad260c30b 100644
--- a/libcxx/include/__exception/operations.h
+++ b/libcxx/include/__exception/operations.h
@@ -20,22 +20,22 @@ _LIBCPP_BEGIN_UNVERSIONED_NAMESPACE_STD
     defined(_LIBCPP_BUILDING_LIBRARY)
 using unexpected_handler = void (*)();
 _LIBCPP_EXPORTED_FROM_ABI unexpected_handler set_unexpected(unexpected_handler) _NOEXCEPT;
-_LIBCPP_EXPORTED_FROM_ABI unexpected_handler get_unexpected() _NOEXCEPT;
+[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI unexpected_handler get_unexpected() _NOEXCEPT;
 [[__noreturn__]] _LIBCPP_EXPORTED_FROM_ABI void unexpected();
 #endif
 
 using terminate_handler = void (*)();
 _LIBCPP_EXPORTED_FROM_ABI terminate_handler set_terminate(terminate_handler) _NOEXCEPT;
-_LIBCPP_EXPORTED_FROM_ABI terminate_handler get_terminate() _NOEXCEPT;
+[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI terminate_handler get_terminate() _NOEXCEPT;
 
 #if _LIBCPP_STD_VER <= 17 || defined(_LIBCPP_ENABLE_CXX20_REMOVED_UNCAUGHT_EXCEPTION)
-_LIBCPP_EXPORTED_FROM_ABI _LIBCPP_DEPRECATED_IN_CXX17 bool uncaught_exception() _NOEXCEPT;
+[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI _LIBCPP_DEPRECATED_IN_CXX17 bool uncaught_exception() _NOEXCEPT;
 #endif // _LIBCPP_STD_VER <= 17 || defined(_LIBCPP_ENABLE_CXX20_REMOVED_UNCAUGHT_EXCEPTION)
-_LIBCPP_EXPORTED_FROM_ABI int uncaught_exceptions() _NOEXCEPT;
+[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI int uncaught_exceptions() _NOEXCEPT;
 
 class _LIBCPP_EXPORTED_FROM_ABI exception_ptr;
 
-_LIBCPP_EXPORTED_FROM_ABI exception_ptr current_exception() _NOEXCEPT;
+[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI exception_ptr current_exception() _NOEXCEPT;
 [[__noreturn__]] _LIBCPP_EXPORTED_FROM_ABI void rethrow_exception(exception_ptr);
 _LIBCPP_END_UNVERSIONED_NAMESPACE_STD
 
diff --git a/libcxx/include/__system_error/error_category.h b/libcxx/include/__system_error/error_category.h
index 191f4d83a90c0..7f7c7355c7e7f 100644
--- a/libcxx/include/__system_error/error_category.h
+++ b/libcxx/include/__system_error/error_category.h
@@ -37,11 +37,11 @@ class _LIBCPP_EXPORTED_FROM_ABI error_category {
   error_category(const error_category&)            = delete;
   error_category& operator=(const error_category&) = delete;
 
-  virtual const char* name() const _NOEXCEPT = 0;
-  virtual error_condition default_error_condition(int __ev) const _NOEXCEPT;
-  virtual bool equivalent(int __code, const error_condition& __condition) const _NOEXCEPT;
-  virtual bool equivalent(const error_code& __code, int __condition) const _NOEXCEPT;
-  virtual string message(int __ev) const = 0;
+  [[__nodiscard__]] virtual const char* name() const _NOEXCEPT = 0;
+  [[__nodiscard__]] virtual error_condition default_error_condition(int __ev) const _NOEXCEPT;
+  [[__nodiscard__]] virtual bool equivalent(int __code, const error_condition& __condition) const _NOEXCEPT;
+  [[__nodiscard__]] virtual bool equivalent(const error_code& __code, int __condition) const _NOEXCEPT;
+  [[__nodiscard__]] virtual string message(int __ev) const = 0;
 
   _LIBCPP_HIDE_FROM_ABI bool operator==(const error_category& __rhs) const _NOEXCEPT { return this == &__rhs; }
 
@@ -67,8 +67,8 @@ class _LIBCPP_HIDDEN __do_message : public error_category {
   string message(int __ev) const override;
 };
 
-[[__gnu__::__const__]] _LIBCPP_EXPORTED_FROM_ABI const error_category& generic_category() _NOEXCEPT;
-[[__gnu__::__const__]] _LIBCPP_EXPORTED_FROM_ABI const error_category& system_category() _NOEXCEPT;
+[[__gnu__::__const__]] [[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI const error_category& generic_category() _NOEXCEPT;
+[[__gnu__::__const__]] [[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI const error_category& system_category() _NOEXCEPT;
 
 _LIBCPP_END_NAMESPACE_STD
 
diff --git a/libcxx/include/__system_error/error_code.h b/libcxx/include/__system_error/error_code.h
index f6ea40d6efcb9..e904376939753 100644
--- a/libcxx/include/__system_error/error_code.h
+++ b/libcxx/include/__system_error/error_code.h
@@ -71,20 +71,20 @@ class _LIBCPP_EXPORTED_FROM_ABI error_code {
     __cat_ = &system_category();
   }
 
-  _LIBCPP_HIDE_FROM_ABI int value() const _NOEXCEPT { return __val_; }
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI int value() const _NOEXCEPT { return __val_; }
 
-  _LIBCPP_HIDE_FROM_ABI const error_category& category() const _NOEXCEPT { return *__cat_; }
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const error_category& category() const _NOEXCEPT { return *__cat_; }
 
-  _LIBCPP_HIDE_FROM_ABI error_condition default_error_condition() const _NOEXCEPT {
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI error_condition default_error_condition() const _NOEXCEPT {
     return __cat_->default_error_condition(__val_);
   }
 
-  string message() const;
+  [[__nodiscard__]] string message() const;
 
   _LIBCPP_HIDE_FROM_ABI explicit operator bool() const _NOEXCEPT { return __val_ != 0; }
 };
 
-inline _LIBCPP_HIDE_FROM_ABI error_code make_error_code(errc __e) _NOEXCEPT {
+[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI error_code make_error_code(errc __e) _NOEXCEPT {
   return error_code(static_cast<int>(__e), generic_category());
 }
 
diff --git a/libcxx/include/__system_error/error_condition.h b/libcxx/include/__system_error/error_condition.h
index 34819f4b6de4c..be7deaba0444c 100644
--- a/libcxx/include/__system_error/error_condition.h
+++ b/libcxx/include/__system_error/error_condition.h
@@ -80,15 +80,15 @@ class _LIBCPP_EXPORTED_FROM_ABI error_condition {
     __cat_ = &generic_category();
   }
 
-  _LIBCPP_HIDE_FROM_ABI int value() const _NOEXCEPT { return __val_; }
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI int value() const _NOEXCEPT { return __val_; }
 
-  _LIBCPP_HIDE_FROM_ABI const error_category& category() const _NOEXCEPT { return *__cat_; }
-  string message() const;
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const error_category& category() const _NOEXCEPT { return *__cat_; }
+  [[__nodiscard__]] string message() const;
 
   _LIBCPP_HIDE_FROM_ABI explicit operator bool() const _NOEXCEPT { return __val_ != 0; }
 };
 
-inline _LIBCPP_HIDE_FROM_ABI error_condition make_error_condition(errc __e) _NOEXCEPT {
+[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI error_condition make_error_condition(errc __e) _NOEXCEPT {
   return error_condition(static_cast<int>(__e), generic_category());
 }
 
diff --git a/libcxx/include/__system_error/system_error.h b/libcxx/include/__system_error/system_error.h
index 36ccf94cc010d..74427d8f0bf9b 100644
--- a/libcxx/include/__system_error/system_error.h
+++ b/libcxx/include/__system_error/system_error.h
@@ -36,7 +36,7 @@ class _LIBCPP_EXPORTED_FROM_ABI system_error : public runtime_error {
   _LIBCPP_HIDE_FROM_ABI system_error(const system_error&) _NOEXCEPT = default;
   ~system_error() _NOEXCEPT override;
 
-  _LIBCPP_HIDE_FROM_ABI const error_code& code() const _NOEXCEPT { return __ec_; }
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const error_code& code() const _NOEXCEPT { return __ec_; }
 };
 
 // __ev is expected to be an error in the generic_category domain (e.g. from
diff --git a/libcxx/include/stdexcept b/libcxx/include/stdexcept
index 85e11629bd6e3..d01de5c46211c 100644
--- a/libcxx/include/stdexcept
+++ b/libcxx/include/stdexcept
@@ -91,7 +91,7 @@ public:
 
   ~logic_error() _NOEXCEPT override;
 
-  const char* what() const _NOEXCEPT override;
+  [[__nodiscard__]] const char* what() const _NOEXCEPT override;
 #  else
 
 public:
@@ -115,7 +115,7 @@ public:
 
   ~runtime_error() _NOEXCEPT override;
 
-  const char* what() const _NOEXCEPT override;
+  [[__nodiscard__]] const char* what() const _NOEXCEPT override;
 #  else
 
 public:
diff --git a/libcxx/test/libcxx/diagnostics/syserr/nodiscard.verify.cpp b/libcxx/test/libcxx/diagnostics/syserr/nodiscard.verify.cpp
new file mode 100644
index 0000000000000..26565a1ecdd10
--- /dev/null
+++ b/libcxx/test/libcxx/diagnostics/syserr/nodiscard.verify.cpp
@@ -0,0 +1,108 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// Check that functions are marked [[nodiscard]]
+
+#include <stdexcept>
+#include <system_error>
+
+void test() {
+  { // <stdexcept>
+    std::logic_error le("logic error");
+    le.what(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+
+    std::runtime_error re("runtime error");
+    re.what(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+
+    std::domain_error de("domain error");
+    de.what(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+
+    std::invalid_argument ia("invalid argument");
+    ia.what(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+
+    std::length_error lerr("length error");
+    lerr.what(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+
+    std::out_of_range oor("out of range");
+    oor.what(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+
+    std::range_error rerr("range error");
+    rerr.what(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+
+    std::overflow_error oferr("overflow error");
+    oferr.what(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+
+    std::underflow_error uferr("underflow error");
+    uferr.what(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+  }
+  { // <system_error>
+    {
+      // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+      std::generic_category();
+
+      const std::error_category& ec = std::generic_category();
+
+      // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+      ec.name();
+      // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+      ec.default_error_condition(94);
+      // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+      ec.equivalent(94, ec.default_error_condition(82));
+      // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+      ec.equivalent(std::error_code(49, ec), 94);
+      // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+      ec.message(82);
+    }
+    {
+      // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+      std::system_category();
+
+      const std::error_category& ec = std::system_category();
+
+      // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+      ec.name();
+      // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+      ec.default_error_condition(94);
+      // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+      ec.equivalent(94, ec.default_error_condition(82));
+      // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+      ec.equivalent(std::error_code(49, ec), 94);
+      // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+      ec.message(82);
+    }
+    {
+      std::error_code ec;
+
+      // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+      ec.value();
+      // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+      ec.category();
+      // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+      ec.default_error_condition();
+
+      // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+      ec.message();
+
+      // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+      std::make_error_code(std::errc::invalid_argument);
+    }
+    {
+      std::error_condition ec;
+
+      // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+      ec.value();
+      // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+      ec.category();
+      // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+      ec.message();
+
+      // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+      std::make_error_condition(std::errc::invalid_argument);
+    }
+  }
+}
diff --git a/libcxx/test/libcxx/language.support/nodiscard.verify.cpp b/libcxx/test/libcxx/language.support/nodiscard.verify.cpp
index b87b04ad9f1ef..40dbe5c90afee 100644
--- a/libcxx/test/libcxx/language.support/nodiscard.verify.cpp
+++ b/libcxx/test/libcxx/language.support/nodiscard.verify.cpp
@@ -6,12 +6,15 @@
 //
 //===----------------------------------------------------------------------===//
 
-// UNSUPPORTED: c++03
+// ADDITIONAL_COMPILE_FLAGS: -Wno-deprecated
+// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_CXX17_REMOVED_UNEXPECTED_FUNCTIONS
+// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_CXX20_REMOVED_UNCAUGHT_EXCEPTION
 
 // Check that functions are marked [[nodiscard]]
 
 #include <compare>
 #include <coroutine>
+#include <exception>
 #include <functional>
 #include <initializer_list>
 
@@ -81,6 +84,41 @@ void test() {
   }
 #endif
 
+  { // <exception>
+    {
+      std::bad_exception bex;
+
+      bex.what(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+    }
+    {
+      std::exception ex;
+
+      ex.what(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+    }
+    {
+      std::nested_exception nex;
+
+      nex.nested_ptr(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+    }
+
+#if TEST_STD_VER <= 14
+    std::get_unexpected(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+#endif
+
+    std::get_terminate(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+
+#if _LIBCPP_STD_VER <= 17
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    std::uncaught_exception();
+#endif
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    std::uncaught_exceptions();
+
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    std::current_exception();
+  }
+
+#if TEST_STD_VER >= 11
   { // <initializer_list>
     std::initializer_list<int> il{94, 82, 49};
 
@@ -88,4 +126,5 @@ void test() {
     il.begin(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
     il.end();   // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
   }
+#endif
 }

``````````

</details>


https://github.com/llvm/llvm-project/pull/170837


More information about the libcxx-commits mailing list