[libcxx-commits] [libcxx] [libc++] Applied `[[nodiscard]]` to `<fstream>`, `<sstream>`, `<strstream>`, `<synchstream>` (PR #173842)

Hristo Hristov via libcxx-commits libcxx-commits at lists.llvm.org
Mon Dec 29 08:47:58 PST 2025


https://github.com/H-G-Hristov updated https://github.com/llvm/llvm-project/pull/173842

>From d447e52168b2c40512c27d0f78dae91d3f168ca9 Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Mon, 29 Dec 2025 11:01:28 +0200
Subject: [PATCH] [libc++] Applied `[[nodiscard]]` to `<fstream>`, `<sstream>`,
 `<strstream>`, `<synchstream>`

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

- https://libcxx.llvm.org/CodingGuidelines.html
- https://wg21.link/input.output

Towards #172124
---
 libcxx/include/fstream                        |  28 +++--
 libcxx/include/sstream                        |  54 +++++-----
 libcxx/include/strstream                      |  20 ++--
 libcxx/include/syncstream                     |   8 +-
 .../depr/depr.strstream/nodiscard.verify.cpp  |  58 ++++++++++
 .../fstreams/nodiscard.verify.cpp             |  67 ++++++++++++
 .../string.streams/nodiscard.verify.cpp       | 101 ++++++++++++++++++
 .../synchstream/nodiscard.verify.cpp          |  41 +++++++
 8 files changed, 328 insertions(+), 49 deletions(-)
 create mode 100644 libcxx/test/libcxx/depr/depr.strstream/nodiscard.verify.cpp
 create mode 100644 libcxx/test/libcxx/input.output/file.streams/fstreams/nodiscard.verify.cpp
 create mode 100644 libcxx/test/libcxx/input.output/string.streams/nodiscard.verify.cpp
 create mode 100644 libcxx/test/libcxx/input.output/synchstream/nodiscard.verify.cpp

diff --git a/libcxx/include/fstream b/libcxx/include/fstream
index 95fc8129fa206..3f81d4217019b 100644
--- a/libcxx/include/fstream
+++ b/libcxx/include/fstream
@@ -254,7 +254,7 @@ public:
   void swap(basic_filebuf& __rhs);
 
   // 27.9.1.4 Members:
-  _LIBCPP_HIDE_FROM_ABI bool is_open() const;
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool is_open() const;
   basic_filebuf* open(const char* __s, ios_base::openmode __mode);
 #    if _LIBCPP_HAS_OPEN_WITH_WCHAR
   basic_filebuf* open(const wchar_t* __s, ios_base::openmode __mode);
@@ -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_);
@@ -1163,11 +1163,13 @@ public:
   _LIBCPP_HIDE_FROM_ABI basic_ifstream& operator=(basic_ifstream&& __rhs);
   _LIBCPP_HIDE_FROM_ABI void swap(basic_ifstream& __rhs);
 
-  _LIBCPP_HIDE_FROM_ABI basic_filebuf<char_type, traits_type>* rdbuf() const;
+  [[__nodiscard__]] _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;
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool is_open() const;
   void open(const char* __s, ios_base::openmode __mode = ios_base::in);
 #    if _LIBCPP_HAS_OPEN_WITH_WCHAR
   void open(const wchar_t* __s, ios_base::openmode __mode = ios_base::in);
@@ -1319,11 +1321,13 @@ public:
   _LIBCPP_HIDE_FROM_ABI basic_ofstream& operator=(basic_ofstream&& __rhs);
   _LIBCPP_HIDE_FROM_ABI void swap(basic_ofstream& __rhs);
 
-  _LIBCPP_HIDE_FROM_ABI basic_filebuf<char_type, traits_type>* rdbuf() const;
+  [[__nodiscard__]] _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;
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool is_open() const;
   void open(const char* __s, ios_base::openmode __mode = ios_base::out);
 #    if _LIBCPP_HAS_OPEN_WITH_WCHAR
   void open(const wchar_t* __s, ios_base::openmode __mode = ios_base::out);
@@ -1481,11 +1485,13 @@ public:
 
   _LIBCPP_HIDE_FROM_ABI void swap(basic_fstream& __rhs);
 
-  _LIBCPP_HIDE_FROM_ABI basic_filebuf<char_type, traits_type>* rdbuf() const;
+  [[__nodiscard__]] _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;
+  [[__nodiscard__]] _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);
 #    if _LIBCPP_HAS_OPEN_WITH_WCHAR
   void open(const wchar_t* __s, ios_base::openmode __mode = ios_base::in | ios_base::out);
