[libcxx-commits] [libcxx] [libc++][locale] Applied `[[nodiscard]]` (PR #200726)

A. Jiang via libcxx-commits libcxx-commits at lists.llvm.org
Sun May 31 22:55:08 PDT 2026


https://github.com/frederick-vs-ja updated https://github.com/llvm/llvm-project/pull/200726

>From acab1a0a7756ee3fc789de008713acda8a5d0444 Mon Sep 17 00:00:00 2001
From: "A. Jiang" <de34 at live.cn>
Date: Mon, 1 Jun 2026 13:48:59 +0800
Subject: [PATCH] [libc++][locale] Applied `[[nodiscard]]`

`[[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/localization

Remarks:
- Virtual functions are not marked `[[nodiscard]]` because they are not
expected to be directly called by users.
- `messages::open` is marked `[[nodiscard]]` because it is logically
similar to `operator new` and its friends.
---
 libcxx/include/__locale                       | 143 +++++-----
 libcxx/include/__locale_dir/messages.h        |   5 +-
 libcxx/include/__locale_dir/money.h           |  18 +-
 .../libcxx/localization/nodiscard.verify.cpp  | 245 ++++++++++++++++++
 4 files changed, 334 insertions(+), 77 deletions(-)
 create mode 100644 libcxx/test/libcxx/localization/nodiscard.verify.cpp

diff --git a/libcxx/include/__locale b/libcxx/include/__locale
index 1d5f12431588c..a6face1f52bb8 100644
--- a/libcxx/include/__locale
+++ b/libcxx/include/__locale
@@ -89,7 +89,7 @@ public:
   const locale& operator=(const locale&) _NOEXCEPT;
 
   template <class _Facet>
-  _LIBCPP_HIDE_FROM_ABI locale combine(const locale& __other) const {
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI locale combine(const locale& __other) const {
     if (!std::has_facet<_Facet>(__other))
       __throw_runtime_error("locale::combine: locale missing facet");
 
@@ -97,12 +97,13 @@ public:
   }
 
   // locale operations:
-  string name() const;
+  [[__nodiscard__]] string name() const;
   bool operator==(const locale&) const;
 #  if _LIBCPP_STD_VER <= 17
   _LIBCPP_HIDE_FROM_ABI bool operator!=(const locale& __y) const { return !(*this == __y); }
 #  endif
   template <class _CharT, class _Traits, class _Allocator>
+  [[__nodiscard__]]
   _LIBCPP_HIDE_FROM_ABI bool operator()(const basic_string<_CharT, _Traits, _Allocator>& __x,
                                         const basic_string<_CharT, _Traits, _Allocator>& __y) const {
     return std::use_facet<std::collate<_CharT> >(*this).compare(
@@ -111,7 +112,7 @@ public:
 
   // global locale objects:
   static locale global(const locale&);
-  static const locale& classic();
+  [[__nodiscard__]] static const locale& classic();
 
 private:
   class __imp;
@@ -172,12 +173,12 @@ inline _LIBCPP_HIDE_FROM_ABI locale::locale(const locale& __other, _Facet* __f)
 }
 
 template <class _Facet>
-inline _LIBCPP_HIDE_FROM_ABI bool has_facet(const locale& __l) _NOEXCEPT {
+[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI bool has_facet(const locale& __l) _NOEXCEPT {
   return __l.has_facet(_Facet::id);
 }
 
 template <class _Facet>
-inline _LIBCPP_HIDE_FROM_ABI const _Facet& use_facet(const locale& __l) {
+[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI const _Facet& use_facet(const locale& __l) {
   return static_cast<const _Facet&>(*__l.use_facet(_Facet::id));
 }
 
@@ -191,19 +192,21 @@ public:
 
   _LIBCPP_HIDE_FROM_ABI explicit collate(size_t __refs = 0) : locale::facet(__refs) {}
 
-  _LIBCPP_HIDE_FROM_ABI int
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI int
   compare(const char_type* __lo1, const char_type* __hi1, const char_type* __lo2, const char_type* __hi2) const {
     return do_compare(__lo1, __hi1, __lo2, __hi2);
   }
 
   // FIXME(EricWF): The _LIBCPP_ALWAYS_INLINE is needed on Windows to work
   // around a dllimport bug that expects an external instantiation.
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_ALWAYS_INLINE string_type
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_ALWAYS_INLINE string_type
   transform(const char_type* __lo, const char_type* __hi) const {
     return do_transform(__lo, __hi);
   }
 
-  _LIBCPP_HIDE_FROM_ABI long hash(const char_type* __lo, const char_type* __hi) const { return do_hash(__lo, __hi); }
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI long hash(const char_type* __lo, const char_type* __hi) const {
+    return do_hash(__lo, __hi);
+  }
 
   static locale::id id;
 
@@ -463,39 +466,43 @@ public:
 
   _LIBCPP_HIDE_FROM_ABI explicit ctype(size_t __refs = 0) : locale::facet(__refs) {}
 
-  _LIBCPP_HIDE_FROM_ABI bool is(mask __m, char_type __c) const { return do_is(__m, __c); }
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool is(mask __m, char_type __c) const { return do_is(__m, __c); }
 
   _LIBCPP_HIDE_FROM_ABI const char_type* is(const char_type* __low, const char_type* __high, mask* __vec) const {
     return do_is(__low, __high, __vec);
   }
 
-  _LIBCPP_HIDE_FROM_ABI const char_type* scan_is(mask __m, const char_type* __low, const char_type* __high) const {
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const char_type*
+  scan_is(mask __m, const char_type* __low, const char_type* __high) const {
     return do_scan_is(__m, __low, __high);
   }
 
-  _LIBCPP_HIDE_FROM_ABI const char_type* scan_not(mask __m, const char_type* __low, const char_type* __high) const {
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const char_type*
+  scan_not(mask __m, const char_type* __low, const char_type* __high) const {
     return do_scan_not(__m, __low, __high);
   }
 
-  _LIBCPP_HIDE_FROM_ABI char_type toupper(char_type __c) const { return do_toupper(__c); }
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI char_type toupper(char_type __c) const { return do_toupper(__c); }
 
   _LIBCPP_HIDE_FROM_ABI const char_type* toupper(char_type* __low, const char_type* __high) const {
     return do_toupper(__low, __high);
   }
 
-  _LIBCPP_HIDE_FROM_ABI char_type tolower(char_type __c) const { return do_tolower(__c); }
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI char_type tolower(char_type __c) const { return do_tolower(__c); }
 
   _LIBCPP_HIDE_FROM_ABI const char_type* tolower(char_type* __low, const char_type* __high) const {
     return do_tolower(__low, __high);
   }
 
-  _LIBCPP_HIDE_FROM_ABI char_type widen(char __c) const { return do_widen(__c); }
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI char_type widen(char __c) const { return do_widen(__c); }
 
   _LIBCPP_HIDE_FROM_ABI const char* widen(const char* __low, const char* __high, char_type* __to) const {
     return do_widen(__low, __high, __to);
   }
 
-  _LIBCPP_HIDE_FROM_ABI char narrow(char_type __c, char __dfault) const { return do_narrow(__c, __dfault); }
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI char narrow(char_type __c, char __dfault) const {
+    return do_narrow(__c, __dfault);
+  }
 
   _LIBCPP_HIDE_FROM_ABI const char_type*
   narrow(const char_type* __low, const char_type* __high, char __dfault, char* __to) const {
@@ -534,7 +541,7 @@ public:
 
   explicit ctype(const mask* __tab = nullptr, bool __del = false, size_t __refs = 0);
 
-  _LIBCPP_HIDE_FROM_ABI bool is(mask __m, char_type __c) const {
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool is(mask __m, char_type __c) const {
     return std::__libcpp_isascii(__c) ? (__tab_[static_cast<int>(__c)] & __m) != 0 : false;
   }
 
@@ -544,39 +551,43 @@ public:
     return __low;
   }
 
-  _LIBCPP_HIDE_FROM_ABI const char_type* scan_is(mask __m, const char_type* __low, const char_type* __high) const {
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const char_type*
+  scan_is(mask __m, const char_type* __low, const char_type* __high) const {
     for (; __low != __high; ++__low)
       if (std::__libcpp_isascii(*__low) && (__tab_[static_cast<int>(*__low)] & __m))
         break;
     return __low;
   }
 
-  _LIBCPP_HIDE_FROM_ABI const char_type* scan_not(mask __m, const char_type* __low, const char_type* __high) const {
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const char_type*
+  scan_not(mask __m, const char_type* __low, const char_type* __high) const {
     for (; __low != __high; ++__low)
       if (!std::__libcpp_isascii(*__low) || !(__tab_[static_cast<int>(*__low)] & __m))
         break;
     return __low;
   }
 
-  _LIBCPP_HIDE_FROM_ABI char_type toupper(char_type __c) const { return do_toupper(__c); }
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI char_type toupper(char_type __c) const { return do_toupper(__c); }
 
   _LIBCPP_HIDE_FROM_ABI const char_type* toupper(char_type* __low, const char_type* __high) const {
     return do_toupper(__low, __high);
   }
 
-  _LIBCPP_HIDE_FROM_ABI char_type tolower(char_type __c) const { return do_tolower(__c); }
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI char_type tolower(char_type __c) const { return do_tolower(__c); }
 
   _LIBCPP_HIDE_FROM_ABI const char_type* tolower(char_type* __low, const char_type* __high) const {
     return do_tolower(__low, __high);
   }
 
-  _LIBCPP_HIDE_FROM_ABI char_type widen(char __c) const { return do_widen(__c); }
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI char_type widen(char __c) const { return do_widen(__c); }
 
   _LIBCPP_HIDE_FROM_ABI const char* widen(const char* __low, const char* __high, char_type* __to) const {
     return do_widen(__low, __high, __to);
   }
 
-  _LIBCPP_HIDE_FROM_ABI char narrow(char_type __c, char __dfault) const { return do_narrow(__c, __dfault); }
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI char narrow(char_type __c, char __dfault) const {
+    return do_narrow(__c, __dfault);
+  }
 
   _LIBCPP_HIDE_FROM_ABI const char*
   narrow(const char_type* __low, const char_type* __high, char __dfault, char* __to) const {
@@ -590,8 +601,8 @@ public:
 #  else
   static const size_t table_size = 256;
 #  endif
-  _LIBCPP_HIDE_FROM_ABI const mask* table() const _NOEXCEPT { return __tab_; }
-  static const mask* classic_table() _NOEXCEPT;
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const mask* table() const _NOEXCEPT { return __tab_; }
+  [[__nodiscard__]] static const mask* classic_table() _NOEXCEPT;
 
 protected:
   ~ctype() override;
@@ -654,72 +665,72 @@ protected:
 #  endif // _LIBCPP_HAS_WIDE_CHARACTERS
 
 template <class _CharT>
-inline _LIBCPP_HIDE_FROM_ABI bool isspace(_CharT __c, const locale& __loc) {
+[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI bool isspace(_CharT __c, const locale& __loc) {
   return std::use_facet<ctype<_CharT> >(__loc).is(ctype_base::space, __c);
 }
 
 template <class _CharT>
-inline _LIBCPP_HIDE_FROM_ABI bool isprint(_CharT __c, const locale& __loc) {
+[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI bool isprint(_CharT __c, const locale& __loc) {
   return std::use_facet<ctype<_CharT> >(__loc).is(ctype_base::print, __c);
 }
 
 template <class _CharT>
-inline _LIBCPP_HIDE_FROM_ABI bool iscntrl(_CharT __c, const locale& __loc) {
+[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI bool iscntrl(_CharT __c, const locale& __loc) {
   return std::use_facet<ctype<_CharT> >(__loc).is(ctype_base::cntrl, __c);
 }
 
 template <class _CharT>
-inline _LIBCPP_HIDE_FROM_ABI bool isupper(_CharT __c, const locale& __loc) {
+[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI bool isupper(_CharT __c, const locale& __loc) {
   return std::use_facet<ctype<_CharT> >(__loc).is(ctype_base::upper, __c);
 }
 
 template <class _CharT>
-inline _LIBCPP_HIDE_FROM_ABI bool islower(_CharT __c, const locale& __loc) {
+[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI bool islower(_CharT __c, const locale& __loc) {
   return std::use_facet<ctype<_CharT> >(__loc).is(ctype_base::lower, __c);
 }
 
 template <class _CharT>
-inline _LIBCPP_HIDE_FROM_ABI bool isalpha(_CharT __c, const locale& __loc) {
+[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI bool isalpha(_CharT __c, const locale& __loc) {
   return std::use_facet<ctype<_CharT> >(__loc).is(ctype_base::alpha, __c);
 }
 
 template <class _CharT>
-inline _LIBCPP_HIDE_FROM_ABI bool isdigit(_CharT __c, const locale& __loc) {
+[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI bool isdigit(_CharT __c, const locale& __loc) {
   return std::use_facet<ctype<_CharT> >(__loc).is(ctype_base::digit, __c);
 }
 
 template <class _CharT>
-inline _LIBCPP_HIDE_FROM_ABI bool ispunct(_CharT __c, const locale& __loc) {
+[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI bool ispunct(_CharT __c, const locale& __loc) {
   return std::use_facet<ctype<_CharT> >(__loc).is(ctype_base::punct, __c);
 }
 
 template <class _CharT>
-inline _LIBCPP_HIDE_FROM_ABI bool isxdigit(_CharT __c, const locale& __loc) {
+[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI bool isxdigit(_CharT __c, const locale& __loc) {
   return std::use_facet<ctype<_CharT> >(__loc).is(ctype_base::xdigit, __c);
 }
 
 template <class _CharT>
-inline _LIBCPP_HIDE_FROM_ABI bool isalnum(_CharT __c, const locale& __loc) {
+[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI bool isalnum(_CharT __c, const locale& __loc) {
   return std::use_facet<ctype<_CharT> >(__loc).is(ctype_base::alnum, __c);
 }
 
 template <class _CharT>
-inline _LIBCPP_HIDE_FROM_ABI bool isgraph(_CharT __c, const locale& __loc) {
+[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI bool isgraph(_CharT __c, const locale& __loc) {
   return std::use_facet<ctype<_CharT> >(__loc).is(ctype_base::graph, __c);
 }
 
 template <class _CharT>
-_LIBCPP_HIDE_FROM_ABI bool isblank(_CharT __c, const locale& __loc) {
+[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool isblank(_CharT __c, const locale& __loc) {
   return std::use_facet<ctype<_CharT> >(__loc).is(ctype_base::blank, __c);
 }
 
 template <class _CharT>
-inline _LIBCPP_HIDE_FROM_ABI _CharT toupper(_CharT __c, const locale& __loc) {
+[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _CharT toupper(_CharT __c, const locale& __loc) {
   return std::use_facet<ctype<_CharT> >(__loc).toupper(__c);
 }
 
 template <class _CharT>
-inline _LIBCPP_HIDE_FROM_ABI _CharT tolower(_CharT __c, const locale& __loc) {
+[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _CharT tolower(_CharT __c, const locale& __loc) {
   return std::use_facet<ctype<_CharT> >(__loc).tolower(__c);
 }
 
@@ -774,16 +785,16 @@ public:
     return do_in(__st, __frm, __frm_end, __frm_nxt, __to, __to_end, __to_nxt);
   }
 
-  _LIBCPP_HIDE_FROM_ABI int encoding() const _NOEXCEPT { return do_encoding(); }
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI int encoding() const _NOEXCEPT { return do_encoding(); }
 
-  _LIBCPP_HIDE_FROM_ABI bool always_noconv() const _NOEXCEPT { return do_always_noconv(); }
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool always_noconv() const _NOEXCEPT { return do_always_noconv(); }
 
   _LIBCPP_HIDE_FROM_ABI int
   length(state_type& __st, const extern_type* __frm, const extern_type* __end, size_t __mx) const {
     return do_length(__st, __frm, __end, __mx);
   }
 
-  _LIBCPP_HIDE_FROM_ABI int max_length() const _NOEXCEPT { return do_max_length(); }
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI int max_length() const _NOEXCEPT { return do_max_length(); }
 
   static locale::id id;
 
@@ -856,16 +867,16 @@ public:
     return do_in(__st, __frm, __frm_end, __frm_nxt, __to, __to_end, __to_nxt);
   }
 
-  _LIBCPP_HIDE_FROM_ABI int encoding() const _NOEXCEPT { return do_encoding(); }
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI int encoding() const _NOEXCEPT { return do_encoding(); }
 
-  _LIBCPP_HIDE_FROM_ABI bool always_noconv() const _NOEXCEPT { return do_always_noconv(); }
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool always_noconv() const _NOEXCEPT { return do_always_noconv(); }
 
   _LIBCPP_HIDE_FROM_ABI int
   length(state_type& __st, const extern_type* __frm, const extern_type* __end, size_t __mx) const {
     return do_length(__st, __frm, __end, __mx);
   }
 
-  _LIBCPP_HIDE_FROM_ABI int max_length() const _NOEXCEPT { return do_max_length(); }
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI int max_length() const _NOEXCEPT { return do_max_length(); }
 
   static locale::id id;
 
@@ -937,16 +948,16 @@ public:
     return do_in(__st, __frm, __frm_end, __frm_nxt, __to, __to_end, __to_nxt);
   }
 
-  _LIBCPP_HIDE_FROM_ABI int encoding() const _NOEXCEPT { return do_encoding(); }
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI int encoding() const _NOEXCEPT { return do_encoding(); }
 
-  _LIBCPP_HIDE_FROM_ABI bool always_noconv() const _NOEXCEPT { return do_always_noconv(); }
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool always_noconv() const _NOEXCEPT { return do_always_noconv(); }
 
   _LIBCPP_HIDE_FROM_ABI int
   length(state_type& __st, const extern_type* __frm, const extern_type* __end, size_t __mx) const {
     return do_length(__st, __frm, __end, __mx);
   }
 
-  _LIBCPP_HIDE_FROM_ABI int max_length() const _NOEXCEPT { return do_max_length(); }
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI int max_length() const _NOEXCEPT { return do_max_length(); }
 
   static locale::id id;
 
@@ -1018,16 +1029,16 @@ public:
     return do_in(__st, __frm, __frm_end, __frm_nxt, __to, __to_end, __to_nxt);
   }
 
-  _LIBCPP_HIDE_FROM_ABI int encoding() const _NOEXCEPT { return do_encoding(); }
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI int encoding() const _NOEXCEPT { return do_encoding(); }
 
-  _LIBCPP_HIDE_FROM_ABI bool always_noconv() const _NOEXCEPT { return do_always_noconv(); }
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool always_noconv() const _NOEXCEPT { return do_always_noconv(); }
 
   _LIBCPP_HIDE_FROM_ABI int
   length(state_type& __st, const extern_type* __frm, const extern_type* __end, size_t __mx) const {
     return do_length(__st, __frm, __end, __mx);
   }
 
-  _LIBCPP_HIDE_FROM_ABI int max_length() const _NOEXCEPT { return do_max_length(); }
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI int max_length() const _NOEXCEPT { return do_max_length(); }
 
   static locale::id id;
 
@@ -1100,16 +1111,16 @@ public:
     return do_in(__st, __frm, __frm_end, __frm_nxt, __to, __to_end, __to_nxt);
   }
 
-  _LIBCPP_HIDE_FROM_ABI int encoding() const _NOEXCEPT { return do_encoding(); }
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI int encoding() const _NOEXCEPT { return do_encoding(); }
 
-  _LIBCPP_HIDE_FROM_ABI bool always_noconv() const _NOEXCEPT { return do_always_noconv(); }
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool always_noconv() const _NOEXCEPT { return do_always_noconv(); }
 
   _LIBCPP_HIDE_FROM_ABI int
   length(state_type& __st, const extern_type* __frm, const extern_type* __end, size_t __mx) const {
     return do_length(__st, __frm, __end, __mx);
   }
 
-  _LIBCPP_HIDE_FROM_ABI int max_length() const _NOEXCEPT { return do_max_length(); }
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI int max_length() const _NOEXCEPT { return do_max_length(); }
 
   static locale::id id;
 
@@ -1181,16 +1192,16 @@ public:
     return do_in(__st, __frm, __frm_end, __frm_nxt, __to, __to_end, __to_nxt);
   }
 
-  _LIBCPP_HIDE_FROM_ABI int encoding() const _NOEXCEPT { return do_encoding(); }
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI int encoding() const _NOEXCEPT { return do_encoding(); }
 
-  _LIBCPP_HIDE_FROM_ABI bool always_noconv() const _NOEXCEPT { return do_always_noconv(); }
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool always_noconv() const _NOEXCEPT { return do_always_noconv(); }
 
   _LIBCPP_HIDE_FROM_ABI int
   length(state_type& __st, const extern_type* __frm, const extern_type* __end, size_t __mx) const {
     return do_length(__st, __frm, __end, __mx);
   }
 
-  _LIBCPP_HIDE_FROM_ABI int max_length() const _NOEXCEPT { return do_max_length(); }
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI int max_length() const _NOEXCEPT { return do_max_length(); }
 
   static locale::id id;
 
@@ -1413,11 +1424,11 @@ public:
 
   explicit numpunct(size_t __refs = 0);
 
-  _LIBCPP_HIDE_FROM_ABI char_type decimal_point() const { return do_decimal_point(); }
-  _LIBCPP_HIDE_FROM_ABI char_type thousands_sep() const { return do_thousands_sep(); }
-  _LIBCPP_HIDE_FROM_ABI string grouping() const { return do_grouping(); }
-  _LIBCPP_HIDE_FROM_ABI string_type truename() const { return do_truename(); }
-  _LIBCPP_HIDE_FROM_ABI string_type falsename() const { return do_falsename(); }
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI char_type decimal_point() const { return do_decimal_point(); }
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI char_type thousands_sep() const { return do_thousands_sep(); }
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI string grouping() const { return do_grouping(); }
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI string_type truename() const { return do_truename(); }
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI string_type falsename() const { return do_falsename(); }
 
   static locale::id id;
 
@@ -1443,11 +1454,11 @@ public:
 
   explicit numpunct(size_t __refs = 0);
 
-  _LIBCPP_HIDE_FROM_ABI char_type decimal_point() const { return do_decimal_point(); }
-  _LIBCPP_HIDE_FROM_ABI char_type thousands_sep() const { return do_thousands_sep(); }
-  _LIBCPP_HIDE_FROM_ABI string grouping() const { return do_grouping(); }
-  _LIBCPP_HIDE_FROM_ABI string_type truename() const { return do_truename(); }
-  _LIBCPP_HIDE_FROM_ABI string_type falsename() const { return do_falsename(); }
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI char_type decimal_point() const { return do_decimal_point(); }
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI char_type thousands_sep() const { return do_thousands_sep(); }
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI string grouping() const { return do_grouping(); }
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI string_type truename() const { return do_truename(); }
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI string_type falsename() const { return do_falsename(); }
 
   static locale::id id;
 
diff --git a/libcxx/include/__locale_dir/messages.h b/libcxx/include/__locale_dir/messages.h
index 4023d2d5688d0..986a57d8b17b2 100644
--- a/libcxx/include/__locale_dir/messages.h
+++ b/libcxx/include/__locale_dir/messages.h
@@ -50,11 +50,12 @@ class messages : public locale::facet, public messages_base {
 
   _LIBCPP_HIDE_FROM_ABI explicit messages(size_t __refs = 0) : locale::facet(__refs) {}
 
-  _LIBCPP_HIDE_FROM_ABI catalog open(const basic_string<char>& __nm, const locale& __loc) const {
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI catalog open(const basic_string<char>& __nm, const locale& __loc) const {
     return do_open(__nm, __loc);
   }
 
-  _LIBCPP_HIDE_FROM_ABI string_type get(catalog __c, int __set, int __msgid, const string_type& __dflt) const {
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI string_type
+  get(catalog __c, int __set, int __msgid, const string_type& __dflt) const {
     return do_get(__c, __set, __msgid, __dflt);
   }
 
diff --git a/libcxx/include/__locale_dir/money.h b/libcxx/include/__locale_dir/money.h
index bb67f95ca2e0b..ba1cccb131f20 100644
--- a/libcxx/include/__locale_dir/money.h
+++ b/libcxx/include/__locale_dir/money.h
@@ -56,15 +56,15 @@ class moneypunct : public locale::facet, public money_base {
 
   _LIBCPP_HIDE_FROM_ABI explicit moneypunct(size_t __refs = 0) : locale::facet(__refs) {}
 
-  _LIBCPP_HIDE_FROM_ABI char_type decimal_point() const { return do_decimal_point(); }
-  _LIBCPP_HIDE_FROM_ABI char_type thousands_sep() const { return do_thousands_sep(); }
-  _LIBCPP_HIDE_FROM_ABI string grouping() const { return do_grouping(); }
-  _LIBCPP_HIDE_FROM_ABI string_type curr_symbol() const { return do_curr_symbol(); }
-  _LIBCPP_HIDE_FROM_ABI string_type positive_sign() const { return do_positive_sign(); }
-  _LIBCPP_HIDE_FROM_ABI string_type negative_sign() const { return do_negative_sign(); }
-  _LIBCPP_HIDE_FROM_ABI int frac_digits() const { return do_frac_digits(); }
-  _LIBCPP_HIDE_FROM_ABI pattern pos_format() const { return do_pos_format(); }
-  _LIBCPP_HIDE_FROM_ABI pattern neg_format() const { return do_neg_format(); }
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI char_type decimal_point() const { return do_decimal_point(); }
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI char_type thousands_sep() const { return do_thousands_sep(); }
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI string grouping() const { return do_grouping(); }
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI string_type curr_symbol() const { return do_curr_symbol(); }
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI string_type positive_sign() const { return do_positive_sign(); }
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI string_type negative_sign() const { return do_negative_sign(); }
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI int frac_digits() const { return do_frac_digits(); }
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI pattern pos_format() const { return do_pos_format(); }
+  [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI pattern neg_format() const { return do_neg_format(); }
 
   static locale::id id;
   static const bool intl = _International;
diff --git a/libcxx/test/libcxx/localization/nodiscard.verify.cpp b/libcxx/test/libcxx/localization/nodiscard.verify.cpp
new file mode 100644
index 0000000000000..80691e276deab
--- /dev/null
+++ b/libcxx/test/libcxx/localization/nodiscard.verify.cpp
@@ -0,0 +1,245 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+
+// Check that functions are marked [[nodiscard]]
+
+#include <cwchar>
+#include <locale>
+#include <string>
+
+#include "test_macros.h"
+
+template <class Facet>
+struct derived_facet : Facet {
+  derived_facet() {}
+};
+
+void test() {
+  // [locales]
+  {
+    std::locale l;
+
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    l.combine<std::messages<char> >(l);
+    l.name(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+#if TEST_STD_VER >= 26
+    // l.encoding(); // TODO: Verify this once P1885R12 (https://llvm.org/PR105373) is implemented.
+#endif
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    l(std::string(), std::string());
+
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    std::locale::classic();
+
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    std::use_facet<std::messages<char> >(l);
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    std::has_facet<std::messages<char> >(l);
+
+    std::isspace('\r', l); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+    std::isprint('*', l);  // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+    std::iscntrl('\n', l); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+    std::isupper('A', l);  // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+    std::islower('b', l);  // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+    std::isalpha('C', l);  // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+    std::isdigit('0', l);  // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+    std::ispunct(',', l);  // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+    std::isxdigit('d', l); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+    std::isalnum('Z', l);  // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+    std::isgraph('!', l);  // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+    std::isblank(' ', l);  // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+
+    std::toupper('g', l); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+    std::tolower('H', l); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+  }
+
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+  // [locale.ctype.general]
+  {
+    derived_facet<std::ctype<wchar_t> > f;
+
+    f.is(0, L'\0'); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    f.scan_is(0, nullptr, nullptr);
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    f.scan_not(0, nullptr, nullptr);
+
+    f.toupper(L'a'); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+    f.tolower(L'B'); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+
+    f.widen('c');         // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+    f.narrow(L'D', L'*'); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+  }
+#endif
+  // [facet.ctype.special.general]
+  {
+    derived_facet<std::ctype<char> > f;
+
+    f.is(0, '\0'); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    f.scan_is(0, nullptr, nullptr);
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    f.scan_not(0, nullptr, nullptr);
+
+    f.toupper('a'); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+    f.tolower('B'); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+
+    f.widen('c');       // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+    f.narrow('D', '*'); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+
+    f.table(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    std::ctype<char>::classic_table();
+  }
+
+  // [locale.codecvt.general]
+  {
+    derived_facet<std::codecvt<char, char, std::mbstate_t> > f;
+
+    f.encoding();      // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+    f.always_noconv(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+    f.max_length();    // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+  }
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+  {
+    derived_facet<std::codecvt<wchar_t, char, std::mbstate_t> > f;
+
+    f.encoding();      // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+    f.always_noconv(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+    f.max_length();    // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+  }
+#endif
+  {
+    derived_facet<std::codecvt<char16_t, char, std::mbstate_t> > f;
+
+    f.encoding();      // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+    f.always_noconv(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+    f.max_length();    // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+  }
+  {
+    derived_facet<std::codecvt<char32_t, char, std::mbstate_t> > f;
+
+    f.encoding();      // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+    f.always_noconv(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+    f.max_length();    // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+  }
+#ifndef TEST_HAS_NO_CHAR8_T
+  {
+    derived_facet<std::codecvt<char16_t, char8_t, std::mbstate_t> > f;
+
+    f.encoding();      // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+    f.always_noconv(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+    f.max_length();    // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+  }
+  {
+    derived_facet<std::codecvt<char32_t, char8_t, std::mbstate_t> > f;
+
+    f.encoding();      // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+    f.always_noconv(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+    f.max_length();    // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+  }
+#endif
+
+  // [locale.numpunct.general]
+  {
+    derived_facet<std::numpunct<char> > f;
+
+    f.decimal_point(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+    f.thousands_sep(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+    f.grouping();      // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+    f.truename();      // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+    f.falsename();     // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+  }
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+  {
+    derived_facet<std::numpunct<wchar_t> > f;
+
+    f.decimal_point(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+    f.thousands_sep(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+    f.grouping();      // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+    f.truename();      // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+    f.falsename();     // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+  }
+#endif
+
+  // [locale.collate.general]
+  {
+    derived_facet<std::collate<char> > f;
+
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    f.compare(nullptr, nullptr, nullptr, nullptr);
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    f.transform(nullptr, nullptr);
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    f.hash(nullptr, nullptr);
+  }
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+  {
+    derived_facet<std::collate<wchar_t> > f;
+
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    f.compare(nullptr, nullptr, nullptr, nullptr);
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    f.transform(nullptr, nullptr);
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    f.hash(nullptr, nullptr);
+  }
+#endif
+
+  // [locale.moneypunct.general]
+  {
+    derived_facet<std::moneypunct<char> > f;
+
+    f.decimal_point(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+    f.thousands_sep(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+    f.grouping();      // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+    f.curr_symbol();   // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+    f.positive_sign(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+    f.negative_sign(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+    f.frac_digits();   // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+    f.pos_format();    // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+    f.neg_format();    // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+  }
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+  {
+    derived_facet<std::moneypunct<wchar_t> > f;
+
+    f.decimal_point(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+    f.thousands_sep(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+    f.grouping();      // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+    f.curr_symbol();   // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+    f.positive_sign(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+    f.negative_sign(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+    f.frac_digits();   // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+    f.pos_format();    // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+    f.neg_format();    // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+  }
+#endif
+
+  // [locale.messages.general]
+  {
+    derived_facet<std::messages<char> > f;
+
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    f.open(std::string(), std::locale());
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    f.get(0, 0, 0, std::string());
+  }
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+  {
+    derived_facet<std::messages<wchar_t> > f;
+
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    f.open(std::string(), std::locale());
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    f.get(0, 0, 0, std::wstring());
+  }
+#endif
+}



More information about the libcxx-commits mailing list