diff options
Diffstat (limited to 'libcxx/test/std/utilities/meta')
-rw-r--r-- | libcxx/test/std/utilities/meta/meta.trans/meta.trans.other/underlying_type.fail.cpp | 38 | ||||
-rw-r--r-- | libcxx/test/std/utilities/meta/meta.trans/meta.trans.other/underlying_type.pass.cpp | 88 |
2 files changed, 106 insertions, 20 deletions
diff --git a/libcxx/test/std/utilities/meta/meta.trans/meta.trans.other/underlying_type.fail.cpp b/libcxx/test/std/utilities/meta/meta.trans/meta.trans.other/underlying_type.fail.cpp new file mode 100644 index 00000000000..9f762ad7e34 --- /dev/null +++ b/libcxx/test/std/utilities/meta/meta.trans/meta.trans.other/underlying_type.fail.cpp @@ -0,0 +1,38 @@ +//===----------------------------------------------------------------------===// +// +// 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++98, c++03, c++11, C++14, c++17 +// type_traits + +// underlying_type +// Mandates: enum must not be an incomplete enumeration type. + +#include <type_traits> +#include <climits> + +#include "test_macros.h" + +enum E1 { E1Zero, E1One, E1Two = sizeof(std::underlying_type<E1>::type) }; // expected-error@type_traits:* {{cannot determine underlying type of incomplete enumeration type 'E1'}} + +// None of these are incomplete. +// Scoped enums have an underlying type of 'int' unless otherwise specified +// Unscoped enums with a specified underlying type become complete as soon as that type is specified. +// enum E2 : char { E2Zero, E2One, E2Two = sizeof(std::underlying_type<E2>::type) }; +// enum class E3 { E3Zero, E3One, E3Two = sizeof(std::underlying_type<E3>::type) }; +// enum struct E4 : unsigned { E4Zero, E4One, E4Two = sizeof(std::underlying_type<E4>::type) }; +// enum struct E5 { E5Zero, E5One, E5Two = sizeof(std::underlying_type<E5>::type) }; +// enum class E6 : unsigned { E6Zero, E6One, E6Two = sizeof(std::underlying_type<E6>::type) }; + +// These error messages will have to change if clang ever gets fixed. But at least they're being rejected. +enum E7 : std::underlying_type_t<E7> {}; // expected-error {{use of undeclared identifier 'E7'}} +enum class E8 : std::underlying_type_t<E8> {}; // expected-error {{use of undeclared identifier 'E8'}} +enum struct E9 : std::underlying_type_t<E9> {}; // expected-error {{use of undeclared identifier 'E9'}} + +int main(int, char**) +{ + return 0; +} diff --git a/libcxx/test/std/utilities/meta/meta.trans/meta.trans.other/underlying_type.pass.cpp b/libcxx/test/std/utilities/meta/meta.trans/meta.trans.other/underlying_type.pass.cpp index 21f7408696b..fbbab50049d 100644 --- a/libcxx/test/std/utilities/meta/meta.trans/meta.trans.other/underlying_type.pass.cpp +++ b/libcxx/test/std/utilities/meta/meta.trans/meta.trans.other/underlying_type.pass.cpp @@ -9,46 +9,94 @@ // type_traits // underlying_type +// As of C++20, std::underlying_type is SFINAE-friendly; if you hand it +// a non-enumeration, it returns an empty struct. #include <type_traits> #include <climits> #include "test_macros.h" -enum E { V = INT_MIN }; +// MSVC's ABI doesn't follow the standard #if !defined(_WIN32) || defined(__MINGW32__) #define TEST_UNSIGNED_UNDERLYING_TYPE 1 -#else - #define TEST_UNSIGNED_UNDERLYING_TYPE 0 // MSVC's ABI doesn't follow the Standard #endif -#if TEST_UNSIGNED_UNDERLYING_TYPE + +#if TEST_STD_VER > 17 +template <class, class = std::void_t<>> +struct has_type_member : std::false_type {}; + +template <class T> +struct has_type_member<T, + std::void_t<typename std::underlying_type<T>::type>> : std::true_type {}; + +struct S {}; +union U { int i; float f;}; +#endif + +template <typename T, typename Expected> +void check() +{ + ASSERT_SAME_TYPE(Expected, typename std::underlying_type<T>::type); +#if TEST_STD_VER > 11 + ASSERT_SAME_TYPE(Expected, typename std::underlying_type_t<T>); +#endif +} + +enum E { V = INT_MIN }; + +#ifdef TEST_UNSIGNED_UNDERLYING_TYPE enum F { W = UINT_MAX }; #endif // TEST_UNSIGNED_UNDERLYING_TYPE +#if TEST_STD_VER >= 11 +enum G : char {}; +enum class H { red, green = 20, blue }; +enum class I : long { red, green = 20, blue }; +enum struct J { red, green = 20, blue }; +enum struct K : short { red, green = 20, blue }; +#endif + int main(int, char**) { - ASSERT_SAME_TYPE(int, std::underlying_type<E>::type); -#if TEST_UNSIGNED_UNDERLYING_TYPE - ASSERT_SAME_TYPE(unsigned, std::underlying_type<F>::type); +// Basic tests + check<E, int>(); +#ifdef TEST_UNSIGNED_UNDERLYING_TYPE + check<F, unsigned>(); #endif // TEST_UNSIGNED_UNDERLYING_TYPE -#if TEST_STD_VER > 11 - ASSERT_SAME_TYPE(int, std::underlying_type_t<E>); -#if TEST_UNSIGNED_UNDERLYING_TYPE - ASSERT_SAME_TYPE(unsigned, std::underlying_type_t<F>); -#endif // TEST_UNSIGNED_UNDERLYING_TYPE -#endif // TEST_STD_VER > 11 - +// Class enums and enums with specified underlying type #if TEST_STD_VER >= 11 - enum G : char { }; + check<G, char>(); + check<H, int>(); + check<I, long>(); + check<J, int>(); + check<K, short>(); +#endif - ASSERT_SAME_TYPE(char, std::underlying_type<G>::type); -#if TEST_STD_VER > 11 - ASSERT_SAME_TYPE(char, std::underlying_type_t<G>); -#endif // TEST_STD_VER > 11 -#endif // TEST_STD_VER >= 11 +// SFINAE-able underlying_type +#if TEST_STD_VER > 17 + static_assert( has_type_member<E>::value, ""); + static_assert( has_type_member<F>::value, ""); + static_assert( has_type_member<G>::value, ""); + + static_assert(!has_type_member<void>::value, ""); + static_assert(!has_type_member<int>::value, ""); + static_assert(!has_type_member<double>::value, ""); + static_assert(!has_type_member<int[]>::value, ""); + static_assert(!has_type_member<S>::value, ""); + static_assert(!has_type_member<void (S::*)(int)>::value, ""); + static_assert(!has_type_member<void (S::*)(int, ...)>::value, ""); + static_assert(!has_type_member<U>::value, ""); + static_assert(!has_type_member<void(int)>::value, ""); + static_assert(!has_type_member<void(int, ...)>::value, ""); + static_assert(!has_type_member<int&>::value, ""); + static_assert(!has_type_member<int&&>::value, ""); + static_assert(!has_type_member<int*>::value, ""); + static_assert(!has_type_member<std::nullptr_t>::value, ""); +#endif return 0; } |