diff mbox series

[committed] libstdc++: Add std::is_scoped_enum for C++23

Message ID YFUFeY7SpkPrTNc9@redhat.com
State New
Headers show
Series [committed] libstdc++: Add std::is_scoped_enum for C++23 | expand

Commit Message

Jonathan Wakely March 19, 2021, 8:11 p.m. UTC
Implement this C++23 feature, as proposed by P1048R1.

This implementation assumes that a C++23 compiler supports concepts
already. I don't see any point in using preprocessor hacks to detect
compilers which define __cplusplus to a post-C++20 value but don't
support concepts yet.

libstdc++-v3/ChangeLog:

	* include/std/type_traits (is_scoped_enum): Define.
	* include/std/version (__cpp_lib_is_scoped_enum): Define.
	* testsuite/20_util/is_scoped_enum/value.cc: New test.
	* testsuite/20_util/is_scoped_enum/version.cc: New test.

Tested powerpc64le-linux. Committed to trunk.
commit b8ecdc772703729b75fba8b4bb94acfcb6f7cfae
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Fri Mar 19 19:42:18 2021

    libstdc++: Add std::is_scoped_enum for C++23
    
    Implement this C++23 feature, as proposed by P1048R1.
    
    This implementation assumes that a C++23 compiler supports concepts
    already. I don't see any point in using preprocessor hacks to detect
    compilers which define __cplusplus to a post-C++20 value but don't
    support concepts yet.
    
    libstdc++-v3/ChangeLog:
    
            * include/std/type_traits (is_scoped_enum): Define.
            * include/std/version (__cpp_lib_is_scoped_enum): Define.
            * testsuite/20_util/is_scoped_enum/value.cc: New test.
            * testsuite/20_util/is_scoped_enum/version.cc: New test.

Comments

Tim Song March 20, 2021, 1:11 a.m. UTC | #1
On Fri, Mar 19, 2021 at 3:13 PM Jonathan Wakely via Libstdc++
<libstdc++@gcc.gnu.org> wrote:
>
> Implement this C++23 feature, as proposed by P1048R1.
>
> This implementation assumes that a C++23 compiler supports concepts
> already. I don't see any point in using preprocessor hacks to detect
> compilers which define __cplusplus to a post-C++20 value but don't
> support concepts yet.
>
> libstdc++-v3/ChangeLog:
>
>         * include/std/type_traits (is_scoped_enum): Define.
>         * include/std/version (__cpp_lib_is_scoped_enum): Define.
>         * testsuite/20_util/is_scoped_enum/value.cc: New test.
>         * testsuite/20_util/is_scoped_enum/version.cc: New test.
>
> Tested powerpc64le-linux. Committed to trunk.
>

Using __underlying_type breaks for incomplete enumeration types. GCC
doesn't have incomplete scoped enums due to
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=89025 but unscoped ones
exist:

enum E {
    x = std::is_scoped_enum_v<E>
};
Jonathan Wakely March 20, 2021, 8:58 a.m. UTC | #2
On Sat, 20 Mar 2021, 01:13 Tim Song via Libstdc++, <libstdc++@gcc.gnu.org>
wrote:

> On Fri, Mar 19, 2021 at 3:13 PM Jonathan Wakely via Libstdc++
> <libstdc++@gcc.gnu.org> wrote:
> >
> > Implement this C++23 feature, as proposed by P1048R1.
> >
> > This implementation assumes that a C++23 compiler supports concepts
> > already. I don't see any point in using preprocessor hacks to detect
> > compilers which define __cplusplus to a post-C++20 value but don't
> > support concepts yet.
> >
> > libstdc++-v3/ChangeLog:
> >
> >         * include/std/type_traits (is_scoped_enum): Define.
> >         * include/std/version (__cpp_lib_is_scoped_enum): Define.
> >         * testsuite/20_util/is_scoped_enum/value.cc: New test.
> >         * testsuite/20_util/is_scoped_enum/version.cc: New test.
> >
> > Tested powerpc64le-linux. Committed to trunk.
> >
>
> Using __underlying_type breaks for incomplete enumeration types. GCC
> doesn't have incomplete scoped enums due to
> https://gcc.gnu.org/bugzilla/show_bug.cgi?id=89025 but unscoped ones
> exist:
>
> enum E {
>     x = std::is_scoped_enum_v<E>
> };
>

