[libcxx-commits] [libcxx] fd001c1 - [libc++] Workaround clang bug in __has_unique_object_representations (#95314)
via libcxx-commits
libcxx-commits at lists.llvm.org
Thu Jun 20 13:34:05 PDT 2024
Author: Louis Dionne
Date: 2024-06-20T16:34:02-04:00
New Revision: fd001c16fed19249eec47d16ade9ad5810489c37
URL: https://github.com/llvm/llvm-project/commit/fd001c16fed19249eec47d16ade9ad5810489c37
DIFF: https://github.com/llvm/llvm-project/commit/fd001c16fed19249eec47d16ade9ad5810489c37.diff
LOG: [libc++] Workaround clang bug in __has_unique_object_representations (#95314)
Clang currently has a bug in the __has_unique_object_representations
builtin where it doesn't provide consistent answers based on the order
of instantiation of templates. This was reported as #95311.
This patch adds a workaround in libc++ to avoid breaking users until
Clang has been fixed. It also revamps the tests a bit.
Added:
libcxx/test/std/utilities/meta/meta.unary/meta.unary.prop/has_unique_object_representations.compile.pass.cpp
Modified:
libcxx/include/__type_traits/has_unique_object_representation.h
Removed:
libcxx/test/std/utilities/meta/meta.unary/meta.unary.prop/has_unique_object_representations.pass.cpp
################################################################################
diff --git a/libcxx/include/__type_traits/has_unique_object_representation.h b/libcxx/include/__type_traits/has_unique_object_representation.h
index 1aa044990032a..98c440c16bf26 100644
--- a/libcxx/include/__type_traits/has_unique_object_representation.h
+++ b/libcxx/include/__type_traits/has_unique_object_representation.h
@@ -11,6 +11,7 @@
#include <__config>
#include <__type_traits/integral_constant.h>
+#include <__type_traits/remove_all_extents.h>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
@@ -22,7 +23,12 @@ _LIBCPP_BEGIN_NAMESPACE_STD
template <class _Tp>
struct _LIBCPP_TEMPLATE_VIS has_unique_object_representations
- : public integral_constant<bool, __has_unique_object_representations(_Tp)> {};
+ // TODO: We work around a Clang and GCC bug in __has_unique_object_representations by using remove_all_extents
+ // even though it should not be necessary. This was reported to the compilers:
+ // - Clang: https://github.com/llvm/llvm-project/issues/95311
+ // - GCC: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=115476
+ // remove_all_extents_t can be removed once all the compilers we support have fixed this bug.
+ : 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);
diff --git a/libcxx/test/std/utilities/meta/meta.unary/meta.unary.prop/has_unique_object_representations.compile.pass.cpp b/libcxx/test/std/utilities/meta/meta.unary/meta.unary.prop/has_unique_object_representations.compile.pass.cpp
new file mode 100644
index 0000000000000..bd7da40daf2bc
--- /dev/null
+++ b/libcxx/test/std/utilities/meta/meta.unary/meta.unary.prop/has_unique_object_representations.compile.pass.cpp
@@ -0,0 +1,106 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14
+
+// type_traits
+
+// has_unique_object_representations
+
+#include <type_traits>
+
+template <bool ExpectedValue, class T>
+void test() {
+ static_assert(std::has_unique_object_representations<T>::value == ExpectedValue);
+ static_assert(std::has_unique_object_representations<const T>::value == ExpectedValue);
+ static_assert(std::has_unique_object_representations<volatile T>::value == ExpectedValue);
+ static_assert(std::has_unique_object_representations<const volatile T>::value == ExpectedValue);
+
+ static_assert(std::has_unique_object_representations_v<T> == ExpectedValue);
+ static_assert(std::has_unique_object_representations_v<const T> == ExpectedValue);
+ static_assert(std::has_unique_object_representations_v<volatile T> == ExpectedValue);
+ static_assert(std::has_unique_object_representations_v<const volatile T> == ExpectedValue);
+}
+
+class Empty {};
+
+union EmptyUnion {};
+
+struct NonEmptyUnion {
+ int x;
+ unsigned y;
+};
+
+struct ZeroWidthBitfield {
+ int : 0;
+};
+
+class Virtual {
+ virtual ~Virtual();
+};
+
+class Abstract {
+ virtual ~Abstract() = 0;
+};
+
+struct UnsignedInt {
+ unsigned foo;
+};
+
+struct WithoutPadding {
+ int x;
+ int y;
+};
+
+struct WithPadding {
+ char bar;
+ int foo;
+};
+
+template <int>
+class NTTP_ClassType_WithoutPadding {
+ int x;
+};
+
+void test() {
+ test<false, void>();
+ test<false, Empty>();
+ test<false, EmptyUnion>();
+ test<false, Virtual>();
+ test<false, ZeroWidthBitfield>();
+ test<false, Abstract>();
+ test<false, WithPadding>();
+ test<false, WithPadding[]>();
+ test<false, WithPadding[][3]>();
+
+ // I would also expect that there are systems where they do not.
+ // I would expect all three of these to have unique representations.
+ // test<false, int&>();
+ // test<false, int *>();
+ // test<false, double>();
+
+ test<true, unsigned>();
+ test<true, UnsignedInt>();
+ test<true, WithoutPadding>();
+ test<true, NonEmptyUnion>();
+ test<true, char[3]>();
+ test<true, char[3][4]>();
+ test<true, char[3][4][5]>();
+ test<true, char[]>();
+ test<true, char[][2]>();
+ test<true, char[][2][3]>();
+
+ // Important test case for https://github.com/llvm/llvm-project/issues/95311.
+ // Note that the order is important here, we want to instantiate the array
+ // variants before the non-array ones, otherwise we don't trigger the bug.
+ {
+ test<true, NTTP_ClassType_WithoutPadding<0>[]>();
+ test<true, NTTP_ClassType_WithoutPadding<0>[][3]>();
+ test<true, NTTP_ClassType_WithoutPadding<0>>();
+ }
+}
diff --git a/libcxx/test/std/utilities/meta/meta.unary/meta.unary.prop/has_unique_object_representations.pass.cpp b/libcxx/test/std/utilities/meta/meta.unary/meta.unary.prop/has_unique_object_representations.pass.cpp
deleted file mode 100644
index b8b84bb908827..0000000000000
--- a/libcxx/test/std/utilities/meta/meta.unary/meta.unary.prop/has_unique_object_representations.pass.cpp
+++ /dev/null
@@ -1,108 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-// UNSUPPORTED: c++03, c++11, c++14
-
-// type_traits
-
-// has_unique_object_representations
-
-#include <type_traits>
-
-#include "test_macros.h"
-
-template <class T>
-void test_has_unique_object_representations()
-{
- static_assert( std::has_unique_object_representations<T>::value, "");
- static_assert( std::has_unique_object_representations<const T>::value, "");
- static_assert( std::has_unique_object_representations<volatile T>::value, "");
- static_assert( std::has_unique_object_representations<const volatile T>::value, "");
-
- static_assert( std::has_unique_object_representations_v<T>, "");
- static_assert( std::has_unique_object_representations_v<const T>, "");
- static_assert( std::has_unique_object_representations_v<volatile T>, "");
- static_assert( std::has_unique_object_representations_v<const volatile T>, "");
-}
-
-template <class T>
-void test_has_not_has_unique_object_representations()
-{
- static_assert(!std::has_unique_object_representations<T>::value, "");
- static_assert(!std::has_unique_object_representations<const T>::value, "");
- static_assert(!std::has_unique_object_representations<volatile T>::value, "");
- static_assert(!std::has_unique_object_representations<const volatile T>::value, "");
-
- static_assert(!std::has_unique_object_representations_v<T>, "");
- static_assert(!std::has_unique_object_representations_v<const T>, "");
- static_assert(!std::has_unique_object_representations_v<volatile T>, "");
- static_assert(!std::has_unique_object_representations_v<const volatile T>, "");
-}
-
-class Empty
-{
-};
-
-class NotEmpty
-{
- virtual ~NotEmpty();
-};
-
-union EmptyUnion {};
-struct NonEmptyUnion {int x; unsigned y;};
-
-struct bit_zero
-{
- int : 0;
-};
-
-class Abstract
-{
- virtual ~Abstract() = 0;
-};
-
-struct A
-{
- ~A();
- unsigned foo;
-};
-
-struct B
-{
- char bar;
- int foo;
-};
-
-
-int main(int, char**)
-{
- test_has_not_has_unique_object_representations<void>();
- test_has_not_has_unique_object_representations<Empty>();
- test_has_not_has_unique_object_representations<EmptyUnion>();
- test_has_not_has_unique_object_representations<NotEmpty>();
- test_has_not_has_unique_object_representations<bit_zero>();
- test_has_not_has_unique_object_representations<Abstract>();
- test_has_not_has_unique_object_representations<B>();
-
-// I would expect all three of these to have unique representations.
-// I would also expect that there are systems where they do not.
-// test_has_not_has_unique_object_representations<int&>();
-// test_has_not_has_unique_object_representations<int *>();
-// test_has_not_has_unique_object_representations<double>();
-
-
- test_has_unique_object_representations<unsigned>();
- test_has_unique_object_representations<NonEmptyUnion>();
- test_has_unique_object_representations<char[3]>();
- test_has_unique_object_representations<char[3][4]>();
- test_has_unique_object_representations<char[3][4][5]>();
- test_has_unique_object_representations<char[]>();
-
-
- return 0;
-}
More information about the libcxx-commits
mailing list