Begin tracking trivialness of move constructors and move assignment
operators in C++ record declarations.

This patch starts off by updating a bunch of the standard citations to
refer to the draft 0x standard so that the semantics intended for move
varianst is clear. Where necessary these are duplicated so they'll be
available in doxygen.

It adds bit fields to keep track of the state for the move constructs,
and updates all the code necessary to track this state (I think) as
members are declared for a class. It also wires the state into the
various trait-like accessors in the AST's API, and tests that the type
trait expressions now behave correctly in the presence of move
constructors and move assignment operators.

This isn't complete yet due to these glaring FIXMEs:
1) No synthesis of implicit move constructors or assignment operators.
2) I don't think we correctly enforce the new logic for both copy and
   move trivial checks: that the *selected* copy/move
   constructor/operator is trivial. Currently this requires *all* of them
   to be trivial.
3) Some of the trait logic needs to be folded into the fine-grained
   trivial bits to more closely match the wording of the standard. For
   example, many of the places we currently set a bit to track POD-ness
   could be removed by querying other more fine grained traits on
   demand.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@130076 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp
index 015b49a..af796d5 100644
--- a/lib/AST/DeclCXX.cpp
+++ b/lib/AST/DeclCXX.cpp
@@ -32,7 +32,8 @@
     UserDeclaredCopyAssignment(false), UserDeclaredDestructor(false),
     Aggregate(true), PlainOldData(true), Empty(true), Polymorphic(false),
     Abstract(false), HasTrivialConstructor(true),
-    HasTrivialCopyConstructor(true), HasTrivialCopyAssignment(true),
+    HasTrivialCopyConstructor(true), HasTrivialMoveConstructor(true),
+    HasTrivialCopyAssignment(true), HasTrivialMoveAssignment(true),
     HasTrivialDestructor(true), ComputedVisibleConversions(false),
     DeclaredDefaultConstructor(false), DeclaredCopyConstructor(false), 
     DeclaredCopyAssignment(false), DeclaredDestructor(false),
@@ -139,16 +140,20 @@
       // C++ [class.ctor]p5:
       //   A constructor is trivial if its class has no virtual base classes.
       data().HasTrivialConstructor = false;
-      
-      // C++ [class.copy]p6:
-      //   A copy constructor is trivial if its class has no virtual base 
-      //   classes.
+
+      // C++0x [class.copy]p13:
+      //   A copy/move constructor for class X is trivial if it is neither
+      //   user-provided nor deleted and if
+      //    -- class X has no virtual functions and no virtual base classes, and
       data().HasTrivialCopyConstructor = false;
-      
-      // C++ [class.copy]p11:
-      //   A copy assignment operator is trivial if its class has no virtual
-      //   base classes.
+      data().HasTrivialMoveConstructor = false;
+
+      // C++0x [class.copy]p27:
+      //   A copy/move assignment operator for class X is trivial if it is
+      //   neither user-provided nor deleted and if
+      //    -- class X has no virtual functions and no virtual base classes, and
       data().HasTrivialCopyAssignment = false;
+      data().HasTrivialMoveAssignment = false;
     } else {
       // C++ [class.ctor]p5:
       //   A constructor is trivial if all the direct base classes of its
@@ -156,17 +161,29 @@
       if (!BaseClassDecl->hasTrivialConstructor())
         data().HasTrivialConstructor = false;
       
-      // C++ [class.copy]p6:
-      //   A copy constructor is trivial if all the direct base classes of its
-      //   class have trivial copy constructors.
+      // C++0x [class.copy]p13:
+      //   A copy/move constructor for class X is trivial if [...]
+      //    [...]
+      //    -- the constructor selected to copy/move each direct base class
+      //       subobject is trivial, and
+      // FIXME: C++0x: We need to only consider the selected constructor
+      // instead of all of them.
       if (!BaseClassDecl->hasTrivialCopyConstructor())
         data().HasTrivialCopyConstructor = false;
-      
-      // C++ [class.copy]p11:
-      //   A copy assignment operator is trivial if all the direct base classes
-      //   of its class have trivial copy assignment operators.
+      if (!BaseClassDecl->hasTrivialMoveConstructor())
+        data().HasTrivialMoveConstructor = false;
+
+      // C++0x [class.copy]p27:
+      //   A copy/move assignment operator for class X is trivial if [...]
+      //    [...]
+      //    -- the assignment operator selected to copy/move each direct base
+      //       class subobject is trivial, and
+      // FIXME: C++0x: We need to only consider the selected operator instead
+      // of all of them.
       if (!BaseClassDecl->hasTrivialCopyAssignment())
         data().HasTrivialCopyAssignment = false;
+      if (!BaseClassDecl->hasTrivialMoveAssignment())
+        data().HasTrivialMoveAssignment = false;
     }
     
     // C++ [class.ctor]p3:
@@ -223,11 +240,11 @@
   //   -- has no non-trivial copy constructors,
   if (!hasTrivialCopyConstructor()) return false;
   //   -- has no non-trivial move constructors,
-  // FIXME: C++0x: Track and check trivial move constructors.
+  if (!hasTrivialMoveConstructor()) return false;
   //   -- has no non-trivial copy assignment operators,
   if (!hasTrivialCopyAssignment()) return false;
   //   -- has no non-trivial move assignment operators, and
-  // FIXME: C++0x: Track and check trivial move assignment operators.
+  if (!hasTrivialMoveAssignment()) return false;
   //   -- has a trivial destructor.
   if (!hasTrivialDestructor()) return false;
 
@@ -374,8 +391,18 @@
       
       // None of the special member functions are trivial.
       data().HasTrivialConstructor = false;
+
+      // C++0x [class.copy]p13:
+      //   A copy/move constructor for class X is trivial if [...]
+      //    -- class X has no virtual functions [...]
       data().HasTrivialCopyConstructor = false;
+      data().HasTrivialMoveConstructor = false;
+
+      // C++0x [class.copy]p27:
+      //   A copy/move assignment operator for class X is trivial if [...]
+      //    -- class X has no virtual functions [...]
       data().HasTrivialCopyAssignment = false;
+      data().HasTrivialMoveAssignment = false;
       // FIXME: Destructor?
     }
   }
@@ -439,18 +466,27 @@
     // FIXME: C++0x: don't do this for "= default" default constructors.
     data().HasTrivialConstructor = false;
 
-    // Note when we have a user-declared copy constructor, which will
-    // suppress the implicit declaration of a copy constructor.
-    if (!FunTmpl && Constructor->isCopyConstructor()) {
-      data().UserDeclaredCopyConstructor = true;
-      data().DeclaredCopyConstructor = true;
-      
-      // C++ [class.copy]p6:
-      //   A copy constructor is trivial if it is implicitly declared.
-      // FIXME: C++0x: don't do this for "= default" copy constructors.
-      data().HasTrivialCopyConstructor = false;
+    // Note when we have a user-declared copy or move constructor, which will
+    // suppress the implicit declaration of those constructors.
+    if (!FunTmpl) {
+      if (Constructor->isCopyConstructor()) {
+        data().UserDeclaredCopyConstructor = true;
+        data().DeclaredCopyConstructor = true;
+
+        // C++0x [class.copy]p13:
+        //   A copy/move constructor for class X is trivial if it is neither
+        //   user-provided nor deleted
+        // FIXME: C++0x: don't do this for "= default" copy constructors.
+        data().HasTrivialCopyConstructor = false;
+      } else if (Constructor->isMoveConstructor()) {
+        // C++0x [class.copy]p13:
+        //   A copy/move constructor for class X is trivial if it is neither
+        //   user-provided nor deleted
+        // FIXME: C++0x: don't do this for "= default" move constructors.
+        data().HasTrivialMoveConstructor = false;
+      }
     }
-    
+
     return;
   }
 
@@ -488,35 +524,53 @@
         return;
       
       ASTContext &Context = getASTContext();
-      QualType ArgType = FnType->getArgType(0);
-      if (const LValueReferenceType *Ref =ArgType->getAs<LValueReferenceType>())
-        ArgType = Ref->getPointeeType();
-      
-      ArgType = ArgType.getUnqualifiedType();
       QualType ClassType = Context.getCanonicalType(Context.getTypeDeclType(
                                              const_cast<CXXRecordDecl*>(this)));
