[llvm] [libc] Add type_traits tests (PR #65956)

Guillaume Chatelet via llvm-commits llvm-commits at lists.llvm.org
Mon Sep 11 07:10:45 PDT 2023


https://github.com/gchatelet updated https://github.com/llvm/llvm-project/pull/65956:

>From 138dbdfb88a694bef8fd88b14641e69e51018e31 Mon Sep 17 00:00:00 2001
From: Guillaume Chatelet <gchatelet at google.com>
Date: Mon, 11 Sep 2023 12:51:54 +0000
Subject: [PATCH 1/3] [libc] Add type_traits tests

---
 libc/test/src/__support/CPP/CMakeLists.txt    |  10 +
 .../src/__support/CPP/type_traits_test.cpp    | 268 ++++++++++++++++++
 .../libc/test/src/__support/CPP/BUILD.bazel   |  10 +
 3 files changed, 288 insertions(+)
 create mode 100644 libc/test/src/__support/CPP/type_traits_test.cpp

diff --git a/libc/test/src/__support/CPP/CMakeLists.txt b/libc/test/src/__support/CPP/CMakeLists.txt
index be2bc20d780471a..5772a83a65cad13 100644
--- a/libc/test/src/__support/CPP/CMakeLists.txt
+++ b/libc/test/src/__support/CPP/CMakeLists.txt
@@ -106,3 +106,13 @@ add_libc_test(
   libc.src.__support.CPP.string
   libc.src.__support.CPP.string_view
 )
+
+add_libc_test(
+  type_traits_test
+  SUITE
+    libc-cpp-utils-tests
+  SRCS
+  type_traits_test.cpp
+  DEPENDS
+  libc.src.__support.CPP.type_traits
+)
diff --git a/libc/test/src/__support/CPP/type_traits_test.cpp b/libc/test/src/__support/CPP/type_traits_test.cpp
new file mode 100644
index 000000000000000..69b7009e636b3a8
--- /dev/null
+++ b/libc/test/src/__support/CPP/type_traits_test.cpp
@@ -0,0 +1,268 @@
+//===-- Unittests for type_traits -----------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/__support/CPP/type_traits.h"
+#include "test/UnitTest/Test.h"
+
+// TODO: Split this file if it becomes too big.
+
+namespace __llvm_libc::cpp {
+
+class Class {};
+union Union {};
+struct Struct {};
+
+using UnqualObjectTypes = testing::TypeList<int, float, Class, Union, Struct>;
+
+TYPED_TEST(LlvmLibcTypeTraitsTest, add_lvalue_reference, UnqualObjectTypes) {
+
+  // non-ref cv, adds ref
+  EXPECT_TRUE((is_same_v<add_lvalue_reference_t<T>, T &>));
+  EXPECT_TRUE((is_same_v<add_lvalue_reference_t<const T>, const T &>));
+  EXPECT_TRUE((is_same_v<add_lvalue_reference_t<volatile T>, volatile T &>));
+  EXPECT_TRUE((
+      is_same_v<add_lvalue_reference_t<const volatile T>, const volatile T &>));
+
+  // ref cv, returns same type
+  EXPECT_TRUE((is_same_v<add_lvalue_reference_t<T &>, T &>));
+  EXPECT_TRUE((is_same_v<add_lvalue_reference_t<const T &>, const T &>));
+  EXPECT_TRUE((is_same_v<add_lvalue_reference_t<volatile T &>, volatile T &>));
+  EXPECT_TRUE((is_same_v<add_lvalue_reference_t<const volatile T &>,
+                         const volatile T &>));
+}
+
+TEST(LlvmLibcTypeTraitsTest, add_lvalue_reference_void) {
+  // void cannot be referenced
+  EXPECT_TRUE((is_same_v<add_lvalue_reference_t<void>, void>));
+  EXPECT_TRUE((is_same_v<add_lvalue_reference_t<const void>, const void>));
+  EXPECT_TRUE(
+      (is_same_v<add_lvalue_reference_t<volatile void>, volatile void>));
+  EXPECT_TRUE((is_same_v<add_lvalue_reference_t<const volatile void>,
+                         const volatile void>));
+}
+
+TYPED_TEST(LlvmLibcTypeTraitsTest, add_pointer, UnqualObjectTypes) {
+  // object types -> pointer type
+  EXPECT_TRUE((is_same_v<add_pointer_t<T>, T *>));
+  EXPECT_TRUE((is_same_v<add_pointer_t<const T>, const T *>));
+  EXPECT_TRUE((is_same_v<add_pointer_t<volatile T>, volatile T *>));
+  EXPECT_TRUE((is_same_v<add_pointer_t<const volatile T>, const volatile T *>));
+
+  // reference type -> pointer type
+  EXPECT_TRUE((is_same_v<add_pointer_t<T &>, T *>));
+  EXPECT_TRUE((is_same_v<add_pointer_t<const T &>, const T *>));
+  EXPECT_TRUE((is_same_v<add_pointer_t<volatile T &>, volatile T *>));
+  EXPECT_TRUE(
+      (is_same_v<add_pointer_t<const volatile T &>, const volatile T *>));
+}
+
+TEST(LlvmLibcTypeTraitsTest, add_pointer_void) {
+  // void -> pointer type
+  EXPECT_TRUE((is_same_v<add_pointer_t<void>, void *>));
+  EXPECT_TRUE((is_same_v<add_pointer_t<const void>, const void *>));
+  EXPECT_TRUE((is_same_v<add_pointer_t<volatile void>, volatile void *>));
+  EXPECT_TRUE(
+      (is_same_v<add_pointer_t<const volatile void>, const volatile void *>));
+}
+
+TYPED_TEST(LlvmLibcTypeTraitsTest, add_rvalue_reference, UnqualObjectTypes) {
+
+  // non-ref cv, adds ref
+  EXPECT_TRUE((is_same_v<add_rvalue_reference_t<T>, T &&>));
+  EXPECT_TRUE((is_same_v<add_rvalue_reference_t<const T>, const T &&>));
+  EXPECT_TRUE((is_same_v<add_rvalue_reference_t<volatile T>, volatile T &&>));
+  EXPECT_TRUE((is_same_v<add_rvalue_reference_t<const volatile T>,
+                         const volatile T &&>));
+
+  // ref cv, returns same type
+  EXPECT_TRUE((is_same_v<add_rvalue_reference_t<T &>, T &>));
+  EXPECT_TRUE((is_same_v<add_rvalue_reference_t<const T &>, const T &>));
+  EXPECT_TRUE((is_same_v<add_rvalue_reference_t<volatile T &>, volatile T &>));
+  EXPECT_TRUE((is_same_v<add_rvalue_reference_t<const volatile T &>,
+                         const volatile T &>));
+}
+
+TEST(LlvmLibcTypeTraitsTest, add_rvalue_reference_void) {
+  // void cannot be referenced
+  EXPECT_TRUE((is_same_v<add_rvalue_reference_t<void>, void>));
+  EXPECT_TRUE((is_same_v<add_rvalue_reference_t<const void>, const void>));
+  EXPECT_TRUE(
+      (is_same_v<add_rvalue_reference_t<volatile void>, volatile void>));
+  EXPECT_TRUE((is_same_v<add_rvalue_reference_t<const volatile void>,
+                         const volatile void>));
+}
+
+TEST(LlvmLibcTypeTraitsTest, bool_constant) {
+  EXPECT_TRUE((bool_constant<true>::value));
+  EXPECT_FALSE((bool_constant<false>::value));
+}
+
+TEST(LlvmLibcTypeTraitsTest, conditional_t) {
+  EXPECT_TRUE((is_same_v<conditional_t<true, int, float>, int>));
+  EXPECT_TRUE((is_same_v<conditional_t<false, int, float>, float>));
+}
+
+TEST(LlvmLibcTypeTraitsTest, decay) {
+  EXPECT_TRUE((is_same_v<decay_t<int>, int>));
+
+  // array decay
+  EXPECT_TRUE((is_same_v<decay_t<int[2]>, int *>));
+  EXPECT_TRUE((is_same_v<decay_t<int[2]>, int *>));
+  EXPECT_TRUE((is_same_v<decay_t<int[2][4]>, int(*)[4]>));
+
+  // cv ref decay
+  EXPECT_TRUE((is_same_v<decay_t<int &>, int>));
+  EXPECT_TRUE((is_same_v<decay_t<const int &>, int>));
+  EXPECT_TRUE((is_same_v<decay_t<volatile int &>, int>));
+  EXPECT_TRUE((is_same_v<decay_t<const volatile int &>, int>));
+}
+
+// TODO enable_if
+
+TEST(LlvmLibcTypeTraitsTest, false_type) { EXPECT_FALSE((false_type::value)); }
+
+TEST(LlvmLibcTypeTraitsTest, integral_constant) {
+  EXPECT_EQ((integral_constant<int, 4>::value), 4);
+}
+
+using IntegralTypes =
+    testing::TypeList<bool, char, short, int, long, long long, unsigned char,
+                      unsigned short, unsigned int, unsigned long,
+                      unsigned long long>;
+
+TYPED_TEST(LlvmLibcTypeTraitsTest, is_arithmetic, IntegralTypes) {
+  EXPECT_TRUE((is_arithmetic_v<T>));
+  EXPECT_TRUE((is_arithmetic_v<const T>));
+  EXPECT_TRUE((is_arithmetic_v<volatile T>));
+  EXPECT_TRUE((is_arithmetic_v<const volatile T>));
+
+  EXPECT_FALSE((is_arithmetic_v<T *>));
+  EXPECT_FALSE((is_arithmetic_v<T &>));
+}
+
+TEST(LlvmLibcTypeTraitsTest, is_arithmetic_non_integral) {
+  EXPECT_FALSE((is_arithmetic_v<Union>));
+  EXPECT_FALSE((is_arithmetic_v<Class>));
+  EXPECT_FALSE((is_arithmetic_v<Struct>));
+}
+
+TEST(LlvmLibcTypeTraitsTest, is_array) {
+  EXPECT_FALSE((is_array_v<int>));
+  EXPECT_FALSE((is_array_v<float>));
+  EXPECT_FALSE((is_array_v<Struct>));
+
+  EXPECT_TRUE((is_array_v<Class[]>));
+  EXPECT_TRUE((is_array_v<Union[4]>));
+}
+
+TEST(LlvmLibcTypeTraitsTest, is_base_of) {
+  struct A {};
+  EXPECT_TRUE((is_base_of_v<A, A>));
+
+  struct B : public A {};
+  EXPECT_TRUE((is_base_of_v<A, B>));
+  EXPECT_FALSE((is_base_of_v<B, A>));
+
+  struct C : protected A {};
+  EXPECT_TRUE((is_base_of_v<A, C>));
+  EXPECT_FALSE((is_base_of_v<C, A>));
+
+  struct D : private A {};
+  EXPECT_TRUE((is_base_of_v<A, D>));
+  EXPECT_FALSE((is_base_of_v<D, A>));
+}
+
+TEST(LlvmLibcTypeTraitsTest, is_class) {
+  EXPECT_TRUE((is_class_v<Struct>));
+  EXPECT_TRUE((is_class_v<Class>));
+  EXPECT_FALSE((is_class_v<Union>));
+  EXPECT_FALSE((is_class_v<int>));
+}
+
+TYPED_TEST(LlvmLibcTypeTraitsTest, is_const, UnqualObjectTypes) {
+  EXPECT_FALSE((is_const_v<T>));
+  EXPECT_TRUE((is_const_v<const T>));
+}
+
+// TODO is_convertible
+
+TYPED_TEST(LlvmLibcTypeTraitsTest, is_destructible, UnqualObjectTypes) {
+  EXPECT_TRUE((is_destructible_v<T>));
+}
+TEST(LlvmLibcTypeTraitsTest, is_destructible_no_destructor) {
+  struct S {
+    ~S() = delete;
+  };
+  EXPECT_FALSE((is_destructible_v<S>));
+}
+
+TYPED_TEST(LlvmLibcTypeTraitsTest, is_enum, UnqualObjectTypes) {
+  EXPECT_FALSE((is_enum_v<T>));
+}
+TEST(LlvmLibcTypeTraitsTest, is_enum_enum) {
+  enum Enum {};
+  EXPECT_TRUE((is_enum_v<Enum>));
+}
+
+// TODO is_floating_point
+
+// TODO is_function
+
+// TODO is_integral
+
+// TODO is_lvalue_reference
+
+// TODO is_member_pointer
+
+// TODO is_null_pointer
+
+// TODO is_pointer
+
+// TODO is_reference
+
+// TODO is_rvalue_reference
+
+// TODO is_same
+
+// TODO is_scalar
+
+// TODO is_signed
+
+// TODO is_trivially_constructible
+
+// TODO is_trivially_copyable
+
+// TODO is_trivially_destructible
+
+// TODO is_union
+
+// TODO is_unsigned
+
+// TODO is_void
+
+// TODO make_signed
+
+// TODO make_unsigned
+
+// TODO remove_all_extents
+
+// TODO remove_cv
+
+// TODO remove_cvref
+
+// TODO remove_extent
+
+// TODO remove_reference
+
+TEST(LlvmLibcTypeTraitsTest, true_type) { EXPECT_TRUE((true_type::value)); }
+
+// TODO type_identity
+
+// TODO void_t
+
+} // namespace __llvm_libc::cpp
diff --git a/utils/bazel/llvm-project-overlay/libc/test/src/__support/CPP/BUILD.bazel b/utils/bazel/llvm-project-overlay/libc/test/src/__support/CPP/BUILD.bazel
index c74f9821849a7a0..5ebd8260035792d 100644
--- a/utils/bazel/llvm-project-overlay/libc/test/src/__support/CPP/BUILD.bazel
+++ b/utils/bazel/llvm-project-overlay/libc/test/src/__support/CPP/BUILD.bazel
@@ -110,3 +110,13 @@ cc_test(
         "//libc/test/UnitTest:LibcUnitTest",
     ],
 )
