[libcxx-commits] [libcxx] 43e4214 - [libc++] [C++2b] [P1682] Add to_underlying.

Marek Kurdej via libcxx-commits libcxx-commits at lists.llvm.org
Fri Mar 5 01:31:26 PST 2021


Author: Marek Kurdej
Date: 2021-03-05T10:31:21+01:00
New Revision: 43e421417378bab378eccdf88a66a0a46304fa13

URL: https://github.com/llvm/llvm-project/commit/43e421417378bab378eccdf88a66a0a46304fa13
DIFF: https://github.com/llvm/llvm-project/commit/43e421417378bab378eccdf88a66a0a46304fa13.diff

LOG: [libc++] [C++2b] [P1682] Add to_underlying.

* https://wg21.link/P1682

Reviewed By: ldionne, Mordante, #libc

Differential Revision: https://reviews.llvm.org/D97365

Added: 
    libcxx/test/std/utilities/utility/utility.underlying/to_underlying.pass.cpp
    libcxx/test/std/utilities/utility/utility.underlying/to_underlying.verify.cpp

Modified: 
    libcxx/docs/Cxx2bStatusPaperStatus.csv
    libcxx/docs/FeatureTestMacroTable.rst
    libcxx/include/utility
    libcxx/include/version
    libcxx/test/std/language.support/support.limits/support.limits.general/utility.version.pass.cpp
    libcxx/test/std/language.support/support.limits/support.limits.general/version.version.pass.cpp
    libcxx/utils/generate_feature_test_macro_components.py

Removed: 
    


################################################################################
diff  --git a/libcxx/docs/Cxx2bStatusPaperStatus.csv b/libcxx/docs/Cxx2bStatusPaperStatus.csv
index c6efa2037cff..79b5db076937 100644
--- a/libcxx/docs/Cxx2bStatusPaperStatus.csv
+++ b/libcxx/docs/Cxx2bStatusPaperStatus.csv
@@ -4,7 +4,7 @@
 "`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","|Complete|","12.0"
 "","","","","",""
-"`P1682R3 <https://wg21.link/P1682R3>`__","LWG","std::to_underlying for enumerations","February 2021","",""
+"`P1682R3 <https://wg21.link/P1682R3>`__","LWG","std::to_underlying for enumerations","February 2021","|Complete|","13.0"
 "`P2017R1 <https://wg21.link/P2017R1>`__","LWG","Conditionally borrowed ranges","February 2021","",""
 "`P2160R1 <https://wg21.link/P2160R1>`__","LWG","Locks lock lockables","February 2021","",""
 "`P2162R2 <https://wg21.link/P2162R2>`__","LWG","Inheriting from std::variant","February 2021","",""

diff  --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst
index 77010b574eb3..693a6683f702 100644
--- a/libcxx/docs/FeatureTestMacroTable.rst
+++ b/libcxx/docs/FeatureTestMacroTable.rst
@@ -301,5 +301,7 @@ Status
     ``__cpp_lib_stdatomic_h``                         *unimplemented*
     ------------------------------------------------- -----------------
     ``__cpp_lib_string_contains``                     ``202011L``
+    ------------------------------------------------- -----------------
+    ``__cpp_lib_to_underlying``                       ``202102L``
     ================================================= =================
 

diff  --git a/libcxx/include/utility b/libcxx/include/utility
index 6f27af70646b..ca3d3fe7dbaa 100644
--- a/libcxx/include/utility
+++ b/libcxx/include/utility
@@ -191,6 +191,10 @@ template <size_t I>
 template <size_t I>
   inline constexpr in_place_index_t<I> in_place_index{};
 
+// [utility.underlying], to_underlying
+template <class T>
+    constexpr underlying_type_t<T> to_underlying( T value ) noexcept; // C++2b
+
 }  // std
 
 */
@@ -1622,8 +1626,21 @@ template <class _Type, class ...>
 using __enable_hash_helper _LIBCPP_NODEBUG_TYPE = _Type;
 #endif
 
+template <class _Tp>
+_LIBCPP_INLINE_VISIBILITY constexpr typename underlying_type<_Tp>::type
+__to_underlying(_Tp __val) noexcept {
+  return static_cast<typename underlying_type<_Tp>::type>(__val);
+}
 #endif // !_LIBCPP_CXX03_LANG
 
+#if _LIBCPP_STD_VER > 20
+template <class _Tp>
+_LIBCPP_INLINE_VISIBILITY constexpr underlying_type_t<_Tp>
+to_underlying(_Tp __val) noexcept {
+  return _VSTD::__to_underlying(__val);
+}
+#endif
+
 _LIBCPP_END_NAMESPACE_STD
 
 #endif  // _LIBCPP_UTILITY

diff  --git a/libcxx/include/version b/libcxx/include/version
index 49648a0fa9e9..becbfa5c2cdb 100644
--- a/libcxx/include/version
+++ b/libcxx/include/version
@@ -150,6 +150,7 @@ __cpp_lib_three_way_comparison                          201907L <compare>
 __cpp_lib_to_address                                    201711L <memory>
 __cpp_lib_to_array                                      201907L <array>
 __cpp_lib_to_chars                                      201611L <utility>
+__cpp_lib_to_underlying                                 202102L <utility>
 __cpp_lib_transformation_trait_aliases                  201304L <type_traits>
 __cpp_lib_transparent_operators                         201510L <functional> <memory>
                                                         201210L // C++14
@@ -365,6 +366,7 @@ __cpp_lib_void_t                                        201411L <type_traits>
 // # define __cpp_lib_stacktrace                           202011L
 // # define __cpp_lib_stdatomic_h                          202011L
 # define __cpp_lib_string_contains                      202011L
+# define __cpp_lib_to_underlying                        202102L
 #endif
 
 // clang-format on

diff  --git a/libcxx/test/std/language.support/support.limits/support.limits.general/utility.version.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/utility.version.pass.cpp
index ab495be78e9a..1ec2f43fdf52 100644
--- a/libcxx/test/std/language.support/support.limits/support.limits.general/utility.version.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/utility.version.pass.cpp
@@ -22,6 +22,7 @@
     __cpp_lib_integer_comparison_functions    202002L [C++20]
     __cpp_lib_integer_sequence                201304L [C++14]
     __cpp_lib_to_chars                        201611L [C++17]
+    __cpp_lib_to_underlying                   202102L [C++2b]
     __cpp_lib_tuples_by_type                  201304L [C++14]
 */
 
@@ -54,6 +55,10 @@
 #   error "__cpp_lib_to_chars should not be defined before c++17"
 # endif
 
+# ifdef __cpp_lib_to_underlying
+#   error "__cpp_lib_to_underlying should not be defined before c++2b"
+# endif
+
 # ifdef __cpp_lib_tuples_by_type
 #   error "__cpp_lib_tuples_by_type should not be defined before c++14"
 # endif
@@ -90,6 +95,10 @@
 #   error "__cpp_lib_to_chars should not be defined before c++17"
 # endif
 
+# ifdef __cpp_lib_to_underlying
+#   error "__cpp_lib_to_underlying should not be defined before c++2b"
+# endif
+
 # ifndef __cpp_lib_tuples_by_type
 #   error "__cpp_lib_tuples_by_type should be defined in c++14"
 # endif
@@ -141,6 +150,10 @@
 #   endif
 # endif
 
+# ifdef __cpp_lib_to_underlying
+#   error "__cpp_lib_to_underlying should not be defined before c++2b"
+# endif
+
 # ifndef __cpp_lib_tuples_by_type
 #   error "__cpp_lib_tuples_by_type should be defined in c++17"
 # endif
@@ -204,6 +217,10 @@
 #   endif
 # endif
 
+# ifdef __cpp_lib_to_underlying
+#   error "__cpp_lib_to_underlying should not be defined before c++2b"
+# endif
+
 # ifndef __cpp_lib_tuples_by_type
 #   error "__cpp_lib_tuples_by_type should be defined in c++20"
 # endif
@@ -267,6 +284,13 @@
 #   endif
 # endif
 
+# ifndef __cpp_lib_to_underlying
+#   error "__cpp_lib_to_underlying should be defined in c++2b"
+# endif
+# if __cpp_lib_to_underlying != 202102L
+#   error "__cpp_lib_to_underlying should have the value 202102L in c++2b"
+# endif
+
 # ifndef __cpp_lib_tuples_by_type
 #   error "__cpp_lib_tuples_by_type should be defined in c++2b"
 # endif

diff  --git a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.pass.cpp
index 337714f1e385..3a668768d5e5 100644
--- a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.pass.cpp
@@ -140,6 +140,7 @@
     __cpp_lib_to_address                           201711L [C++20]
     __cpp_lib_to_array                             201907L [C++20]
     __cpp_lib_to_chars                             201611L [C++17]
+    __cpp_lib_to_underlying                        202102L [C++2b]
     __cpp_lib_transformation_trait_aliases         201304L [C++14]
     __cpp_lib_transparent_operators                201210L [C++14]
                                                    201510L [C++17]
@@ -642,6 +643,10 @@
 #   error "__cpp_lib_to_chars should not be defined before c++17"
 # endif
 
+# ifdef __cpp_lib_to_underlying
+#   error "__cpp_lib_to_underlying should not be defined before c++2b"
+# endif
+
 # ifdef __cpp_lib_transformation_trait_aliases
 #   error "__cpp_lib_transformation_trait_aliases should not be defined before c++14"
 # endif
@@ -1222,6 +1227,10 @@
 #   error "__cpp_lib_to_chars should not be defined before c++17"
 # endif
 
+# ifdef __cpp_lib_to_underlying
+#   error "__cpp_lib_to_underlying should not be defined before c++2b"
+# endif
+
 # ifndef __cpp_lib_transformation_trait_aliases
 #   error "__cpp_lib_transformation_trait_aliases should be defined in c++14"
 # endif
@@ -2021,6 +2030,10 @@
 #   endif
 # endif
 
+# ifdef __cpp_lib_to_underlying
+#   error "__cpp_lib_to_underlying should not be defined before c++2b"
+# endif
+
 # ifndef __cpp_lib_transformation_trait_aliases
 #   error "__cpp_lib_transformation_trait_aliases should be defined in c++17"
 # endif
@@ -3225,6 +3238,10 @@
 #   endif
 # endif
 
+# ifdef __cpp_lib_to_underlying
+#   error "__cpp_lib_to_underlying should not be defined before c++2b"
+# endif
+
 # ifndef __cpp_lib_transformation_trait_aliases
 #   error "__cpp_lib_transformation_trait_aliases should be defined in c++20"
 # endif
@@ -4456,6 +4473,13 @@
 #   endif
 # endif
 
+# ifndef __cpp_lib_to_underlying
+#   error "__cpp_lib_to_underlying should be defined in c++2b"
+# endif
+# if __cpp_lib_to_underlying != 202102L
+#   error "__cpp_lib_to_underlying should have the value 202102L in c++2b"
+# endif
+
 # ifndef __cpp_lib_transformation_trait_aliases
 #   error "__cpp_lib_transformation_trait_aliases should be defined in c++2b"
 # endif

