Skip to content

[libc++] Fix the visibility of type traits #111522

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from

Conversation

philnik777
Copy link
Contributor

The standard requires all type traits variables to have default visibility, since they are implicitly inline and thus have to always have the same address. To observe the bug currently, -fvisibility=hidden has to be specified.

The standard requires all type traits variables to have default visibility, since they are implicitly inline and thus have to always have the same address. To observe the bug currently, `-fvisibility=hidden` has to be specified.
@philnik777 philnik777 requested a review from a team as a code owner October 8, 2024 11:25
@llvmbot llvmbot added the libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi. label Oct 8, 2024
@llvmbot
Copy link
Member

llvmbot commented Oct 8, 2024

@llvm/pr-subscribers-libcxx

Author: Nikolas Klauser (philnik777)

Changes

The standard requires all type traits variables to have default visibility, since they are implicitly inline and thus have to always have the same address. To observe the bug currently, -fvisibility=hidden has to be specified.


Patch is 59.35 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/111522.diff

55 Files Affected:

  • (modified) libcxx/include/__type_traits/alignment_of.h (+1-1)
  • (modified) libcxx/include/__type_traits/extent.h (+1-1)
  • (modified) libcxx/include/__type_traits/has_unique_object_representation.h (+1-1)
  • (modified) libcxx/include/__type_traits/has_virtual_destructor.h (+1-1)
  • (modified) libcxx/include/__type_traits/invoke.h (+4-4)
  • (modified) libcxx/include/__type_traits/is_abstract.h (+1-1)
  • (modified) libcxx/include/__type_traits/is_aggregate.h (+1-1)
  • (modified) libcxx/include/__type_traits/is_arithmetic.h (+1-1)
  • (modified) libcxx/include/__type_traits/is_array.h (+1-1)
  • (modified) libcxx/include/__type_traits/is_assignable.h (+3-3)
  • (modified) libcxx/include/__type_traits/is_base_of.h (+2-2)
  • (modified) libcxx/include/__type_traits/is_bounded_array.h (+1-1)
  • (modified) libcxx/include/__type_traits/is_class.h (+1-1)
  • (modified) libcxx/include/__type_traits/is_compound.h (+2-2)
  • (modified) libcxx/include/__type_traits/is_const.h (+2-2)
  • (modified) libcxx/include/__type_traits/is_constructible.h (+4-4)
  • (modified) libcxx/include/__type_traits/is_convertible.h (+1-1)
  • (modified) libcxx/include/__type_traits/is_destructible.h (+2-2)
  • (modified) libcxx/include/__type_traits/is_empty.h (+1-1)
  • (modified) libcxx/include/__type_traits/is_enum.h (+2-2)
  • (modified) libcxx/include/__type_traits/is_final.h (+1-1)
  • (modified) libcxx/include/__type_traits/is_floating_point.h (+1-1)
  • (modified) libcxx/include/__type_traits/is_function.h (+1-1)
  • (modified) libcxx/include/__type_traits/is_fundamental.h (+2-2)
  • (modified) libcxx/include/__type_traits/is_integral.h (+1-1)
  • (modified) libcxx/include/__type_traits/is_member_pointer.h (+3-3)
  • (modified) libcxx/include/__type_traits/is_nothrow_assignable.h (+3-3)
  • (modified) libcxx/include/__type_traits/is_nothrow_constructible.h (+4-4)
  • (modified) libcxx/include/__type_traits/is_nothrow_convertible.h (+2-2)
  • (modified) libcxx/include/__type_traits/is_nothrow_destructible.h (+1-1)
  • (modified) libcxx/include/__type_traits/is_null_pointer.h (+1-1)
  • (modified) libcxx/include/__type_traits/is_object.h (+1-1)
  • (modified) libcxx/include/__type_traits/is_pointer.h (+1-1)
  • (modified) libcxx/include/__type_traits/is_polymorphic.h (+1-1)
  • (modified) libcxx/include/__type_traits/is_reference.h (+5-5)
  • (modified) libcxx/include/__type_traits/is_same.h (+1-1)
  • (modified) libcxx/include/__type_traits/is_scalar.h (+2-2)
  • (modified) libcxx/include/__type_traits/is_signed.h (+2-2)
  • (modified) libcxx/include/__type_traits/is_standard_layout.h (+1-1)
  • (modified) libcxx/include/__type_traits/is_swappable.h (+4-4)
  • (modified) libcxx/include/__type_traits/is_trivial.h (+1-1)
  • (modified) libcxx/include/__type_traits/is_trivially_assignable.h (+3-3)
  • (modified) libcxx/include/__type_traits/is_trivially_constructible.h (+4-4)
  • (modified) libcxx/include/__type_traits/is_trivially_copyable.h (+1-1)
  • (modified) libcxx/include/__type_traits/is_trivially_destructible.h (+1-1)
  • (modified) libcxx/include/__type_traits/is_unbounded_array.h (+1-1)
  • (modified) libcxx/include/__type_traits/is_union.h (+1-1)
  • (modified) libcxx/include/__type_traits/is_unsigned.h (+2-2)
  • (modified) libcxx/include/__type_traits/is_void.h (+1-1)
  • (modified) libcxx/include/__type_traits/is_volatile.h (+2-2)
  • (modified) libcxx/include/__type_traits/rank.h (+1-1)
  • (added) libcxx/test/std/utilities/meta/meta.rel/visibility.sh.cpp (+72)
  • (added) libcxx/test/std/utilities/meta/meta.trans/visibility.sh.cpp (+71)
  • (added) libcxx/test/std/utilities/meta/meta.unary.prop.query/visibility.sh.cpp (+52)
  • (added) libcxx/test/std/utilities/meta/meta.unary/visibility.sh.cpp (+202)
diff --git a/libcxx/include/__type_traits/alignment_of.h b/libcxx/include/__type_traits/alignment_of.h
index 8871c8ce110d67..1bb12530037651 100644
--- a/libcxx/include/__type_traits/alignment_of.h
+++ b/libcxx/include/__type_traits/alignment_of.h
@@ -24,7 +24,7 @@ struct _LIBCPP_TEMPLATE_VIS alignment_of : public integral_constant<size_t, _LIB
 
 #if _LIBCPP_STD_VER >= 17
 template <class _Tp>
