]> granicus.if.org Git - clang/commitdiff
Clang support for __is_assignable intrinsic
authorDavid Majnemer <david.majnemer@gmail.com>
Mon, 23 May 2016 17:21:55 +0000 (17:21 +0000)
committerDavid Majnemer <david.majnemer@gmail.com>
Mon, 23 May 2016 17:21:55 +0000 (17:21 +0000)
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

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@270458 91177308-0d34-0410-b5e6-96231b3b80d8

docs/LanguageExtensions.rst
include/clang/Basic/TokenKinds.def
include/clang/Basic/TypeTraits.h
lib/Lex/PPMacroExpansion.cpp
lib/Parse/ParseDeclCXX.cpp
lib/Parse/ParseExpr.cpp
lib/Sema/SemaExprCXX.cpp
test/Lexer/has_feature_type_traits.cpp
test/PCH/cxx-traits.cpp
test/PCH/cxx-traits.h
test/SemaCXX/type-traits.cpp

index 59faa9e5196f0f9bbe4e839cf381cf8ac5af8524..c715164461662ca57e323f28b157d2c835990696 100644 (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
 ======
index 9d97a81773ee4ab9654c42e215eb164125aff410..a08d280e7ea16597824dc617c9a8a14d0de86f64 100644 (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)
index 765246b4cc5491b46f3e89cc4b3390c102d7d63d..730ecba3d4fa58da4618299e7f85be3f3ed1fc26 100644 (file)
@@ -74,6 +74,7 @@ namespace clang {
     BTT_IsConvertibleTo,
     BTT_IsSame,
     BTT_TypeCompatible,
+    BTT_IsAssignable,
     BTT_IsNothrowAssignable,
     BTT_IsTriviallyAssignable,
     BTT_Last = BTT_IsTriviallyAssignable,
index df4fdbaa96e6021fe12a0669ec7c16b1628a3756..79ca9ebb706a662690853a92f9b8a275e731b827 100644 (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)
index 049e9ceae70071125a4bae562384af0bb728e175..b80f9ee1b02a7eba7e93f2ffc77b4bf7c09c732e 100644 (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,
index 5b7c839454a99c44ed2a487c5fa145e9034d66ec..927bb208c7554780bbb4f8981e325b5043ccc845 100644 (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);
index 67d2cdbb070fde8fe09e64af7bd6ae4f5cd6ecda..7365f6cc8d22c27e463305542af5913979346c1c 100644 (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;
 
index f772d6d18452a9474cd47f77d221f33e95e2828d..6636e7b39638a62c6422fea7b8cc41646636f147 100644 (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
index fc3e1335dd60c0b256dbd4de80db6ca597b925d2..b0f1d9d2c3debfa96de0e878e9bfce64d8e2caca 100644 (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);
index 21324768186eed82b5366cf87d0601c231021581..1d7d40450fe2ddd931d164ab8a61560470367435 100644 (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}}
index 69760fd6bd068762e46a63f3545e6a593909f9ed..c53b02774aca9288bf71c8975a2f42bf78b76001 100644 (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() {