Thanks, I'll just use int then. Maybe not until Monday though.
Tim Song March 20, 2021, 2:18 p.m. UTC | #3
On Sat, Mar 20, 2021 at 3:58 AM Jonathan Wakely <jwakely.gcc@gmail.com> wrote:
>
>
>
> On Sat, 20 Mar 2021, 01:13 Tim Song via Libstdc++, <libstdc++@gcc.gnu.org> wrote:
>>
>> On Fri, Mar 19, 2021 at 3:13 PM Jonathan Wakely via Libstdc++
>> <libstdc++@gcc.gnu.org> wrote:
>> >
>> > Implement this C++23 feature, as proposed by P1048R1.
>> >
>> > This implementation assumes that a C++23 compiler supports concepts
>> > already. I don't see any point in using preprocessor hacks to detect
>> > compilers which define __cplusplus to a post-C++20 value but don't
>> > support concepts yet.
>> >
>> > libstdc++-v3/ChangeLog:
>> >
>> >         * include/std/type_traits (is_scoped_enum): Define.
>> >         * include/std/version (__cpp_lib_is_scoped_enum): Define.
>> >         * testsuite/20_util/is_scoped_enum/value.cc: New test.
>> >         * testsuite/20_util/is_scoped_enum/version.cc: New test.
>> >
>> > Tested powerpc64le-linux. Committed to trunk.
>> >
>>
>> Using __underlying_type breaks for incomplete enumeration types. GCC
>> doesn't have incomplete scoped enums due to
>> https://gcc.gnu.org/bugzilla/show_bug.cgi?id=89025 but unscoped ones
>> exist:
>>
>> enum E {
>>     x = std::is_scoped_enum_v<E>
>> };
>
>
> Thanks, I'll just use int then. Maybe not until Monday though.
>
>

Using int avoids the hard error, but it appears to give the wrong
answer (presumably because the is_convertible check fails due to E
being incomplete). This may need to be handled explicitly?
Jonathan Wakely April 8, 2021, 11:09 a.m. UTC | #4
On 20/03/21 09:18 -0500, Tim Song wrote:
>On Sat, Mar 20, 2021 at 3:58 AM Jonathan Wakely <jwakely.gcc@gmail.com> wrote:
>>
>>
>>
>> On Sat, 20 Mar 2021, 01:13 Tim Song via Libstdc++, <libstdc++@gcc.gnu.org> wrote:
>>>
>>> On Fri, Mar 19, 2021 at 3:13 PM Jonathan Wakely via Libstdc++
>>> <libstdc++@gcc.gnu.org> wrote:
>>> >
>>> > Implement this C++23 feature, as proposed by P1048R1.
>>> >
>>> > This implementation assumes that a C++23 compiler supports concepts
>>> > already. I don't see any point in using preprocessor hacks to detect
>>> > compilers which define __cplusplus to a post-C++20 value but don't
>>> > support concepts yet.
>>> >
>>> > libstdc++-v3/ChangeLog:
>>> >
>>> >         * include/std/type_traits (is_scoped_enum): Define.
>>> >         * include/std/version (__cpp_lib_is_scoped_enum): Define.
>>> >         * testsuite/20_util/is_scoped_enum/value.cc: New test.
>>> >         * testsuite/20_util/is_scoped_enum/version.cc: New test.
>>> >
>>> > Tested powerpc64le-linux. Committed to trunk.
>>> >
>>>
>>> Using __underlying_type breaks for incomplete enumeration types. GCC
>>> doesn't have incomplete scoped enums due to
>>> https://gcc.gnu.org/bugzilla/show_bug.cgi?id=89025 but unscoped ones
>>> exist:
>>>
>>> enum E {
>>>     x = std::is_scoped_enum_v<E>
>>> };
>>
>>
>> Thanks, I'll just use int then. Maybe not until Monday though.
>>
>>
>
>Using int avoids the hard error, but it appears to give the wrong
>answer (presumably because the is_convertible check fails due to E
>being incomplete). This may need to be handled explicitly?

