aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikolas Klauser <nikolasklauser@berlin.de>2024-02-02 19:15:58 +0100
committerGitHub <noreply@github.com>2024-02-02 19:15:58 +0100
commit9cc2122bf5a81f7063c2a32b2cb78c8d615578a1 (patch)
tree9d134f55f730dee29a90e3d5c85719d64bf5a268
parent1156bbc5b1837e688b0e5d6952f1a900aca29062 (diff)
downloadllvm-9cc2122bf5a81f7063c2a32b2cb78c8d615578a1.zip
llvm-9cc2122bf5a81f7063c2a32b2cb78c8d615578a1.tar.gz
llvm-9cc2122bf5a81f7063c2a32b2cb78c8d615578a1.tar.bz2
[Clang][libc++] Implement __is_nothrow_convertible and use it in libc++ (#80436)
GCC 13 has implemented this builtin.
-rw-r--r--clang/docs/LanguageExtensions.rst1
-rw-r--r--clang/include/clang/Basic/TokenKinds.def1
-rw-r--r--clang/lib/Sema/SemaExprCXX.cpp11
-rw-r--r--clang/test/SemaCXX/type-traits.cpp16
-rw-r--r--libcxx/include/__type_traits/is_nothrow_convertible.h12
5 files changed, 37 insertions, 4 deletions
diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst
index c142007..e911568 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 9117e43..23817cd 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 3a32754..246d231 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 c5d196a..5659594 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 eda7a49..bfc5a94 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