[libcxx-commits] [libcxx] [libc++][regex] Applied `[[nodiscard]]` (PR #170974)
Hristo Hristov via libcxx-commits
libcxx-commits at lists.llvm.org
Sat Dec 6 01:57:38 PST 2025
https://github.com/H-G-Hristov created https://github.com/llvm/llvm-project/pull/170974
`[[nodiscard]]` should be applied to functions where discarding the return value is most likely a correctness issue.
- https://libcxx.llvm.org/CodingGuidelines.html
>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] [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}}
+ }
}
More information about the libcxx-commits
mailing list