https://gcc.gnu.org/bugzilla/show_bug.cgi?id=119748
Bug ID: 119748 Summary: std::string::string(InputIterator, InputIterator) rejects volatile charT* as iterator Product: gcc Version: unknown Status: UNCONFIRMED Keywords: rejects-valid Severity: normal Priority: P3 Component: libstdc++ Assignee: unassigned at gcc dot gnu.org Reporter: redi at gcc dot gnu.org CC: hewillk at gmail dot com Target Milestone: --- #include <string> volatile char vs[42] = {}; std::string s(std::begin(vs), std::end(vs)); // ? On trunk this fails because my r15-9381-g648d5c26e25497 assumes that a contiguous iterator with value_type of char will give us a const char*, but that's not true for a pointer to volatile char. With that fixed, it fails for the same reason as GCC 14 and all previous releases: include/c++/14.2.1/bits/cow_string.h:426:32: error: binding reference of type 'const std::char_traits<char>::char_type&' {aka 'const char&'} to 'volatile char' discards qualifiers 426 | traits_type::assign(*__p, *__k1); // These types are off. | ~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~ *__k1 gives us volatile char& which cannot bind to const char& This explains the "These types are off" comment which has been there for decades! For X(i, j) the sequence requirements only require that "T is Cpp17EmplaceConstructible into X from *i" and that means that *i is not required to be implicitly convertible to the container's value_type, an explicit conversion might be required. So the fix is: --- a/libstdc++-v3/include/bits/basic_string.h +++ b/libstdc++-v3/include/bits/basic_string.h @@ -489,7 +489,8 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 _S_copy(__p, std::__niter_base(__k1), __k2 - __k1); #if __cpp_lib_concepts else if constexpr (contiguous_iterator<_Iterator> - && is_same_v<iter_value_t<_Iterator>, _CharT>) + && requires { { std::to_address(__k1) } + -> convertible_to<const _CharT*>; }) { const auto __d = __k2 - __k1; (void) (__k1 + __d); // See P3349R1 @@ -498,8 +499,8 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 #endif else #endif - for (; __k1 != __k2; ++__k1, (void)++__p) - traits_type::assign(*__p, *__k1); // These types are off. + for (; __k1 != __k2; ++__k1, (void)++__p) + traits_type::assign(*__p, static_cast<_CharT>(*__k1)); } #pragma GCC diagnostic pop