Skip to content

Conversation

@H-G-Hristov
Copy link
Contributor

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

@H-G-Hristov H-G-Hristov force-pushed the hgh/libcxx/nodiscard-to-exception branch 3 times, most recently from 40a08d7 to 50ab874 Compare December 5, 2025 11:48
@github-actions
Copy link

github-actions bot commented Dec 5, 2025

✅ With the latest revision this PR passed the C/C++ code formatter.

@frederick-vs-ja frederick-vs-ja changed the title [libc++] Applied [[nodiscard] to <exception>, <stdexcept> and <system_error> [libc++] Applied [[nodiscard]] to <exception>, <stdexcept> and <system_error> Dec 5, 2025
…<system_error>`

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

- https://libcxx.llvm.org/CodingGuidelines.html
@H-G-Hristov H-G-Hristov force-pushed the hgh/libcxx/nodiscard-to-exception branch from 50ab874 to 5f2d335 Compare December 6, 2025 05:48
@H-G-Hristov H-G-Hristov marked this pull request as ready for review December 6, 2025 09:56
@H-G-Hristov H-G-Hristov requested a review from a team as a code owner December 6, 2025 09:56
@llvmbot llvmbot added the libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi. label Dec 6, 2025
@llvmbot
Copy link
Member

llvmbot commented Dec 6, 2025

@llvm/pr-subscribers-libcxx

Author: Hristo Hristov (H-G-Hristov)

Changes

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


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 --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@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+      std::generic_category();
+
+      const std::error_category& ec = std::generic_category();
+
+      // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+      ec.name();
+      // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+      ec.default_error_condition(94);
+      // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+      ec.equivalent(94, ec.default_error_condition(82));
+      // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+      ec.equivalent(std::error_code(49, ec), 94);
+      // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+      ec.message(82);
+    }
+    {
+      // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+      std::system_category();
+
+      const std::error_category& ec = std::system_category();
+
+      // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+      ec.name();
+      // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+      ec.default_error_condition(94);
+      // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+      ec.equivalent(94, ec.default_error_condition(82));
+      // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+      ec.equivalent(std::error_code(49, ec), 94);
+      // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+      ec.message(82);
+    }
+    {
+      std::error_code ec;
+
+      // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+      ec.value();
+      // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+      ec.category();
+      // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+      ec.default_error_condition();
+
+      // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+      ec.message();
+
+      // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+      std::make_error_code(std::errc::invalid_argument);
+    }
+    {
+      std::error_condition ec;
+
+      // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+      ec.value();
+      // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+      ec.category();
+      // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+      ec.message();
+
+      // expected-warning@+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@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    std::uncaught_exception();
+#endif
+    // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    std::uncaught_exceptions();
+
+    // expected-warning@+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
 }

@H-G-Hristov
Copy link
Contributor Author

@frederick-vs-ja Sorry for nagging! Can we merge this?

@Zingam Zingam merged commit ddd770d into llvm:main Dec 6, 2025
83 checks passed
@H-G-Hristov H-G-Hristov deleted the hgh/libcxx/nodiscard-to-exception branch December 6, 2025 17:22
honeygoyal pushed a commit to honeygoyal/llvm-project that referenced this pull request Dec 9, 2025
…`<system_error>` (llvm#170837)

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

- https://libcxx.llvm.org/CodingGuidelines.html
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants