You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
libstdc++ apparently has a convention where the typeinfo name for a class declared in an anonymous namespace begins with an asterisk ('*'), which tells std::type_info::operator== to consider two type_info objects unequal even if their names are equal. Clang is not outputting this asterisk on GNU/Linux. Because it's omitted, if I declare two classes with the same name, in two different anonymous namespaces, the two class types are considered equal according to std::type_info::operator==, and I can cast from one type to another with dynamic_cast. G++ outputs the asterisk, so the types are treated as unequal.
The asterisk is stripped off in GNU's std::type_info::name(), so it's not user visible.
AFAICT, libc++ doesn't have this convention, but for ARM64 iOS, there is a different convention of setting the highest(?) bit of the type_info's __type_name pointer to indicate that string comparison should be performed. (Look for the _LIBCPP_HAS_NONUNIQUE_TYPEINFO and _LIBCPP_NONUNIQUE_RTTI_BIT flags in libc++. I wonder if ARM64 iOS also sets _LIBCXX_DYNAMIC_FALLBACK for libc++abi?)
I'm wondering whether there's a compatibility concern here w.r.t. previous versions of Clang. My first guess is that compatibility with G++/libstdc++/libsupc++ (and correctness) is sufficient to motivate changing Clang. I guess Clang would have to generate different code for -stdlib=libstdc++ and -stdlib=libc++?
def A == run A: 0
&def A == &run A: 0
name of def A: N12_GLOBAL__N_11AE
name of run A: N12_GLOBAL__N_11AE
def A name == run A name: 0
SUCCESS: dynamic_cast returned nullptr
__GXX_TYPEINFO_EQUALITY_INLINE = 1
__GXX_MERGED_TYPEINFO_NAMES = 0
def A == run A: 1
&def A == &run A: 0
name of def A: N12_GLOBAL__N_11AE
name of run A: N12_GLOBAL__N_11AE
def A name == run A name: 0
ERROR: run func called, field=0
__GXX_TYPEINFO_EQUALITY_INLINE = 1
__GXX_MERGED_TYPEINFO_NAMES = 0
Simple example showing another manifestation of this:
$ cat a.cpp
namespace {
struct S {};
} // namespace
void f() { throw S(); }
$ cat b.cpp
namespace {
struct S {};
} // namespace
void f();
int main() {
try {
f();
} catch (S &) {
}
}
$ g++ a.cpp b.cpp
$ ./a.out
terminate called after throwing an instance of '(anonymous namespace)::S'
[1] 3562076 abort (core dumped) ./a.out
$ clang++ a.cpp b.cpp
$ ./a.out # exits successfully
libc++ gained the ability to perform string equality-based typeinfo comparisons in https://reviews.llvm.org/rL361913, but those don't take the leading asterisk into account either.
I guess Clang would have to generate different code for -stdlib=libstdc++ and -stdlib=libc++?
The difference is by target platform, not by target standard library. Darwin generally uses the strict Itanium ABI rule, but on arm64 it tweaks it as you observe. GCC decided years ago to diverge from the official Itanium rule in a few ways, and I think this is just another aspect of that divergence. Since GCC defines the ABI for Linux, both Clang and libc++ need to use GCC's modified rule on Linux and probably several other targets.
Extended Description
libstdc++ apparently has a convention where the typeinfo name for a class declared in an anonymous namespace begins with an asterisk ('*'), which tells std::type_info::operator== to consider two type_info objects unequal even if their names are equal. Clang is not outputting this asterisk on GNU/Linux. Because it's omitted, if I declare two classes with the same name, in two different anonymous namespaces, the two class types are considered equal according to std::type_info::operator==, and I can cast from one type to another with dynamic_cast. G++ outputs the asterisk, so the types are treated as unequal.
The asterisk is stripped off in GNU's std::type_info::name(), so it's not user visible.
AFAICT, libc++ doesn't have this convention, but for ARM64 iOS, there is a different convention of setting the highest(?) bit of the type_info's __type_name pointer to indicate that string comparison should be performed. (Look for the _LIBCPP_HAS_NONUNIQUE_TYPEINFO and _LIBCPP_NONUNIQUE_RTTI_BIT flags in libc++. I wonder if ARM64 iOS also sets _LIBCXX_DYNAMIC_FALLBACK for libc++abi?)
I'm wondering whether there's a compatibility concern here w.r.t. previous versions of Clang. My first guess is that compatibility with G++/libstdc++/libsupc++ (and correctness) is sufficient to motivate changing Clang. I guess Clang would have to generate different code for -stdlib=libstdc++ and -stdlib=libc++?
Test case:
test.h
test-def.cc
test-run.cc
$ cat /etc/issue
Ubuntu 14.04.5 LTS \n \l
$ uname -m
x86_64
$ g++ test-def.cc test-run.cc -std=c++11 && ./a.out
$ ~/clang+llvm-5.0.0-linux-x86_64-ubuntu14.04/bin/clang++ test-def.cc test-run.cc -std=c++11 && ./a.out
$ g++ test-def.cc -S && cat test-def.s
...
_ZTSN12_GLOBAL__N_11AE:
.string "*N12_GLOBAL__N_11AE"
...
$ ~/clang+llvm-5.0.0-linux-x86_64-ubuntu14.04/bin/clang++ test-def.cc -S && cat test-def.s
...
_ZTSN12_GLOBAL__N_11AE:
.asciz "N12_GLOBAL__N_11AE"
...
The text was updated successfully, but these errors were encountered: