[clang] [libcxx] [Clang][libc++] Implement __is_nothrow_convertible and use it in libc++ (PR #80436)

via cfe-commits cfe-commits at lists.llvm.org
Fri Feb 2 06:17:37 PST 2024


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang

Author: Nikolas Klauser (philnik777)

<details>
<summary>Changes</summary>

GCC 13 has implemented this builtin.


---
Full diff: https://github.com/llvm/llvm-project/pull/80436.diff


5 Files Affected:

- (modified) clang/docs/LanguageExtensions.rst (+1) 
- (modified) clang/include/clang/Basic/TokenKinds.def (+1) 
- (modified) clang/lib/Sema/SemaExprCXX.cpp (+9-2) 
- (modified) clang/test/SemaCXX/type-traits.cpp (+14-2) 
- (modified) libcxx/include/__type_traits/is_nothrow_convertible.h (+12) 


``````````diff
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..2f9b4f953c140 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

``````````

</details>


https://github.com/llvm/llvm-project/pull/80436


More information about the cfe-commits mailing list