summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--clang/docs/LanguageExtensions.rst1
-rw-r--r--clang/include/clang/Basic/TokenKinds.def3
-rw-r--r--clang/include/clang/Basic/TypeTraits.h1
-rw-r--r--clang/lib/Lex/PPMacroExpansion.cpp1
-rw-r--r--clang/lib/Parse/ParseDeclCXX.cpp1
-rw-r--r--clang/lib/Parse/ParseExpr.cpp1
-rw-r--r--clang/lib/Sema/SemaExprCXX.cpp4
-rw-r--r--clang/test/Lexer/has_feature_type_traits.cpp5
-rw-r--r--clang/test/PCH/cxx-traits.cpp1
-rw-r--r--clang/test/PCH/cxx-traits.h1
-rw-r--r--clang/test/SemaCXX/type-traits.cpp43
11 files changed, 62 insertions, 0 deletions
diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst
index 59faa9e5196..c7151644616 100644
--- a/clang/docs/LanguageExtensions.rst
+++ b/clang/docs/LanguageExtensions.rst
@@ -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
======
diff --git a/clang/include/clang/Basic/TokenKinds.def b/clang/include/clang/Basic/TokenKinds.def
index 9d97a81773e..a08d280e7ea 100644
--- a/clang/include/clang/Basic/TokenKinds.def
+++ b/clang/include/clang/Basic/TokenKinds.def
@@ -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)
diff --git a/clang/include/clang/Basic/TypeTraits.h b/clang/include/clang/Basic/TypeTraits.h
index 765246b4cc5..730ecba3d4f 100644
--- a/clang/include/clang/Basic/TypeTraits.h
+++ b/clang/include/clang/Basic/TypeTraits.h
@@ -74,6 +74,7 @@ namespace clang {
BTT_IsConvertibleTo,
BTT_IsSame,
BTT_TypeCompatible,
+ BTT_IsAssignable,
BTT_IsNothrowAssignable,
BTT_IsTriviallyAssignable,
BTT_Last = BTT_IsTriviallyAssignable,
diff --git a/clang/lib/Lex/PPMacroExpansion.cpp b/clang/lib/Lex/PPMacroExpansion.cpp
index df4fdbaa96e..79ca9ebb706 100644
--- a/clang/lib/Lex/PPMacroExpansion.cpp
+++ b/clang/lib/Lex/PPMacroExpansion.cpp
@@ -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)
diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp
index 049e9ceae70..b80f9ee1b02 100644
--- a/clang/lib/Parse/ParseDeclCXX.cpp
+++ b/clang/lib/Parse/ParseDeclCXX.cpp
@@ -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,
diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp
index 5b7c839454a..927bb208c75 100644
--- a/clang/lib/Parse/ParseExpr.cpp
+++ b/clang/lib/Parse/ParseExpr.cpp
@@ -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);
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index 67d2cdbb070..7365f6cc8d2 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -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;
diff --git a/clang/test/Lexer/has_feature_type_traits.cpp b/clang/test/Lexer/has_feature_type_traits.cpp
index f772d6d1845..6636e7b3963 100644
--- a/clang/test/Lexer/has_feature_type_traits.cpp
+++ b/clang/test/Lexer/has_feature_type_traits.cpp
@@ -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
diff --git a/clang/test/PCH/cxx-traits.cpp b/clang/test/PCH/cxx-traits.cpp
index fc3e1335dd6..b0f1d9d2c3d 100644
--- a/clang/test/PCH/cxx-traits.cpp
+++ b/clang/test/PCH/cxx-traits.cpp
@@ -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);
diff --git a/clang/test/PCH/cxx-traits.h b/clang/test/PCH/cxx-traits.h
index 21324768186..1d7d40450fe 100644
--- a/clang/test/PCH/cxx-traits.h
+++ b/clang/test/PCH/cxx-traits.h
@@ -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}}
diff --git a/clang/test/SemaCXX/type-traits.cpp b/clang/test/SemaCXX/type-traits.cpp
index 69760fd6bd0..c53b02774ac 100644
--- a/clang/test/SemaCXX/type-traits.cpp
+++ b/clang/test/SemaCXX/type-traits.cpp
@@ -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() {
OpenPOWER on IntegriCloud