diff  --git a/libcxx/test/std/utilities/utility/utility.underlying/to_underlying.pass.cpp b/libcxx/test/std/utilities/utility/utility.underlying/to_underlying.pass.cpp
new file mode 100644
index 000000000000..0b2bc199a831
--- /dev/null
+++ b/libcxx/test/std/utilities/utility/utility.underlying/to_underlying.pass.cpp
@@ -0,0 +1,84 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+
+// [utility.underlying], to_underlying
+// template <class T>
+//     constexpr underlying_type_t<T> to_underlying( T value ) noexcept; // C++2b
+
+#include <utility>
+#include <cassert>
+#include <limits>
+
+#include "test_macros.h"
+
+enum class e_default { a = 0, b = 1, c = 2 };
+enum class e_ushort : unsigned short { d = 10, e = 25, f = 50 };
+enum class e_longlong : long long {
+  low = std::numeric_limits<long long>::min(),
+  high = std::numeric_limits<long long>::max()
+};
+enum e_non_class { enum_a = 10, enum_b = 11, enum_c = 12 };
+enum e_int : int {
+  enum_min = std::numeric_limits<int>::min(),
+  enum_max = std::numeric_limits<int>::max()
+};
+enum class e_bool : std::uint8_t { f = 0, t = 1 };
+
+struct WithBitfieldEnums {
+  e_default e1 : 3;
+  e_ushort e2 : 6;
+  e_bool e3 : 1;
+};
+
+constexpr bool test() {
+  ASSERT_NOEXCEPT(std::to_underlying(e_default::a));
+  ASSERT_SAME_TYPE(int, decltype(std::to_underlying(e_default::a)));
+  ASSERT_SAME_TYPE(unsigned short, decltype(std::to_underlying(e_ushort::d)));
+  ASSERT_SAME_TYPE(long long, decltype(std::to_underlying(e_longlong::low)));
+  ASSERT_SAME_TYPE(int, decltype(std::to_underlying(enum_min)));
+  ASSERT_SAME_TYPE(int, decltype(std::to_underlying(enum_max)));
+
+  assert(0 == std::to_underlying(e_default::a));
+  assert(1 == std::to_underlying(e_default::b));
+  assert(2 == std::to_underlying(e_default::c));
+
+  assert(10 == std::to_underlying(e_ushort::d));
+  assert(25 == std::to_underlying(e_ushort::e));
+  assert(50 == std::to_underlying(e_ushort::f));
+
+  // Check no truncating.
+  assert(std::numeric_limits<long long>::min() ==
+         std::to_underlying(e_longlong::low));
+  assert(std::numeric_limits<long long>::max() ==
+         std::to_underlying(e_longlong::high));
+
+  assert(10 == std::to_underlying(enum_a));
+  assert(11 == std::to_underlying(enum_b));
+  assert(12 == std::to_underlying(enum_c));
+  assert(std::numeric_limits<int>::min() == std::to_underlying(enum_min));
+  assert(std::numeric_limits<int>::max() == std::to_underlying(enum_max));
+
+  WithBitfieldEnums bf;
+  bf.e1 = static_cast<e_default>(3);
+  bf.e2 = e_ushort::e;
+  bf.e3 = e_bool::t;
+  assert(3 == std::to_underlying(bf.e1));
+  assert(25 == std::to_underlying(bf.e2));
+  assert(1 == std::to_underlying(bf.e3));
+
+  return true;
+}
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+
+  return 0;
+}

diff  --git a/libcxx/test/std/utilities/utility/utility.underlying/to_underlying.verify.cpp b/libcxx/test/std/utilities/utility/utility.underlying/to_underlying.verify.cpp
new file mode 100644
index 000000000000..9064ba4067c5
--- /dev/null
+++ b/libcxx/test/std/utilities/utility/utility.underlying/to_underlying.verify.cpp
@@ -0,0 +1,24 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+
+// [utility.underlying], to_underlying
+// template <class T>
+//     constexpr underlying_type_t<T> to_underlying( T value ) noexcept; // C++2b
+
+#include <utility>
+
+struct S {};
+
+int main(int, char**) {
+  std::to_underlying(125); // expected-error {{no matching function for call}}
+  std::to_underlying(S{}); // expected-error {{no matching function for call}}
+
+  return 0;
+}

diff  --git a/libcxx/utils/generate_feature_test_macro_components.py b/libcxx/utils/generate_feature_test_macro_components.py
index 24780f87a58a..7351da3b2a4d 100755
--- a/libcxx/utils/generate_feature_test_macro_components.py
+++ b/libcxx/utils/generate_feature_test_macro_components.py
@@ -593,6 +593,10 @@ def add_version_header(tc):
     "values": { "c++17": 201611 },
     "headers": ["utility"],
     "unimplemented": True,
+  }, {
+    "name": "__cpp_lib_to_underlying",
+    "values": { "c++2b": 202102 },
+    "headers": ["utility"],
   }, {
     "name": "__cpp_lib_transformation_trait_aliases",
     "values": { "c++14": 201304 },


        


More information about the libcxx-commits mailing list