Clang support for __is_assignable intrinsic

MSVC now supports the __is_assignable type trait intrinsic,
to enable easier and more efficient implementation of the
Standard Library's is_assignable trait.
As of Visual Studio 2015 Update 3, the VC Standard Library
implementation uses the new intrinsic unconditionally.

The implementation is pretty straightforward due to the previously
existing is_nothrow_assignable and is_trivially_assignable.
We handle __is_assignable via the same code as the other two except
that we skip the extra checks for nothrow or triviality.

Patch by Dave Bartolomeo!

Differential Revision: http://reviews.llvm.org/D20492

llvm-svn: 270458
This commit is contained in:
David Majnemer 2016-05-23 17:21:55 +00:00
parent cd3ebfe293
commit b3d96882ec
11 changed files with 62 additions and 0 deletions

View File

@ -1022,6 +1022,7 @@ The following type trait primitives are supported by Clang:
* ``__is_nothrow_assignable`` (MSVC 2013, clang)
* ``__is_constructible`` (MSVC 2013, clang)
* ``__is_nothrow_constructible`` (MSVC 2013, clang)
* ``__is_assignable`` (MSVC 2015, clang)
Blocks
======

View File

@ -407,6 +407,9 @@ TYPE_TRAIT_2(__is_nothrow_assignable, IsNothrowAssignable, KEYCXX)
TYPE_TRAIT_N(__is_constructible, IsConstructible, KEYCXX)
TYPE_TRAIT_N(__is_nothrow_constructible, IsNothrowConstructible, KEYCXX)
// MSVC14.0 / VS2015 Type Traits
TYPE_TRAIT_2(__is_assignable, IsAssignable, KEYCXX)
// GNU and MS Type Traits
TYPE_TRAIT_1(__has_nothrow_assign, HasNothrowAssign, KEYCXX)
TYPE_TRAIT_1(__has_nothrow_move_assign, HasNothrowMoveAssign, KEYCXX)

View File

@ -74,6 +74,7 @@ namespace clang {
BTT_IsConvertibleTo,
BTT_IsSame,
BTT_TypeCompatible,
BTT_IsAssignable,
BTT_IsNothrowAssignable,
BTT_IsTriviallyAssignable,
BTT_Last = BTT_IsTriviallyAssignable,

View File

@ -1196,6 +1196,7 @@ static bool HasFeature(const Preprocessor &PP, StringRef Feature) {
.Case("has_trivial_destructor", LangOpts.CPlusPlus)
.Case("has_virtual_destructor", LangOpts.CPlusPlus)
.Case("is_abstract", LangOpts.CPlusPlus)
.Case("is_assignable", LangOpts.CPlusPlus)
.Case("is_base_of", LangOpts.CPlusPlus)
.Case("is_class", LangOpts.CPlusPlus)
.Case("is_constructible", LangOpts.CPlusPlus)

View File

@ -1269,6 +1269,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
Tok.isOneOf(tok::kw___is_abstract,
tok::kw___is_arithmetic,
tok::kw___is_array,
tok::kw___is_assignable,
tok::kw___is_base_of,
tok::kw___is_class,
tok::kw___is_complete_type,

View File

@ -796,6 +796,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
REVERTIBLE_TYPE_TRAIT(__is_abstract);
REVERTIBLE_TYPE_TRAIT(__is_arithmetic);
REVERTIBLE_TYPE_TRAIT(__is_array);
REVERTIBLE_TYPE_TRAIT(__is_assignable);
REVERTIBLE_TYPE_TRAIT(__is_base_of);
REVERTIBLE_TYPE_TRAIT(__is_class);
REVERTIBLE_TYPE_TRAIT(__is_complete_type);

View File

@ -4459,6 +4459,7 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, QualType LhsT,
return !Result.isInvalid() && !SFINAE.hasErrorOccurred();
}
case BTT_IsAssignable:
case BTT_IsNothrowAssignable:
case BTT_IsTriviallyAssignable: {
// C++11 [meta.unary.prop]p3:
@ -4506,6 +4507,9 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, QualType LhsT,
if (Result.isInvalid() || SFINAE.hasErrorOccurred())
return false;
if (BTT == BTT_IsAssignable)
return true;
if (BTT == BTT_IsNothrowAssignable)
return Self.canThrow(Result.get()) == CT_Cannot;

View File

@ -45,6 +45,11 @@ int is_abstract();
#endif
// CHECK: int is_abstract();
#if __has_feature(is_assignable)
int is_assignable();
#endif
// CHECK: int is_assignable();
#if __has_feature(is_base_of)
int is_base_of();
#endif

View File

@ -18,6 +18,7 @@ bool copy_construct_int = n::is_trivially_constructible<int, const int&>::value;
bool _is_abstract_result = __is_abstract(int);
bool _is_arithmetic_result = __is_arithmetic(int);
bool _is_array_result = __is_array(int);
bool _is_assignable_result = __is_assignable(int, int);
bool _is_base_of_result = __is_base_of(int, int);
bool _is_class_result = __is_class(int);
bool _is_complete_type_result = __is_complete_type(int);

View File

@ -20,6 +20,7 @@ struct is_trivially_constructible {
struct __is_abstract {}; // expected-warning {{made available}}
struct __is_arithmetic {}; // expected-warning {{made available}}
struct __is_array {}; // expected-warning {{made available}}
struct __is_assignable {}; // expected-warning {{made available}}
struct __is_base_of {}; // expected-warning {{made available}}
struct __is_class {}; // expected-warning {{made available}}
struct __is_complete_type {}; // expected-warning {{made available}}

View File

@ -1514,6 +1514,9 @@ void has_nothrow_move_assign() {
{ int arr[T(__is_nothrow_assignable(HasNoThrowMoveAssign, HasNoThrowMoveAssign))]; }
{ int arr[F(__is_nothrow_assignable(HasThrowMoveAssign, HasThrowMoveAssign))]; }
{ int arr[T(__is_assignable(HasNoThrowMoveAssign, HasNoThrowMoveAssign))]; }
{ int arr[T(__is_assignable(HasThrowMoveAssign, HasThrowMoveAssign))]; }
}
void has_trivial_move_assign() {
@ -1974,6 +1977,46 @@ void trivial_checks()
TrivialMoveButNotCopy)))]; }
{ int arr[T((__is_trivially_assignable(TrivialMoveButNotCopy&,
TrivialMoveButNotCopy&&)))]; }
{ int arr[T((__is_trivially_assignable(int&, int)))]; }
{ int arr[T((__is_trivially_assignable(int&, int&)))]; }
{ int arr[T((__is_trivially_assignable(int&, int&&)))]; }
{ int arr[T((__is_trivially_assignable(int&, const int&)))]; }
{ int arr[T((__is_trivially_assignable(POD&, POD)))]; }
{ int arr[T((__is_trivially_assignable(POD&, POD&)))]; }
{ int arr[T((__is_trivially_assignable(POD&, POD&&)))]; }
{ int arr[T((__is_trivially_assignable(POD&, const POD&)))]; }
{ int arr[T((__is_trivially_assignable(int*&, int*)))]; }
{ int arr[T((__is_trivially_assignable(AllDefaulted,
const AllDefaulted &)))]; }
{ int arr[T((__is_trivially_assignable(AllDefaulted,
AllDefaulted &&)))]; }
{ int arr[F((__is_assignable(int *&, float *)))]; }
{ int arr[T((__is_assignable(HasCopyAssign &, HasCopyAssign)))]; }
{ int arr[T((__is_assignable(HasCopyAssign &, HasCopyAssign &)))]; }
{ int arr[T((__is_assignable(HasCopyAssign &, const HasCopyAssign &)))]; }
{ int arr[T((__is_assignable(HasCopyAssign &, HasCopyAssign &&)))]; }
{ int arr[T((__is_assignable(TrivialMoveButNotCopy &,
TrivialMoveButNotCopy &)))]; }
{ int arr[T((__is_assignable(TrivialMoveButNotCopy &,
const TrivialMoveButNotCopy &)))]; }
{ int arr[F((__is_assignable(AllDeleted,
const AllDeleted &)))]; }
{ int arr[F((__is_assignable(AllDeleted,
AllDeleted &&)))]; }
{ int arr[T((__is_assignable(ExtDefaulted,
const ExtDefaulted &)))]; }
{ int arr[T((__is_assignable(ExtDefaulted,
ExtDefaulted &&)))]; }
{ int arr[T((__is_assignable(HasDefaultTrivialCopyAssign &,
HasDefaultTrivialCopyAssign &)))]; }
{ int arr[T((__is_assignable(HasDefaultTrivialCopyAssign &,
const HasDefaultTrivialCopyAssign &)))]; }
{ int arr[T((__is_assignable(TrivialMoveButNotCopy &,
TrivialMoveButNotCopy)))]; }
{ int arr[T((__is_assignable(TrivialMoveButNotCopy &,
TrivialMoveButNotCopy &&)))]; }
}
void constructible_checks() {