[libcxx-commits] [libcxx] [libc++][regex] Applied `[[nodiscard]]` (PR #170974)
Hristo Hristov via libcxx-commits
libcxx-commits at lists.llvm.org
Sun Dec 14 08:38:52 PST 2025
https://github.com/H-G-Hristov updated https://github.com/llvm/llvm-project/pull/170974
>From b739452c61e708730874faee25191e6cadd55481 Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Sat, 6 Dec 2025 11:56:57 +0200
Subject: [PATCH 1/4] [libc++][regex] 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
---
libcxx/include/regex | 58 ++++++++--------
.../diagnostics/regex.nodiscard.verify.cpp | 68 ++++++++++++++++++-
2 files changed, 96 insertions(+), 30 deletions(-)
diff --git a/libcxx/include/regex b/libcxx/include/regex
index b6c19518be301..89370583c9a04 100644
--- a/libcxx/include/regex
+++ b/libcxx/include/regex
@@ -986,7 +986,7 @@ public:
explicit regex_error(regex_constants::error_type __ecode);
_LIBCPP_HIDE_FROM_ABI regex_error(const regex_error&) _NOEXCEPT = default;
~regex_error() _NOEXCEPT override;
- _LIBCPP_HIDE_FROM_ABI regex_constants::error_type code() const { return __code_; }
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI regex_constants::error_type code() const { return __code_; }
};
template <regex_constants::error_type _Ev>
@@ -2412,16 +2412,16 @@ public:
# endif // _LIBCPP_CXX03_LANG
// const operations:
- _LIBCPP_HIDE_FROM_ABI unsigned mark_count() const { return __marked_count_; }
- _LIBCPP_HIDE_FROM_ABI flag_type flags() const { return __flags_; }
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI unsigned mark_count() const { return __marked_count_; }
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI flag_type flags() const { return __flags_; }
// locale:
- _LIBCPP_HIDE_FROM_ABI locale_type imbue(locale_type __loc) {
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI locale_type imbue(locale_type __loc) {
__member_init(ECMAScript);
__start_.reset();
return __traits_.imbue(__loc);
}
- _LIBCPP_HIDE_FROM_ABI locale_type getloc() const { return __traits_.getloc(); }
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI locale_type getloc() const { return __traits_.getloc(); }
// swap:
void swap(basic_regex& __r);
@@ -4206,17 +4206,17 @@ public:
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR sub_match() : matched() {}
- _LIBCPP_HIDE_FROM_ABI difference_type length() const {
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI difference_type length() const {
return matched ? std::distance(this->first, this->second) : 0;
}
- _LIBCPP_HIDE_FROM_ABI string_type str() const {
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI string_type str() const {
return matched ? string_type(this->first, this->second) : string_type();
}
_LIBCPP_HIDE_FROM_ABI operator string_type() const { return str(); }
- _LIBCPP_HIDE_FROM_ABI int compare(const sub_match& __s) const { return str().compare(__s.str()); }
- _LIBCPP_HIDE_FROM_ABI int compare(const string_type& __s) const { return str().compare(__s); }
- _LIBCPP_HIDE_FROM_ABI int compare(const value_type* __s) const { return str().compare(__s); }
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI int compare(const sub_match& __s) const { return str().compare(__s.str()); }
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI int compare(const string_type& __s) const { return str().compare(__s); }
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI int compare(const value_type* __s) const { return str().compare(__s); }
_LIBCPP_HIDE_FROM_ABI void swap(sub_match& __s) _NOEXCEPT_(__is_nothrow_swappable_v<_BidirectionalIterator>) {
this->pair<_BidirectionalIterator, _BidirectionalIterator>::swap(__s);
@@ -4581,49 +4581,53 @@ public:
_LIBCPP_HIDE_FROM_ABI bool ready() const { return __ready_; }
// size:
- _LIBCPP_HIDE_FROM_ABI size_type size() const _NOEXCEPT { return __matches_.size(); }
- _LIBCPP_HIDE_FROM_ABI size_type max_size() const _NOEXCEPT { return __matches_.max_size(); }
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI size_type size() const _NOEXCEPT { return __matches_.size(); }
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI size_type max_size() const _NOEXCEPT { return __matches_.max_size(); }
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool empty() const _NOEXCEPT { return size() == 0; }
// element access:
- _LIBCPP_HIDE_FROM_ABI difference_type length(size_type __sub = 0) const {
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI difference_type length(size_type __sub = 0) const {
// If the match results are not ready, this will return `0`.
_LIBCPP_ASSERT_PEDANTIC(ready(), "match_results::length() called when not ready");
return (*this)[__sub].length();
}
- _LIBCPP_HIDE_FROM_ABI difference_type position(size_type __sub = 0) const {
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI difference_type position(size_type __sub = 0) const {
// If the match results are not ready, this will return the result of subtracting two default-constructed iterators
// (which is typically a well-defined operation).
_LIBCPP_ASSERT_PEDANTIC(ready(), "match_results::position() called when not ready");
return std::distance(__position_start_, (*this)[__sub].first);
}
- _LIBCPP_HIDE_FROM_ABI string_type str(size_type __sub = 0) const {
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI string_type str(size_type __sub = 0) const {
// If the match results are not ready, this will return an empty string.
_LIBCPP_ASSERT_PEDANTIC(ready(), "match_results::str() called when not ready");
return (*this)[__sub].str();
}
- _LIBCPP_HIDE_FROM_ABI const_reference operator[](size_type __n) const {
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_reference operator[](size_type __n) const {
// If the match results are not ready, this call will be equivalent to calling this function with `__n >= size()`,
// returning an empty subrange.
_LIBCPP_ASSERT_PEDANTIC(ready(), "match_results::operator[]() called when not ready");
return __n < __matches_.size() ? __matches_[__n] : __unmatched_;
}
- _LIBCPP_HIDE_FROM_ABI const_reference prefix() const {
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_reference prefix() const {
// If the match results are not ready, this will return a default-constructed empty `__suffix_`.
_LIBCPP_ASSERT_PEDANTIC(ready(), "match_results::prefix() called when not ready");
return __prefix_;
}
- _LIBCPP_HIDE_FROM_ABI const_reference suffix() const {
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_reference suffix() const {
// If the match results are not ready, this will return a default-constructed empty `__suffix_`.
_LIBCPP_ASSERT_PEDANTIC(ready(), "match_results::suffix() called when not ready");
return __suffix_;
}
- _LIBCPP_HIDE_FROM_ABI const_iterator begin() const { return empty() ? __matches_.end() : __matches_.begin(); }
- _LIBCPP_HIDE_FROM_ABI const_iterator end() const { return __matches_.end(); }
- _LIBCPP_HIDE_FROM_ABI const_iterator cbegin() const { return empty() ? __matches_.end() : __matches_.begin(); }
- _LIBCPP_HIDE_FROM_ABI const_iterator cend() const { return __matches_.end(); }
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_iterator begin() const {
+ return empty() ? __matches_.end() : __matches_.begin();
+ }
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_iterator end() const { return __matches_.end(); }
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_iterator cbegin() const {
+ return empty() ? __matches_.end() : __matches_.begin();
+ }
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_iterator cend() const { return __matches_.end(); }
// format:
template <class _OutputIter>
@@ -4639,14 +4643,14 @@ public:
return format(__output_iter, __fmt.data(), __fmt.data() + __fmt.size(), __flags);
}
template <class _ST, class _SA>
- _LIBCPP_HIDE_FROM_ABI basic_string<char_type, _ST, _SA>
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI basic_string<char_type, _ST, _SA>
format(const basic_string<char_type, _ST, _SA>& __fmt,
regex_constants::match_flag_type __flags = regex_constants::format_default) const {
basic_string<char_type, _ST, _SA> __r;
format(std::back_inserter(__r), __fmt.data(), __fmt.data() + __fmt.size(), __flags);
return __r;
}
- _LIBCPP_HIDE_FROM_ABI string_type
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI string_type
format(const char_type* __fmt, regex_constants::match_flag_type __flags = regex_constants::format_default) const {
string_type __r;
format(std::back_inserter(__r), __fmt, __fmt + char_traits<char_type>::length(__fmt), __flags);
@@ -4654,7 +4658,7 @@ public:
}
// allocator:
- _LIBCPP_HIDE_FROM_ABI allocator_type get_allocator() const { return __matches_.get_allocator(); }
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI allocator_type get_allocator() const { return __matches_.get_allocator(); }
// swap:
void swap(match_results& __m);
@@ -5375,7 +5379,7 @@ public:
_LIBCPP_HIDE_FROM_ABI bool operator!=(const regex_iterator& __x) const { return !(*this == __x); }
# endif
- _LIBCPP_HIDE_FROM_ABI reference operator*() const { return __match_; }
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI reference operator*() const { return __match_; }
_LIBCPP_HIDE_FROM_ABI pointer operator->() const { return std::addressof(__match_); }
regex_iterator& operator++();
@@ -5556,7 +5560,7 @@ public:
_LIBCPP_HIDE_FROM_ABI bool operator!=(const regex_token_iterator& __x) const { return !(*this == __x); }
# endif
- _LIBCPP_HIDE_FROM_ABI const value_type& operator*() const { return *__result_; }
+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const value_type& operator*() const { return *__result_; }
_LIBCPP_HIDE_FROM_ABI const value_type* operator->() const { return __result_; }
regex_token_iterator& operator++();
diff --git a/libcxx/test/libcxx/diagnostics/regex.nodiscard.verify.cpp b/libcxx/test/libcxx/diagnostics/regex.nodiscard.verify.cpp
index 0959ec5e26bd6..1d989fe14b1f9 100644
--- a/libcxx/test/libcxx/diagnostics/regex.nodiscard.verify.cpp
+++ b/libcxx/test/libcxx/diagnostics/regex.nodiscard.verify.cpp
@@ -6,15 +6,77 @@
//
//===----------------------------------------------------------------------===//
-// UNSUPPORTED: c++03
+// REQUIRES: std-at-least-c++11
// UNSUPPORTED: no-localization
// check that <regex> functions are marked [[nodiscard]]
#include <regex>
+#include <string>
void test() {
- std::cmatch match_result;
- match_result.empty(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ {
+ std::basic_regex<char> re;
+
+ re.mark_count(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ re.flags(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+
+ re.imbue({}); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+
+ re.getloc(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ }
+ {
+ std::sub_match<const char*> sm;
+
+ sm.length(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ sm.str(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+
+ // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ sm.compare(sm);
+ // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ sm.compare(std::string{});
+ // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ sm.compare("");
+ }
+ {
+ std::match_results<const char*> m;
+
+ m.size(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ m.max_size(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ m.empty(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+
+ m.length(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ m.position(0); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ m.str(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ m[0]; // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+
+ m.prefix(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ m.suffix(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+
+ m.begin(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ m.end(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ m.cbegin(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ m.cend(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+
+ // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ m.format(std::string{});
+ // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ m.format("");
+ }
+ {
+ std::regex_iterator<const char*> ri;
+
+ *ri; // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ }
+ {
+ std::regex_token_iterator<const char*> rti;
+
+ *rti; // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ }
+ {
+ std::regex_error err{std::regex_constants::error_backref};
+
+ err.code(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ }
}
>From f766063241c3c08345ea087f8b21fab6d700c250 Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hristo.goshev.hristov at gmail.com>
Date: Sun, 14 Dec 2025 18:07:43 +0200
Subject: [PATCH 2/4] Apply suggestion from @H-G-Hristov
---
libcxx/test/libcxx/diagnostics/regex.nodiscard.verify.cpp | 1 -
1 file changed, 1 deletion(-)
diff --git a/libcxx/test/libcxx/diagnostics/regex.nodiscard.verify.cpp b/libcxx/test/libcxx/diagnostics/regex.nodiscard.verify.cpp
index 1d989fe14b1f9..a0623d3ead801 100644
--- a/libcxx/test/libcxx/diagnostics/regex.nodiscard.verify.cpp
+++ b/libcxx/test/libcxx/diagnostics/regex.nodiscard.verify.cpp
@@ -6,7 +6,6 @@
//
//===----------------------------------------------------------------------===//
-// REQUIRES: std-at-least-c++11
// UNSUPPORTED: no-localization
>From 2f0a9ff050b15d96d6381a619cb4247d4d755cf8 Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Sun, 14 Dec 2025 18:13:26 +0200
Subject: [PATCH 3/4] Addressed comment
---
libcxx/test/libcxx/diagnostics/regex.nodiscard.verify.cpp | 1 -
1 file changed, 1 deletion(-)
diff --git a/libcxx/test/libcxx/diagnostics/regex.nodiscard.verify.cpp b/libcxx/test/libcxx/diagnostics/regex.nodiscard.verify.cpp
index a0623d3ead801..b66d375817bb9 100644
--- a/libcxx/test/libcxx/diagnostics/regex.nodiscard.verify.cpp
+++ b/libcxx/test/libcxx/diagnostics/regex.nodiscard.verify.cpp
@@ -6,7 +6,6 @@
//
//===----------------------------------------------------------------------===//
-
// UNSUPPORTED: no-localization
// check that <regex> functions are marked [[nodiscard]]
>From 55067333ae2553a44a141ca6acef80812f83b075 Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Sun, 14 Dec 2025 18:38:12 +0200
Subject: [PATCH 4/4] Enable in C++03
---
.../test/libcxx/diagnostics/regex.nodiscard.verify.cpp | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)
diff --git a/libcxx/test/libcxx/diagnostics/regex.nodiscard.verify.cpp b/libcxx/test/libcxx/diagnostics/regex.nodiscard.verify.cpp
index b66d375817bb9..167a2bca1cb28 100644
--- a/libcxx/test/libcxx/diagnostics/regex.nodiscard.verify.cpp
+++ b/libcxx/test/libcxx/diagnostics/regex.nodiscard.verify.cpp
@@ -10,6 +10,7 @@
// check that <regex> functions are marked [[nodiscard]]
+#include <locale>
#include <regex>
#include <string>
@@ -20,7 +21,8 @@ void test() {
re.mark_count(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
re.flags(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
- re.imbue({}); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ re.imbue(std::locale());
re.getloc(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
}
@@ -33,7 +35,7 @@ void test() {
// expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
sm.compare(sm);
// expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
- sm.compare(std::string{});
+ sm.compare(std::string());
// expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
sm.compare("");
}
@@ -58,7 +60,7 @@ void test() {
m.cend(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
// expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
- m.format(std::string{});
+ m.format(std::string());
// expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
m.format("");
}
@@ -73,7 +75,7 @@ void test() {
*rti; // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
}
{
- std::regex_error err{std::regex_constants::error_backref};
+ std::regex_error err(std::regex_constants::error_backref);
err.code(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
}
More information about the libcxx-commits
mailing list