+
+cc_test(
+    name = "type_traits_test",
+    srcs = ["type_traits_test.cpp"],
+    deps = [
+        "//libc:__support_cpp_type_traits",
+        "//libc:libc_root",
+        "//libc/test/UnitTest:LibcUnitTest",
+    ],
+)

>From 801f82bd8397535a85fe5ee38c2a8dd420b1337c Mon Sep 17 00:00:00 2001
From: Guillaume Chatelet <gchatelet at google.com>
Date: Mon, 11 Sep 2023 14:07:58 +0000
Subject: [PATCH 2/3] Address commetns

---
 .../src/__support/CPP/type_traits_test.cpp    | 39 ++++++++++++++++---
 1 file changed, 34 insertions(+), 5 deletions(-)

diff --git a/libc/test/src/__support/CPP/type_traits_test.cpp b/libc/test/src/__support/CPP/type_traits_test.cpp
index 69b7009e636b3a8..849a35799e1c552 100644
--- a/libc/test/src/__support/CPP/type_traits_test.cpp
+++ b/libc/test/src/__support/CPP/type_traits_test.cpp
@@ -16,11 +16,12 @@ namespace __llvm_libc::cpp {
 class Class {};
 union Union {};
 struct Struct {};
+enum Enum {};
+enum class EnumClass {};
 
 using UnqualObjectTypes = testing::TypeList<int, float, Class, Union, Struct>;
 
 TYPED_TEST(LlvmLibcTypeTraitsTest, add_lvalue_reference, UnqualObjectTypes) {
-
   // non-ref cv, adds ref
   EXPECT_TRUE((is_same_v<add_lvalue_reference_t<T>, T &>));
   EXPECT_TRUE((is_same_v<add_lvalue_reference_t<const T>, const T &>));
@@ -28,6 +29,13 @@ TYPED_TEST(LlvmLibcTypeTraitsTest, add_lvalue_reference, UnqualObjectTypes) {
   EXPECT_TRUE((
       is_same_v<add_lvalue_reference_t<const volatile T>, const volatile T &>));
 
+  // pointer cv, adds ref
+  EXPECT_TRUE((is_same_v<add_lvalue_reference_t<T *>, T *&>));
+  EXPECT_TRUE((is_same_v<add_lvalue_reference_t<const T *>, const T *&>));
+  EXPECT_TRUE((is_same_v<add_lvalue_reference_t<volatile T *>, volatile T *&>));
+  EXPECT_TRUE((is_same_v<add_lvalue_reference_t<const volatile T *>,
+                         const volatile T *&>));
+
   // ref cv, returns same type
   EXPECT_TRUE((is_same_v<add_lvalue_reference_t<T &>, T &>));
   EXPECT_TRUE((is_same_v<add_lvalue_reference_t<const T &>, const T &>));
@@ -53,6 +61,13 @@ TYPED_TEST(LlvmLibcTypeTraitsTest, add_pointer, UnqualObjectTypes) {
   EXPECT_TRUE((is_same_v<add_pointer_t<volatile T>, volatile T *>));
   EXPECT_TRUE((is_same_v<add_pointer_t<const volatile T>, const volatile T *>));
 
+  // pointer types -> pointer type
+  EXPECT_TRUE((is_same_v<add_pointer_t<T *>, T **>));
+  EXPECT_TRUE((is_same_v<add_pointer_t<const T *>, const T **>));
+  EXPECT_TRUE((is_same_v<add_pointer_t<volatile T *>, volatile T **>));
+  EXPECT_TRUE(
+      (is_same_v<add_pointer_t<const volatile T *>, const volatile T **>));
+
   // reference type -> pointer type
   EXPECT_TRUE((is_same_v<add_pointer_t<T &>, T *>));
   EXPECT_TRUE((is_same_v<add_pointer_t<const T &>, const T *>));
@@ -130,12 +145,12 @@ TEST(LlvmLibcTypeTraitsTest, integral_constant) {
   EXPECT_EQ((integral_constant<int, 4>::value), 4);
 }
 
-using IntegralTypes =
+using IntegralAndFloatingTypes =
     testing::TypeList<bool, char, short, int, long, long long, unsigned char,
                       unsigned short, unsigned int, unsigned long,
-                      unsigned long long>;
+                      unsigned long long, float, double, long double>;
 
-TYPED_TEST(LlvmLibcTypeTraitsTest, is_arithmetic, IntegralTypes) {
+TYPED_TEST(LlvmLibcTypeTraitsTest, is_arithmetic, IntegralAndFloatingTypes) {
   EXPECT_TRUE((is_arithmetic_v<T>));
   EXPECT_TRUE((is_arithmetic_v<const T>));
   EXPECT_TRUE((is_arithmetic_v<volatile T>));
@@ -149,12 +164,14 @@ TEST(LlvmLibcTypeTraitsTest, is_arithmetic_non_integral) {
   EXPECT_FALSE((is_arithmetic_v<Union>));
   EXPECT_FALSE((is_arithmetic_v<Class>));
   EXPECT_FALSE((is_arithmetic_v<Struct>));
+  EXPECT_FALSE((is_arithmetic_v<Enum>));
 }
 
 TEST(LlvmLibcTypeTraitsTest, is_array) {
   EXPECT_FALSE((is_array_v<int>));
   EXPECT_FALSE((is_array_v<float>));
   EXPECT_FALSE((is_array_v<Struct>));
+  EXPECT_FALSE((is_array_v<int *>));
 
   EXPECT_TRUE((is_array_v<Class[]>));
   EXPECT_TRUE((is_array_v<Union[4]>));
@@ -164,6 +181,7 @@ TEST(LlvmLibcTypeTraitsTest, is_base_of) {
   struct A {};
   EXPECT_TRUE((is_base_of_v<A, A>));
 
+  // Test public, protected and private inheritance.
   struct B : public A {};
   EXPECT_TRUE((is_base_of_v<A, B>));
   EXPECT_FALSE((is_base_of_v<B, A>));
@@ -175,13 +193,24 @@ TEST(LlvmLibcTypeTraitsTest, is_base_of) {
   struct D : private A {};
   EXPECT_TRUE((is_base_of_v<A, D>));
   EXPECT_FALSE((is_base_of_v<D, A>));
+
+  // Test inheritance chain.
+  struct E : private B {};
+  EXPECT_TRUE((is_base_of_v<A, E>));
 }
 
 TEST(LlvmLibcTypeTraitsTest, is_class) {
   EXPECT_TRUE((is_class_v<Struct>));
   EXPECT_TRUE((is_class_v<Class>));
+
+  // Pointer or ref do not qualify.
+  EXPECT_FALSE((is_class_v<Class *>));
+  EXPECT_FALSE((is_class_v<Class &>));
+
+  // Neither other types.
   EXPECT_FALSE((is_class_v<Union>));
   EXPECT_FALSE((is_class_v<int>));
+  EXPECT_FALSE((is_class_v<EnumClass>));
 }
 
 TYPED_TEST(LlvmLibcTypeTraitsTest, is_const, UnqualObjectTypes) {
@@ -205,8 +234,8 @@ TYPED_TEST(LlvmLibcTypeTraitsTest, is_enum, UnqualObjectTypes) {
   EXPECT_FALSE((is_enum_v<T>));
 }
 TEST(LlvmLibcTypeTraitsTest, is_enum_enum) {
-  enum Enum {};
   EXPECT_TRUE((is_enum_v<Enum>));
+  EXPECT_TRUE((is_enum_v<EnumClass>));
 }
 
 // TODO is_floating_point

>From 71936cde14df474aaf5951d8a59e524cee00ccfd Mon Sep 17 00:00:00 2001
From: Guillaume Chatelet <gchatelet at google.com>
Date: Mon, 11 Sep 2023 14:10:26 +0000
Subject: [PATCH 3/3] Fixing a missed comment

---
 libc/test/src/__support/CPP/type_traits_test.cpp | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/libc/test/src/__support/CPP/type_traits_test.cpp b/libc/test/src/__support/CPP/type_traits_test.cpp
index 849a35799e1c552..a48d646d29e5c45 100644
--- a/libc/test/src/__support/CPP/type_traits_test.cpp
+++ b/libc/test/src/__support/CPP/type_traits_test.cpp
@@ -216,6 +216,9 @@ TEST(LlvmLibcTypeTraitsTest, is_class) {
 TYPED_TEST(LlvmLibcTypeTraitsTest, is_const, UnqualObjectTypes) {
   EXPECT_FALSE((is_const_v<T>));
   EXPECT_TRUE((is_const_v<const T>));
+
+  using Aliased = const T;
+  EXPECT_TRUE((is_const_v<Aliased>));
 }
 
 // TODO is_convertible



More information about the llvm-commits mailing list