Implement LWG-4259 P1148R0 changed the return values of searching functions of std::basic_string on some platforms#6236
Implement LWG-4259 P1148R0 changed the return values of searching functions of std::basic_string on some platforms#6236YexuanXiao wants to merge 3 commits intomicrosoft:mainfrom
std::basic_string on some platforms#6236Conversation
…nctions of std::basic_string on some platforms
std::basic_string on some platforms
There was a problem hiding this comment.
Pull request overview
Implements the LWG-4259/P1148R0 behavior change so std::basic_string searching functions return basic_string::npos (not a truncated size_t(-1)/string_view::npos) when basic_string::size_type is wider than size_t, and adds a regression test for that scenario.
Changes:
- Add an internal helper to cast search results from
size_ttobasic_string::size_type, mappingsize_t(-1)tobasic_string::nposwhen needed. - Update all
basic_stringsearch-family functions (find*/rfind*) to use the helper. - Add a test using a custom allocator with a wider
size_typeto validatenposreturn values.
Show a summary per file
| File | Description |
|---|---|
| tests/std/tests/GH_005546_containers_size_type_cast/test.cpp | Adds a wide-size_type allocator + new test cases covering basic_string search functions returning npos. |
| stl/inc/xstring | Fixes return-value casting for basic_string searching functions when size_type is wider than size_t. |
Copilot's findings
Tip
Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Files reviewed: 2/2 changed files
- Comments generated: 3
| constexpr T* allocate(size_type n) { | ||
| return allocator<T>{}.allocate(static_cast<size_t>(n)); | ||
| } | ||
| constexpr void deallocate(T* p, size_type n) noexcept { |
There was a problem hiding this comment.
WideSizeAllocator::allocate/deallocate are declared constexpr unconditionally, but they call std::allocator<T>::allocate/deallocate, which isn't constexpr before C++20. This can make pre-C++20 builds ill-formed even if these functions are never used in a constant expression. Use the existing CONSTEXPR20 macro for these member functions (and consider calling check_alloc_in_range_of_size_t(n) before the size_t cast to avoid silent truncation, matching redifference_allocator).
| constexpr T* allocate(size_type n) { | |
| return allocator<T>{}.allocate(static_cast<size_t>(n)); | |
| } | |
| constexpr void deallocate(T* p, size_type n) noexcept { | |
| CONSTEXPR20 T* allocate(size_type n) { | |
| check_alloc_in_range_of_size_t(n); | |
| return allocator<T>{}.allocate(static_cast<size_t>(n)); | |
| } | |
| CONSTEXPR20 void deallocate(T* p, size_type n) noexcept { | |
| check_alloc_in_range_of_size_t(n); |
| template <typename T = char> | ||
| struct WideSizeAllocator { | ||
| using value_type = T; | ||
| using size_type = unsigned long long; | ||
|
|
There was a problem hiding this comment.
WideSizeAllocator doesn't define allocator equality (operator==/!=). Allocators used with standard containers are expected to be equality comparable, and basic_string operations may instantiate allocator comparisons (e.g. swap/move assignment) even if this test currently doesn't. Consider adding the same style of friend constexpr bool operator== (and != when needed) used by redifference_allocator earlier in this file.
| _NODISCARD static _CONSTEXPR20 size_type _Find_result_cast(const size_t _Off) noexcept { | ||
| if constexpr (sizeof(size_type) > sizeof(size_t)) { // only happens on 32-bit platforms with 64-bit size_type | ||
| if (_Off == static_cast<size_t>(-1)) { | ||
| return npos; | ||
| } | ||
| } | ||
| return static_cast<size_type>(_Off); |
There was a problem hiding this comment.
_Find_result_cast takes a parameter named _Off, but it is the result from the internal _Traits_* search helpers, not an offset. Renaming the parameter (e.g. _Result/_Pos) would make the intent clearer and reduce the chance of accidental misuse when additional callers are added.
| _NODISCARD static _CONSTEXPR20 size_type _Find_result_cast(const size_t _Off) noexcept { | |
| if constexpr (sizeof(size_type) > sizeof(size_t)) { // only happens on 32-bit platforms with 64-bit size_type | |
| if (_Off == static_cast<size_t>(-1)) { | |
| return npos; | |
| } | |
| } | |
| return static_cast<size_type>(_Off); | |
| _NODISCARD static _CONSTEXPR20 size_type _Find_result_cast(const size_t _Result) noexcept { | |
| if constexpr (sizeof(size_type) > sizeof(size_t)) { // only happens on 32-bit platforms with 64-bit size_type | |
| if (_Result == static_cast<size_t>(-1)) { | |
| return npos; | |
| } | |
| } | |
| return static_cast<size_type>(_Result); |
Fixes #6208.