-inline constexpr size_t alignment_of_v = _LIBCPP_ALIGNOF(_Tp);
+_LIBCPP_EXPORTED_FROM_ABI inline constexpr size_t alignment_of_v = _LIBCPP_ALIGNOF(_Tp);
 #endif
 
 _LIBCPP_END_NAMESPACE_STD
diff --git a/libcxx/include/__type_traits/extent.h b/libcxx/include/__type_traits/extent.h
index 1c34a4db1c4b52..a1f4ebc7f068cd 100644
--- a/libcxx/include/__type_traits/extent.h
+++ b/libcxx/include/__type_traits/extent.h
@@ -26,7 +26,7 @@ struct _LIBCPP_TEMPLATE_VIS extent : integral_constant<size_t, __array_extent(_T
 
 #  if _LIBCPP_STD_VER >= 17
 template <class _Tp, unsigned _Ip = 0>
-inline constexpr size_t extent_v = __array_extent(_Tp, _Ip);
+_LIBCPP_EXPORTED_FROM_ABI inline constexpr size_t extent_v = __array_extent(_Tp, _Ip);
 #  endif
 
 #else // __has_builtin(__array_extent)
diff --git a/libcxx/include/__type_traits/has_unique_object_representation.h b/libcxx/include/__type_traits/has_unique_object_representation.h
index 98c440c16bf26b..ff474f731e24b3 100644
--- a/libcxx/include/__type_traits/has_unique_object_representation.h
+++ b/libcxx/include/__type_traits/has_unique_object_representation.h
@@ -31,7 +31,7 @@ struct _LIBCPP_TEMPLATE_VIS has_unique_object_representations
     : public integral_constant<bool, __has_unique_object_representations(remove_all_extents_t<_Tp>)> {};
 
 template <class _Tp>
-inline constexpr bool has_unique_object_representations_v = __has_unique_object_representations(_Tp);
+_LIBCPP_EXPORTED_FROM_ABI inline constexpr bool has_unique_object_representations_v = __has_unique_object_representations(_Tp);
 
 #endif
 
diff --git a/libcxx/include/__type_traits/has_virtual_destructor.h b/libcxx/include/__type_traits/has_virtual_destructor.h
index 4ce96e649e67a1..4c96b6b7a45ac5 100644
--- a/libcxx/include/__type_traits/has_virtual_destructor.h
+++ b/libcxx/include/__type_traits/has_virtual_destructor.h
@@ -23,7 +23,7 @@ struct _LIBCPP_TEMPLATE_VIS has_virtual_destructor : public integral_constant<bo
 
 #if _LIBCPP_STD_VER >= 17
 template <class _Tp>
-inline constexpr bool has_virtual_destructor_v = __has_virtual_destructor(_Tp);
+_LIBCPP_EXPORTED_FROM_ABI inline constexpr bool has_virtual_destructor_v = __has_virtual_destructor(_Tp);
 #endif
 
 _LIBCPP_END_NAMESPACE_STD
diff --git a/libcxx/include/__type_traits/invoke.h b/libcxx/include/__type_traits/invoke.h
index 71db32ae6a3cef..10725f0f612e46 100644
--- a/libcxx/include/__type_traits/invoke.h
+++ b/libcxx/include/__type_traits/invoke.h
@@ -236,10 +236,10 @@ template <class _Ret, class _Fn, class... _Args>
 struct _LIBCPP_TEMPLATE_VIS is_invocable_r : integral_constant<bool, __invokable_r<_Ret, _Fn, _Args...>::value> {};
 
 template <class _Fn, class... _Args>
-inline constexpr bool is_invocable_v = is_invocable<_Fn, _Args...>::value;
+_LIBCPP_EXPORTED_FROM_ABI inline constexpr bool is_invocable_v = is_invocable<_Fn, _Args...>::value;
 
 template <class _Ret, class _Fn, class... _Args>
-inline constexpr bool is_invocable_r_v = is_invocable_r<_Ret, _Fn, _Args...>::value;
+_LIBCPP_EXPORTED_FROM_ABI inline constexpr bool is_invocable_r_v = is_invocable_r<_Ret, _Fn, _Args...>::value;
 
 // is_nothrow_invocable
 
@@ -252,10 +252,10 @@ struct _LIBCPP_TEMPLATE_VIS is_nothrow_invocable_r
     : integral_constant<bool, __nothrow_invokable_r<_Ret, _Fn, _Args...>::value> {};
 
 template <class _Fn, class... _Args>
-inline constexpr bool is_nothrow_invocable_v = is_nothrow_invocable<_Fn, _Args...>::value;
+_LIBCPP_EXPORTED_FROM_ABI inline constexpr bool is_nothrow_invocable_v = is_nothrow_invocable<_Fn, _Args...>::value;
 
 template <class _Ret, class _Fn, class... _Args>
-inline constexpr bool is_nothrow_invocable_r_v = is_nothrow_invocable_r<_Ret, _Fn, _Args...>::value;
+_LIBCPP_EXPORTED_FROM_ABI inline constexpr bool is_nothrow_invocable_r_v = is_nothrow_invocable_r<_Ret, _Fn, _Args...>::value;
 
 template <class _Fn, class... _Args>
 struct _LIBCPP_TEMPLATE_VIS invoke_result : __invoke_of<_Fn, _Args...> {};
diff --git a/libcxx/include/__type_traits/is_abstract.h b/libcxx/include/__type_traits/is_abstract.h
index 4aa456be1c48e8..f1ec0ffb54410d 100644
--- a/libcxx/include/__type_traits/is_abstract.h
+++ b/libcxx/include/__type_traits/is_abstract.h
@@ -23,7 +23,7 @@ struct _LIBCPP_TEMPLATE_VIS is_abstract : public integral_constant<bool, __is_ab
 
 #if _LIBCPP_STD_VER >= 17
 template <class _Tp>
-inline constexpr bool is_abstract_v = __is_abstract(_Tp);
+_LIBCPP_EXPORTED_FROM_ABI inline constexpr bool is_abstract_v = __is_abstract(_Tp);
 #endif
 
 _LIBCPP_END_NAMESPACE_STD
diff --git a/libcxx/include/__type_traits/is_aggregate.h b/libcxx/include/__type_traits/is_aggregate.h
index 4e0988071adeec..4313fbdcd9421b 100644
--- a/libcxx/include/__type_traits/is_aggregate.h
+++ b/libcxx/include/__type_traits/is_aggregate.h
@@ -24,7 +24,7 @@ template <class _Tp>
 struct _LIBCPP_TEMPLATE_VIS is_aggregate : public integral_constant<bool, __is_aggregate(_Tp)> {};
 
 template <class _Tp>
-inline constexpr bool is_aggregate_v = __is_aggregate(_Tp);
+_LIBCPP_EXPORTED_FROM_ABI inline constexpr bool is_aggregate_v = __is_aggregate(_Tp);
 
 #endif // _LIBCPP_STD_VER >= 17
 
diff --git a/libcxx/include/__type_traits/is_arithmetic.h b/libcxx/include/__type_traits/is_arithmetic.h
index c9713e1840a7b1..952200c2ea5953 100644
--- a/libcxx/include/__type_traits/is_arithmetic.h
+++ b/libcxx/include/__type_traits/is_arithmetic.h
@@ -26,7 +26,7 @@ struct _LIBCPP_TEMPLATE_VIS is_arithmetic
 
 #if _LIBCPP_STD_VER >= 17
 template <class _Tp>
-inline constexpr bool is_arithmetic_v = is_arithmetic<_Tp>::value;
+_LIBCPP_EXPORTED_FROM_ABI inline constexpr bool is_arithmetic_v = is_arithmetic<_Tp>::value;
 #endif
 
 _LIBCPP_END_NAMESPACE_STD
diff --git a/libcxx/include/__type_traits/is_array.h b/libcxx/include/__type_traits/is_array.h
index f34204e19ed899..559eeab7d38859 100644
--- a/libcxx/include/__type_traits/is_array.h
+++ b/libcxx/include/__type_traits/is_array.h
@@ -27,7 +27,7 @@ struct _LIBCPP_TEMPLATE_VIS is_array : _BoolConstant<__is_array(_Tp)> {};
 
 #  if _LIBCPP_STD_VER >= 17
 template <class _Tp>
-inline constexpr bool is_array_v = __is_array(_Tp);
+_LIBCPP_EXPORTED_FROM_ABI inline constexpr bool is_array_v = __is_array(_Tp);
 #  endif
 
 #else
diff --git a/libcxx/include/__type_traits/is_assignable.h b/libcxx/include/__type_traits/is_assignable.h
index cfb46997778782..44367bbc2f834e 100644
--- a/libcxx/include/__type_traits/is_assignable.h
+++ b/libcxx/include/__type_traits/is_assignable.h
@@ -25,7 +25,7 @@ struct _LIBCPP_TEMPLATE_VIS is_assignable : _BoolConstant<__is_assignable(_Tp, _
 
 #if _LIBCPP_STD_VER >= 17
 template <class _Tp, class _Arg>
-inline constexpr bool is_assignable_v = __is_assignable(_Tp, _Arg);
+_LIBCPP_EXPORTED_FROM_ABI inline constexpr bool is_assignable_v = __is_assignable(_Tp, _Arg);
 #endif
 
 template <class _Tp>
@@ -35,7 +35,7 @@ struct _LIBCPP_TEMPLATE_VIS is_copy_assignable
 
 #if _LIBCPP_STD_VER >= 17
 template <class _Tp>
-inline constexpr bool is_copy_assignable_v = is_copy_assignable<_Tp>::value;
+_LIBCPP_EXPORTED_FROM_ABI inline constexpr bool is_copy_assignable_v = is_copy_assignable<_Tp>::value;
 #endif
 
 template <class _Tp>
@@ -44,7 +44,7 @@ struct _LIBCPP_TEMPLATE_VIS is_move_assignable
 
 #if _LIBCPP_STD_VER >= 17
 template <class _Tp>
-inline constexpr bool is_move_assignable_v = is_move_assignable<_Tp>::value;
+_LIBCPP_EXPORTED_FROM_ABI inline constexpr bool is_move_assignable_v = is_move_assignable<_Tp>::value;
 #endif
 
 _LIBCPP_END_NAMESPACE_STD
diff --git a/libcxx/include/__type_traits/is_base_of.h b/libcxx/include/__type_traits/is_base_of.h
index 488b63719eb600..fc3ce8afaf8ed4 100644
--- a/libcxx/include/__type_traits/is_base_of.h
+++ b/libcxx/include/__type_traits/is_base_of.h
@@ -23,7 +23,7 @@ struct _LIBCPP_TEMPLATE_VIS is_base_of : public integral_constant<bool, __is_bas
 
 #if _LIBCPP_STD_VER >= 17
 template <class _Bp, class _Dp>
-inline constexpr bool is_base_of_v = __is_base_of(_Bp, _Dp);
+_LIBCPP_EXPORTED_FROM_ABI inline constexpr bool is_base_of_v = __is_base_of(_Bp, _Dp);
 #endif
 
 #if _LIBCPP_STD_VER >= 26
@@ -33,7 +33,7 @@ template <class _Base, class _Derived>
 struct _LIBCPP_TEMPLATE_VIS is_virtual_base_of : public bool_constant<__builtin_is_virtual_base_of(_Base, _Derived)> {};
 
 template <class _Base, class _Derived>
-inline constexpr bool is_virtual_base_of_v = __builtin_is_virtual_base_of(_Base, _Derived);
+_LIBCPP_EXPORTED_FROM_ABI inline constexpr bool is_virtual_base_of_v = __builtin_is_virtual_base_of(_Base, _Derived);
 
 #  endif
 #endif
diff --git a/libcxx/include/__type_traits/is_bounded_array.h b/libcxx/include/__type_traits/is_bounded_array.h
index a78b52e7062b82..10e72d94bb988d 100644
--- a/libcxx/include/__type_traits/is_bounded_array.h
+++ b/libcxx/include/__type_traits/is_bounded_array.h
@@ -32,7 +32,7 @@ template <class _Tp, size_t _Np>
 struct _LIBCPP_TEMPLATE_VIS is_bounded_array<_Tp[_Np]> : true_type {};
 
 template <class _Tp>
-inline constexpr bool is_bounded_array_v = is_bounded_array<_Tp>::value;
+_LIBCPP_EXPORTED_FROM_ABI inline constexpr bool is_bounded_array_v = is_bounded_array<_Tp>::value;
 
 #endif
 
diff --git a/libcxx/include/__type_traits/is_class.h b/libcxx/include/__type_traits/is_class.h
index 034f76a7865e3d..95f839ed1c0efb 100644
--- a/libcxx/include/__type_traits/is_class.h
+++ b/libcxx/include/__type_traits/is_class.h
@@ -23,7 +23,7 @@ struct _LIBCPP_TEMPLATE_VIS is_class : public integral_constant<bool, __is_class
 
 #if _LIBCPP_STD_VER >= 17
 template <class _Tp>
-inline constexpr bool is_class_v = __is_class(_Tp);
+_LIBCPP_EXPORTED_FROM_ABI inline constexpr bool is_class_v = __is_class(_Tp);
 #endif
 
 _LIBCPP_END_NAMESPACE_STD
diff --git a/libcxx/include/__type_traits/is_compound.h b/libcxx/include/__type_traits/is_compound.h
index cd208ceab28863..42f38e65e15ea7 100644
--- a/libcxx/include/__type_traits/is_compound.h
+++ b/libcxx/include/__type_traits/is_compound.h
@@ -26,7 +26,7 @@ struct _LIBCPP_TEMPLATE_VIS is_compound : _BoolConstant<__is_compound(_Tp)> {};
 
 #  if _LIBCPP_STD_VER >= 17
 template <class _Tp>
-inline constexpr bool is_compound_v = __is_compound(_Tp);
+_LIBCPP_EXPORTED_FROM_ABI inline constexpr bool is_compound_v = __is_compound(_Tp);
 #  endif
 
 #else // __has_builtin(__is_compound)
@@ -36,7 +36,7 @@ struct _LIBCPP_TEMPLATE_VIS is_compound : public integral_constant<bool, !is_fun
 
 #  if _LIBCPP_STD_VER >= 17
 template <class _Tp>
-inline constexpr bool is_compound_v = is_compound<_Tp>::value;
+_LIBCPP_EXPORTED_FROM_ABI inline constexpr bool is_compound_v = is_compound<_Tp>::value;
 #  endif
 
 #endif // __has_builtin(__is_compound)
diff --git a/libcxx/include/__type_traits/is_const.h b/libcxx/include/__type_traits/is_const.h
index 47ef70872b790a..38a51866e144f3 100644
--- a/libcxx/include/__type_traits/is_const.h
+++ b/libcxx/include/__type_traits/is_const.h
@@ -25,7 +25,7 @@ struct _LIBCPP_TEMPLATE_VIS is_const : _BoolConstant<__is_const(_Tp)> {};
 
 #  if _LIBCPP_STD_VER >= 17
 template <class _Tp>
-inline constexpr bool is_const_v = __is_const(_Tp);
+_LIBCPP_EXPORTED_FROM_ABI inline constexpr bool is_const_v = __is_const(_Tp);
 #  endif
 
 #else
@@ -37,7 +37,7 @@ struct _LIBCPP_TEMPLATE_VIS is_const<_Tp const> : public true_type {};
 
 #  if _LIBCPP_STD_VER >= 17
 template <class _Tp>
-inline constexpr bool is_const_v = is_const<_Tp>::value;
+_LIBCPP_EXPORTED_FROM_ABI inline constexpr bool is_const_v = is_const<_Tp>::value;
 #  endif
 
 #endif // __has_builtin(__is_const)
diff --git a/libcxx/include/__type_traits/is_constructible.h b/libcxx/include/__type_traits/is_constructible.h
index 567bd165c71520..0aa8eff0701324 100644
--- a/libcxx/include/__type_traits/is_constructible.h
+++ b/libcxx/include/__type_traits/is_constructible.h
@@ -25,7 +25,7 @@ struct _LIBCPP_TEMPLATE_VIS is_constructible : public integral_constant<bool, __
 
 #if _LIBCPP_STD_VER >= 17
 template <class _Tp, class... _Args>
-inline constexpr bool is_constructible_v = __is_constructible(_Tp, _Args...);
+_LIBCPP_EXPORTED_FROM_ABI inline constexpr bool is_constructible_v = __is_constructible(_Tp, _Args...);
 #endif
 
 template <class _Tp>
@@ -34,7 +34,7 @@ struct _LIBCPP_TEMPLATE_VIS is_copy_constructible
 
 #if _LIBCPP_STD_VER >= 17
 template <class _Tp>
-inline constexpr bool is_copy_constructible_v = is_copy_constructible<_Tp>::value;
+_LIBCPP_EXPORTED_FROM_ABI inline constexpr bool is_copy_constructible_v = is_copy_constructible<_Tp>::value;
 #endif
 
 template <class _Tp>
@@ -43,7 +43,7 @@ struct _LIBCPP_TEMPLATE_VIS is_move_constructible
 
 #if _LIBCPP_STD_VER >= 17
 template <class _Tp>
-inline constexpr bool is_move_constructible_v = is_move_constructible<_Tp>::value;
+_LIBCPP_EXPORTED_FROM_ABI inline constexpr bool is_move_constructible_v = is_move_constructible<_Tp>::value;
 #endif
 
 template <class _Tp>
@@ -51,7 +51,7 @@ struct _LIBCPP_TEMPLATE_VIS is_default_constructible : public integral_constant<
 
 #if _LIBCPP_STD_VER >= 17
 template <class _Tp>
-inline constexpr bool is_default_constructible_v = __is_constructible(_Tp);
+_LIBCPP_EXPORTED_FROM_ABI inline constexpr bool is_default_constructible_v = __is_constructible(_Tp);
 #endif
 
 _LIBCPP_END_NAMESPACE_STD
diff --git a/libcxx/include/__type_traits/is_convertible.h b/libcxx/include/__type_traits/is_convertible.h
index 414c2a6d6a0de0..ed92e5086b620b 100644
--- a/libcxx/include/__type_traits/is_convertible.h
+++ b/libcxx/include/__type_traits/is_convertible.h
@@ -23,7 +23,7 @@ struct _LIBCPP_TEMPLATE_VIS is_convertible : public integral_constant<bool, __is
 
 #if _LIBCPP_STD_VER >= 17
 template <class _From, class _To>
-inline constexpr bool is_convertible_v = __is_convertible(_From, _To);
+_LIBCPP_EXPORTED_FROM_ABI inline constexpr bool is_convertible_v = __is_convertible(_From, _To);
 #endif
 
 _LIBCPP_END_NAMESPACE_STD
diff --git a/libcxx/include/__type_traits/is_destructible.h b/libcxx/include/__type_traits/is_destructible.h
index 3248b07d36ee67..5a716803247d8b 100644
--- a/libcxx/include/__type_traits/is_destructible.h
+++ b/libcxx/include/__type_traits/is_destructible.h
@@ -29,7 +29,7 @@ struct _LIBCPP_TEMPLATE_VIS is_destructible : _BoolConstant<__is_destructible(_T
 
 #  if _LIBCPP_STD_VER >= 17
 template <class _Tp>
-inline constexpr bool is_destructible_v = __is_destructible(_Tp);
+_LIBCPP_EXPORTED_FROM_ABI inline constexpr bool is_destructible_v = __is_destructible(_Tp);
 #  endif
 
 #else // __has_builtin(__is_destructible)
@@ -87,7 +87,7 @@ struct is_destructible<void> : public false_type {};
 
 #  if _LIBCPP_STD_VER >= 17
 template <class _Tp>
-inline constexpr bool is_destructible_v = is_destructible<_Tp>::value;
+_LIBCPP_EXPORTED_FROM_ABI inline constexpr bool is_destructible_v = is_destructible<_Tp>::value;
 #  endif
 
 #endif // __has_builtin(__is_destructible)
diff --git a/libcxx/include/__type_traits/is_empty.h b/libcxx/include/__type_traits/is_empty.h
index 951d93b5a2f10e..4d522b294f7bf9 100644
--- a/libcxx/include/__type_traits/is_empty.h
+++ b/libcxx/include/__type_traits/is_empty.h
@@ -23,7 +23,7 @@ struct _LIBCPP_TEMPLATE_VIS is_empty : public integral_constant<bool, __is_empty
 
 #if _LIBCPP_STD_VER >= 17
 template <class _Tp>
-inline constexpr bool is_empty_v = __is_empty(_Tp);
+_LIBCPP_EXPORTED_FROM_ABI inline constexpr bool is_empty_v = __is_empty(_Tp);
 #endif
 
 _LIBCPP_END_NAMESPACE_STD
diff --git a/libcxx/include/__type_traits/is_enum.h b/libcxx/include/__type_traits/is_enum.h
index 2fab6db2c8d50f..b437b602d7c216 100644
--- a/libcxx/include/__type_traits/is_enum.h
+++ b/libcxx/include/__type_traits/is_enum.h
@@ -23,7 +23,7 @@ struct _LIBCPP_TEMPLATE_VIS is_enum : public integral_constant<bool, __is_enum(_
 
 #if _LIBCPP_STD_VER >= 17
 template <class _Tp>
-inline constexpr bool is_enum_v = __is_enum(_Tp);
+_LIBCPP_EXPORTED_FROM_ABI inline constexpr bool is_enum_v = __is_enum(_Tp);
 #endif
 
 #if _LIBCPP_STD_VER >= 23
@@ -32,7 +32,7 @@ template <class _Tp>
 struct _LIBCPP_TEMPLATE_VIS is_scoped_enum : bool_constant<__is_scoped_enum(_Tp)> {};
 
 template <class _Tp>
-inline constexpr bool is_scoped_enum_v = __is_scoped_enum(_Tp);
+_LIBCPP_EXPORTED_FROM_ABI inline constexpr bool is_scoped_enum_v = __is_scoped_enum(_Tp);
 
 #endif // _LIBCPP_STD_VER >= 23
 
diff --git a/libcxx/include/__type_traits/is_final.h b/libcxx/include/__type_traits/is_final.h
index 499c5e3a1edca4..daff36583b804a 100644
--- a/libcxx/include/__type_traits/is_final.h
+++ b/libcxx/include/__type_traits/is_final.h
@@ -28,7 +28,7 @@ struct _LIBCPP_TEMPLATE_VIS is_final : public integral_constant<bool, __is_final
 
 #if _LIBCPP_STD_VER >= 17
 template <class _Tp>
-inline constexpr bool is_final_v = __is_final(_Tp);
+_LIBCPP_EXPORTED_FROM_ABI inline constexpr bool is_final_v = __is_final(_Tp);
 #endif
 
 _LIBCPP_END_NAMESPACE_STD
diff --git a/libcxx/include/__type_traits/is_floating_point.h b/libcxx/include/__type_traits/is_floating_point.h
index add34782dfa099..d981e78d59ea07 100644
--- a/libcxx/include/__type_traits/is_floating_point.h
+++ b/libcxx/include/__type_traits/is_floating_point.h
@@ -31,7 +31,7 @@ struct _LIBCPP_TEMPLATE_VIS is_floating_point : public __libcpp_is_floating_poin
 
 #if _LIBCPP_STD_VER >= 17
 template <class _Tp>
-inline constexpr bool is_floating_point_v = is_floating_point<_Tp>::value;
+_LIBCPP_EXPORTED_FROM_ABI inline constexpr bool is_floating_point_v = is_floating_point<_Tp>::value;
 #endif
 
 _LIBCPP_END_NAMESPACE_STD
diff --git a/libcxx/include/__type_traits/is_function.h b/libcxx/include/__type_traits/is_function.h
index 98fedd0ad96d9b..adfa9363e93c43 100644
--- a/libcxx/include/__type_traits/is_function.h
+++ b/libcxx/include/__type_traits/is_function.h
@@ -23,7 +23,7 @@ struct _LIBCPP_TEMPLATE_VIS is_function : integral_constant<bool, __is_function(
 
 #if _LIBCPP_STD_VER >= 17
 template <class _Tp>
-inline constexpr bool is_function_v = __is_function(_Tp);
+_LIBCPP_EXPORTED_FROM_ABI inline constexpr bool is_function_v = __is_function(_Tp);
 #endif
 
 _LIBCPP_END_NAMESPACE_STD
diff --git a/libcxx/include/__type_traits/is_fundamental.h b/libcxx/include/__type_traits/is_fundamental.h
index 55f8e41f75f457..8e3c8587cedf26 100644
--- a/libcxx/include/__type_traits/is_fundamental.h
+++ b/libcxx/include/__type_traits/is_fundamental.h
@@ -27,7 +27,7 @@ struct _LIBCPP_TEMPLATE_VIS is_fundamental : _BoolConstant<__is_fundamental(_Tp)
 
 #  if _LIBCPP_STD_VER >= 17
 template <class _Tp>
-inline constexpr bool is_fundamental_v = __is_fundamental(_Tp);
+_LIBCPP_EXPORTED_FROM_ABI inline constexpr bool is_fundamental_v = __is_fundamental(_Tp);
 #  endif
 
 #else // __has_builtin(__is_fundamental)
@@ -38,7 +38,7 @@ struct _LIBCPP_TEMPLATE_VIS is_fundamental
 
 #  if _LIBCPP_STD_VER >= 17
 template <class _Tp>
-inline constexpr bool is_fundamental_v = is_fundamental<_Tp>::value;
+_LIBCPP_EXPORTED_FROM_ABI inline constexpr bool is_fundamental_v = is_fundamental<_Tp>::value;
 #  endif
 
 #endif // __has_builtin(__is_fundamental)
diff --git a/libcxx/include/__type_traits/is_integral.h b/libcxx/include/__type_traits/is_integral.h
index 26969885af8dfd..bcbf190a04dd1e 100644
--- a/libcxx/include/__type_traits/is_integral.h
+++ b/libcxx/include/__type_traits/is_integral.h
@@ -54,7 +54,7 @@ struct _LIBCPP_TEMPLATE_VIS is_integral : _BoolConstant<__is_integral(_Tp)> {};
 
 #  if _LIBCPP_STD_VER >= 17
 template <class _Tp>
-inline constexpr bool is_integral_v = __is_integral(_Tp);
+_LIBCPP_EXPORTED_FROM_ABI inline constexpr bool is_integral_v = __is_integral(_Tp);
 #  endif
 
 #else
diff --git a/libcxx/include/__type_traits/is_member_pointer.h b/libcxx/include/__type_traits/is_member_pointer.h
index 3e2753ac4228c2..4c6bf7b3c0f56a 100644
--- a/libcxx/include/__type_traits/is_member_pointer.h
+++ b/libcxx/include/__type_traits/is_member_pointer.h
@@ -29,13 +29,13 @@ struct _LIBCPP_TEMPLATE_VIS is_member_function_pointer : _BoolConstant<__is_memb
 
 #if _LIBCPP_STD_VER >= 17
 template <class _Tp>
-inline constexpr bool is_member_pointer_v = __is_member_pointer(_Tp);
+_LIBCPP_EXPORTED_FROM_ABI inline constexpr bool is_member_pointer_v = __is_member_pointer(_Tp);
 
 template <class _Tp>
-...
[truncated]

Copy link

github-actions bot commented Oct 8, 2024

⚠️ C/C++ code formatter, clang-format found issues in your code. ⚠️

You can test this locally with the following command:
git-clang-format --diff 1df8ccd35b7140b4f1ca9e6d9d2fdf67f93357d4 b92b11f7affcff01131a1a1f4fe2ba23adf0233c --extensions cpp,h -- libcxx/test/std/utilities/meta/meta.rel/visibility.sh.cpp libcxx/test/std/utilities/meta/meta.trans/visibility.sh.cpp libcxx/test/std/utilities/meta/meta.unary.prop.query/visibility.sh.cpp libcxx/test/std/utilities/meta/meta.unary/visibility.sh.cpp libcxx/include/__type_traits/alignment_of.h libcxx/include/__type_traits/extent.h libcxx/include/__type_traits/has_unique_object_representation.h libcxx/include/__type_traits/has_virtual_destructor.h libcxx/include/__type_traits/invoke.h libcxx/include/__type_traits/is_abstract.h libcxx/include/__type_traits/is_aggregate.h libcxx/include/__type_traits/is_arithmetic.h libcxx/include/__type_traits/is_array.h libcxx/include/__type_traits/is_assignable.h libcxx/include/__type_traits/is_base_of.h libcxx/include/__type_traits/is_bounded_array.h libcxx/include/__type_traits/is_class.h libcxx/include/__type_traits/is_compound.h libcxx/include/__type_traits/is_const.h libcxx/include/__type_traits/is_constructible.h libcxx/include/__type_traits/is_convertible.h libcxx/include/__type_traits/is_destructible.h libcxx/include/__type_traits/is_empty.h libcxx/include/__type_traits/is_enum.h libcxx/include/__type_traits/is_final.h libcxx/include/__type_traits/is_floating_point.h libcxx/include/__type_traits/is_function.h libcxx/include/__type_traits/is_fundamental.h libcxx/include/__type_traits/is_integral.h libcxx/include/__type_traits/is_member_pointer.h libcxx/include/__type_traits/is_nothrow_assignable.h libcxx/include/__type_traits/is_nothrow_constructible.h libcxx/include/__type_traits/is_nothrow_convertible.h libcxx/include/__type_traits/is_nothrow_destructible.h libcxx/include/__type_traits/is_null_pointer.h libcxx/include/__type_traits/is_object.h libcxx/include/__type_traits/is_pointer.h libcxx/include/__type_traits/is_polymorphic.h libcxx/include/__type_traits/is_reference.h libcxx/include/__type_traits/is_same.h libcxx/include/__type_traits/is_scalar.h libcxx/include/__type_traits/is_signed.h libcxx/include/__type_traits/is_standard_layout.h libcxx/include/__type_traits/is_swappable.h libcxx/include/__type_traits/is_trivial.h libcxx/include/__type_traits/is_trivially_assignable.h libcxx/include/__type_traits/is_trivially_constructible.h libcxx/include/__type_traits/is_trivially_copyable.h libcxx/include/__type_traits/is_trivially_destructible.h libcxx/include/__type_traits/is_unbounded_array.h libcxx/include/__type_traits/is_union.h libcxx/include/__type_traits/is_unsigned.h libcxx/include/__type_traits/is_void.h libcxx/include/__type_traits/is_volatile.h libcxx/include/__type_traits/rank.h
View the diff from clang-format here.
diff --git a/libcxx/include/__type_traits/has_unique_object_representation.h b/libcxx/include/__type_traits/has_unique_object_representation.h
index ff474f731e..ec7040a8ec 100644
--- a/libcxx/include/__type_traits/has_unique_object_representation.h
+++ b/libcxx/include/__type_traits/has_unique_object_representation.h
@@ -31,7 +31,8 @@ struct _LIBCPP_TEMPLATE_VIS has_unique_object_representations
     : public integral_constant<bool, __has_unique_object_representations(remove_all_extents_t<_Tp>)> {};
 
 template <class _Tp>
-_LIBCPP_EXPORTED_FROM_ABI inline constexpr bool has_unique_object_representations_v = __has_unique_object_representations(_Tp);
+_LIBCPP_EXPORTED_FROM_ABI inline constexpr bool has_unique_object_representations_v =
+    __has_unique_object_representations(_Tp);
 
 #endif
 
diff --git a/libcxx/include/__type_traits/invoke.h b/libcxx/include/__type_traits/invoke.h
index 10725f0f61..5e9cd7504d 100644
--- a/libcxx/include/__type_traits/invoke.h
+++ b/libcxx/include/__type_traits/invoke.h
@@ -255,7 +255,8 @@ template <class _Fn, class... _Args>
 _LIBCPP_EXPORTED_FROM_ABI inline constexpr bool is_nothrow_invocable_v = is_nothrow_invocable<_Fn, _Args...>::value;
 
 template <class _Ret, class _Fn, class... _Args>
-_LIBCPP_EXPORTED_FROM_ABI inline constexpr bool is_nothrow_invocable_r_v = is_nothrow_invocable_r<_Ret, _Fn, _Args...>::value;
+_LIBCPP_EXPORTED_FROM_ABI inline constexpr bool is_nothrow_invocable_r_v =
+    is_nothrow_invocable_r<_Ret, _Fn, _Args...>::value;
 
 template <class _Fn, class... _Args>
 struct _LIBCPP_TEMPLATE_VIS invoke_result : __invoke_of<_Fn, _Args...> {};
diff --git a/libcxx/include/__type_traits/is_nothrow_constructible.h b/libcxx/include/__type_traits/is_nothrow_constructible.h
index 762936b9c1..27c4f35111 100644
--- a/libcxx/include/__type_traits/is_nothrow_constructible.h
+++ b/libcxx/include/__type_traits/is_nothrow_constructible.h
@@ -26,7 +26,8 @@ struct _LIBCPP_TEMPLATE_VIS is_nothrow_constructible
 
 #if _LIBCPP_STD_VER >= 17
 template <class _Tp, class... _Args>
-_LIBCPP_EXPORTED_FROM_ABI inline constexpr bool is_nothrow_constructible_v = is_nothrow_constructible<_Tp, _Args...>::value;
+_LIBCPP_EXPORTED_FROM_ABI inline constexpr bool is_nothrow_constructible_v =
+    is_nothrow_constructible<_Tp, _Args...>::value;
 #endif
 
 template <class _Tp>
@@ -35,7 +36,8 @@ struct _LIBCPP_TEMPLATE_VIS is_nothrow_copy_constructible
 
 #if _LIBCPP_STD_VER >= 17
 template <class _Tp>
-_LIBCPP_EXPORTED_FROM_ABI inline constexpr bool is_nothrow_copy_constructible_v = is_nothrow_copy_constructible<_Tp>::value;
+_LIBCPP_EXPORTED_FROM_ABI inline constexpr bool is_nothrow_copy_constructible_v =
+    is_nothrow_copy_constructible<_Tp>::value;
 #endif
 
 template <class _Tp>
@@ -44,7 +46,8 @@ struct _LIBCPP_TEMPLATE_VIS is_nothrow_move_constructible
 
 #if _LIBCPP_STD_VER >= 17
 template <class _Tp>
-_LIBCPP_EXPORTED_FROM_ABI inline constexpr bool is_nothrow_move_constructible_v = is_nothrow_move_constructible<_Tp>::value;
+_LIBCPP_EXPORTED_FROM_ABI inline constexpr bool is_nothrow_move_constructible_v =
+    is_nothrow_move_constructible<_Tp>::value;
 #endif
 
 template <class _Tp>
diff --git a/libcxx/include/__type_traits/is_trivially_assignable.h b/libcxx/include/__type_traits/is_trivially_assignable.h
index 20e4991dee..d6f9bb0eb4 100644
--- a/libcxx/include/__type_traits/is_trivially_assignable.h
+++ b/libcxx/include/__type_traits/is_trivially_assignable.h
@@ -37,7 +37,8 @@ struct _LIBCPP_TEMPLATE_VIS is_trivially_copy_assignable
 
 #if _LIBCPP_STD_VER >= 17
 template <class _Tp>
-_LIBCPP_EXPORTED_FROM_ABI inline constexpr bool is_trivially_copy_assignable_v = is_trivially_copy_assignable<_Tp>::value;
+_LIBCPP_EXPORTED_FROM_ABI inline constexpr bool is_trivially_copy_assignable_v =
+    is_trivially_copy_assignable<_Tp>::value;
 #endif
 
 template <class _Tp>
@@ -48,7 +49,8 @@ struct _LIBCPP_TEMPLATE_VIS is_trivially_move_assignable
 
 #if _LIBCPP_STD_VER >= 17
 template <class _Tp>
-_LIBCPP_EXPORTED_FROM_ABI inline constexpr bool is_trivially_move_assignable_v = is_trivially_move_assignable<_Tp>::value;
+_LIBCPP_EXPORTED_FROM_ABI inline constexpr bool is_trivially_move_assignable_v =
+    is_trivially_move_assignable<_Tp>::value;
 #endif
 
 _LIBCPP_END_NAMESPACE_STD
diff --git a/libcxx/include/__type_traits/is_trivially_constructible.h b/libcxx/include/__type_traits/is_trivially_constructible.h
index 06f8bee52f..4f0ef24457 100644
--- a/libcxx/include/__type_traits/is_trivially_constructible.h
+++ b/libcxx/include/__type_traits/is_trivially_constructible.h
@@ -26,7 +26,8 @@ struct _LIBCPP_TEMPLATE_VIS is_trivially_constructible
 
 #if _LIBCPP_STD_VER >= 17
 template <class _Tp, class... _Args>
-_LIBCPP_EXPORTED_FROM_ABI inline constexpr bool is_trivially_constructible_v = __is_trivially_constructible(_Tp, _Args...);
+_LIBCPP_EXPORTED_FROM_ABI inline constexpr bool is_trivially_constructible_v =
+    __is_trivially_constructible(_Tp, _Args...);
 #endif
 
 template <class _Tp>
@@ -35,7 +36,8 @@ struct _LIBCPP_TEMPLATE_VIS is_trivially_copy_constructible
 
 #if _LIBCPP_STD_VER >= 17
 template <class _Tp>
-_LIBCPP_EXPORTED_FROM_ABI inline constexpr bool is_trivially_copy_constructible_v = is_trivially_copy_constructible<_Tp>::value;
+_LIBCPP_EXPORTED_FROM_ABI inline constexpr bool is_trivially_copy_constructible_v =
+    is_trivially_copy_constructible<_Tp>::value;
 #endif
 
 template <class _Tp>
@@ -44,7 +46,8 @@ struct _LIBCPP_TEMPLATE_VIS is_trivially_move_constructible
 
 #if _LIBCPP_STD_VER >= 17
 template <class _Tp>
-_LIBCPP_EXPORTED_FROM_ABI inline constexpr bool is_trivially_move_constructible_v = is_trivially_move_constructible<_Tp>::value;
+_LIBCPP_EXPORTED_FROM_ABI inline constexpr bool is_trivially_move_constructible_v =
+    is_trivially_move_constructible<_Tp>::value;
 #endif
 
 template <class _Tp>
@@ -53,7 +56,8 @@ struct _LIBCPP_TEMPLATE_VIS is_trivially_default_constructible
 
 #if _LIBCPP_STD_VER >= 17
 template <class _Tp>
-_LIBCPP_EXPORTED_FROM_ABI inline constexpr bool is_trivially_default_constructible_v = __is_trivially_constructible(_Tp);
+_LIBCPP_EXPORTED_FROM_ABI inline constexpr bool is_trivially_default_constructible_v =
+    __is_trivially_constructible(_Tp);
 #endif
 
 _LIBCPP_END_NAMESPACE_STD
diff --git a/libcxx/test/std/utilities/meta/meta.unary/visibility.sh.cpp b/libcxx/test/std/utilities/meta/meta.unary/visibility.sh.cpp
index dabe3a9a9d..a9fae71b5c 100644
--- a/libcxx/test/std/utilities/meta/meta.unary/visibility.sh.cpp
+++ b/libcxx/test/std/utilities/meta/meta.unary/visibility.sh.cpp
@@ -106,7 +106,7 @@ inline std::vector<void*> get_ptrs() {
 }
 
 inline std::vector<const std::type_info*> get_type_infos() {
-    return {
+  return {
       // [meta.unary.cat]
       &typeid(std::is_void<int>),
       &typeid(std::is_null_pointer<int>),


inline std::vector<const std::type_info*> get_type_infos() {
return {
&typeid(std::remove_const<int>),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I really question the value of this. For the inline variables, sure, but do we really want to get into the business of providing this guarantee for arbitrary type traits? The value this provides to users seems to be really small.

By the way, do we have the same problem for nearly all other types in the library?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Technically we have to do that to be conforming I think.

Depends on what you mean by problem. We have default visibility for all the type symbols, at least on clang, so this is really just testing what we do already here. If you mean that we don't test this for any type in the library, then yes, this is the first test to make sure any type symbols have default visibility.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This has the potential to get really out of hands for a questionable benefit, don't you think? Some types definitely need their visibility to be correct, like exception types. If we make a mistake on one of those, the exception handling mechanism won't work properly. But for e.g. type traits, this really doesn't matter that much. I think that's why I'm surprised you're starting with those tests.

If we follow the reasoning here, we would end up adding a test that every type we add to the library has the right visibility. And we would add a new test like that whenever we implement a new user-visible type. Is that what you have in mind?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree that type traits aren't the most useful to have correct RTTI for. I really just started with those because I had to write a test for the variables anyways. Adding a test for the classes was not significantly more work than copy-pasting the code. OTOH I could see a use-case for pretty much every non-empty type, so adding the few empty types doesn't seem like that much extra work for a tick-mark in "fully conforming across dylib boundaries".

I think it would be good to add tests for the important types (string, vector, exception types, etc.), since I did almost regress on this a few times in the past. Then again, the situation has changed now, since all types are properly annotated through _LIBCPP_BEGIN_NAMESPACE_STD except when using GCC. So maybe it would be good enough to add a clang-tidy test ensuring all public types have the proper annotations.

FYI we'll probably have a longer discussion on GCC and ABI guarantees tomorrow, so maybe we could talk about this more at that point if there is some time.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking forward to that discussion. Those are always a treat!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Per live review, you are correct that this is needed for standards conformance. However, the question of whether we care enough about this aspect of conformance to take (a hypothetical) load-time performance hit is something worth asking.

I wonder if this will truly cause an increase in the number of weak symbols in normal programs. It's OK if a program that clearly ODR-uses foo_v ends up with a weak-def, since that's necessary for correctness. What's bad is if idiomatic usage of these traits end up generating weak-defs that can't be removed: then we'd introduce a load-time regression for the purpose of standards conformance, but for an aspect of conformance that provides very very marginal actual value.

In order to know whether this is worth it, could you please check in which cases a weak def is actually emitted? Also, I think it could be insightful to run the test suite and nm the executables produced while looking for weak-defs. If the number of weak-defs increases significantly after this change, that's some data point we could use to make a decision. If it doesn't, and if Clang seems to not be emitting weak-defs in "useless" cases, then I don't think there's much to push back against this change.

The level of testing is another aspect we could discuss if we decide to move forward, but I think that's a minor point.


For the nm experiment, I would personally modify format.py to automatically run nm %t.exe with some post-processing after every .pass.cpp test. I think that would be good enough.


inline std::vector<const std::type_info*> get_type_infos() {
return {
&typeid(std::remove_const<int>),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Per live review, you are correct that this is needed for standards conformance. However, the question of whether we care enough about this aspect of conformance to take (a hypothetical) load-time performance hit is something worth asking.

I wonder if this will truly cause an increase in the number of weak symbols in normal programs. It's OK if a program that clearly ODR-uses foo_v ends up with a weak-def, since that's necessary for correctness. What's bad is if idiomatic usage of these traits end up generating weak-defs that can't be removed: then we'd introduce a load-time regression for the purpose of standards conformance, but for an aspect of conformance that provides very very marginal actual value.

In order to know whether this is worth it, could you please check in which cases a weak def is actually emitted? Also, I think it could be insightful to run the test suite and nm the executables produced while looking for weak-defs. If the number of weak-defs increases significantly after this change, that's some data point we could use to make a decision. If it doesn't, and if Clang seems to not be emitting weak-defs in "useless" cases, then I don't think there's much to push back against this change.

The level of testing is another aspect we could discuss if we decide to move forward, but I think that's a minor point.


For the nm experiment, I would personally modify format.py to automatically run nm %t.exe with some post-processing after every .pass.cpp test. I think that would be good enough.

@philnik777 philnik777 closed this May 19, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants