Skip to content

Commit

Permalink
[Clang][libc++] Implement __is_nothrow_convertible and use it in libc…
Browse files Browse the repository at this point in the history
…++ (#80436)

GCC 13 has implemented this builtin.
  • Loading branch information
philnik777 authored Feb 2, 2024
1 parent 1156bbc commit 9cc2122
Show file tree
Hide file tree
Showing 5 changed files with 37 additions and 4 deletions.
1 change: 1 addition & 0 deletions clang/docs/LanguageExtensions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/Basic/TokenKinds.def
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
11 changes: 9 additions & 2 deletions clang/lib/Sema/SemaExprCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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:
//
Expand Down Expand Up @@ -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:
Expand Down
16 changes: 14 additions & 2 deletions clang/test/SemaCXX/type-traits.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2118,15 +2118,15 @@ struct IntWrapper
{
int value;
IntWrapper(int _value) : value(_value) {}
operator int() const {
operator int() const noexcept {
return value;
}
};

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 {
Expand All @@ -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();
Expand Down
12 changes: 12 additions & 0 deletions libcxx/include/__type_traits/is_nothrow_convertible.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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
Expand Down

0 comments on commit 9cc2122

Please sign in to comment.