]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
libstdc++: Set active member of union in std::string [PR103295]
authorJonathan Wakely <jwakely@redhat.com>
Wed, 17 Nov 2021 10:23:14 +0000 (10:23 +0000)
committerJonathan Wakely <jwakely@redhat.com>
Wed, 17 Nov 2021 17:21:25 +0000 (17:21 +0000)
Clang diagnoses that the new constexpr std::string constructors are not
usable in constant expressions, because they start to write to members
of the union without setting an active member.

This adds a new helper function which returns the address of the local
buffer after making it the active member.

This doesn't fix all problems with Clang, because it still refuses to
write to memory returned by the allocator.

libstdc++-v3/ChangeLog:

PR libstdc++/103295
* include/bits/basic_string.h (_M_use_local_data()): New
member function to make local buffer the active member.
(assign(const basic_string&)): Use it.
* include/bits/basic_string.tcc (_M_construct, reserve()):
Likewise.

libstdc++-v3/include/bits/basic_string.h
libstdc++-v3/include/bits/basic_string.tcc

index 0b7d6c0a98181a817b5b31e7d20c5d19ff0a0252..9d281f5daf28297a49142da9de358f7f5d2ba834 100644 (file)
@@ -325,6 +325,19 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
       _M_get_allocator() const
       { return _M_dataplus; }
 
+      // Ensure that _M_local_buf is the active member of the union.
+      __attribute__((__always_inline__))
+      _GLIBCXX14_CONSTEXPR
+      pointer
+      _M_use_local_data() _GLIBCXX_NOEXCEPT
+      {
+#if __cpp_lib_is_constant_evaluated
+       if (__builtin_is_constant_evaluated())
+         _M_local_buf[0] = _CharT();
+#endif
+       return _M_local_data();
+      }
+
     private:
 
 #ifdef _GLIBCXX_DISAMBIGUATE_REPLACE_INST
@@ -1487,7 +1500,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
                if (__str.size() <= _S_local_capacity)
                  {
                    _M_destroy(_M_allocated_capacity);
-                   _M_data(_M_local_data());
+                   _M_data(_M_use_local_data());
                    _M_set_length(0);
                  }
                else
index 5743770b42a8db2980f18094534366d1091eaa3d..5a51f7e21b5f9df84dc823a0e5f9c7b4e39c571a 100644 (file)
@@ -170,9 +170,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
        size_type __len = 0;
        size_type __capacity = size_type(_S_local_capacity);
 
+       pointer __p = _M_use_local_data();
+
        while (__beg != __end && __len < __capacity)
          {
-           _M_data()[__len++] = *__beg;
+           __p[__len++] = *__beg;
            ++__beg;
          }
 
@@ -223,6 +225,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
            _M_data(_M_create(__dnew, size_type(0)));
            _M_capacity(__dnew);
          }
+       else
+         _M_use_local_data();
 
        // Check for out_of_range and length_error exceptions.
        __try
@@ -247,6 +251,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
          _M_data(_M_create(__n, size_type(0)));
          _M_capacity(__n);
        }
+      else
+       _M_use_local_data();
 
       if (__n)
        this->_S_assign(_M_data(), __n, __c);
@@ -355,7 +361,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
       if (__length <= size_type(_S_local_capacity))
        {
-         this->_S_copy(_M_local_data(), _M_data(), __length + 1);
+         this->_S_copy(_M_use_local_data(), _M_data(), __length + 1);
          _M_destroy(__capacity);
          _M_data(_M_local_data());
        }