-      
+
+      bool isRValueRefArg = false;
+      QualType ArgType = FnType->getArgType(0);
+      if (const LValueReferenceType *Ref =
+          ArgType->getAs<LValueReferenceType>()) {
+        ArgType = Ref->getPointeeType();
+      } else if (const RValueReferenceType *Ref =
+               ArgType->getAs<RValueReferenceType>()) {
+        ArgType = Ref->getPointeeType();
+        isRValueRefArg = true;
+      }
       if (!Context.hasSameUnqualifiedType(ClassType, ArgType))
         return;
-      
-      // This is a copy assignment operator.
-      // FIXME: Move assignment operators.
-      
-      // Suppress the implicit declaration of a copy constructor.
-      data().UserDeclaredCopyAssignment = true;
-      data().DeclaredCopyAssignment = true;
-      
-      // C++ [class.copy]p11:
-      //   A copy assignment operator is trivial if it is implicitly declared.
-      // FIXME: C++0x: don't do this for "= default" copy operators.
-      data().HasTrivialCopyAssignment = false;
-      
+
       // C++ [class]p4:
-      //   A POD-struct is an aggregate class that [...] has no user-defined copy
-      //   assignment operator [...].
+      //   A POD-struct is an aggregate class that [...] has no user-defined
+      //   copy assignment operator [...].
+      // FIXME: This should be probably determined dynamically in terms of
+      // other more precise attributes to correctly model how it is specified
+      // in C++0x. Setting it here happens to do the right thing.
       data().PlainOldData = false;
+
+      if (!isRValueRefArg) {
+        // This is a copy assignment operator.
+
+        // Suppress the implicit declaration of a copy constructor.
+        data().UserDeclaredCopyAssignment = true;
+        data().DeclaredCopyAssignment = true;
+
+        // C++0x [class.copy]p27:
+        //   A copy/move assignment operator for class X is trivial if it is
+        //   neither user-provided nor deleted [...]
+        // FIXME: C++0x: don't do this for "= default" copy operators.
+        data().HasTrivialCopyAssignment = false;
+      } else {
+        // This is a move assignment operator.
+
+        // C++0x [class.copy]p27:
+        //   A copy/move assignment operator for class X is trivial if it is
+        //   neither user-provided nor deleted [...]
+        // FIXME: C++0x: don't do this for "= default" copy operators.
+        data().HasTrivialMoveAssignment = false;
+      }
     }
-    
+
     // Keep the list of conversion functions up-to-date.
     if (CXXConversionDecl *Conversion = dyn_cast<CXXConversionDecl>(D)) {
       // We don't record specializations.
@@ -556,7 +610,7 @@
       data().PlainOldData = false;
     }
     
-    // C++ [class]p9:
+    // C++0x [class]p9:
     //   A POD struct is a class that is both a trivial class and a 
     //   standard-layout class, and has no non-static data members of type 
     //   non-POD struct, non-POD union (or array of such types).
@@ -572,10 +626,31 @@
       if (FieldRec->getDefinition()) {
         if (!FieldRec->hasTrivialConstructor())
           data().HasTrivialConstructor = false;
+
+        // C++0x [class.copy]p13:
+        //   A copy/move constructor for class X is trivial if [...]
+        //    [...]
+        //    -- for each non-static data member of X that is of class type (or
+        //       an array thereof), the constructor selected to copy/move that
+        //       member is trivial;
+        // FIXME: C++0x: We don't correctly model 'selected' constructors.
         if (!FieldRec->hasTrivialCopyConstructor())
           data().HasTrivialCopyConstructor = false;
+        if (!FieldRec->hasTrivialMoveConstructor())
+          data().HasTrivialMoveConstructor = false;
+
+        // C++0x [class.copy]p27:
+        //   A copy/move assignment operator for class X is trivial if [...]
+        //    [...]
+        //    -- for each non-static data member of X that is of class type (or
+        //       an array thereof), the assignment operator selected to
+        //       copy/move that member is trivial;
+        // FIXME: C++0x: We don't correctly model 'selected' operators.
         if (!FieldRec->hasTrivialCopyAssignment())
           data().HasTrivialCopyAssignment = false;
+        if (!FieldRec->hasTrivialMoveAssignment())
+          data().HasTrivialMoveAssignment = false;
+
         if (!FieldRec->hasTrivialDestructor())
           data().HasTrivialDestructor = false;
       }