diff --git a/libcxx/include/sstream b/libcxx/include/sstream
index c42dbff9eee5f..a42e8fbc9b72e 100644
--- a/libcxx/include/sstream
+++ b/libcxx/include/sstream
@@ -461,15 +461,15 @@ public:
   // [stringbuf.members] Member functions:
 
 #    if _LIBCPP_STD_VER >= 20
-  _LIBCPP_HIDE_FROM_ABI allocator_type get_allocator() const noexcept { return __str_.get_allocator(); }
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI allocator_type get_allocator() const noexcept { return __str_.get_allocator(); }
 #    endif
 
 #    if _LIBCPP_STD_VER <= 17 || defined(_LIBCPP_BUILDING_LIBRARY)
-  string_type str() const;
+  [[__nodiscard__]] string_type str() const;
 #    else
-  _LIBCPP_HIDE_FROM_ABI string_type str() const& { return str(__str_.get_allocator()); }
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI string_type str() const& { return str(__str_.get_allocator()); }
 
-  _LIBCPP_HIDE_FROM_ABI string_type str() && {
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI string_type str() && {
     const basic_string_view<_CharT, _Traits> __view = view();
     typename string_type::size_type __pos           = __view.empty() ? 0 : __view.data() - __str_.data();
     // In C++23, this is just string_type(std::move(__str_), __pos, __view.size(), __str_.get_allocator());
@@ -485,11 +485,11 @@ public:
 #    if _LIBCPP_STD_VER >= 20
   template <class _SAlloc>
     requires __is_allocator_v<_SAlloc>
-  _LIBCPP_HIDE_FROM_ABI basic_string<char_type, traits_type, _SAlloc> str(const _SAlloc& __sa) const {
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI basic_string<char_type, traits_type, _SAlloc> str(const _SAlloc& __sa) const {
     return basic_string<_CharT, _Traits, _SAlloc>(view(), __sa);
   }
 
-  _LIBCPP_HIDE_FROM_ABI basic_string_view<char_type, traits_type> view() const noexcept;
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI basic_string_view<char_type, traits_type> view() const noexcept;
 #    endif // _LIBCPP_STD_VER >= 20
 
   void str(const string_type& __s) {
@@ -949,26 +949,28 @@ public:
   }
 
   // [istringstream.members] Member functions:
-  _LIBCPP_HIDE_FROM_ABI basic_stringbuf<char_type, traits_type, allocator_type>* rdbuf() const {
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI basic_stringbuf<char_type, traits_type, allocator_type>* rdbuf() const {
     return const_cast<basic_stringbuf<char_type, traits_type, allocator_type>*>(std::addressof(__sb_));
   }
 
 #    if _LIBCPP_STD_VER <= 17 || defined(_LIBCPP_BUILDING_LIBRARY)
-  _LIBCPP_HIDE_FROM_ABI string_type str() const { return __sb_.str(); }
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI string_type str() const { return __sb_.str(); }
 #    else
-  _LIBCPP_HIDE_FROM_ABI string_type str() const& { return __sb_.str(); }
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI string_type str() const& { return __sb_.str(); }
 
-  _LIBCPP_HIDE_FROM_ABI string_type str() && { return std::move(__sb_).str(); }
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI string_type str() && { return std::move(__sb_).str(); }
 #    endif
 
 #    if _LIBCPP_STD_VER >= 20
   template <class _SAlloc>
     requires __is_allocator_v<_SAlloc>
-  _LIBCPP_HIDE_FROM_ABI basic_string<char_type, traits_type, _SAlloc> str(const _SAlloc& __sa) const {
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI basic_string<char_type, traits_type, _SAlloc> str(const _SAlloc& __sa) const {
     return __sb_.str(__sa);
   }
 
-  _LIBCPP_HIDE_FROM_ABI basic_string_view<char_type, traits_type> view() const noexcept { return __sb_.view(); }
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI basic_string_view<char_type, traits_type> view() const noexcept {
+    return __sb_.view();
+  }
 #    endif // _LIBCPP_STD_VER >= 20
 
   _LIBCPP_HIDE_FROM_ABI void str(const string_type& __s) { __sb_.str(__s); }
@@ -1087,26 +1089,28 @@ public:
   }
 
   // [ostringstream.members] Member functions:
-  _LIBCPP_HIDE_FROM_ABI basic_stringbuf<char_type, traits_type, allocator_type>* rdbuf() const {
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI basic_stringbuf<char_type, traits_type, allocator_type>* rdbuf() const {
     return const_cast<basic_stringbuf<char_type, traits_type, allocator_type>*>(std::addressof(__sb_));
   }
 
 #    if _LIBCPP_STD_VER <= 17 || defined(_LIBCPP_BUILDING_LIBRARY)
-  _LIBCPP_HIDE_FROM_ABI string_type str() const { return __sb_.str(); }
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI string_type str() const { return __sb_.str(); }
 #    else
-  _LIBCPP_HIDE_FROM_ABI string_type str() const& { return __sb_.str(); }
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI string_type str() const& { return __sb_.str(); }
 
-  _LIBCPP_HIDE_FROM_ABI string_type str() && { return std::move(__sb_).str(); }
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI string_type str() && { return std::move(__sb_).str(); }
 #    endif
 
 #    if _LIBCPP_STD_VER >= 20
   template <class _SAlloc>
     requires __is_allocator_v<_SAlloc>
-  _LIBCPP_HIDE_FROM_ABI basic_string<char_type, traits_type, _SAlloc> str(const _SAlloc& __sa) const {
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI basic_string<char_type, traits_type, _SAlloc> str(const _SAlloc& __sa) const {
     return __sb_.str(__sa);
   }
 
-  _LIBCPP_HIDE_FROM_ABI basic_string_view<char_type, traits_type> view() const noexcept { return __sb_.view(); }
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI basic_string_view<char_type, traits_type> view() const noexcept {
+    return __sb_.view();
+  }
 #    endif // _LIBCPP_STD_VER >= 20
 
   _LIBCPP_HIDE_FROM_ABI void str(const string_type& __s) { __sb_.str(__s); }
@@ -1227,26 +1231,28 @@ public:
   }
 
   // [stringstream.members] Member functions:
-  _LIBCPP_HIDE_FROM_ABI basic_stringbuf<char_type, traits_type, allocator_type>* rdbuf() const {
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI basic_stringbuf<char_type, traits_type, allocator_type>* rdbuf() const {
     return const_cast<basic_stringbuf<char_type, traits_type, allocator_type>*>(std::addressof(__sb_));
   }
 
 #    if _LIBCPP_STD_VER <= 17 || defined(_LIBCPP_BUILDING_LIBRARY)
-  _LIBCPP_HIDE_FROM_ABI string_type str() const { return __sb_.str(); }
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI string_type str() const { return __sb_.str(); }
 #    else
-  _LIBCPP_HIDE_FROM_ABI string_type str() const& { return __sb_.str(); }
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI string_type str() const& { return __sb_.str(); }
 
-  _LIBCPP_HIDE_FROM_ABI string_type str() && { return std::move(__sb_).str(); }
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI string_type str() && { return std::move(__sb_).str(); }
 #    endif
 
 #    if _LIBCPP_STD_VER >= 20
   template <class _SAlloc>
     requires __is_allocator_v<_SAlloc>
-  _LIBCPP_HIDE_FROM_ABI basic_string<char_type, traits_type, _SAlloc> str(const _SAlloc& __sa) const {
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI basic_string<char_type, traits_type, _SAlloc> str(const _SAlloc& __sa) const {
     return __sb_.str(__sa);
   }
 
-  _LIBCPP_HIDE_FROM_ABI basic_string_view<char_type, traits_type> view() const noexcept { return __sb_.view(); }
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI basic_string_view<char_type, traits_type> view() const noexcept {
+    return __sb_.view();
+  }
 #    endif // _LIBCPP_STD_VER >= 20
 
   _LIBCPP_HIDE_FROM_ABI void str(const string_type& __s) { __sb_.str(__s); }
diff --git a/libcxx/include/strstream b/libcxx/include/strstream
index 1a17f8389c078..b33977ff66e21 100644
--- a/libcxx/include/strstream
+++ b/libcxx/include/strstream
@@ -179,8 +179,8 @@ public:
   void swap(strstreambuf& __rhs);
 
   void freeze(bool __freezefl = true);
-  char* str();
-  int pcount() const;
+  [[__nodiscard__]] char* str();
+  [[__nodiscard__]] int pcount() const;
 
 protected:
   int_type overflow(int_type __c = EOF) override;
@@ -264,8 +264,8 @@ public:
     __sb_.swap(__rhs.__sb_);
   }
 
-  _LIBCPP_HIDE_FROM_ABI strstreambuf* rdbuf() const { return const_cast<strstreambuf*>(&__sb_); }
-  _LIBCPP_HIDE_FROM_ABI char* str() { return __sb_.str(); }
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI strstreambuf* rdbuf() const { return const_cast<strstreambuf*>(&__sb_); }
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI char* str() { return __sb_.str(); }
 
 private:
   strstreambuf __sb_;
@@ -297,10 +297,10 @@ public:
     __sb_.swap(__rhs.__sb_);
   }
 
-  _LIBCPP_HIDE_FROM_ABI strstreambuf* rdbuf() const { return const_cast<strstreambuf*>(&__sb_); }
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI strstreambuf* rdbuf() const { return const_cast<strstreambuf*>(&__sb_); }
   _LIBCPP_HIDE_FROM_ABI void freeze(bool __freezefl = true) { __sb_.freeze(__freezefl); }
-  _LIBCPP_HIDE_FROM_ABI char* str() { return __sb_.str(); }
-  _LIBCPP_HIDE_FROM_ABI int pcount() const { return __sb_.pcount(); }
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI char* str() { return __sb_.str(); }
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI int pcount() const { return __sb_.pcount(); }
 
 private:
   strstreambuf __sb_; // exposition only
@@ -340,10 +340,10 @@ public:
   }
 
   // Members:
-  _LIBCPP_HIDE_FROM_ABI strstreambuf* rdbuf() const { return const_cast<strstreambuf*>(&__sb_); }
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI strstreambuf* rdbuf() const { return const_cast<strstreambuf*>(&__sb_); }
   _LIBCPP_HIDE_FROM_ABI void freeze(bool __freezefl = true) { __sb_.freeze(__freezefl); }
-  _LIBCPP_HIDE_FROM_ABI int pcount() const { return __sb_.pcount(); }
-  _LIBCPP_HIDE_FROM_ABI char* str() { return __sb_.str(); }
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI int pcount() const { return __sb_.pcount(); }
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI char* str() { return __sb_.str(); }
 
 private:
   strstreambuf __sb_; // exposition only
diff --git a/libcxx/include/syncstream b/libcxx/include/syncstream
index 1f7605e06aa21..bd64453683c7c 100644
--- a/libcxx/include/syncstream
+++ b/libcxx/include/syncstream
@@ -317,9 +317,9 @@ public:
 
   _LIBCPP_HIDE_FROM_ABI bool emit() { return emit(false); }
 
-  _LIBCPP_HIDE_FROM_ABI streambuf_type* get_wrapped() const noexcept { return __wrapped_; }
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI streambuf_type* get_wrapped() const noexcept { return __wrapped_; }
 
-  _LIBCPP_HIDE_FROM_ABI allocator_type get_allocator() const noexcept { return __str_.get_allocator(); }
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI allocator_type get_allocator() const noexcept { return __str_.get_allocator(); }
 
   _LIBCPP_HIDE_FROM_ABI void set_emit_on_sync(bool __b) noexcept { __emit_on_sync_ = __b; }
 
@@ -496,9 +496,9 @@ public:
     }
   }
 
-  _LIBCPP_HIDE_FROM_ABI streambuf_type* get_wrapped() const noexcept { return __sb_.get_wrapped(); }
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI streambuf_type* get_wrapped() const noexcept { return __sb_.get_wrapped(); }
 
-  _LIBCPP_HIDE_FROM_ABI syncbuf_type* rdbuf() const noexcept {
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI syncbuf_type* rdbuf() const noexcept {
     return const_cast<syncbuf_type*>(std::addressof(__sb_));
   }
 
diff --git a/libcxx/test/libcxx/depr/depr.strstream/nodiscard.verify.cpp b/libcxx/test/libcxx/depr/depr.strstream/nodiscard.verify.cpp
new file mode 100644
index 0000000000000..86db867ad9e41
--- /dev/null
+++ b/libcxx/test/libcxx/depr/depr.strstream/nodiscard.verify.cpp
@@ -0,0 +1,58 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_DISABLE_DEPRECATION_WARNINGS -D_LIBCPP_ENABLE_CXX26_REMOVED_STRSTREAM
+
+// <strstream>
+
+// Check that functions are marked [[nodiscard]]
+
+#include <strstream>
+
+void test() {
+  {
+    std::strstreambuf sb;
+
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    sb.str();
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    sb.pcount();
+  }
+
+  {
+    const char buff[] = "";
+    std::istrstream stream(buff);
+
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    stream.rdbuf();
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    stream.str();
+  }
+
+  {
+    std::ostrstream stream;
+
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    stream.rdbuf();
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    stream.str();
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    stream.pcount();
+  }
+
+  {
+    std::strstream stream;
+
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    stream.rdbuf();
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    stream.str();
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    stream.pcount();
+  }
+}
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..98b09405e84e7
--- /dev/null
+++ b/libcxx/test/libcxx/input.output/file.streams/fstreams/nodiscard.verify.cpp
@@ -0,0 +1,67 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// <fstream>
+
+// Check that functions are marked [[nodiscard]]
+
+#include <fstream>
+
+#include "test_macros.h"
+
+void test() {
+  {
+    std::basic_filebuf<char> fb;
+
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    fb.is_open();
+#if TEST_STD_VER >= 26
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    fb.native_handle();
+#endif
+  }
+
+  {
+    std::basic_ifstream<char> stream;
+
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    stream.rdbuf();
+#if TEST_STD_VER >= 26
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    stream.native_handle();
+#endif
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    stream.is_open();
+  }
+
+  {
+    std::basic_ofstream<char> stream;
+
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    stream.rdbuf();
+#if TEST_STD_VER >= 26
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    stream.native_handle();
+#endif
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    stream.is_open();
+  }
+
+  {
+    std::basic_fstream<char> stream;
+
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    stream.rdbuf();
+#if TEST_STD_VER >= 26
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    stream.native_handle();
+#endif
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    stream.is_open();
+  }
+}
diff --git a/libcxx/test/libcxx/input.output/string.streams/nodiscard.verify.cpp b/libcxx/test/libcxx/input.output/string.streams/nodiscard.verify.cpp
new file mode 100644
index 0000000000000..56ceb63b26697
--- /dev/null
+++ b/libcxx/test/libcxx/input.output/string.streams/nodiscard.verify.cpp
@@ -0,0 +1,101 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// <sstream>
+
+// Check that functions are marked [[nodiscard]]
+
+#include <memory>
+#include <sstream>
+#include <utility>
+
+#include "test_macros.h"
+
+void test() {
+#if TEST_STD_VER >= 20
+  std::allocator<char> alloc;
+#endif
+
+  {
+    std::basic_stringbuf<char> sb;
+
+#if TEST_STD_VER >= 20
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    sb.get_allocator();
+#endif
+
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    sb.str();
+#if TEST_STD_VER >= 20
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    std::move(sb).str();
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    sb.str({});
+
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    sb.view();
+#endif
+  }
+
+  {
+    std::basic_istringstream<char> stream;
+
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    stream.rdbuf();
+
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    stream.str();
+#if TEST_STD_VER >= 20
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    std::move(stream).str();
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    stream.str({});
+
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    stream.view();
+#endif
+  }
+
+  {
+    std::basic_ostringstream<char> stream;
+
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    stream.rdbuf();
+
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    stream.str();
+#if TEST_STD_VER >= 20
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    std::move(stream).str();
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    stream.str({});
+
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    stream.view();
+#endif
+  }
+
+  {
+    std::basic_stringstream<char> stream;
+
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    stream.rdbuf();
+
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    stream.str();
+#if TEST_STD_VER >= 20
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    std::move(stream).str();
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    stream.str({});
+
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    stream.view();
+#endif
+  }
+}
diff --git a/libcxx/test/libcxx/input.output/synchstream/nodiscard.verify.cpp b/libcxx/test/libcxx/input.output/synchstream/nodiscard.verify.cpp
new file mode 100644
index 0000000000000..ccb269233619b
--- /dev/null
+++ b/libcxx/test/libcxx/input.output/synchstream/nodiscard.verify.cpp
@@ -0,0 +1,41 @@
+//===----------------------------------------------------------------------===//
+//
+// 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++20
+// UNSUPPORTED: no-localization
+// UNSUPPORTED: libcpp-has-no-experimental-syncstream
+
+// <synchstream>
+
+// Check that functions are marked [[nodiscard]]
+
+#include <sstream>
+#include <synchstream>
+
+#include "test_macros.h"
+
+void test() {
+  {
+    std::basic_synchbuf<char> sb;
+
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    sb.get_wrapped();
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    sb.get_allocator();
+  }
+
+  {
+    std::basic_ostringstream<char> os;
+    std::basic_osynchstream<char> stream{os};
+
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    stream.get_wrapped();
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    stream.rdbuf();
+  }
+}



More information about the libcxx-commits mailing list