[clang] 9cc2122 - [Clang][libc++] Implement __is_nothrow_convertible and use it in libc++ (#80436)

via cfe-commits cfe-commits at lists.llvm.org
Fri Feb 2 10:16:03 PST 2024


Author: Nikolas Klauser
Date: 2024-02-02T19:15:58+01:00
New Revision: 9cc2122bf5a81f7063c2a32b2cb78c8d615578a1

URL: https://github.com/llvm/llvm-project/commit/9cc2122bf5a81f7063c2a32b2cb78c8d615578a1
DIFF: https://github.com/llvm/llvm-project/commit/9cc2122bf5a81f7063c2a32b2cb78c8d615578a1.diff

LOG: [Clang][libc++] Implement __is_nothrow_convertible and use it in libc++ (#80436)

GCC 13 has implemented this builtin.

Added: 
    

Modified: 
    clang/docs/LanguageExtensions.rst
    clang/include/clang/Basic/TokenKinds.def
    clang/lib/Sema/SemaExprCXX.cpp
    clang/test/SemaCXX/type-traits.cpp
    libcxx/include/__type_traits/is_nothrow_convertible.h

Removed: 
    


################################################################################
diff  --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst
index c1420079f7511..e91156837290f 100644
--- a/clang/docs/LanguageExtensions.rst
+++ b/clang/docs/LanguageExtensions.rst
@@ -1569,6 +1569,7 @@ The following type trait primitives are supported by Clang. Those traits marked
 * ``__is_const`` (C++, Embarcadero)
 * ``__is_constructible`` (C++, MSVC 2013)
 * ``__is_convertible`` (C++, Embarcadero)
+* ``__is_nothrow_convertible`` (C++, GNU)
 * ``__is_convertible_to`` (Microsoft):
   Synonym for ``__is_convertible``.
 * ``__is_destructible`` (C++, MSVC 2013)

diff  --git a/clang/include/clang/Basic/TokenKinds.def b/clang/include/clang/Basic/TokenKinds.def
index 9117e4376c371..23817cde7a935 100644
--- a/clang/include/clang/Basic/TokenKinds.def
+++ b/clang/include/clang/Basic/TokenKinds.def
@@ -567,6 +567,7 @@ TYPE_TRAIT_1(__is_unsigned, IsUnsigned, KEYCXX)
 // Embarcadero Binary Type Traits
 TYPE_TRAIT_2(__is_same, IsSame, KEYCXX)
 TYPE_TRAIT_2(__is_convertible, IsConvertible, KEYCXX)
+TYPE_TRAIT_2(__is_nothrow_convertible, IsNothrowConvertible, KEYCXX)
 ARRAY_TYPE_TRAIT(__array_rank, ArrayRank, KEYCXX)
 ARRAY_TYPE_TRAIT(__array_extent, ArrayExtent, KEYCXX)
 // Name for GCC 6 compatibility.

diff  --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index 3a32754e5376e..246d2313e089f 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -5779,7 +5779,8 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, QualType LhsT,
     return Self.Context.typesAreCompatible(Lhs, Rhs);
   }
   case BTT_IsConvertible:
-  case BTT_IsConvertibleTo: {
+  case BTT_IsConvertibleTo:
+  case BTT_IsNothrowConvertible: {
     // C++0x [meta.rel]p4:
     //   Given the following function prototype:
     //
@@ -5840,7 +5841,13 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, QualType LhsT,
       return false;
 
     ExprResult Result = Init.Perform(Self, To, Kind, FromPtr);
-    return !Result.isInvalid() && !SFINAE.hasErrorOccurred();
+    if (Result.isInvalid() || SFINAE.hasErrorOccurred())
+      return false;
+
+    if (BTT != BTT_IsNothrowConvertible)
+      return true;
+
+    return Self.canThrow(Result.get()) == CT_Cannot;
   }
 
   case BTT_IsAssignable:

diff  --git a/clang/test/SemaCXX/type-traits.cpp b/clang/test/SemaCXX/type-traits.cpp
index c5d196a2590f8..5659594577111 100644
--- a/clang/test/SemaCXX/type-traits.cpp
+++ b/clang/test/SemaCXX/type-traits.cpp
@@ -2118,7 +2118,7 @@ struct IntWrapper
 {
   int value;
   IntWrapper(int _value) : value(_value) {}
-  operator int() const {
+  operator int() const noexcept {
     return value;
   }
 };
@@ -2126,7 +2126,7 @@ struct IntWrapper
 struct FloatWrapper
 {
   float value;
-  FloatWrapper(float _value) : value(_value) {}
+  FloatWrapper(float _value) noexcept : value(_value) {}
   FloatWrapper(const IntWrapper& obj)
     : value(static_cast<float>(obj.value)) {}
   operator float() const {
@@ -2149,6 +2149,18 @@ void is_convertible()
   int t08[T(__is_convertible(float, FloatWrapper))];
 }
 
+void is_nothrow_convertible()
+{
+  int t01[T(__is_nothrow_convertible(IntWrapper, IntWrapper))];
+  int t02[T(__is_nothrow_convertible(IntWrapper, const IntWrapper))];
+  int t03[T(__is_nothrow_convertible(IntWrapper, int))];
+  int t04[F(__is_nothrow_convertible(int, IntWrapper))];
+  int t05[F(__is_nothrow_convertible(IntWrapper, FloatWrapper))];
+  int t06[F(__is_nothrow_convertible(FloatWrapper, IntWrapper))];
+  int t07[F(__is_nothrow_convertible(FloatWrapper, float))];
+  int t08[T(__is_nothrow_convertible(float, FloatWrapper))];
+}
+
 struct FromInt { FromInt(int); };
 struct ToInt { operator int(); };
 typedef void Function();

diff  --git a/libcxx/include/__type_traits/is_nothrow_convertible.h b/libcxx/include/__type_traits/is_nothrow_convertible.h
index eda7a49d7224c..bfc5a94cbadec 100644
--- a/libcxx/include/__type_traits/is_nothrow_convertible.h
+++ b/libcxx/include/__type_traits/is_nothrow_convertible.h
@@ -26,6 +26,16 @@ _LIBCPP_BEGIN_NAMESPACE_STD
 
 #if _LIBCPP_STD_VER >= 20
 
+#  if __has_builtin(__is_nothrow_convertible)
+
+template <class _Tp, class _Up>
+struct is_nothrow_convertible : bool_constant<__is_nothrow_convertible(_Tp, _Up)> {};
+
+template <class _Tp, class _Up>
+inline constexpr bool is_nothrow_convertible_v = __is_nothrow_convertible(_Tp, _Up);
+
+#  else // __has_builtin(__is_nothrow_convertible)
+
 template <typename _Tp>
 void __test_noexcept(_Tp) noexcept;
 
@@ -43,6 +53,8 @@ struct is_nothrow_convertible
 template <typename _Fm, typename _To>
 inline constexpr bool is_nothrow_convertible_v = is_nothrow_convertible<_Fm, _To>::value;
 
+#  endif // __has_builtin(__is_nothrow_convertible)
+
 #endif // _LIBCPP_STD_VER >= 20
 
 _LIBCPP_END_NAMESPACE_STD


        


More information about the cfe-commits mailing list