[libcxx-commits] [libcxx] [libc++] Add test to ensure that the mangling of types stays the same (PR #143556)
via libcxx-commits
libcxx-commits at lists.llvm.org
Sat Jun 21 08:54:37 PDT 2025
================
@@ -0,0 +1,72 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// We're using `std::from_chars` in this test
+// UNSUPPORTED: c++03, c++11, c++14
+
+// Make sure that the mangling of our public types stays the same
+
+#include <cassert>
+#include <charconv>
+#include <iostream>
+#include <map>
+#include <typeinfo>
+#include <string_view>
+
+template <class>
+struct mangling {};
+
+struct test_struct {};
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+struct ns_mangling {};
+_LIBCPP_END_NAMESPACE_STD
+
+namespace std::__name {
+struct ns_mangling {};
+} // namespace std::__name
+
+namespace std::__long_name_to_make_sure_multiple_digits_work {
+struct ns_mangling {};
+} // namespace std::__long_name_to_make_sure_multiple_digits_work
+
+std::string get_std_inline_namespace_mangling(const std::type_info& info) {
+ std::string name = info.name();
+ assert(name.starts_with("NSt"));
+ unsigned name_len;
+ auto res = std::from_chars(name.data() + 3, name.data() + name.size(), name_len);
+ assert(res.ec == std::errc{});
+ return std::move(name).substr(0, (res.ptr + name_len) - name.data());
+}
+
+void expect_mangling(const std::type_info& info, std::string expected_name) {
+ if (expected_name != info.name())
+ std::__libcpp_verbose_abort("Expected: '%s'\n Got: '%s'\n", expected_name.c_str(), info.name());
+}
+
+#define EXPECT_MANGLING(expected_mangling, ...) expect_mangling(typeid(__VA_ARGS__), expected_mangling)
+
+// Mangling names are really long, but splitting it up into multiple lines doesn't make it any more readable
+// clang-format off
+int main(int, char**) {
+ // self-test inline namespace recovery
+ assert(get_std_inline_namespace_mangling(typeid(std::__name::ns_mangling)) == "NSt6__name");
+ assert(get_std_inline_namespace_mangling(typeid(std::__long_name_to_make_sure_multiple_digits_work::ns_mangling)) == "NSt45__long_name_to_make_sure_multiple_digits_work");
+
+ // selftest
+ EXPECT_MANGLING("11test_struct", test_struct);
+
+ std::string ns_std = get_std_inline_namespace_mangling(typeid(std::ns_mangling));
+
+ // std::map
----------------
EricWF wrote:
The goal here seems similar to the symbol list tests.
We want to ensure that a users program which exposes the mangled name of `std::foo` as part of one of their symbols continues to link when compiler before & after a libc++ change.
It seems to me that given the specification of `std::type_info::name`, that it's not the most suitable tool for the job. In particular:
> Returns an implementation defined null-terminated character string containing the name of the type. No guarantees are given; in particular, the returned string can be identical for several types and change between invocations of the same program.
I would consider simply generating a big symbol name, containing all of the types we want to test the names of, and then ensuring code generated before a given change can link to code generated after the change.
For example:
```c++
#include <string>
#include <vector>
#include <tuple>
// Compile the definition with the headers in trunk
// RUN: %{cxx} -c -cxx-isystem %{trunk-headers} -o %t.o -DDEFINE_TARGET
// Then compile the main
// RUN: %{cxx} -cxx-isystem %{headers-under-test} -o a.out %t.o
// RUN: ./a.out
template <class ...> struct TypeList {};
using TypesUnderTest =
TypeList<
std::vector<int>,
std::vector<int>::iterator,
std::tuple<int, int&>
>;
void target(TypesUnderTest);
#ifdef DEFINE_TARGET
void target(TypesUnderTest) {}
#else
int main() {
target({});
}
#endif
```
This approach sort-of avoids having golden files checked in, which is a pain since they need manual care whenever we add new configurations or to regenerate them. It instead expects that we have two versions of the headers available, and treats one of those versions as "golden" (which is sort of what we want I think).
https://github.com/llvm/llvm-project/pull/143556
More information about the libcxx-commits
mailing list