[libcxx-commits] [libcxx] [libc++] Added `[[nodiscard]]` to `fstream.native_handle`, `span.at` and `in/out_ptr` (PR #167097)

via libcxx-commits libcxx-commits at lists.llvm.org
Fri Nov 7 21:57:34 PST 2025


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-libcxx

Author: Hristo Hristov (H-G-Hristov)

<details>
<summary>Changes</summary>

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

At the time of impelentation the ``nodiscard` policy has not been established yet. I did it as a batch as the changes are trivial and minimal.

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


7 Files Affected:

- (modified) libcxx/include/__memory/inout_ptr.h (+5-3) 
- (modified) libcxx/include/__memory/out_ptr.h (+5-3) 
- (modified) libcxx/include/fstream (+4-4) 
- (modified) libcxx/include/span (+2-2) 
- (added) libcxx/test/libcxx/containers/views/views.span/nodiscard.verify.cpp (+30) 
- (added) libcxx/test/libcxx/input.output/file.streams/fstreams/nodiscard.verify.cpp (+34) 
- (added) libcxx/test/libcxx/utilities/smartptr/adapt/nodiscard.verify.cpp (+50) 


``````````diff
diff --git a/libcxx/include/__memory/inout_ptr.h b/libcxx/include/__memory/inout_ptr.h
index ef345fe469bca..e9de089b8e74e 100644
--- a/libcxx/include/__memory/inout_ptr.h
+++ b/libcxx/include/__memory/inout_ptr.h
@@ -79,9 +79,11 @@ class inout_ptr_t {
     }
   }
 
-  _LIBCPP_HIDE_FROM_ABI operator _Pointer*() const noexcept { return std::addressof(const_cast<_Pointer&>(__p_)); }
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI operator _Pointer*() const noexcept {
+    return std::addressof(const_cast<_Pointer&>(__p_));
+  }
 
-  _LIBCPP_HIDE_FROM_ABI operator void**() const noexcept
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI operator void**() const noexcept
     requires(!is_same_v<_Pointer, void*>)
   {
     static_assert(is_pointer_v<_Pointer>, "The conversion to void** requires _Pointer to be a raw pointer.");
@@ -96,7 +98,7 @@ class inout_ptr_t {
 };
 
 template <class _Pointer = void, class _Smart, class... _Args>
-_LIBCPP_HIDE_FROM_ABI auto inout_ptr(_Smart& __s, _Args&&... __args) {
+[[nodiscard]] _LIBCPP_HIDE_FROM_ABI auto inout_ptr(_Smart& __s, _Args&&... __args) {
   using _Ptr = conditional_t<is_void_v<_Pointer>, __pointer_of_t<_Smart>, _Pointer>;
   return std::inout_ptr_t<_Smart, _Ptr, _Args&&...>(__s, std::forward<_Args>(__args)...);
 }
diff --git a/libcxx/include/__memory/out_ptr.h b/libcxx/include/__memory/out_ptr.h
index e498e3307b9d6..77a21fb05d7dc 100644
--- a/libcxx/include/__memory/out_ptr.h
+++ b/libcxx/include/__memory/out_ptr.h
@@ -71,9 +71,11 @@ class out_ptr_t {
     }
   }
 
-  _LIBCPP_HIDE_FROM_ABI operator _Pointer*() const noexcept { return std::addressof(const_cast<_Pointer&>(__p_)); }
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI operator _Pointer*() const noexcept {
+    return std::addressof(const_cast<_Pointer&>(__p_));
+  }
 
-  _LIBCPP_HIDE_FROM_ABI operator void**() const noexcept
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI operator void**() const noexcept
     requires(!is_same_v<_Pointer, void*>)
   {
     static_assert(is_pointer_v<_Pointer>, "The conversion to void** requires _Pointer to be a raw pointer.");
@@ -88,7 +90,7 @@ class out_ptr_t {
 };
 
 template <class _Pointer = void, class _Smart, class... _Args>
-_LIBCPP_HIDE_FROM_ABI auto out_ptr(_Smart& __s, _Args&&... __args) {
+[[nodiscard]] _LIBCPP_HIDE_FROM_ABI auto out_ptr(_Smart& __s, _Args&&... __args) {
   using _Ptr = conditional_t<is_void_v<_Pointer>, __pointer_of_t<_Smart>, _Pointer>;
   return std::out_ptr_t<_Smart, _Ptr, _Args&&...>(__s, std::forward<_Args>(__args)...);
 }
diff --git a/libcxx/include/fstream b/libcxx/include/fstream
index 1f88d134fe061..a2eb74b61e76b 100644
--- a/libcxx/include/fstream
+++ b/libcxx/include/fstream
@@ -269,7 +269,7 @@ public:
   _LIBCPP_HIDE_FROM_ABI basic_filebuf* __open(int __fd, ios_base::openmode __mode);
   basic_filebuf* close();
 #    if _LIBCPP_STD_VER >= 26
-  _LIBCPP_HIDE_FROM_ABI native_handle_type native_handle() const noexcept {
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI native_handle_type native_handle() const noexcept {
     _LIBCPP_ASSERT_UNCATEGORIZED(this->is_open(), "File must be opened");
 #      if defined(_LIBCPP_WIN32API)
     return std::__filebuf_windows_native_handle(__file_);
@@ -1165,7 +1165,7 @@ public:
 
   _LIBCPP_HIDE_FROM_ABI basic_filebuf<char_type, traits_type>* rdbuf() const;
 #    if _LIBCPP_STD_VER >= 26
-  _LIBCPP_HIDE_FROM_ABI native_handle_type native_handle() const noexcept { return rdbuf()->native_handle(); }
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI native_handle_type native_handle() const noexcept { return rdbuf()->native_handle(); }
 #    endif
   _LIBCPP_HIDE_FROM_ABI bool is_open() const;
   void open(const char* __s, ios_base::openmode __mode = ios_base::in);
@@ -1321,7 +1321,7 @@ public:
 
   _LIBCPP_HIDE_FROM_ABI basic_filebuf<char_type, traits_type>* rdbuf() const;
 #    if _LIBCPP_STD_VER >= 26
-  _LIBCPP_HIDE_FROM_ABI native_handle_type native_handle() const noexcept { return rdbuf()->native_handle(); }
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI native_handle_type native_handle() const noexcept { return rdbuf()->native_handle(); }
 #    endif
   _LIBCPP_HIDE_FROM_ABI bool is_open() const;
   void open(const char* __s, ios_base::openmode __mode = ios_base::out);
@@ -1483,7 +1483,7 @@ public:
 
   _LIBCPP_HIDE_FROM_ABI basic_filebuf<char_type, traits_type>* rdbuf() const;
 #    if _LIBCPP_STD_VER >= 26
-  _LIBCPP_HIDE_FROM_ABI native_handle_type native_handle() const noexcept { return rdbuf()->native_handle(); }
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI native_handle_type native_handle() const noexcept { return rdbuf()->native_handle(); }
 #    endif
   _LIBCPP_HIDE_FROM_ABI bool is_open() const;
   _LIBCPP_HIDE_FROM_ABI void open(const char* __s, ios_base::openmode __mode = ios_base::in | ios_base::out);
diff --git a/libcxx/include/span b/libcxx/include/span
index 3d4f9e4ba7831..68fa3d5987310 100644
--- a/libcxx/include/span
+++ b/libcxx/include/span
@@ -362,7 +362,7 @@ public:
   }
 
 #    if _LIBCPP_STD_VER >= 26
-  _LIBCPP_HIDE_FROM_ABI constexpr reference at(size_type __index) const {
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr reference at(size_type __index) const {
     if (__index >= size())
       std::__throw_out_of_range("span");
     return __data_[__index];
@@ -527,7 +527,7 @@ public:
   }
 
 #    if _LIBCPP_STD_VER >= 26
-  _LIBCPP_HIDE_FROM_ABI constexpr reference at(size_type __index) const {
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr reference at(size_type __index) const {
     if (__index >= size())
       std::__throw_out_of_range("span");
     return __data_[__index];
diff --git a/libcxx/test/libcxx/containers/views/views.span/nodiscard.verify.cpp b/libcxx/test/libcxx/containers/views/views.span/nodiscard.verify.cpp
new file mode 100644
index 0000000000000..6deec90aa0f00
--- /dev/null
+++ b/libcxx/test/libcxx/containers/views/views.span/nodiscard.verify.cpp
@@ -0,0 +1,30 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: std-at-least-c++26
+
+// <span>
+
+// Check that functions are marked [[nodiscard]]
+
+#include <array>
+#include <span>
+#include <vector>
+
+void test() {
+  { // Test with static extent
+    std::array arr{94, 92};
+    std::span sp{arr};
+    sp.at(0); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+  }
+  { // Test with dynamic extent
+    std::vector vec{94, 92};
+    std::span sp{vec};
+    sp.at(0); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+  }
+}
diff --git a/libcxx/test/libcxx/input.output/file.streams/fstreams/nodiscard.verify.cpp b/libcxx/test/libcxx/input.output/file.streams/fstreams/nodiscard.verify.cpp
new file mode 100644
index 0000000000000..a732c8137d6cc
--- /dev/null
+++ b/libcxx/test/libcxx/input.output/file.streams/fstreams/nodiscard.verify.cpp
@@ -0,0 +1,34 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: std-at-least-c++26
+
+// <fstream>
+
+// Check that functions are marked [[nodiscard]]
+
+#include <fstream>
+
+void test() {
+  {
+    std::filebuf fb;
+    fb.native_handle(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+  }
+  {
+    std::fstream fs;
+    fs.native_handle(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+  }
+  {
+    std::ifstream fs;
+    fs.native_handle(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+  }
+  {
+    std::ofstream fs;
+    fs.native_handle(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+  }
+}
\ No newline at end of file
diff --git a/libcxx/test/libcxx/utilities/smartptr/adapt/nodiscard.verify.cpp b/libcxx/test/libcxx/utilities/smartptr/adapt/nodiscard.verify.cpp
new file mode 100644
index 0000000000000..55391f554cc0c
--- /dev/null
+++ b/libcxx/test/libcxx/utilities/smartptr/adapt/nodiscard.verify.cpp
@@ -0,0 +1,50 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: std-at-least-c++23
+
+// <memory>
+
+// Check that functions are marked [[nodiscard]]
+
+#include <memory>
+
+void test() {
+  // clang-format off
+  std::unique_ptr<int> uPtr;
+
+  // [inout.ptr]
+  {
+    { // Test inout_ptr()
+      std::inout_ptr(uPtr); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+    }
+    { // Test operator Pointer*()
+      const std::inout_ptr_t<std::unique_ptr<int>, int*> iPtr{uPtr};
+      iPtr.operator int**(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+    }
+    { // Test operator void**()
+      const std::inout_ptr_t<std::unique_ptr<int>, void*> iPtr{uPtr};
+      iPtr.operator void**(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+    }
+  }
+  // [out.ptr]
+  {
+    { // Test out_ptr()
+      std::out_ptr(uPtr); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+    }
+    { // Test operator Pointer*()
+      const std::out_ptr_t<std::unique_ptr<int>, int*> oPtr{uPtr};
+      oPtr.operator int**(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+    }
+    { // Test operator void**()
+      const std::out_ptr_t<std::unique_ptr<int>, void*> oPtr{uPtr};
+      oPtr.operator void**(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+    }
+  }
+  // clang-format on
+}
\ No newline at end of file

``````````

</details>


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


More information about the libcxx-commits mailing list