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

Reply via email to