Description
This was first seen on Cygwin (x86_64-pc-windows-cygnus), where GCC is built with --with-default-libstdcxx-abi=gcc4-compatible
, but I reproduced it on x86_64-pc-windows-gnu as well, so I decided to report here.
Start with a mingw-w64 gcc built without --enable-fully-dynamic-string
configure argument, and possibly with --with-default-libstdcxx-abi=gcc4-compatible
. It should be possible to switch to the gcc4-compatible ABI with -D_GLIBCXX_USE_CXX11_ABI=0
if not built with that option.
The following test program aborts when built with -O2
, unless built with -std=c++20
or newer:
#include <stdio.h>
#include <string>
class foo
{
public:
foo() { m_str.assign("hello"); }
std::string m_str;
} bar;
int main()
{
printf("%ld - %s\n", __cplusplus, bar.m_str.c_str());
return 0;
}
Output of clang++ -O2 -S -o test.clang.s test.cpp
test.clang.s.txt
output of g++ -O2 -S -o test.gcc.s test.cpp
test.gcc.s.txt
relevant difference:
leaq _ZNSs4_Rep20_S_empty_rep_storageE(%rip), %rdx
cmpq %rdx, %rcx
...
.section .bss$_ZNSs4_Rep20_S_empty_rep_storageE,"bw",discard,_ZNSs4_Rep20_S_empty_rep_storageE
.globl _ZNSs4_Rep20_S_empty_rep_storageE # @_ZNSs4_Rep20_S_empty_rep_storageE
.p2align 4, 0x0
_ZNSs4_Rep20_S_empty_rep_storageE:
.zero 32
vs
cmpq .refptr._ZNSs4_Rep20_S_empty_rep_storageE(%rip), %rcx
...
.section .rdata$.refptr._ZNSs4_Rep20_S_empty_rep_storageE, "dr"
.globl .refptr._ZNSs4_Rep20_S_empty_rep_storageE
.linkonce discard
.refptr._ZNSs4_Rep20_S_empty_rep_storageE:
.quad _ZNSs4_Rep20_S_empty_rep_storageE
relevant bit of libstdc++ header:
// Inhibit implicit instantiations for required instantiations,
// which are defined via explicit instantiations elsewhere.
#if _GLIBCXX_EXTERN_TEMPLATE
// The explicit instantiation definitions in src/c++11/string-inst.cc and
// src/c++17/string-inst.cc only instantiate the members required for C++17
// and earlier standards (so not C++20's starts_with and ends_with).
// Suppress the explicit instantiation declarations for C++20, so C++20
// code will implicitly instantiate std::string and std::wstring as needed.
# if __cplusplus <= 201703L && _GLIBCXX_EXTERN_TEMPLATE > 0
extern template class basic_string<char>;
# elif ! _GLIBCXX_USE_CXX11_ABI
// Still need to prevent implicit instantiation of the COW empty rep,
// to ensure the definition in libstdc++.so is unique (PR 86138).
extern template basic_string<char>::size_type
basic_string<char>::_Rep::_S_empty_rep_storage[];
# elif _GLIBCXX_EXTERN_TEMPLATE > 0
// Export _M_replace_cold even for C++20.
extern template void
basic_string<char>::_M_replace_cold(char *, size_type, const char*,
const size_type, const size_type);
# endif
_GLIBCXX_EXTERN_TEMPLATE
is 1, and the issue manifests when _GLIBCXX_USE_CXX11_ABI
is 0 and __cplusplus
is <= 201703.
see msys2/MSYS2-packages#5329 for history of the investigation.
/cc @mstorsjo