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

Patch by me and Ryan Molden.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@178111 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index 1724624..b586fd7 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -2975,10 +2975,13 @@
     // 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 @@
   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 @@
       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 @@
       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 @@
     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: