Skip to content

Commit

Permalink
[libc++] [C++2b] [P1048] Add is_scoped_enum and is_scoped_enum_v.
Browse files Browse the repository at this point in the history
* https://wg21.link/p1048

Reviewed By: ldionne, #libc

Differential Revision: https://reviews.llvm.org/D94409
  • Loading branch information
mkurdej committed Jan 12, 2021
1 parent 9667d15 commit 1f12501
Show file tree
Hide file tree
Showing 8 changed files with 155 additions and 26 deletions.
2 changes: 1 addition & 1 deletion libcxx/docs/Cxx2bStatusPaperStatus.csv
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"Paper #","Group","Paper Name","Meeting","Status","First released version"
"`P0881R7 <https://wg21.link/P0881R7>`__","LWG","A Proposal to add stacktrace library","Autumn 2020","",""
"`P0943R6 <https://wg21.link/P0943R6>`__","LWG","Support C atomics in C++","Autumn 2020","",""
"`P1048R1 <https://wg21.link/P1048R1>`__","LWG","A proposal for a type trait to detect scoped enumerations","Autumn 2020","",""
"`P1048R1 <https://wg21.link/P1048R1>`__","LWG","A proposal for a type trait to detect scoped enumerations","Autumn 2020","|Complete|","12.0"
"`P1679R3 <https://wg21.link/P1679R3>`__","LWG","string contains function","Autumn 2020","",""
"","","","","",""
2 changes: 1 addition & 1 deletion libcxx/docs/FeatureTestMacroTable.rst
Original file line number Diff line number Diff line change
Expand Up @@ -292,7 +292,7 @@ Status
------------------------------------------------- -----------------
**C++ 2b**
-------------------------------------------------------------------
``__cpp_lib_is_scoped_enum`` *unimplemented*
``__cpp_lib_is_scoped_enum`` ``202011L``
------------------------------------------------- -----------------
``__cpp_lib_stacktrace`` *unimplemented*
------------------------------------------------- -----------------
Expand Down
22 changes: 22 additions & 0 deletions libcxx/include/type_traits
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ namespace std
template <class T> struct is_arithmetic;
template <class T> struct is_fundamental;
template <class T> struct is_member_pointer;
template <class T> struct is_scoped_enum; // C++2b
template <class T> struct is_scalar;
template <class T> struct is_object;
template <class T> struct is_compound;
Expand Down Expand Up @@ -284,6 +285,8 @@ namespace std
= is_compound<T>::value; // C++17
template <class T> inline constexpr bool is_member_pointer_v
= is_member_pointer<T>::value; // C++17
template <class T> inline constexpr bool is_scoped_enum_v
= is_scoped_enum<T>::value; // C++2b
// See C++14 20.10.4.3, type properties
template <class T> inline constexpr bool is_const_v
Expand Down Expand Up @@ -4177,6 +4180,25 @@ struct __has_operator_addressof

#endif // _LIBCPP_CXX03_LANG

// is_scoped_enum [meta.unary.prop]

#if _LIBCPP_STD_VER > 20
template <class _Tp, bool = is_enum_v<_Tp> >
struct __is_scoped_enum_helper : false_type {};

template <class _Tp>
struct __is_scoped_enum_helper<_Tp, true>
: public bool_constant<!is_convertible_v<_Tp, underlying_type_t<_Tp> > > {};

template <class _Tp>
struct _LIBCPP_TEMPLATE_VIS is_scoped_enum
: public __is_scoped_enum_helper<_Tp> {};

template <class _Tp>
_LIBCPP_INLINE_VAR _LIBCPP_CONSTEXPR bool is_scoped_enum_v =
is_scoped_enum<_Tp>::value;
#endif

#if _LIBCPP_STD_VER > 14

template <class... _Args>
Expand Down
2 changes: 1 addition & 1 deletion libcxx/include/version
Original file line number Diff line number Diff line change
Expand Up @@ -355,7 +355,7 @@ __cpp_lib_void_t 201411L <type_traits>
#endif

#if _LIBCPP_STD_VER > 20
// # define __cpp_lib_is_scoped_enum 202011L
# define __cpp_lib_is_scoped_enum 202011L
// # define __cpp_lib_stacktrace 202011L
// # define __cpp_lib_stdatomic_h 202011L
// # define __cpp_lib_string_contains 202011L
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -638,17 +638,11 @@
# endif
# endif

# if !defined(_LIBCPP_VERSION)
# ifndef __cpp_lib_is_scoped_enum
# error "__cpp_lib_is_scoped_enum should be defined in c++2b"
# endif
# if __cpp_lib_is_scoped_enum != 202011L
# error "__cpp_lib_is_scoped_enum should have the value 202011L in c++2b"
# endif
# else // _LIBCPP_VERSION
# ifdef __cpp_lib_is_scoped_enum
# error "__cpp_lib_is_scoped_enum should not be defined because it is unimplemented in libc++!"
# endif
#ifndef __cpp_lib_is_scoped_enum
#error "__cpp_lib_is_scoped_enum should be defined in c++2b"
#endif
#if __cpp_lib_is_scoped_enum != 202011L
#error "__cpp_lib_is_scoped_enum should have the value 202011L in c++2b"
# endif

# ifndef __cpp_lib_is_swappable
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3983,17 +3983,11 @@
# endif
# endif

# if !defined(_LIBCPP_VERSION)
# ifndef __cpp_lib_is_scoped_enum
# error "__cpp_lib_is_scoped_enum should be defined in c++2b"
# endif
# if __cpp_lib_is_scoped_enum != 202011L
# error "__cpp_lib_is_scoped_enum should have the value 202011L in c++2b"
# endif
# else // _LIBCPP_VERSION
# ifdef __cpp_lib_is_scoped_enum
# error "__cpp_lib_is_scoped_enum should not be defined because it is unimplemented in libc++!"
# endif
#ifndef __cpp_lib_is_scoped_enum
#error "__cpp_lib_is_scoped_enum should be defined in c++2b"
#endif
#if __cpp_lib_is_scoped_enum != 202011L
#error "__cpp_lib_is_scoped_enum should have the value 202011L in c++2b"
# endif

# ifndef __cpp_lib_is_swappable
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
//===----------------------------------------------------------------------===//
//
// 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, c++17, c++2a

// type_traits

// is_scoped_enum // C++2b

#include <type_traits>
#include <cstddef> // for std::nullptr_t
#include "test_macros.h"

template <class T>
void test_positive() {
static_assert(std::is_scoped_enum<T>::value);
static_assert(std::is_scoped_enum<const T>::value);
static_assert(std::is_scoped_enum<volatile T>::value);
static_assert(std::is_scoped_enum<const volatile T>::value);

static_assert(std::is_scoped_enum_v<T>);
static_assert(std::is_scoped_enum_v<const T>);
static_assert(std::is_scoped_enum_v<volatile T>);
static_assert(std::is_scoped_enum_v<const volatile T>);
}

template <class T>
void test_negative() {
static_assert(!std::is_scoped_enum<T>::value);
static_assert(!std::is_scoped_enum<const T>::value);
static_assert(!std::is_scoped_enum<volatile T>::value);
static_assert(!std::is_scoped_enum<const volatile T>::value);

static_assert(!std::is_scoped_enum_v<T>);
static_assert(!std::is_scoped_enum_v<const T>);
static_assert(!std::is_scoped_enum_v<volatile T>);
static_assert(!std::is_scoped_enum_v<const volatile T>);
}

class Empty {};

class NotEmpty {
virtual ~NotEmpty();
};

union Union {};

struct bit_zero {
int : 0;
};

class Abstract {
virtual ~Abstract() = 0;
};

enum Enum { zero, one };
enum class CEnum1 { zero, one };
enum class CEnum2;
enum class CEnum3 : short;
struct incomplete_type;

using FunctionPtr = void (*)();
using FunctionType = void();

struct TestMembers {
static int static_method(int) { return 0; }
int method() { return 0; }

enum E1 { m_zero, m_one };
enum class CE1;
};

void func1();
int func2(int);

int main(int, char**) {
test_positive<CEnum1>();
test_positive<CEnum2>();
test_positive<CEnum3>();
test_positive<TestMembers::CE1>();

test_negative<Enum>();
test_negative<TestMembers::E1>();

test_negative<std::nullptr_t>();
test_negative<void>();
test_negative<int>();
test_negative<int&>();
test_negative<int&&>();
test_negative<int*>();
test_negative<double>();
test_negative<const int*>();
test_negative<char[3]>();
test_negative<char[]>();
test_negative<Union>();
test_negative<Empty>();
test_negative<bit_zero>();
test_negative<NotEmpty>();
test_negative<Abstract>();
test_negative<FunctionPtr>();
test_negative<FunctionType>();
test_negative<incomplete_type>();
test_negative<int TestMembers::*>();
test_negative<void (TestMembers::*)()>();

test_negative<decltype(func1)>();
test_negative<decltype(&func1)>();
test_negative<decltype(func2)>();
test_negative<decltype(&func2)>();
test_negative<decltype(TestMembers::static_method)>();
test_negative<decltype(&TestMembers::static_method)>();
test_negative<decltype(&TestMembers::method)>();

return 0;
}
1 change: 0 additions & 1 deletion libcxx/utils/generate_feature_test_macro_components.py
Original file line number Diff line number Diff line change
Expand Up @@ -368,7 +368,6 @@ def add_version_header(tc):
"name": "__cpp_lib_is_scoped_enum",
"values": { "c++2b": 202011 },
"headers": ["type_traits"],
"unimplemented": True,
}, {
"name": "__cpp_lib_is_swappable",
"values": { "c++17": 201603 },
Expand Down

0 comments on commit 1f12501

Please sign in to comment.