Closed H-G-Hristov closed 3 months ago
@llvm/pr-subscribers-libcxx
Author: Hristo Hristov (H-G-Hristov)
:white_check_mark: With the latest revision this PR passed the Python code formatter.
Thanks for working on this. In general it looks correct, but I wonder whether you considered the performance of the wording in the paper.
The paper explicitly states it does not consider this at all for the wording, see https://isocpp.org/files/papers/P2591R5.html#minimizingallocations. There is a link to https://github.com/llvm/llvm-project/blob/llvmorg-14.0.0/libcxx/include/string#L4218.
The paper also mentions an implementation by @hawkinsw (main...hawkinsw:llvm-project:P2591_string_view_concatenation) which at first glance did performance optimizations.
@hawkinsw did you benchmark your implementation?
I did not, only because we were just doing it for "fun" at that point. Now that there is wider interest, I would be more than happy to do those benchmarks. I will respond as soon as I can!
(Note I read about the performance part in the paper after I already left some performance comments.)
@mordante @frederick-vs-ja Thank you for the feedback. I have encountered two issues.
Projects/llvm-project/build/default.debug.libcxx/include/c++/v1/__memory/compressed_pair.h:142:5: note: constexpr evaluation hit maximum step limit; possible infinite loop?
# | 142 | return static_cast<_Base2 const&>(*this).__get();
constexpr_char_traits
when I concatenate StringView + String
, so I used the @hawkinsw implementation (Thanks!) more of a workaround rather than optimization in the current iteration (I mean I haven't done any benchmarks yet):constexpr_char_traits.h:105:12: note: comparison between '&__r.__r_.__compressed_pair_elem::__value_.__compressed_pair_elem::union (anonymous union at /include/c++/v1/string:867:5).__compressed_pair_elem::__s.__compressed_pair_elem::__data_[0]' and '&"short"[0]' has unspecified value
# | 105 | if (s1 < s2)
# | | ^
(this feels like a bug) which is even odder I am not able to reproduce the same behavior on compiler explorer
@mordante @frederick-vs-ja Thank you for the feedback. I have encountered two issues.
* Adding another step of indirection to the tests causes _constexpr evaluation hit maximum step limit; possible infinite loop_. I haven't seen this before, so I refactored the tests to use one less step:
Projects/llvm-project/build/default.debug.libcxx/include/c++/v1/__memory/compressed_pair.h:142:5: note: constexpr evaluation hit maximum step limit; possible infinite loop? # | 142 | return static_cast<_Base2 const&>(*this).__get();
* The second issue is that if I use the paper wording in the code base for the implementation is that I get a compiler error with `constexpr_char_traits` when I concatenate `StringView + String`, so I used the @hawkinsw implementation (Thanks!) more of a workaround rather than optimization in the current iteration (I mean I haven't done any benchmarks yet):
constexpr_char_traits.h:105:12: note: comparison between '&__r.__r_.__compressed_pair_elem::__value_.__compressed_pair_elem::union (anonymous union at /include/c++/v1/string:867:5).__compressed_pair_elem::__s.__compressed_pair_elem::__data_[0]' and '&"short"[0]' has unspecified value # | 105 | if (s1 < s2) # | | ^
(this feels like a bug) which is even odder I am not able to reproduce the same behavior on compiler explorer
Can you create a new branch in your repository with these issues and post the branch name here? Then I want to take a look at both issues. There is a work-around for the step limit; but based on how simple the tests are I wonder whether it's not infinite recursion.
@mordante @frederick-vs-ja Thank you for the feedback. I have encountered two issues.
* Adding another step of indirection to the tests causes _constexpr evaluation hit maximum step limit; possible infinite loop_. I haven't seen this before, so I refactored the tests to use one less step:
Projects/llvm-project/build/default.debug.libcxx/include/c++/v1/__memory/compressed_pair.h:142:5: note: constexpr evaluation hit maximum step limit; possible infinite loop? # | 142 | return static_cast<_Base2 const&>(*this).__get();
* The second issue is that if I use the paper wording in the code base for the implementation is that I get a compiler error with `constexpr_char_traits` when I concatenate `StringView + String`, so I used the @hawkinsw implementation (Thanks!) more of a workaround rather than optimization in the current iteration (I mean I haven't done any benchmarks yet):
This is so cool. Thank you @H-G-Hristov! I am more than happy to help with benchmarking. I will be able to start work on it tonight -- sorry for the delay!
Will
constexpr_char_traits.h:105:12: note: comparison between '&__r.__r_.__compressed_pair_elem::__value_.__compressed_pair_elem::union (anonymous union at /include/c++/v1/string:867:5).__compressed_pair_elem::__s.__compressed_pair_elem::__data_[0]' and '&"short"[0]' has unspecified value # | 105 | if (s1 < s2) # | | ^
(this feels like a bug) which is even odder I am not able to reproduce the same behavior on compiler explorer
Can you create a new branch in your repository with these issues and post the branch name here? Then I want to take a look at both issues. There is a work-around for the step limit; but based on how simple the tests are I wonder whether it's not infinite recursion.
@mordante Thank you for helping!
I use the pre-compiled LLVM-19 packages on Ubuntu. I have created two branches one for each issue:
More details:
This branch should demonstrate the constexpr_char_traits
issue:
https://github.com/llvm/llvm-project/compare/main...H-G-Hristov:llvm-project:hgh/libcxx/P2591R5-Concatenation-of-string-and-string-views-ERROR-constexpr_char_traits
# .---command stderr------------
# | /home//Projects/llvm-project/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string.string_view.pass.cpp:154:17: error: static assertion expression is not an integral constant expression
# | 154 | static_assert(test<char>());
# | | ^~~~~~~~~~~~
# | /home/hristo/Projects/llvm-project/libcxx/test/support/constexpr_char_traits.h:105:12: note: comparison between '&__r.__r_.__compressed_pair_elem::__value_.__compressed_pair_elem::union (anonymous union at /home/hristo/Projects/llvm-project/build/default.debug.libcxx/include/c++/v1/string:868:5).__compressed_pair_elem::__s.__compressed_pair_elem::__data_[0]' and '&"short"[0]' has unspecified value
# | 105 | if (s1 < s2)
# | | ^
# | /home//Projects/llvm-project/build/default.debug.libcxx/include/c++/v1/string:2902:7: note: in call to 'move(&__r.__r_.__compressed_pair_elem::__value_.__compressed_pair_elem::union (anonymous union at /home/hristo/Projects/llvm-project/build/default.debug.libcxx/include/c++/v1/string:868:5).__compressed_pair_elem::__s.__compressed_pair_elem::__data_[0], &"short"[0], 5)'
# | 2902 | traits_type::move(__p + __pos, __s, __n);
# | | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# | /home//Projects/llvm-project/build/default.debug.libcxx/include/c++/v1/string:1478:12: note: in call to 'this->insert(0, &"short"[0], 5)'
# | 1478 | return insert(__pos1, __sv.data(), __sv.size());
# | | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# | /home//Projects/llvm-project/build/default.debug.libcxx/include/c++/v1/string:4048:3: note: in call to '__r.insert<std::basic_string_view<char, constexpr_char_traits<char>>, 0>(0, __lhs)'
# | 4048 | __r.insert(0, __lhs);
# | | ^~~~~~~~~~~~~~~~~~~~
# | /home//Projects/llvm-project/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string.string_view.pass.cpp:87:85: note: in call to 'operator+<char, constexpr_char_traits<char>, std::allocator<char>>({&"short"[0], 5}, st)'
# | 87 | std::same_as<std::basic_string<CharT, TraitsT, AllocT>> decltype(auto) result = sv + st;
# | | ^~~~~~~
# | /home//Projects/llvm-project/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string.string_view.pass.cpp:123:3: note: in call to 'test<char, constexpr_char_traits<char>, std::allocator<char>>(&"short"[0], &""[0], &"short"[0])'
# | 123 | test<CharT, TraitsT, AllocT>(CS("short"), CS(""), CS("short"));
# | | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# | /home//Projects/llvm-project/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string.string_view.pass.cpp:144:3: note: in call to 'test<char, constexpr_char_traits<char>, std::allocator<char>>()'
# | 144 | test<CharT, constexpr_char_traits<CharT>>();
# | | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# | /home//Projects/llvm-project/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string.string_view.pass.cpp:154:17: note: in call to 'test<char>()'
# | 154 | static_assert(test<char>());
# | | ^~~~~~~~~~~~
# | /home//Projects/llvm-project/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string.string_view.pass.cpp:157:17: error: static assertion expression is not an integral constant expression
# | 157 | static_assert(test<wchar_t>());
# | | ^~~~~~~~~~~~~~~
# | /home//Projects/llvm-project/libcxx/test/support/constexpr_char_traits.h:105:12: note: comparison between '&__r.__r_.__compressed_pair_elem::__value_.__compressed_pair_elem::union (anonymous union at /home/hristo/Projects/llvm-project/build/default.debug.libcxx/include/c++/v1/string:868:5).__compressed_pair_elem::__s.__compressed_pair_elem::__data_[0]' and '&L"B"[0]' has unspecified value
# | 105 | if (s1 < s2)
# | | ^
# | /home//Projects/llvm-project/build/default.debug.libcxx/include/c++/v1/string:2902:7: note: in call to 'move(&__r.__r_.__compressed_pair_elem::__value_.__compressed_pair_elem::union (anonymous union at /home/hristo/Projects/llvm-project/build/default.debug.libcxx/include/c++/v1/string:868:5).__compressed_pair_elem::__s.__compressed_pair_elem::__data_[0], &L"B"[0], 1)'
# | 2902 | traits_type::move(__p + __pos, __s, __n);
# | | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# | /home//Projects/llvm-project/build/default.debug.libcxx/include/c++/v1/string:1478:12: note: in call to 'this->insert(0, &L"B"[0], 1)'
# | 1478 | return insert(__pos1, __sv.data(), __sv.size());
# | | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# | /home//Projects/llvm-project/build/default.debug.libcxx/include/c++/v1/string:4048:3: note: in call to '__r.insert<std::basic_string_view<wchar_t, constexpr_char_traits<wchar_t>>, 0>(0, __lhs)'
# | 4048 | __r.insert(0, __lhs);
# | | ^~~~~~~~~~~~~~~~~~~~
# | /home//Projects/llvm-project/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string.string_view.pass.cpp:87:85: note: in call to 'operator+<wchar_t, constexpr_char_traits<wchar_t>, std::allocator<wchar_t>>({&L"B"[0], 1}, st)'
# | 87 | std::same_as<std::basic_string<CharT, TraitsT, AllocT>> decltype(auto) result = sv + st;
# | | ^~~~~~~
# | /home//Projects/llvm-project/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string.string_view.pass.cpp:128:3: note: in call to 'test<wchar_t, constexpr_char_traits<wchar_t>, std::allocator<wchar_t>>(&L"B"[0], &L"D"[0], &L"BD"[0])'
# | 128 | test<CharT, TraitsT, AllocT>(CS("B"), CS("D"), CS("BD"));
# | | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# | /home/hristo/Projects/llvm-project/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string.string_view.pass.cpp:144:3: note: in call to 'test<wchar_t, constexpr_char_traits<wchar_t>, std::allocator<wchar_t>>()'
# | 144 | test<CharT, constexpr_char_traits<CharT>>();
# | | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# | /home//Projects/llvm-project/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string.string_view.pass.cpp:157:17: note: in call to 'test<wchar_t>()'
# | 157 | static_assert(test<wchar_t>());
# | | ^~~~~~~~~~~~~~~
# | /home//Projects/llvm-project/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string.string_view.pass.cpp:161:17: error: static assertion expression is not an integral constant expression
# | 161 | static_assert(test<char8_t>());
# | | ^~~~~~~~~~~~~~~
# | /home//Projects/llvm-project/libcxx/test/support/constexpr_char_traits.h:105:12: note: comparison between '&__r.__r_.__compressed_pair_elem::__value_.__compressed_pair_elem::union (anonymous union at /home/hristo/Projects/llvm-project/build/default.debug.libcxx/include/c++/v1/string:868:5).__compressed_pair_elem::__s.__compressed_pair_elem::__data_[0]' and '&u8"short"[0]' has unspecified value
# | 105 | if (s1 < s2)
# | | ^
# | /home//Projects/llvm-project/build/default.debug.libcxx/include/c++/v1/string:2902:7: note: in call to 'move(&__r.__r_.__compressed_pair_elem::__value_.__compressed_pair_elem::union (anonymous union at /home/hristo/Projects/llvm-project/build/default.debug.libcxx/include/c++/v1/string:868:5).__compressed_pair_elem::__s.__compressed_pair_elem::__data_[0], &u8"short"[0], 5)'
# | 2902 | traits_type::move(__p + __pos, __s, __n);
# | | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# | /home//Projects/llvm-project/build/default.debug.libcxx/include/c++/v1/string:1478:12: note: in call to 'this->insert(0, &u8"short"[0], 5)'
# | 1478 | return insert(__pos1, __sv.data(), __sv.size());
# | | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# | /home//Projects/llvm-project/build/default.debug.libcxx/include/c++/v1/string:4048:3: note: in call to '__r.insert<std::basic_string_view<char8_t, constexpr_char_traits<char8_t>>, 0>(0, __lhs)'
# | 4048 | __r.insert(0, __lhs);
# | | ^~~~~~~~~~~~~~~~~~~~
# | /home//Projects/llvm-project/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string.string_view.pass.cpp:87:85: note: in call to 'operator+<char8_t, constexpr_char_traits<char8_t>, std::allocator<char8_t>>({&u8"short"[0], 5}, st)'
# | 87 | std::same_as<std::basic_string<CharT, TraitsT, AllocT>> decltype(auto) result = sv + st;
# | | ^~~~~~~
# | /home//Projects/llvm-project/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string.string_view.pass.cpp:123:3: note: in call to 'test<char8_t, constexpr_char_traits<char8_t>, std::allocator<char8_t>>(&u8"short"[0], &u8""[0], &u8"short"[0])'
# | 123 | test<CharT, TraitsT, AllocT>(CS("short"), CS(""), CS("short"));
# | | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# | /home//Projects/llvm-project/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string.string_view.pass.cpp:144:3: note: in call to 'test<char8_t, constexpr_char_traits<char8_t>, std::allocator<char8_t>>()'
# | 144 | test<CharT, constexpr_char_traits<CharT>>();
# | | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# | /home//Projects/llvm-project/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string.string_view.pass.cpp:161:17: note: in call to 'test<char8_t>()'
# | 161 | static_assert(test<char8_t>());
# | | ^~~~~~~~~~~~~~~
# | /home//Projects/llvm-project/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string.string_view.pass.cpp:164:17: error: static assertion expression is not an integral constant expression
# | 164 | static_assert(test<char16_t>());
# | | ^~~~~~~~~~~~~~~~
# | /home//Projects/llvm-project/libcxx/test/support/constexpr_char_traits.h:105:12: note: comparison between '&__r.__r_.__compressed_pair_elem::__value_.__compressed_pair_elem::union (anonymous union at /home/hristo/Projects/llvm-project/build/default.debug.libcxx/include/c++/v1/string:868:5).__compressed_pair_elem::__s.__compressed_pair_elem::__data_[0]' and '&u"short"[0]' has unspecified value
# | 105 | if (s1 < s2)
# | | ^
# | /home//Projects/llvm-project/build/default.debug.libcxx/include/c++/v1/string:2902:7: note: in call to 'move(&__r.__r_.__compressed_pair_elem::__value_.__compressed_pair_elem::union (anonymous union at /home/hristo/Projects/llvm-project/build/default.debug.libcxx/include/c++/v1/string:868:5).__compressed_pair_elem::__s.__compressed_pair_elem::__data_[0], &u"short"[0], 5)'
# | 2902 | traits_type::move(__p + __pos, __s, __n);
# | | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# | /home//Projects/llvm-project/build/default.debug.libcxx/include/c++/v1/string:1478:12: note: in call to 'this->insert(0, &u"short"[0], 5)'
# | 1478 | return insert(__pos1, __sv.data(), __sv.size());
# | | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# | /home//Projects/llvm-project/build/default.debug.libcxx/include/c++/v1/string:4048:3: note: in call to '__r.insert<std::basic_string_view<char16_t, constexpr_char_traits<char16_t>>, 0>(0, __lhs)'
# | 4048 | __r.insert(0, __lhs);
# | | ^~~~~~~~~~~~~~~~~~~~
# | /home//Projects/llvm-project/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string.string_view.pass.cpp:87:85: note: in call to 'operator+<char16_t, constexpr_char_traits<char16_t>, std::allocator<char16_t>>({&u"short"[0], 5}, st)'
# | 87 | std::same_as<std::basic_string<CharT, TraitsT, AllocT>> decltype(auto) result = sv + st;
# | | ^~~~~~~
# | /home//Projects/llvm-project/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string.string_view.pass.cpp:123:3: note: in call to 'test<char16_t, constexpr_char_traits<char16_t>, std::allocator<char16_t>>(&u"short"[0], &u""[0], &u"short"[0])'
# | 123 | test<CharT, TraitsT, AllocT>(CS("short"), CS(""), CS("short"));
# | | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# | /home//Projects/llvm-project/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string.string_view.pass.cpp:144:3: note: in call to 'test<char16_t, constexpr_char_traits<char16_t>, std::allocator<char16_t>>()'
# | 144 | test<CharT, constexpr_char_traits<CharT>>();
# | | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# | /home//Projects/llvm-project/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string.string_view.pass.cpp:164:17: note: in call to 'test<char16_t>()'
# | 164 | static_assert(test<char16_t>());
# | | ^~~~~~~~~~~~~~~~
# | /home//Projects/llvm-project/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string.string_view.pass.cpp:166:17: error: static assertion expression is not an integral constant expression
# | 166 | static_assert(test<char32_t>());
# | | ^~~~~~~~~~~~~~~~
# | /home//Projects/llvm-project/libcxx/test/support/constexpr_char_traits.h:105:12: note: comparison between '&__r.__r_.__compressed_pair_elem::__value_.__compressed_pair_elem::union (anonymous union at /home/hristo/Projects/llvm-project/build/default.debug.libcxx/include/c++/v1/string:868:5).__compressed_pair_elem::__s.__compressed_pair_elem::__data_[0]' and '&U"B"[0]' has unspecified value
# | 105 | if (s1 < s2)
# | | ^
# | /home//Projects/llvm-project/build/default.debug.libcxx/include/c++/v1/string:2902:7: note: in call to 'move(&__r.__r_.__compressed_pair_elem::__value_.__compressed_pair_elem::union (anonymous union at /home/hristo/Projects/llvm-project/build/default.debug.libcxx/include/c++/v1/string:868:5).__compressed_pair_elem::__s.__compressed_pair_elem::__data_[0], &U"B"[0], 1)'
# | 2902 | traits_type::move(__p + __pos, __s, __n);
# | | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# | /home//Projects/llvm-project/build/default.debug.libcxx/include/c++/v1/string:1478:12: note: in call to 'this->insert(0, &U"B"[0], 1)'
# | 1478 | return insert(__pos1, __sv.data(), __sv.size());
# | | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# | /home//Projects/llvm-project/build/default.debug.libcxx/include/c++/v1/string:4048:3: note: in call to '__r.insert<std::basic_string_view<char32_t, constexpr_char_traits<char32_t>>, 0>(0, __lhs)'
# | 4048 | __r.insert(0, __lhs);
# | | ^~~~~~~~~~~~~~~~~~~~
# | /home//Projects/llvm-project/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string.string_view.pass.cpp:87:85: note: in call to 'operator+<char32_t, constexpr_char_traits<char32_t>, std::allocator<char32_t>>({&U"B"[0], 1}, st)'
# | 87 | std::same_as<std::basic_string<CharT, TraitsT, AllocT>> decltype(auto) result = sv + st;
# | | ^~~~~~~
# | /home//Projects/llvm-project/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string.string_view.pass.cpp:128:3: note: in call to 'test<char32_t, constexpr_char_traits<char32_t>, std::allocator<char32_t>>(&U"B"[0], &U"D"[0], &U"BD"[0])'
# | 128 | test<CharT, TraitsT, AllocT>(CS("B"), CS("D"), CS("BD"));
# | | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# | /home//Projects/llvm-project/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string.string_view.pass.cpp:144:3: note: in call to 'test<char32_t, constexpr_char_traits<char32_t>, std::allocator<char32_t>>()'
# | 144 | test<CharT, constexpr_char_traits<CharT>>();
# | | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# | /home//Projects/llvm-project/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string.string_view.pass.cpp:166:17: note: in call to 'test<char32_t>()'
# | 166 | static_assert(test<char32_t>());
# | | ^~~~~~~~~~~~~~~~
# | 5 errors generated.
# `-----------------------------
# error: command failed with exit status: 1
--
********************
Testing: 0.. 10.. 20.. 30.. 40.. 50.. 60.. 70.. 80.. 90..
********************
Failed Tests (1):
llvm-libc++-shared.cfg.in :: std/strings/basic.string/string.nonmembers/string_op+/string.string_view.pass.cpp
This branch should demonstrate: constexpr evaluation hit maximum step limit; possible infinite loop?
# .---command stderr------------
# | /home//Projects/llvm-project/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string.string_view.pass.cpp:168:17: error: static assertion expression is not an integral constant expression
# | 168 | static_assert(test());
# | | ^~~~~~
# | /home//Projects/llvm-project/build/default.debug.libcxx/include/c++/v1/__memory/compressed_pair.h:142:5: note: constexpr evaluation hit maximum step limit; possible infinite loop?
# | 142 | return static_cast<_Base2 const&>(*this).__get();
# | | ^
# | /home/hristo/Projects/llvm-project/build/default.debug.libcxx/include/c++/v1/string:1882:100: note: in call to 'this->__r_.second()'
# | 1882 | _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR const allocator_type& __alloc() const _NOEXCEPT { return __r_.second(); }
# | | ^~~~~~~~~~~~~
# | /home//Projects/llvm-project/build/default.debug.libcxx/include/c++/v1/string:1661:12: note: in call to 'this->__alloc()'
# | 1661 | return __alloc();
# | | ^~~~~~~~~
# | /home//Projects/llvm-project/build/default.debug.libcxx/include/c++/v1/string:4056:80: note: in call to '__lhs.get_allocator()'
# | 4056 | _String::__alloc_traits::select_on_container_copy_construction(__lhs.get_allocator()));
# | | ^~~~~~~~~~~~~~~~~~~~~
# | /home//Projects/llvm-project/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string.string_view.pass.cpp:70:42: note: in call to 'operator+<wchar_t, std::char_traits<wchar_t>, test_allocator<wchar_t>>(st, {&L""[0], 0})'
# | 70 | LIBCPP_ASSERT(is_string_asan_correct(st + sv));
# | | ^~~~~~~
# | /home//Projects/llvm-project/libcxx/test/support/test_macros.h:242:35: note: expanded from macro 'LIBCPP_ASSERT'
# | 242 | #define LIBCPP_ASSERT(...) assert(__VA_ARGS__)
# | | ^~~~~~~~~~~
# | /usr/include/assert.h:93:27: note: expanded from macro 'assert'
# | 93 | (static_cast <bool> (expr) \
# | | ^~~~
# | /home//Projects/llvm-project/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string.string_view.pass.cpp:125:3: note: in call to 'test<wchar_t, std::char_traits<wchar_t>, test_allocator<wchar_t>>(&L"this is a much longer string"[0], &L""[0], &L"this is a much longer string"[0])'
# | 125 | test<CharT, TraitsT, AllocT>(CS("this is a much longer string"), CS(""), CS("this is a much longer string"));
# | | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# | /home//Projects/llvm-project/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string.string_view.pass.cpp:142:3: note: in call to 'test<wchar_t, std::char_traits<wchar_t>, test_allocator<wchar_t>>()'
# | 142 | test<CharT, std::char_traits<CharT>, test_allocator<CharT>>();
# | | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# | /home//Projects/llvm-project/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string.string_view.pass.cpp:155:3: note: in call to 'test<wchar_t>()'
# | 155 | test<wchar_t>();
# | | ^~~~~~~~~~~~~~~
# | /home/hristo/Projects/llvm-project/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/string.string_view.pass.cpp:168:17: note: in call to 'test()'
# | 168 | static_assert(test());
# | | ^~~~~~
# | 1 error generated.
# `-----------------------------
# error: command failed with exit status: 1
--
********************
Testing: 0.. 10.. 20.. 30.. 40.. 50.. 60.. 70.. 80.. 90..
********************
Failed Tests (1):
llvm-libc++-shared.cfg.in :: std/strings/basic.string/string.nonmembers/string_op+/string.string_view.pass.cpp
- The second issue is that if I use the paper wording in the code base for the implementation is that I get a compiler error with
constexpr_char_traits
when I concatenateStringView + String
, so I used the @hawkinsw implementation (Thanks!) more of a workaround rather than optimization in the current iteration (I mean I haven't done any benchmarks yet):
The second issue seems because of that constexpr_char_traits::move
compares potentially unrelated pointers s1
and s2
, which can cause constant evaluation failure when they're unrelated.
Error can be generated if we enforce constant evaluation (Godbolt link). It seems to me that we should fix constexpr_char_traits::move
.
This issue looks similar to #74221. I have an untested patch for that, but then other things came in between. I'll work on finishing that patch.
:white_check_mark: With the latest revision this PR passed the C/C++ code formatter.
@Zingam The LLVM-19 branching is in two weeks. It would be great if you have time to get this review done before that time. Is there a way for me to help you getting this done?
Sorry that I haven't been able to help as much on this as I would have liked. I will echo what @mordante said, "Is there anything that I can do to help?"
@mordante @hawkinsw Thank you for asking to help! I've been rather busy and unable to do much libc++ related work. It would be great to complete this PR in time for 19.0. What we have so far:
@mordante Is there anything else besides the benchmarks that you'd like to be addressed?
@Zingam The LLVM-19 branching is in two weeks. It would be great if you have time to get this review done before that time. Is there a way for me to help you getting this done?
I still cannot resolve the issue with building the benchmark:
$ ninja cxx-benchmarks [1/134] Performing configure step for 'google-benchmark-libcxx' ... -- Failed to find LLVM FileCheck -- Google Benchmark version: v0.0.0, normalized to 0.0.0 -- Enabling additional flags: -DINCLUDE_DIRECTORIES=/home//llvm-project/third-party/benchmark/include -- Performing Test HAVE_THREAD_SAFETY_ATTRIBUTES -- success -- Performing Test HAVE_STD_REGEX -- failed to compile -- Performing Test HAVE_GNU_POSIX_REGEX -- failed to compile -- Performing Test HAVE_POSIX_REGEX -- failed to compile CMake Error at CMakeLists.txt:315 (message): Failed to determine the source files for the regular expression backend
@Zingam The LLVM-19 branching is in two weeks. It would be great if you have time to get this review done before that time. Is there a way for me to help you getting this done?
I still cannot resolve the issue with building the benchmark:
$ ninja cxx-benchmarks [1/134] Performing configure step for 'google-benchmark-libcxx' ... -- Failed to find LLVM FileCheck -- Google Benchmark version: v0.0.0, normalized to 0.0.0 -- Enabling additional flags: -DINCLUDE_DIRECTORIES=/home//llvm-project/third-party/benchmark/include -- Performing Test HAVE_THREAD_SAFETY_ATTRIBUTES -- success -- Performing Test HAVE_STD_REGEX -- failed to compile -- Performing Test HAVE_GNU_POSIX_REGEX -- failed to compile -- Performing Test HAVE_POSIX_REGEX -- failed to compile
This looks very odd. I wonder whether this is a regex library issue or a different configuration error. I expect the latter since <regex>
is not available too.
@H-G-Hristov Thank you for doing the excellent work on this!
Implemented: https://wg21.link/P2591R5