-
Notifications
You must be signed in to change notification settings - Fork 15.2k
[libc++][string] Assert resize_and_overwrite operation returns integer-like type #162030
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
@llvm/pr-subscribers-libcxx Author: NagaChaitanya Vellanki (chaitanyav) ChangesVerify that the operation passed to resize_and_overwrite returns an integer-like type, matching the behavior of other standard library implementations like GCC's libstdc++ Fixes #160577 Full diff: https://github.com/llvm/llvm-project/pull/162030.diff 3 Files Affected:
diff --git a/libcxx/include/string b/libcxx/include/string
index dc562e0207630..00592e61547af 100644
--- a/libcxx/include/string
+++ b/libcxx/include/string
@@ -1311,6 +1311,8 @@ public:
# if _LIBCPP_STD_VER >= 23
template <class _Op>
_LIBCPP_HIDE_FROM_ABI constexpr void resize_and_overwrite(size_type __n, _Op __op) {
+ using __result_type = decltype(__op(data(), auto(__n)));
+ static_assert(std::__integer_like<__result_type>, "Operation return type must be integer-like");
size_type __sz = size();
size_type __cap = capacity();
if (__n > __cap)
diff --git a/libcxx/test/std/strings/basic.string/string.capacity/resize_and_overwrite.pass.cpp b/libcxx/test/std/strings/basic.string/string.capacity/resize_and_overwrite.pass.cpp
index abd284852a189..aa0b32bf3f589 100644
--- a/libcxx/test/std/strings/basic.string/string.capacity/resize_and_overwrite.pass.cpp
+++ b/libcxx/test/std/strings/basic.string/string.capacity/resize_and_overwrite.pass.cpp
@@ -90,6 +90,18 @@ void test_value_categories() {
LIBCPP_ASSERT(is_string_asan_correct(s));
}
+void test_integer_like_return_types() {
+ std::string s;
+ s.resize_and_overwrite(10, [](char*, std::size_t) -> int { return 5; });
+ s.resize_and_overwrite(10, [](char*, std::size_t) -> unsigned int { return 5u; });
+ s.resize_and_overwrite(10, [](char*, std::size_t) -> long { return 5l; });
+ s.resize_and_overwrite(10, [](char*, std::size_t) -> unsigned long { return 5ul; });
+ s.resize_and_overwrite(10, [](char*, std::size_t) -> long long { return 5ll; });
+ s.resize_and_overwrite(10, [](char*, std::size_t) -> unsigned long long { return 5ull; });
+ s.resize_and_overwrite(10, [](char*, std::size_t) -> std::size_t { return 5; });
+ s.resize_and_overwrite(10, [](char*, std::size_t) -> std::ptrdiff_t { return 5; });
+}
+
int main(int, char**) {
test<std::basic_string<char, std::char_traits<char>, std::allocator<char>>>();
test<std::basic_string<char8_t, std::char_traits<char8_t>, std::allocator<char8_t>>>();
@@ -105,5 +117,9 @@ int main(int, char**) {
test<std::basic_string<wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t>>>();
static_assert(test<std::basic_string<wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t>>>());
#endif
+
+ test_value_categories();
+ test_integer_like_return_types();
+
return 0;
}
diff --git a/libcxx/test/std/strings/basic.string/string.capacity/resize_and_overwrite.verify.cpp b/libcxx/test/std/strings/basic.string/string.capacity/resize_and_overwrite.verify.cpp
new file mode 100644
index 0000000000000..00d04e56a3aea
--- /dev/null
+++ b/libcxx/test/std/strings/basic.string/string.capacity/resize_and_overwrite.verify.cpp
@@ -0,0 +1,39 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <string>
+
+// template<class Operation>
+// void resize_and_overwrite(size_type n, Operation op)
+
+// Verify that the operation's return type must be integer-like
+
+#include <string>
+
+void test_bool_return_type() {
+ std::string s;
+ s.resize_and_overwrite(10, [](char*, std::size_t) {
+ return true; // expected-error-re@*:* {{{{(static_assertion|static assertion)}}{{.*}}integer-like}}
+ });
+}
+
+void test_pointer_return_type() {
+ std::string s;
+ s.resize_and_overwrite(10, [](char* p, std::size_t) {
+ return p; // expected-error-re@*:* {{{{(static_assertion|static assertion)}}{{.*}}integer-like}}
+ });
+}
+
+void test_float_return_type() {
+ std::string s;
+ s.resize_and_overwrite(10, [](char*, std::size_t) {
+ return 5.0f; // expected-error-re@*:* {{{{(static_assertion|static assertion)}}{{.*}}integer-like}}
+ });
+}
|
✅ With the latest revision this PR passed the C/C++ code formatter. |
…r-like type Verify that the operation passed to resize_and_overwrite returns an integer-like type, matching the behavior of other standard library implementations like GCC's libstdc++ Fixes llvm#160577
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM. CI failures are unrelated.
template <class _Op> | ||
_LIBCPP_HIDE_FROM_ABI constexpr void resize_and_overwrite(size_type __n, _Op __op) { | ||
using __result_type = decltype(std::move(__op)(data(), auto(__n))); | ||
static_assert(std::__integer_like<__result_type>, "Operation return type must be integer-like"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
static_assert(std::__integer_like<__result_type>, "Operation return type must be integer-like"); | |
static_assert(__integer_like<__result_type>, "Operation return type must be integer-like"); |
|
||
void test_integer_like_return_types() { | ||
std::string s; | ||
s.resize_and_overwrite(10, [](char*, std::size_t) -> int { return 5; }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These calls have UB, since you haven't initialized the elements you claim to have initialized. Also, can we return either the exact type or have explicit return types? We can also use types::for_each
with integer_types
here instead.
s.resize_and_overwrite(10, [](char*, std::size_t) -> std::size_t { return 5; }); | ||
s.resize_and_overwrite(10, [](char*, std::size_t) -> std::ptrdiff_t { return 5; }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These tests are entirely redundant.
test_value_categories(); | ||
test_integer_like_return_types(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These should also be run during constant evaluation.
Verify that the operation passed to resize_and_overwrite returns an integer-like type, matching the behavior of other standard library implementations like GCC's libstdc++
Fixes #160577