r178111 - Implement compiler intrinsics needed for compatibility with MSVC 2012 <type_traits>.

Joao Matos ripzonetriton at gmail.com
Tue Mar 26 18:34:17 PDT 2013


Author: triton
Date: Tue Mar 26 20:34:16 2013
New Revision: 178111

URL: http://llvm.org/viewvc/llvm-project?rev=178111&view=rev
Log:
Implement compiler intrinsics needed for compatibility with MSVC 2012 <type_traits>.

Patch by me and Ryan Molden.


Modified:
    cfe/trunk/include/clang/Basic/TokenKinds.def
    cfe/trunk/include/clang/Basic/TypeTraits.h
    cfe/trunk/lib/AST/StmtPrinter.cpp
    cfe/trunk/lib/Parse/ParseExpr.cpp
    cfe/trunk/lib/Parse/ParseExprCXX.cpp
    cfe/trunk/lib/Sema/SemaExprCXX.cpp
    cfe/trunk/test/SemaCXX/type-traits.cpp

Modified: cfe/trunk/include/clang/Basic/TokenKinds.def
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/TokenKinds.def?rev=178111&r1=178110&r2=178111&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/TokenKinds.def (original)
+++ cfe/trunk/include/clang/Basic/TokenKinds.def Tue Mar 26 20:34:16 2013
@@ -351,31 +351,34 @@ KEYWORD(typeof                      , KE
 KEYWORD(L__FUNCTION__               , KEYMS)
 
 // GNU and MS Type Traits
-KEYWORD(__has_nothrow_assign        , KEYCXX)
-KEYWORD(__has_nothrow_copy          , KEYCXX)
-KEYWORD(__has_nothrow_constructor   , KEYCXX)
-KEYWORD(__has_trivial_assign        , KEYCXX)
-KEYWORD(__has_trivial_copy          , KEYCXX)
-KEYWORD(__has_trivial_constructor   , KEYCXX)
-KEYWORD(__has_trivial_destructor    , KEYCXX)
-KEYWORD(__has_virtual_destructor    , KEYCXX)
-KEYWORD(__is_abstract               , KEYCXX)
-KEYWORD(__is_base_of                , KEYCXX)
-KEYWORD(__is_class                  , KEYCXX)
-KEYWORD(__is_convertible_to         , KEYCXX)
-KEYWORD(__is_empty                  , KEYCXX)
-KEYWORD(__is_enum                   , KEYCXX)
-KEYWORD(__is_final                  , KEYCXX)
-KEYWORD(__is_interface_class        , KEYCXX)
+KEYWORD(__has_nothrow_assign          , KEYCXX)
+KEYWORD(__has_nothrow_move_assign     , KEYCXX)
+KEYWORD(__has_nothrow_copy            , KEYCXX)
+KEYWORD(__has_nothrow_constructor     , KEYCXX)
+KEYWORD(__has_trivial_assign          , KEYCXX)
+KEYWORD(__has_trivial_move_assign     , KEYCXX)
+KEYWORD(__has_trivial_copy            , KEYCXX)
+KEYWORD(__has_trivial_constructor     , KEYCXX)
+KEYWORD(__has_trivial_move_constructor, KEYCXX)
+KEYWORD(__has_trivial_destructor      , KEYCXX)
+KEYWORD(__has_virtual_destructor      , KEYCXX)
+KEYWORD(__is_abstract                 , KEYCXX)
+KEYWORD(__is_base_of                  , KEYCXX)
+KEYWORD(__is_class                    , KEYCXX)
+KEYWORD(__is_convertible_to           , KEYCXX)
+KEYWORD(__is_empty                    , KEYCXX)
+KEYWORD(__is_enum                     , KEYCXX)
+KEYWORD(__is_final                    , KEYCXX)
+KEYWORD(__is_interface_class          , KEYCXX)
 // Tentative name - there's no implementation of std::is_literal_type yet.
-KEYWORD(__is_literal                , KEYCXX)
+KEYWORD(__is_literal                  , KEYCXX)
 // Name for GCC 4.6 compatibility - people have already written libraries using
 // this name unfortunately.
-KEYWORD(__is_literal_type           , KEYCXX)
-KEYWORD(__is_pod                    , KEYCXX)
-KEYWORD(__is_polymorphic            , KEYCXX)
-KEYWORD(__is_trivial                , KEYCXX)
-KEYWORD(__is_union                  , KEYCXX)
+KEYWORD(__is_literal_type             , KEYCXX)
+KEYWORD(__is_pod                      , KEYCXX)
+KEYWORD(__is_polymorphic              , KEYCXX)
+KEYWORD(__is_trivial                  , KEYCXX)
+KEYWORD(__is_union                    , KEYCXX)
 
 // Clang-only C++ Type Traits
 KEYWORD(__is_trivially_constructible, KEYCXX)

Modified: cfe/trunk/include/clang/Basic/TypeTraits.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/TypeTraits.h?rev=178111&r1=178110&r2=178111&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/TypeTraits.h (original)
+++ cfe/trunk/include/clang/Basic/TypeTraits.h Tue Mar 26 20:34:16 2013
@@ -20,11 +20,14 @@ namespace clang {
   /// \brief Names for the unary type traits.
   enum UnaryTypeTrait {
     UTT_HasNothrowAssign,
+    UTT_HasNothrowMoveAssign,
     UTT_HasNothrowCopy,
     UTT_HasNothrowConstructor,
     UTT_HasTrivialAssign,
+    UTT_HasTrivialMoveAssign,
     UTT_HasTrivialCopy,
     UTT_HasTrivialDefaultConstructor,
+    UTT_HasTrivialMoveConstructor,
     UTT_HasTrivialDestructor,
     UTT_HasVirtualDestructor,
     UTT_IsAbstract,

Modified: cfe/trunk/lib/AST/StmtPrinter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/StmtPrinter.cpp?rev=178111&r1=178110&r2=178111&view=diff
==============================================================================
--- cfe/trunk/lib/AST/StmtPrinter.cpp (original)
+++ cfe/trunk/lib/AST/StmtPrinter.cpp Tue Mar 26 20:34:16 2013
@@ -1558,9 +1558,12 @@ void StmtPrinter::VisitUnresolvedMemberE
 static const char *getTypeTraitName(UnaryTypeTrait UTT) {
   switch (UTT) {
   case UTT_HasNothrowAssign:      return "__has_nothrow_assign";
+  case UTT_HasNothrowMoveAssign:  return "__has_nothrow_move_assign";
   case UTT_HasNothrowConstructor: return "__has_nothrow_constructor";
   case UTT_HasNothrowCopy:          return "__has_nothrow_copy";
   case UTT_HasTrivialAssign:      return "__has_trivial_assign";
+  case UTT_HasTrivialMoveAssign:      return "__has_trivial_move_assign";
+  case UTT_HasTrivialMoveConstructor: return "__has_trivial_move_constructor";
   case UTT_HasTrivialDefaultConstructor: return "__has_trivial_constructor";
   case UTT_HasTrivialCopy:          return "__has_trivial_copy";
   case UTT_HasTrivialDestructor:  return "__has_trivial_destructor";

Modified: cfe/trunk/lib/Parse/ParseExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseExpr.cpp?rev=178111&r1=178110&r2=178111&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseExpr.cpp (original)
+++ cfe/trunk/lib/Parse/ParseExpr.cpp Tue Mar 26 20:34:16 2013
@@ -1188,10 +1188,13 @@ ExprResult Parser::ParseCastExpression(b
   case tok::kw___is_union:
   case tok::kw___is_final:
   case tok::kw___has_trivial_constructor:
+  case tok::kw___has_trivial_move_constructor:
   case tok::kw___has_trivial_copy:
   case tok::kw___has_trivial_assign:
+  case tok::kw___has_trivial_move_assign:
   case tok::kw___has_trivial_destructor:
   case tok::kw___has_nothrow_assign:
+  case tok::kw___has_nothrow_move_assign:
   case tok::kw___has_nothrow_copy:
   case tok::kw___has_nothrow_constructor:
   case tok::kw___has_virtual_destructor:

Modified: cfe/trunk/lib/Parse/ParseExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseExprCXX.cpp?rev=178111&r1=178110&r2=178111&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseExprCXX.cpp (original)
+++ cfe/trunk/lib/Parse/ParseExprCXX.cpp Tue Mar 26 20:34:16 2013
@@ -2511,11 +2511,15 @@ static UnaryTypeTrait UnaryTypeTraitFrom
   switch(kind) {
   default: llvm_unreachable("Not a known unary type trait.");
   case tok::kw___has_nothrow_assign:      return UTT_HasNothrowAssign;
+  case tok::kw___has_nothrow_move_assign: return UTT_HasNothrowMoveAssign;
   case tok::kw___has_nothrow_constructor: return UTT_HasNothrowConstructor;
   case tok::kw___has_nothrow_copy:           return UTT_HasNothrowCopy;
   case tok::kw___has_trivial_assign:      return UTT_HasTrivialAssign;
+  case tok::kw___has_trivial_move_assign: return UTT_HasTrivialMoveAssign;
   case tok::kw___has_trivial_constructor:
                                     return UTT_HasTrivialDefaultConstructor;
+  case tok::kw___has_trivial_move_constructor:
+                                    return UTT_HasTrivialMoveConstructor;
   case tok::kw___has_trivial_copy:           return UTT_HasTrivialCopy;
   case tok::kw___has_trivial_destructor:  return UTT_HasTrivialDestructor;
   case tok::kw___has_virtual_destructor:  return UTT_HasVirtualDestructor;

Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=178111&r1=178110&r2=178111&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Tue Mar 26 20:34:16 2013
@@ -2975,10 +2975,13 @@ static bool CheckUnaryTypeTraitTypeCompl
     // type due to the overarching C++0x type predicates being implemented
     // requiring the complete type.
   case UTT_HasNothrowAssign:
+  case UTT_HasNothrowMoveAssign:
   case UTT_HasNothrowConstructor:
   case UTT_HasNothrowCopy:
   case UTT_HasTrivialAssign:
+  case UTT_HasTrivialMoveAssign:
   case UTT_HasTrivialDefaultConstructor:
+  case UTT_HasTrivialMoveConstructor:
   case UTT_HasTrivialCopy:
   case UTT_HasTrivialDestructor:
   case UTT_HasVirtualDestructor:
@@ -2997,6 +3000,42 @@ static bool CheckUnaryTypeTraitTypeCompl
   llvm_unreachable("Type trait not handled by switch");
 }
 
+static bool HasNoThrowOperator(const RecordType *RT, OverloadedOperatorKind Op,
+                               Sema &Self, SourceLocation KeyLoc, ASTContext &C,
+                               bool (CXXRecordDecl::*HasTrivial)() const, 
+                               bool (CXXRecordDecl::*HasNonTrivial)() const, 
+                               bool (CXXMethodDecl::*IsDesiredOp)() const)
+{
+  CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
+  if ((RD->*HasTrivial)() && !(RD->*HasNonTrivial)())
+    return true;
+
+  DeclarationName Name = C.DeclarationNames.getCXXOperatorName(Op);
+  DeclarationNameInfo NameInfo(Name, KeyLoc);
+  LookupResult Res(Self, NameInfo, Sema::LookupOrdinaryName);
+  if (Self.LookupQualifiedName(Res, RD)) {
+    bool FoundOperator = false;
+    Res.suppressDiagnostics();
+    for (LookupResult::iterator Op = Res.begin(), OpEnd = Res.end();
+         Op != OpEnd; ++Op) {
+      if (isa<FunctionTemplateDecl>(*Op))
+        continue;
+
+      CXXMethodDecl *Operator = cast<CXXMethodDecl>(*Op);
+      if((Operator->*IsDesiredOp)()) {
+        FoundOperator = true;
+        const FunctionProtoType *CPT =
+          Operator->getType()->getAs<FunctionProtoType>();
+        CPT = Self.ResolveExceptionSpec(KeyLoc, CPT);
+        if (!CPT || !CPT->isNothrow(Self.Context))
+          return false;
+      }
+    }
+    return FoundOperator;
+  }
+  return false;
+}
+
 static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT,
                                    SourceLocation KeyLoc, QualType T) {
   assert(!T->isDependentType() && "Cannot evaluate traits of dependent type");
@@ -3133,6 +3172,15 @@ static bool EvaluateUnaryTypeTrait(Sema
       return RD->hasTrivialDefaultConstructor() &&
              !RD->hasNonTrivialDefaultConstructor();
     return false;
+  case UTT_HasTrivialMoveConstructor:
+    //  This trait is implemented by MSVC 2012 and needed to parse the
+    //  standard library headers. Specifically this is used as the logic
+    //  behind std::is_trivially_move_constructible (20.9.4.3).
+    if (T.isPODType(Self.Context))
+      return true;
+    if (CXXRecordDecl *RD = C.getBaseElementType(T)->getAsCXXRecordDecl())
+      return RD->hasTrivialMoveConstructor() && !RD->hasNonTrivialMoveConstructor();
+    return false;
   case UTT_HasTrivialCopy:
     // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html:
     //   If __is_pod (type) is true or type is a reference type then
@@ -3145,6 +3193,15 @@ static bool EvaluateUnaryTypeTrait(Sema
       return RD->hasTrivialCopyConstructor() &&
              !RD->hasNonTrivialCopyConstructor();
     return false;
+  case UTT_HasTrivialMoveAssign:
+    //  This trait is implemented by MSVC 2012 and needed to parse the
+    //  standard library headers. Specifically it is used as the logic
+    //  behind std::is_trivially_move_assignable (20.9.4.3)
+    if (T.isPODType(Self.Context))
+      return true;
+    if (CXXRecordDecl *RD = C.getBaseElementType(T)->getAsCXXRecordDecl())
+      return RD->hasTrivialMoveAssignment() && !RD->hasNonTrivialMoveAssignment();
+    return false;
   case UTT_HasTrivialAssign:
     // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html:
     //   If type is const qualified or is a reference type then the
@@ -3198,38 +3255,26 @@ static bool EvaluateUnaryTypeTrait(Sema
     if (T->isReferenceType())
       return false;
     if (T.isPODType(Self.Context) || T->isObjCLifetimeType())
-      return true;     
-    if (CXXRecordDecl *RD = T->getAsCXXRecordDecl()) {
-      if (RD->hasTrivialCopyAssignment() && !RD->hasNonTrivialCopyAssignment())
-        return true;
+      return true;
 
-      bool FoundAssign = false;
-      DeclarationName Name = C.DeclarationNames.getCXXOperatorName(OO_Equal);
-      LookupResult Res(Self, DeclarationNameInfo(Name, KeyLoc),
-                       Sema::LookupOrdinaryName);
-      if (Self.LookupQualifiedName(Res, RD)) {
-        Res.suppressDiagnostics();
-        for (LookupResult::iterator Op = Res.begin(), OpEnd = Res.end();
-             Op != OpEnd; ++Op) {
-          if (isa<FunctionTemplateDecl>(*Op))
-            continue;
-          
-          CXXMethodDecl *Operator = cast<CXXMethodDecl>(*Op);
-          if (Operator->isCopyAssignmentOperator()) {
-            FoundAssign = true;
-            const FunctionProtoType *CPT
-                = Operator->getType()->getAs<FunctionProtoType>();
-            CPT = Self.ResolveExceptionSpec(KeyLoc, CPT);
-            if (!CPT)
-              return false;
-            if (!CPT->isNothrow(Self.Context))
-              return false;
-          }
-        }
-      }
-      
-      return FoundAssign;
-    }
+    if (const RecordType *RT = T->getAs<RecordType>())
+      return HasNoThrowOperator(RT, OO_Equal, Self, KeyLoc, C,
+                                &CXXRecordDecl::hasTrivialCopyAssignment,
+                                &CXXRecordDecl::hasNonTrivialCopyAssignment,
+                                &CXXMethodDecl::isCopyAssignmentOperator);
+    return false;
+  case UTT_HasNothrowMoveAssign:
+    //  This trait is implemented by MSVC 2012 and needed to parse the
+    //  standard library headers. Specifically this is used as the logic
+    //  behind std::is_nothrow_move_assignable (20.9.4.3).
+    if (T.isPODType(Self.Context))
+      return true;
+
+    if (const RecordType *RT = C.getBaseElementType(T)->getAs<RecordType>())
+      return HasNoThrowOperator(RT, OO_Equal, Self, KeyLoc, C,
+                                &CXXRecordDecl::hasTrivialMoveAssignment,
+                                &CXXRecordDecl::hasNonTrivialMoveAssignment,
+                                &CXXMethodDecl::isMoveAssignmentOperator);
     return false;
   case UTT_HasNothrowCopy:
     // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html:

Modified: cfe/trunk/test/SemaCXX/type-traits.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/type-traits.cpp?rev=178111&r1=178110&r2=178111&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/type-traits.cpp (original)
+++ cfe/trunk/test/SemaCXX/type-traits.cpp Tue Mar 26 20:34:16 2013
@@ -39,9 +39,34 @@ struct DerivesEmpty : Empty {};
 struct HasCons { HasCons(int); };
 struct HasCopyAssign { HasCopyAssign operator =(const HasCopyAssign&); };
 struct HasMoveAssign { HasMoveAssign operator =(const HasMoveAssign&&); };
+struct HasNoThrowMoveAssign { 
+  HasNoThrowMoveAssign& operator=(
+    const HasNoThrowMoveAssign&&) throw(); };
+struct HasNoExceptNoThrowMoveAssign { 
+  HasNoExceptNoThrowMoveAssign& operator=(
+    const HasNoExceptNoThrowMoveAssign&&) noexcept; 
+};
+struct HasThrowMoveAssign { 
+  HasThrowMoveAssign& operator=(
+    const HasThrowMoveAssign&&) throw(POD); };
+struct HasNoExceptFalseMoveAssign { 
+  HasNoExceptFalseMoveAssign& operator=(
+    const HasNoExceptFalseMoveAssign&&) noexcept(false); };
+struct HasMoveCtor { HasMoveCtor(const HasMoveCtor&&); };
+struct HasMemberMoveCtor { HasMoveCtor member; };
+struct HasMemberMoveAssign { HasMoveAssign member; };
+struct HasStaticMemberMoveCtor { static HasMoveCtor member; };
+struct HasStaticMemberMoveAssign { static HasMoveAssign member; };
+struct HasMemberThrowMoveAssign { HasThrowMoveAssign member; };
+struct HasMemberNoExceptFalseMoveAssign { 
+  HasNoExceptFalseMoveAssign member; };
+struct HasMemberNoThrowMoveAssign { HasNoThrowMoveAssign member; };
+struct HasMemberNoExceptNoThrowMoveAssign { 
+  HasNoExceptNoThrowMoveAssign member; };
+
 struct HasDefaultTrivialCopyAssign { 
-  HasDefaultTrivialCopyAssign &operator =(const HasDefaultTrivialCopyAssign&)
-    = default; 
+  HasDefaultTrivialCopyAssign &operator=(
+    const HasDefaultTrivialCopyAssign&) = default; 
 };
 struct TrivialMoveButNotCopy { 
   TrivialMoveButNotCopy &operator=(TrivialMoveButNotCopy&&) = default;
@@ -69,6 +94,7 @@ struct DerivesHasPriv : HasPriv {};
 struct DerivesHasProt : HasProt {};
 struct DerivesHasRef : HasRef {};
 struct DerivesHasVirt : HasVirt {};
+struct DerivesHasMoveCtor : HasMoveCtor {};
 
 struct HasNoThrowCopyAssign {
   void operator =(const HasNoThrowCopyAssign&) throw();
@@ -165,7 +191,7 @@ typedef Empty EmptyAr[10];
 struct Bit0 { int : 0; };
 struct Bit0Cons { int : 0; Bit0Cons(); };
 struct BitOnly { int x : 3; };
-//struct DerivesVirt : virtual POD {};
+struct DerivesVirt : virtual POD {};
 
 void is_empty()
 {
@@ -941,6 +967,19 @@ struct AllDefaulted {
   ~AllDefaulted() = default;
 };
 
+struct NoDefaultMoveAssignDueToUDCopyCtor {
+  NoDefaultMoveAssignDueToUDCopyCtor(const NoDefaultMoveAssignDueToUDCopyCtor&);
+};
+
+struct NoDefaultMoveAssignDueToUDCopyAssign {
+  NoDefaultMoveAssignDueToUDCopyAssign& operator=(
+    const NoDefaultMoveAssignDueToUDCopyAssign&);
+};
+
+struct NoDefaultMoveAssignDueToDtor {
+  ~NoDefaultMoveAssignDueToDtor();
+};
+
 struct AllDeleted {
   AllDeleted() = delete;
   AllDeleted(const AllDeleted &) = delete;
@@ -1203,6 +1242,32 @@ void has_trivial_default_constructor() {
   { int arr[F(__has_trivial_constructor(ExtDefaulted))]; }
 }
 
+void has_trivial_move_constructor() {
+  // n3376 12.8 [class.copy]/12
+  // A copy/move constructor for class X is trivial if it is not 
+  // user-provided, its declared parameter type is the same as 
+  // if it had been implicitly declared, and if
+  //   — class X has no virtual functions (10.3) and no virtual 
+  //     base classes (10.1), and
+  //   — the constructor selected to copy/move each direct base 
+  //     class subobject is trivial, and
+  //   — for each non-static data member of X that is of class 
+  //     type (or array thereof), the constructor selected
+  //     to copy/move that member is trivial;
+  // otherwise the copy/move constructor is non-trivial.
+  { int arr[T(__has_trivial_move_constructor(POD))]; }
+  { int arr[T(__has_trivial_move_constructor(Union))]; }
+  { int arr[T(__has_trivial_move_constructor(HasCons))]; }
+  { int arr[T(__has_trivial_move_constructor(HasStaticMemberMoveCtor))]; }
+  { int arr[T(__has_trivial_move_constructor(AllDeleted))]; }
+  
+  { int arr[F(__has_trivial_move_constructor(HasVirt))]; }
+  { int arr[F(__has_trivial_move_constructor(DerivesVirt))]; }
+  { int arr[F(__has_trivial_move_constructor(HasMoveCtor))]; }
+  { int arr[F(__has_trivial_move_constructor(DerivesHasMoveCtor))]; }
+  { int arr[F(__has_trivial_move_constructor(HasMemberMoveCtor))]; }
+}
+
 void has_trivial_copy_constructor() {
   { int arr[T(__has_trivial_copy(Int))]; }
   { int arr[T(__has_trivial_copy(IntAr))]; }
@@ -1355,6 +1420,54 @@ void has_nothrow_assign() {
   { int arr[F(__has_nothrow_assign(PR11110))]; }
 }
 
+void has_nothrow_move_assign() {
+  { int arr[T(__has_nothrow_move_assign(Int))]; }
+  { int arr[T(__has_nothrow_move_assign(Enum))]; }
+  { int arr[T(__has_nothrow_move_assign(Int*))]; }
+  { int arr[T(__has_nothrow_move_assign(Enum POD::*))]; }
+  { int arr[T(__has_nothrow_move_assign(POD))]; }
+  { int arr[T(__has_nothrow_move_assign(HasPriv))]; }
+  { int arr[T(__has_nothrow_move_assign(HasNoThrowMoveAssign))]; }
+  { int arr[T(__has_nothrow_move_assign(HasNoExceptNoThrowMoveAssign))]; }
+  { int arr[T(__has_nothrow_move_assign(HasMemberNoThrowMoveAssign))]; }
+  { int arr[T(__has_nothrow_move_assign(HasMemberNoExceptNoThrowMoveAssign))]; }
+  { int arr[T(__has_nothrow_move_assign(AllDeleted))]; }
+
+
+  { int arr[F(__has_nothrow_move_assign(HasThrowMoveAssign))]; }
+  { int arr[F(__has_nothrow_move_assign(HasNoExceptFalseMoveAssign))]; }
+  { int arr[F(__has_nothrow_move_assign(HasMemberThrowMoveAssign))]; }
+  { int arr[F(__has_nothrow_move_assign(HasMemberNoExceptFalseMoveAssign))]; }
+  { int arr[F(__has_nothrow_move_assign(NoDefaultMoveAssignDueToUDCopyCtor))]; }
+  { int arr[F(__has_nothrow_move_assign(NoDefaultMoveAssignDueToUDCopyAssign))]; }
+  { int arr[F(__has_nothrow_move_assign(NoDefaultMoveAssignDueToDtor))]; }
+}
+
+void has_trivial_move_assign() {
+  // n3376 12.8 [class.copy]/25
+  // A copy/move assignment operator for class X is trivial if it 
+  // is not user-provided, its declared parameter type is the same 
+  // as if it had been implicitly declared, and if:
+  //  — class X has no virtual functions (10.3) and no virtual base 
+  //    classes (10.1), and
+  //  — the assignment operator selected to copy/move each direct 
+  //    base class subobject is trivial, and
+  //  — for each non-static data member of X that is of class type 
+  //    (or array thereof), the assignment operator
+  //    selected to copy/move that member is trivial;
+  { int arr[T(__has_trivial_move_assign(Int))]; }
+  { int arr[T(__has_trivial_move_assign(HasStaticMemberMoveAssign))]; }
+  { int arr[T(__has_trivial_move_assign(AllDeleted))]; }
+
+  { int arr[F(__has_trivial_move_assign(HasVirt))]; }
+  { int arr[F(__has_trivial_move_assign(DerivesVirt))]; }
+  { int arr[F(__has_trivial_move_assign(HasMoveAssign))]; }
+  { int arr[F(__has_trivial_move_assign(DerivesHasMoveAssign))]; }
+  { int arr[F(__has_trivial_move_assign(HasMemberMoveAssign))]; }
+  { int arr[F(__has_nothrow_move_assign(NoDefaultMoveAssignDueToUDCopyCtor))]; }
+  { int arr[F(__has_nothrow_move_assign(NoDefaultMoveAssignDueToUDCopyAssign))]; }
+}
+
 void has_nothrow_copy() {
   { int arr[T(__has_nothrow_copy(Int))]; }
   { int arr[T(__has_nothrow_copy(IntAr))]; }





More information about the cfe-commits mailing list