This seems to work, at least until PR 89025 is fixed (because you
can't currently refer to an incomplete scoped enum type).

Tested powerpc64le-linux, pushed to trunk.
diff mbox series

Patch

diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index ad2672d36a6..eeab1ca65fc 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -3279,6 +3279,23 @@  template <typename _From, typename _To>
     inline constexpr bool is_unbounded_array_v
       = is_unbounded_array<_Tp>::value;
 
+#if __cplusplus > 202002L
+#define __cpp_lib_is_scoped_enum 202011L
+
+  template<typename _Tp>
+    struct is_scoped_enum
+    : false_type
+    { };
+
+  template<typename _Tp> requires __is_enum(_Tp)
+    struct is_scoped_enum<_Tp>
+    : __not_<is_convertible<_Tp, __underlying_type(_Tp)>>::type
+    { };
+
+  template<typename _Tp>
+    inline constexpr bool is_scoped_enum_v = is_scoped_enum<_Tp>::value;
+#endif // C++23
+
 #ifdef _GLIBCXX_HAVE_BUILTIN_IS_CONSTANT_EVALUATED
 
 #define __cpp_lib_is_constant_evaluated 201811L
diff --git a/libstdc++-v3/include/std/version b/libstdc++-v3/include/std/version
index e9eca06a72a..cb25148fca5 100644
--- a/libstdc++-v3/include/std/version
+++ b/libstdc++-v3/include/std/version
@@ -259,6 +259,7 @@ 
 
 #if __cplusplus > 202002L
 // c++2b
+#define __cpp_lib_is_scoped_enum 202011L
 #define __cpp_lib_string_contains 202011L
 #define __cpp_lib_to_underlying 202102L
 #endif // C++2b
diff --git a/libstdc++-v3/testsuite/20_util/is_scoped_enum/value.cc b/libstdc++-v3/testsuite/20_util/is_scoped_enum/value.cc
new file mode 100644
index 00000000000..bab7263ae4a
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/is_scoped_enum/value.cc
@@ -0,0 +1,62 @@ 
+// Copyright (C) 2021 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++23" }
+// { dg-do compile { target c++23 } }
+
+#include <type_traits>
+
+#ifndef __cpp_lib_is_scoped_enum
+# error "Feature test macro for is_scoped_enum is missing in <type_traits>"
+#elif __cpp_lib_is_scoped_enum < 202011L
+# error "Feature test macro for is_scoped_enum has wrong value in <type_traits>"
+#endif
+
+#include <testsuite_tr1.h>
+
+template<typename T>
+  concept Is_scoped_enum
+    = __gnu_test::test_category<std::is_scoped_enum, T>(true);
+
+void
+test01()
+{
+  enum class E { e1, e2 };
+  static_assert( Is_scoped_enum<E> );
+  enum class Ec : char { e1, e2 };
+  static_assert( Is_scoped_enum<Ec> );
+
+  // negative tests
+  enum U { u1, u2 };
+  static_assert( ! Is_scoped_enum<U> );
+  enum F : int { f1, f2 };
+  static_assert( ! Is_scoped_enum<F> );
+  struct S { };
+  static_assert( ! Is_scoped_enum<S> );
+
+  static_assert( ! Is_scoped_enum<int> );
+  static_assert( ! Is_scoped_enum<int[]> );
+  static_assert( ! Is_scoped_enum<int[2]> );
+  static_assert( ! Is_scoped_enum<int[][2]> );
+  static_assert( ! Is_scoped_enum<int[2][3]> );
+  static_assert( ! Is_scoped_enum<int*> );
+  static_assert( ! Is_scoped_enum<int&> );
+  static_assert( ! Is_scoped_enum<int*&> );
+  static_assert( ! Is_scoped_enum<int()> );
+  static_assert( ! Is_scoped_enum<int(*)()> );
+  static_assert( ! Is_scoped_enum<int(&)()> );
+}
diff --git a/libstdc++-v3/testsuite/20_util/is_scoped_enum/version.cc b/libstdc++-v3/testsuite/20_util/is_scoped_enum/version.cc
new file mode 100644
index 00000000000..ed78fce5fbe
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/is_scoped_enum/version.cc
@@ -0,0 +1,27 @@ 
+// Copyright (C) 2021 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++23" }
+// { dg-do compile { target c++23 } }
+
+#include <version>
+
+#ifndef __cpp_lib_is_scoped_enum
+# error "Feature test macro for is_scoped_enum is missing in <version>"
+#elif __cpp_lib_is_scoped_enum < 202011L
+# error "Feature test macro for is_scoped_enum has wrong value in <version>"
+#endif