When using recent libstc++ trunk with Clang in C++20 mode, std::u16string literals as in

#include <string>
int main() {
  using namespace std::literals;
  u""s;
}

started to cause linker failures due to undefined

_ZNSt7__cxx1112basic_stringIDsSt11char_traitsIDsESaIDsEE12_M_constructIPKDsEEvT_S8_St20forward_iterator_tag

After some head scratching, I found the more insightful

$ cat test.cc
#include <string>
constexpr std::string s("", 0);

$ clang++ -std=c++20 -fsyntax-only test.cc
test.cc:2:23: error: constexpr variable 's' must be initialized by a constant 
expression
constexpr std::string s("", 0);
                      ^~~~~~~~
~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/12.0.0/../../../../include/c++/12.0.0/bits/basic_string.h:620:2:
 note: undefined function '_M_construct<const char *>' cannot be used in a 
constant expression
        _M_construct(__s, __s + __n, std::forward_iterator_tag());
        ^
test.cc:2:23: note: in call to 'basic_string(&""[0], 0, std::allocator<char>())'
constexpr std::string s("", 0);
                      ^
~/gcc/trunk/inst/lib/gcc/x86_64-pc-linux-gnu/12.0.0/../../../../include/c++/12.0.0/bits/basic_string.h:331:9:
 note: declared here
        _M_construct(_FwdIterator __beg, _FwdIterator __end,
        ^
1 error generated.

and after some more head scratching found Clang to complain about the reduced

template<typename> struct S {
    constexpr void f();
    constexpr S() { f(); };
};
S<void> s1;
template<typename T> constexpr void S<T>::f() {}
constexpr S<void> s2;

(about which GCC does not complain). Not entirely sure who is right, but what would help Clang is to move the definitions of the literal operators in basic_string.h (which implicitly instantiate the corresponding std::basic_string<_Tp> constructor) past the definition of _M_construct (which is called from the constructor) in basic_string.tcc; something like

diff --git a/libstdc++-v3/include/bits/basic_string.h 
b/libstdc++-v3/include/bits/basic_string.h
index 6e7de738308..871ca89e16e 100644
--- a/libstdc++-v3/include/bits/basic_string.h
+++ b/libstdc++-v3/include/bits/basic_string.h
@@ -4304,55 +4304,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     struct __is_fast_hash<hash<u32string>> : std::false_type
     { };
-#if __cplusplus >= 201402L
-
-#define __cpp_lib_string_udls 201304
-
-  inline namespace literals
-  {
-  inline namespace string_literals
-  {
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wliteral-suffix"
-
-#if __cpp_lib_constexpr_string >= 201907L
-# define _GLIBCXX_STRING_CONSTEXPR constexpr
-#else
-# define _GLIBCXX_STRING_CONSTEXPR
-#endif
-
-    _GLIBCXX_DEFAULT_ABI_TAG _GLIBCXX_STRING_CONSTEXPR
-    inline basic_string<char>
-    operator""s(const char* __str, size_t __len)
-    { return basic_string<char>{__str, __len}; }
-
-    _GLIBCXX_DEFAULT_ABI_TAG _GLIBCXX_STRING_CONSTEXPR
-    inline basic_string<wchar_t>
-    operator""s(const wchar_t* __str, size_t __len)
-    { return basic_string<wchar_t>{__str, __len}; }
-
-#ifdef _GLIBCXX_USE_CHAR8_T
-    _GLIBCXX_DEFAULT_ABI_TAG _GLIBCXX_STRING_CONSTEXPR
-    inline basic_string<char8_t>
-    operator""s(const char8_t* __str, size_t __len)
-    { return basic_string<char8_t>{__str, __len}; }
-#endif
-
-    _GLIBCXX_DEFAULT_ABI_TAG _GLIBCXX_STRING_CONSTEXPR
-    inline basic_string<char16_t>
-    operator""s(const char16_t* __str, size_t __len)
-    { return basic_string<char16_t>{__str, __len}; }
-
-    _GLIBCXX_DEFAULT_ABI_TAG _GLIBCXX_STRING_CONSTEXPR
-    inline basic_string<char32_t>
-    operator""s(const char32_t* __str, size_t __len)
-    { return basic_string<char32_t>{__str, __len}; }
-
-#undef _GLIBCXX_STRING_CONSTEXPR
-#pragma GCC diagnostic pop
-  } // inline namespace string_literals
-  } // inline namespace literals
-
 #if __cplusplus >= 201703L
   namespace __detail::__variant
   {
@@ -4369,7 +4320,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       { };
   }  // namespace __detail::__variant
 #endif // C++17
-#endif // C++14
_GLIBCXX_END_NAMESPACE_VERSION
 } // namespace std
diff --git a/libstdc++-v3/include/bits/basic_string.tcc 
b/libstdc++-v3/include/bits/basic_string.tcc
index 6f619a08f70..2fd607ef50a 100644
--- a/libstdc++-v3/include/bits/basic_string.tcc
+++ b/libstdc++-v3/include/bits/basic_string.tcc
@@ -1123,6 +1123,57 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #endif // _GLIBCXX_USE_WCHAR_T
 #endif // _GLIBCXX_EXTERN_TEMPLATE
+#if __cplusplus >= 201402L
+
+#define __cpp_lib_string_udls 201304
+
+  inline namespace literals
+  {
+  inline namespace string_literals
+  {
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wliteral-suffix"
+
+#if __cpp_lib_constexpr_string >= 201907L
+# define _GLIBCXX_STRING_CONSTEXPR constexpr
+#else
+# define _GLIBCXX_STRING_CONSTEXPR
+#endif
+
+    _GLIBCXX_DEFAULT_ABI_TAG _GLIBCXX_STRING_CONSTEXPR
+    inline basic_string<char>
+    operator""s(const char* __str, size_t __len)
+    { return basic_string<char>{__str, __len}; }
+
+    _GLIBCXX_DEFAULT_ABI_TAG _GLIBCXX_STRING_CONSTEXPR
+    inline basic_string<wchar_t>
+    operator""s(const wchar_t* __str, size_t __len)
+    { return basic_string<wchar_t>{__str, __len}; }
+
+#ifdef _GLIBCXX_USE_CHAR8_T
+    _GLIBCXX_DEFAULT_ABI_TAG _GLIBCXX_STRING_CONSTEXPR
+    inline basic_string<char8_t>
+    operator""s(const char8_t* __str, size_t __len)
+    { return basic_string<char8_t>{__str, __len}; }
+#endif
+
+    _GLIBCXX_DEFAULT_ABI_TAG _GLIBCXX_STRING_CONSTEXPR
+    inline basic_string<char16_t>
+    operator""s(const char16_t* __str, size_t __len)
+    { return basic_string<char16_t>{__str, __len}; }
+
+    _GLIBCXX_DEFAULT_ABI_TAG _GLIBCXX_STRING_CONSTEXPR
+    inline basic_string<char32_t>
+    operator""s(const char32_t* __str, size_t __len)
+    { return basic_string<char32_t>{__str, __len}; }
+
+#undef _GLIBCXX_STRING_CONSTEXPR
+#pragma GCC diagnostic pop
+  } // inline namespace string_literals
+  } // inline namespace literals
+
+#endif // C++14
+
 _GLIBCXX_END_NAMESPACE_VERSION
 } // namespace std

Reply via email to